📄 vhd-util-scan.c
字号:
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(©, ldst, sizeof(copy));
memcpy(ldst, lsrc, sizeof(*ldst));
memcpy(lsrc, ©, 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 + -