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

📄 vhd-util-scan.c

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

		if (err) {
			image->message = "reading header";
			image->error   = err;
			goto out;
		}

		vhd->spb = vhd->header.block_size >> VHD_SECTOR_SHIFT;
		vhd->bm_secs = secs_round_up_no_zero(vhd->spb >> 3);
	}

out:
	free(buf);
	return image->error;
}

static int
vhd_util_scan_open_volume(vhd_context_t *vhd, struct vhd_image *image)
{
	int err;
	struct target *target;

	target = image->target;
	memset(vhd, 0, sizeof(*vhd));
	vhd->oflags = VHD_OPEN_RDONLY | VHD_OPEN_FAST;

	if (target->end - target->start < 4096) {
		image->message = "device too small";
		image->error   = -EINVAL;
		return image->error;
	}

	vhd->file = strdup(image->name);
	if (!vhd->file) {
		image->message = "allocating device";
		image->error   = -ENOMEM;
		return image->error;
	}

	vhd->fd = open(target->device, O_RDONLY | O_DIRECT | O_LARGEFILE);
	if (vhd->fd == -1) {
		free(vhd->file);
		vhd->file = NULL;

		image->message = "opening device";
		image->error   = -errno;
		return image->error;
	}

	if (target_vhd(target->type))
		return vhd_util_scan_read_volume_headers(vhd, image);

	return 0;
}

static int
vhd_util_scan_open(vhd_context_t *vhd, struct vhd_image *image)
{
	struct target *target;

	target = image->target;

	if (target_volume(image->target->type) || !(flags & VHD_SCAN_PRETTY))
		image->name = target->name;
	else {
		image->name = realpath(target->name, NULL);
		if (!image->name) {
			image->name    = target->name;
			image->message = "resolving name";
			image->error   = -errno;
			return image->error;
		}
	}

	if (target_volume(target->type))
		return vhd_util_scan_open_volume(vhd, image);
	else
		return vhd_util_scan_open_file(vhd, image);
}

static int
vhd_util_scan_init_file_target(struct target *target,
			       const char *file, uint8_t type)
{
	int err;
	struct stat stats;

	err = stat(file, &stats);
	if (err == -1)
		return -errno;

	err = copy_name(target->name, file);
	if (err)
		return err;

	err = copy_name(target->device, file);
	if (err)
		return err;

	target->type  = type;
	target->start = 0;
	target->size  = stats.st_size;
	target->end   = stats.st_size;

	return 0;
}

static int
vhd_util_scan_init_volume_target(struct target *target,
				 struct lv *lv, uint8_t type)
{
	int err;

	if (lv->first_segment.type != LVM_SEG_TYPE_LINEAR)
		return -ENOSYS;

	err = copy_name(target->name, lv->name);
	if (err)
		return err;

	err = copy_name(target->device, lv->first_segment.device);
	if (err)
		return err;

	target->type  = type;
	target->size  = lv->size;
	target->start = lv->first_segment.pe_start;
	target->end   = target->start + lv->first_segment.pe_size;

	return 0;
}

static int
iterator_init(struct iterator *itr, int cnt, struct target *targets)
{
	memset(itr, 0, sizeof(*itr));

	itr->targets = malloc(sizeof(struct target) * cnt);
	if (!itr->targets)
		return -ENOMEM;

	memcpy(itr->targets, targets, sizeof(struct target) * cnt);

	itr->cur      = 0;
	itr->cur_size = cnt;
	itr->max_size = cnt;

	return 0;
}

static struct target *
iterator_next(struct iterator *itr)
{
	if (itr->cur == itr->cur_size)
		return NULL;

	return itr->targets + itr->cur++;
}

static int
iterator_add_file(struct iterator *itr,
		  struct target *target, const char *parent, uint8_t type)
{
	int i;
	struct target *t;
	char *lname, *rname;

	for (i = 0; i < itr->cur_size; i++) {
		t = itr->targets + i;
		lname = basename((char *)t->name);
		rname = basename((char *)parent);

		if (!strcmp(lname, rname))
			return -EEXIST;
	}

	return vhd_util_scan_init_file_target(target, parent, type);
}

static int
iterator_add_volume(struct iterator *itr,
		    struct target *target, const char *parent, uint8_t type)
{
	int i, err;
	struct lv *lv;

	lv  = NULL;
	err = -ENOENT;

	for (i = 0; i < itr->cur_size; i++)
		if (!strcmp(parent, itr->targets[i].name))
			return -EEXIST;

	for (i = 0; i < vg.lv_cnt; i++) {
		err = fnmatch(parent, vg.lvs[i].name, FNM_PATHNAME);
		if (err != FNM_NOMATCH) {
			lv = vg.lvs + i;
			break;
		}
	}

	if (err && err != FNM_PATHNAME)
		return err;

	if (!lv)
		return -ENOENT;

	return vhd_util_scan_init_volume_target(target, lv, type);
}

static int
iterator_add(struct iterator *itr, const char *parent, uint8_t type)
{
	int err;
	struct target *target;

	if (itr->cur_size == itr->max_size) {
		struct target *new;

		new = realloc(itr->targets,
			      sizeof(struct target) *
			      itr->max_size * 2);
		if (!new)
			return -ENOMEM;

		itr->max_size *= 2;
		itr->targets   = new;
	}

	target = itr->targets + itr->cur_size;

	if (target_volume(type))
		err = iterator_add_volume(itr, target, parent, type);
	else
		err = iterator_add_file(itr, target, parent, type);

	if (err)
		memset(target, 0, sizeof(*target));
	else
		itr->cur_size++;

	return (err == -EEXIST ? 0 : err);
}

static void
iterator_free(struct iterator *itr)
{
	free(itr->targets);
	memset(itr, 0, sizeof(*itr));
}

static void
vhd_util_scan_add_parent(struct iterator *itr,
			 vhd_context_t *vhd, struct vhd_image *image)
{
	int err;
	uint8_t type;

	if (vhd_parent_raw(vhd))
		type = target_volume(image->target->type) ? 
			VHD_TYPE_RAW_VOLUME : VHD_TYPE_RAW_FILE;
	else
		type = target_volume(image->target->type) ? 
			VHD_TYPE_VHD_VOLUME : VHD_TYPE_VHD_FILE;

	err = iterator_add(itr, image->parent, type);
	if (err)
		vhd_util_scan_error(image->parent, err);
}

static int
vhd_util_scan_targets(int cnt, struct target *targets)
{
	int ret, err;
	vhd_context_t vhd;
	struct iterator itr;
	struct target *target;
	struct vhd_image image;

	ret = 0;
	err = 0;

	err = iterator_init(&itr, cnt, targets);
	if (err)
		return err;

	while ((target = iterator_next(&itr))) {
		memset(&vhd, 0, sizeof(vhd));
		memset(&image, 0, sizeof(image));

		image.target = target;

		err = vhd_util_scan_open(&vhd, &image);
		if (err) {
			ret = -EAGAIN;
			goto end;
		}

		err = vhd_util_scan_get_size(&vhd, &image);
		if (err) {
			ret           = -EAGAIN;
			image.message = "getting physical size";
			image.error   = err;
			goto end;
		}

		err = vhd_util_scan_get_hidden(&vhd, &image);
		if (err) {
			ret           = -EAGAIN;
			image.message = "checking 'hidden' field";
			image.error   = err;
			goto end;
		}

		if (vhd.footer.type == HD_TYPE_DIFF) {
			err = vhd_util_scan_get_parent(&vhd, &image);
			if (err) {
				ret           = -EAGAIN;
				image.message = "getting parent";
				image.error   = err;
				goto end;
			}
		}

	end:
		vhd_util_scan_print_image(&image);

		if (flags & VHD_SCAN_PARENTS && image.parent)
			vhd_util_scan_add_parent(&itr, &vhd, &image);

		if (vhd.file)
			vhd_close(&vhd);
		if (image.name != target->name)
			free(image.name);
		free(image.parent);

		if (err && !(flags & VHD_SCAN_NOFAIL))
			break;
	}

	iterator_free(&itr);

	if (flags & VHD_SCAN_NOFAIL)
		return ret;

	return err;
}

static int
vhd_util_scan_targets_pretty(int cnt, struct target *targets)
{
	int err;

	err = vhd_util_scan_pretty_allocate_list(cnt);
	if (err) {
		printf("scan failed: no memory\n");
		return -ENOMEM;
	}

	err = vhd_util_scan_targets(cnt, targets);

	vhd_util_scan_pretty_print_images();
	vhd_util_scan_pretty_free_list();

	return ((flags & VHD_SCAN_NOFAIL) ? 0 : err);
}

static int
vhd_util_scan_find_file_targets(int cnt, char **names,
				const char *filter,
				struct target **_targets, int *_total)
{
	glob_t g;
	struct target *targets;
	int i, globs, err, total;

	total     = cnt;
	globs     = 0;
	*_total   = 0;
	*_targets = NULL;
	
	memset(&g, 0, sizeof(g));

	if (filter) {
		int gflags = ((flags & VHD_SCAN_FAST) ? GLOB_NOSORT : 0);

		errno = 0;
		err   = glob(filter, gflags, vhd_util_scan_error, &g);

		switch (err) {
		case GLOB_NOSPACE:
			err = -ENOMEM;
			break;
		case GLOB_ABORTED:
			err = -EIO;
			break;
		case GLOB_NOMATCH:
			err = -errno;
			break;
		}

		if (err) {
			vhd_util_scan_error(filter, err);
			return err;
		}

		globs  = g.gl_pathc;
		total += globs;
	}

	targets = calloc(total, sizeof(struct target));
	if (!targets) {
		err = -ENOMEM;
		goto out;
	}

	for (i = 0; i < g.gl_pathc; i++) {
		err = vhd_util_scan_init_file_target(targets + i,
						     g.gl_pathv[i],
						     VHD_TYPE_VHD_FILE);
		if (err) {
			vhd_util_scan_error(g.gl_pathv[i], err);
			if (!(flags & VHD_SCAN_NOFAIL))
				goto out;
		}
	}

	for (i = 0; i + globs < total; i++) {
		err = vhd_util_scan_init_file_target(targets + i + globs,
						     names[i],
						     VHD_TYPE_VHD_FILE);
		if (err) {
			vhd_util_scan_error(names[i], err);
			if (!(flags & VHD_SCAN_NOFAIL))
				goto out;
		}
	}

	err       = 0;
	*_total   = total;
	*_targets = targets;

out:
	if (err)
		free(targets);
	if (filter)
		globfree(&g);

	return err;
}

static inline void
swap_volume(struct lv *lvs, int dst, int src)
{
	struct lv copy, *ldst, *lsrc;

	if (dst == src)
		return;

	lsrc = lvs + src;
	ldst = lvs + dst;

	memcpy(&copy, ldst, sizeof(copy));
	memcpy(ldst, lsrc, sizeof(*ldst));
	memcpy(lsrc, &copy, sizeof(copy));
}

static int
vhd_util_scan_sort_volumes(struct lv *lvs, int cnt,
			   const char *filter, int *_matches)
{
	struct lv *lv;
	int i, err, matches;

	matches   = 0;
	*_matches = 0;

	if (!filter)
		return 0;

	for (i = 0; i < cnt; i++) {
		lv  = lvs + i;

		err = fnmatch(filter, lv->name, FNM_PATHNAME);
		if (err) {
			if (err != FNM_NOMATCH) {
				vhd_util_scan_error(lv->name, err);
				if (!(flags & VHD_SCAN_NOFAIL))
					return err;
			}

			continue;
		}

		swap_volume(lvs, matches++, i);
	}

	*_matches = matches;
	return 0;
}

static int
vhd_util_scan_find_volume_targets(int cnt, char **names,
				  const char *volume, const char *filter,
				  struct target **_targets, int *_total)
{
	struct target *targets;
	int i, err, total, matches;

	*_total   = 0;
	*_targets = NULL;
	targets   = NULL;

	err = lvm_scan_vg(volume, &vg);
	if (err)
		return err;

	err = vhd_util_scan_sort_volumes(vg.lvs, vg.lv_cnt,
					 filter, &matches);
	if (err)
		goto out;

	total = matches;
	for (i = 0; i < cnt; i++) {
		err = vhd_util_scan_sort_volumes(vg.lvs + total,
						 vg.lv_cnt - total,
						 names[i], &matches);
		if (err)
			goto out;

		total += matches;
	}

	targets = calloc(total, sizeof(struct target));
	if (!targets) {
		err = -ENOMEM;
		goto out;
	}

	for (i = 0; i < total; i++) {
		err = vhd_util_scan_init_volume_target(targets + i,
						       vg.lvs + i,
						       VHD_TYPE_VHD_VOLUME);
		if (err) {
			vhd_util_scan_error(vg.lvs[i].name, err);
			if (!(flags & VHD_SCAN_NOFAIL))
				goto out;
		}
	}

	err       = 0;
	*_total   = total;
	*_targets = targets;

out:
	if (err)
		free(targets);
	return err;
}

static int
vhd_util_scan_find_targets(int cnt, char **names,
			   const char *volume, const char *filter,
			   struct target **targets, int *total)
{
	if (flags & VHD_SCAN_VOLUME)
		return vhd_util_scan_find_volume_targets(cnt, names,
							 volume, filter,
							 targets, total);
	return vhd_util_scan_find_file_targets(cnt, names,
					       filter, targets, total);
}

int
vhd_util_scan(int argc, char **argv)
{
	int c, ret, err, cnt;
	char *filter, *volume;
	struct target *targets;

	cnt     = 0;
	ret     = 0;
	err     = 0;
	flags   = 0;
	filter  = NULL;
	volume  = NULL;
	targets = NULL;

	optind = 0;
	while ((c = getopt(argc, argv, "m:fcl:pavh")) != -1) {
		switch (c) {
		case 'm':
			filter = optarg;
			break;
		case 'f':
			flags |= VHD_SCAN_FAST;
			break;
		case 'c':
			flags |= VHD_SCAN_NOFAIL;
			break;
		case 'l':
			volume = optarg;
			flags |= VHD_SCAN_VOLUME;
			break;
		case 'p':
			flags |= VHD_SCAN_PRETTY;
			break;
		case 'a':
			flags |= VHD_SCAN_PARENTS;
			break;
		case 'v':
			flags |= VHD_SCAN_VERBOSE;
			break;
		case 'h':
			goto usage;
		default:
			err = -EINVAL;
			goto usage;
		}
	}

	if (!filter && argc - optind == 0) {
		err = -EINVAL;
		goto usage;
	}

	if (flags & VHD_SCAN_PRETTY)
		flags &= ~VHD_SCAN_FAST;

	err = vhd_util_scan_find_targets(argc - optind, argv + optind,
					 volume, filter, &targets, &cnt);
	if (err) {
		printf("scan failed: %d\n", err);
		return err;
	}

	if (!cnt)
		return 0;

	if (flags & VHD_SCAN_PRETTY)
		err = vhd_util_scan_targets_pretty(cnt, targets);
	else
		err = vhd_util_scan_targets(cnt, targets);

	free(targets);
	lvm_free_vg(&vg);

	return ((flags & VHD_SCAN_NOFAIL) ? 0 : err);

usage:
	printf("usage: [OPTIONS] FILES\n"
	       "options: [-m match filter] [-f fast] [-c continue on failure] "
	       "[-l LVM volume] [-p pretty print] [-a scan parents] "
	       "[-v verbose] [-h help]\n");
	return err;
}

⌨️ 快捷键说明

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