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

📄 vhd-util-scan.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 <glob.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fnmatch.h>

#include "list.h"
#include "libvhd.h"
#include "lvm-util.h"

#define VHD_SCAN_FAST        0x01
#define VHD_SCAN_PRETTY      0x02
#define VHD_SCAN_VOLUME      0x04
#define VHD_SCAN_NOFAIL      0x08
#define VHD_SCAN_VERBOSE     0x10
#define VHD_SCAN_PARENTS     0x20

#define VHD_TYPE_RAW_FILE    0x01
#define VHD_TYPE_VHD_FILE    0x02
#define VHD_TYPE_RAW_VOLUME  0x04
#define VHD_TYPE_VHD_VOLUME  0x08

static inline int
target_volume(uint8_t type)
{
	return (type == VHD_TYPE_RAW_VOLUME || type == VHD_TYPE_VHD_VOLUME);
}

static inline int
target_vhd(uint8_t type)
{
	return (type == VHD_TYPE_VHD_FILE || type == VHD_TYPE_VHD_VOLUME);
}

struct target {
	char                 name[VHD_MAX_NAME_LEN];
	char                 device[VHD_MAX_NAME_LEN];
	uint64_t             size;
	uint64_t             start;
	uint64_t             end;
	uint8_t              type;
};

struct iterator {
	int                  cur;
	int                  cur_size;
	int                  max_size;
	struct target       *targets;
};

struct vhd_image {
	char                *name;
	char                *parent;
	uint64_t             capacity;
	off64_t              size;
	uint8_t              hidden;
	int                  error;
	char                *message;

	struct target       *target;

	struct list_head     sibling;
	struct list_head     children;
	struct vhd_image    *parent_image;
};

struct vhd_scan {
	int                  cur;
	int                  size;

	int                  lists_cur;
	int                  lists_size;

	struct vhd_image   **images;
	struct vhd_image   **lists;
};

static int flags;
static struct vg vg;
static struct vhd_scan scan;

static int
vhd_util_scan_pretty_allocate_list(int cnt)
{
	int i;
	struct vhd_image *list;

	memset(&scan, 0, sizeof(scan));

	scan.lists_cur  = 1;
	scan.lists_size = 10;

	scan.lists = calloc(scan.lists_size, sizeof(struct vhd_image *));
	if (!scan.lists)
		goto fail;

	scan.lists[0] = calloc(cnt, sizeof(struct vhd_image));
	if (!scan.lists[0])
		goto fail;

	scan.images = calloc(cnt, sizeof(struct vhd_image *));
	if (!scan.images)
		goto fail;

	for (i = 0; i < cnt; i++)
		scan.images[i] = scan.lists[0] + i;

	scan.cur  = 0;
	scan.size = cnt;

	return 0;

fail:
	if (scan.lists) {
		free(scan.lists[0]);
		free(scan.lists);
	}

	free(scan.images);
	memset(&scan, 0, sizeof(scan));
	return -ENOMEM;
}

static void
vhd_util_scan_pretty_free_list(void)
{
	int i;

	if (scan.lists) {
		for (i = 0; i < scan.lists_cur; i++)
			free(scan.lists[i]);
		free(scan.lists);
	}

	free(scan.images);
	memset(&scan, 0, sizeof(scan));
}

static int
vhd_util_scan_pretty_add_image(struct vhd_image *image)
{
	int i;
	struct vhd_image *img;

	for (i = 0; i < scan.cur; i++) {
		img = scan.images[i];
		if (!strcmp(img->name, image->name))
			return 0;
	}

	if (scan.cur >= scan.size) {
		struct vhd_image *new, **list;

		if (scan.lists_cur >= scan.lists_size) {
			list = realloc(scan.lists, scan.lists_size * 2 *
				       sizeof(struct vhd_image *));
			if (!list)
				return -ENOMEM;

			scan.lists_size *= 2;
			scan.lists       = list;
		}

		new = calloc(scan.size, sizeof(struct vhd_image));
		if (!new)
			return -ENOMEM;

		scan.lists[scan.lists_cur++] = new;
		scan.size *= 2;

		list = realloc(scan.images, scan.size *
			       sizeof(struct vhd_image *));
		if (!list)
			return -ENOMEM;

		scan.images = list;
		for (i = 0; i + scan.cur < scan.size; i++)
			scan.images[i + scan.cur] = new + i;
	}

	img = scan.images[scan.cur];
	INIT_LIST_HEAD(&img->sibling);
	INIT_LIST_HEAD(&img->children);

	img->capacity = image->capacity;
	img->size     = image->size;
	img->hidden   = image->hidden;
	img->error    = image->error;
	img->message  = image->message;

	img->name = strdup(image->name);
	if (!img->name)
		goto fail;

	if (image->parent) {
		img->parent = strdup(image->parent);
		if (!img->parent)
			goto fail;
	}

	scan.cur++;
	return 0;

fail:
	free(img->name);
	free(img->parent);
	memset(img, 0, sizeof(*img));
	return -ENOMEM;
}

static int
vhd_util_scan_pretty_image_compare(const void *lhs, const void *rhs)
{
	struct vhd_image *l, *r;

	l = *(struct vhd_image **)lhs;
	r = *(struct vhd_image **)rhs;

	return strcmp(l->name, r->name);
}

static void
vhd_util_scan_print_image_indent(struct vhd_image *image, int tab)
{
	char *pad, *name, *pmsg, *parent;

	pad    = (tab ? " " : "");
	name   = image->name;
	parent = (image->parent ? : "none");

	if ((flags & VHD_SCAN_PRETTY) && image->parent && !image->parent_image)
		pmsg = " (not found in scan)";
	else
		pmsg = "";

	if (!(flags & VHD_SCAN_VERBOSE)) {
		name = basename(image->name);
		if (image->parent)
			parent = basename(image->parent);
	}

	if (image->error)
		printf("%*svhd=%s scan-error=%d error-message='%s'\n",
		       tab, pad, image->name, image->error, image->message);
	else
		printf("%*svhd=%s capacity=%"PRIu64" size=%"PRIu64" hidden=%u "
		       "parent=%s%s\n", tab, pad, name, image->capacity,
		       image->size, image->hidden, parent, pmsg);
}

static void
vhd_util_scan_pretty_print_tree(struct vhd_image *image, int depth)
{
	struct vhd_image *img, *tmp;

	vhd_util_scan_print_image_indent(image, depth * 3);

	list_for_each_entry_safe(img, tmp, &image->children, sibling)
		if (!img->hidden)
			vhd_util_scan_pretty_print_tree(img, depth + 1);

	list_for_each_entry_safe(img, tmp, &image->children, sibling)
		if (img->hidden)
			vhd_util_scan_pretty_print_tree(img, depth + 1);

	free(image->name);
	free(image->parent);

	image->name   = NULL;
	image->parent = NULL;
}

static void
vhd_util_scan_pretty_print_images(void)
{
	int i;
	struct vhd_image *image, **parentp, *parent, *keyp, key;

	qsort(scan.images, scan.cur, sizeof(scan.images[0]),
	      vhd_util_scan_pretty_image_compare);

	for (i = 0; i < scan.cur; i++) {
		image = scan.images[i];

		if (!image->parent) {
			image->parent_image = NULL;
			continue;
		}

		memset(&key, 0, sizeof(key));
		key.name = image->parent;
		keyp     = &key;

		parentp  = bsearch(&keyp, scan.images, scan.cur,
				   sizeof(scan.images[0]),
				   vhd_util_scan_pretty_image_compare);
		if (!parentp) {
			image->parent_image = NULL;
			continue;
		}

		parent = *parentp;
		image->parent_image = parent;
		list_add_tail(&image->sibling, &parent->children);
	}

	for (i = 0; i < scan.cur; i++) {
		image = scan.images[i];

		if (image->parent_image || !image->hidden)
			continue;

		vhd_util_scan_pretty_print_tree(image, 0);
	}

	for (i = 0; i < scan.cur; i++) {
		image = scan.images[i];

		if (!image->name || image->parent_image)
			continue;

		vhd_util_scan_pretty_print_tree(image, 0);
	}

	for (i = 0; i < scan.cur; i++) {
		image = scan.images[i];

		if (!image->name)
			continue;

		vhd_util_scan_pretty_print_tree(image, 0);
	}
}

static void
vhd_util_scan_print_image(struct vhd_image *image)
{
	int err;

	if (!image->error && (flags & VHD_SCAN_PRETTY)) {
		err = vhd_util_scan_pretty_add_image(image);
		if (!err)
			return;

		if (!image->error) {
			image->error   = err;
			image->message = "allocating memory";
		}
	}

	vhd_util_scan_print_image_indent(image, 0);
}

static int
vhd_util_scan_error(const char *file, int err)
{
	struct vhd_image image;

	memset(&image, 0, sizeof(image));
	image.name    = (char *)file;
	image.error   = err;
	image.message = "failure scanning target";

	vhd_util_scan_print_image(&image);

	/*
	if (flags & VHD_SCAN_NOFAIL)
		return 0;
	*/

	return err;
}

static vhd_parent_locator_t *
vhd_util_scan_get_parent_locator(vhd_context_t *vhd)
{
	int i;
	vhd_parent_locator_t *loc;

	loc = NULL;

	for (i = 0; i < 8; i++) {
		if (vhd->header.loc[i].code == PLAT_CODE_MACX) {
			loc = vhd->header.loc + i;
			break;
		}

		if (vhd->header.loc[i].code == PLAT_CODE_W2RU)
			loc = vhd->header.loc + i;

		if (!loc && vhd->header.loc[i].code != PLAT_CODE_NONE)
			loc = vhd->header.loc + i;
	}

	return loc;
}

static inline int
copy_name(char *dst, const char *src)
{
	if (snprintf(dst, VHD_MAX_NAME_LEN, "%s", src) < VHD_MAX_NAME_LEN)
		return 0;

	return -ENAMETOOLONG;
}

/*
 * LVHD stores realpath(parent) in parent locators, so
 * /dev/<vol-group>/<lv-name> becomes /dev/mapper/<vol--group>-<lv--name>
 */
static int
vhd_util_scan_extract_volume_name(char *dst, const char *src)
{
	int err;
	char copy[VHD_MAX_NAME_LEN], *name, *s, *c;

	name = strrchr(src, '/');
	if (!name)
		name = (char *)src;

	/* convert single dashes to slashes, double dashes to single dashes */
	for (c = copy, s = name; *s != '\0'; s++, c++) {
		if (*s == '-') {
			if (s[1] != '-')
				*c = '/';
			else {
				s++;
				*c = '-';
			}
		} else
			*c = *s;
	}

	*c = '\0';
	c = strrchr(copy, '/');
	if (c == name) {
		/* unrecognized format */
		strcpy(dst, src);
		return -EINVAL;
	}

	strcpy(dst, ++c);
	return 0;
}

static int
vhd_util_scan_get_volume_parent(vhd_context_t *vhd, struct vhd_image *image)
{
	int err;
	char name[VHD_MAX_NAME_LEN];
	vhd_parent_locator_t *loc, copy;

	if (flags & VHD_SCAN_FAST) {
		err = vhd_header_decode_parent(vhd,
					       &vhd->header, &image->parent);
		if (!err)
			goto found;
	}

	loc = vhd_util_scan_get_parent_locator(vhd);
	if (!loc)
		return -EINVAL;

	copy = *loc;
	copy.data_offset += image->target->start;
	err = vhd_parent_locator_read(vhd, &copy, &image->parent);
	if (err)
		return err;

found:
	err = vhd_util_scan_extract_volume_name(name, image->parent);
	if (!err)
		return copy_name(image->parent, name);

	return 0;
}

static int
vhd_util_scan_get_parent(vhd_context_t *vhd, struct vhd_image *image)
{
	int i, err;
	vhd_parent_locator_t *loc;

	if (!target_vhd(image->target->type)) {
		image->parent = NULL;
		return 0;
	}

	loc = NULL;

	if (target_volume(image->target->type))
		return vhd_util_scan_get_volume_parent(vhd, image);

	if (flags & VHD_SCAN_FAST) {
		err = vhd_header_decode_parent(vhd,
					       &vhd->header, &image->parent);
		if (!err)
			return 0;
	} else {
		/*
		 * vhd_parent_locator_get checks for the existence of the 
		 * parent file. if this call succeeds, all is well; if not,
		 * we'll try to return whatever string we have before failing
		 * outright.
		 */
		err = vhd_parent_locator_get(vhd, &image->parent);
		if (!err)
			return 0;
	}

	loc = vhd_util_scan_get_parent_locator(vhd);
	if (!loc)
		return -EINVAL;

	return vhd_parent_locator_read(vhd, loc, &image->parent);
}

static int
vhd_util_scan_get_hidden(vhd_context_t *vhd, struct vhd_image *image)
{
	int err, hidden;

	err    = 0;
	hidden = 0;

	if (target_vhd(image->target->type))
		err = vhd_hidden(vhd, &hidden);
	else
		hidden = 1;

	if (err)
		return err;

	image->hidden = hidden;
	return 0;
}

static int
vhd_util_scan_get_size(vhd_context_t *vhd, struct vhd_image *image)
{
	image->size = image->target->size;

	if (target_vhd(image->target->type))
		image->capacity = vhd->footer.curr_size;
	else
		image->capacity = image->size;

	return 0;
}

static int
vhd_util_scan_open_file(vhd_context_t *vhd, struct vhd_image *image)
{
	int err, vhd_flags;

	if (!target_vhd(image->target->type))
		return 0;

	vhd_flags = VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED;
	if (flags & VHD_SCAN_FAST)
		vhd_flags |= VHD_OPEN_FAST;

	err = vhd_open(vhd, image->name, vhd_flags);
	if (err) {
		vhd->file      = NULL;
		image->message = "opening file";
		image->error   = err;
		return image->error;
	}

	return 0;
}

static int
vhd_util_scan_read_volume_headers(vhd_context_t *vhd, struct vhd_image *image)
{
	int err;
	char *buf;
	size_t size;
	struct target *target;

	buf    = NULL;
	target = image->target;
	size   = sizeof(vhd_footer_t) + sizeof(vhd_header_t);

	err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
	if (err) {
		buf            = NULL;
		image->message = "allocating image";
		image->error   = -err;
		goto out;
	}

	err = vhd_seek(vhd, target->start, SEEK_SET);
	if (err) {
		image->message = "seeking to headers";
		image->error   = err;
		goto out;
	}

	err = vhd_read(vhd, buf, size);
	if (err) {
		image->message = "reading headers";
		image->error   = err;
		goto out;
	}

	memcpy(&vhd->footer, buf, sizeof(vhd_footer_t));
	vhd_footer_in(&vhd->footer);
	err = vhd_validate_footer(&vhd->footer);
	if (err) {
		image->message = "invalid footer";
		image->error   = err;
		goto out;
	}

	/* lvhd vhds should always be dynamic */
	if (vhd_type_dynamic(vhd)) {
		if (vhd->footer.data_offset != sizeof(vhd_footer_t))
			err = vhd_read_header_at(vhd, &vhd->header,
						 vhd->footer.data_offset +
						 target->start);
		else {
			memcpy(&vhd->header,
			       buf + sizeof(vhd_footer_t),
			       sizeof(vhd_header_t));
			vhd_header_in(&vhd->header);
			err = vhd_validate_header(&vhd->header);
		}

⌨️ 快捷键说明

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