mirror of https://github.com/xemu-project/xemu.git
block: make bdrv_find_backing_image compare canonical filenames
Currently, bdrv_find_backing_image compares bs->backing_file with what is passed in as a backing_file name. Mismatches may occur, however, when bs->backing_file and backing_file are not both absolute or relative. Use path_combine() to make sure any relative backing filenames are relative to the current image filename being searched, and then use realpath() to make all comparisons based on absolute filenames. If either backing_file or bs->backing_file is determine to be a protocol, then no filename normalization is performed. This also changes bdrv_find_backing_image to no longer be recursive, but iterative. Signed-off-by: Jeff Cody <jcody@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
a616673dd1
commit
b1b1d783ea
60
block.c
60
block.c
|
@ -3123,22 +3123,70 @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs,
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* backing_file can either be relative, or absolute, or a protocol. If it is
|
||||
* relative, it must be relative to the chain. So, passing in bs->filename
|
||||
* from a BDS as backing_file should not be done, as that may be relative to
|
||||
* the CWD rather than the chain. */
|
||||
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
|
||||
const char *backing_file)
|
||||
{
|
||||
if (!bs->drv) {
|
||||
char *filename_full = NULL;
|
||||
char *backing_file_full = NULL;
|
||||
char *filename_tmp = NULL;
|
||||
int is_protocol = 0;
|
||||
BlockDriverState *curr_bs = NULL;
|
||||
BlockDriverState *retval = NULL;
|
||||
|
||||
if (!bs || !bs->drv || !backing_file) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bs->backing_hd) {
|
||||
if (strcmp(bs->backing_file, backing_file) == 0) {
|
||||
return bs->backing_hd;
|
||||
filename_full = g_malloc(PATH_MAX);
|
||||
backing_file_full = g_malloc(PATH_MAX);
|
||||
filename_tmp = g_malloc(PATH_MAX);
|
||||
|
||||
is_protocol = path_has_protocol(backing_file);
|
||||
|
||||
for (curr_bs = bs; curr_bs->backing_hd; curr_bs = curr_bs->backing_hd) {
|
||||
|
||||
/* If either of the filename paths is actually a protocol, then
|
||||
* compare unmodified paths; otherwise make paths relative */
|
||||
if (is_protocol || path_has_protocol(curr_bs->backing_file)) {
|
||||
if (strcmp(backing_file, curr_bs->backing_file) == 0) {
|
||||
retval = curr_bs->backing_hd;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return bdrv_find_backing_image(bs->backing_hd, backing_file);
|
||||
/* If not an absolute filename path, make it relative to the current
|
||||
* image's filename path */
|
||||
path_combine(filename_tmp, PATH_MAX, curr_bs->filename,
|
||||
backing_file);
|
||||
|
||||
/* We are going to compare absolute pathnames */
|
||||
if (!realpath(filename_tmp, filename_full)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We need to make sure the backing filename we are comparing against
|
||||
* is relative to the current image filename (or absolute) */
|
||||
path_combine(filename_tmp, PATH_MAX, curr_bs->filename,
|
||||
curr_bs->backing_file);
|
||||
|
||||
if (!realpath(filename_tmp, backing_file_full)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(backing_file_full, filename_full) == 0) {
|
||||
retval = curr_bs->backing_hd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
g_free(filename_full);
|
||||
g_free(backing_file_full);
|
||||
g_free(filename_tmp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int bdrv_get_backing_file_depth(BlockDriverState *bs)
|
||||
|
|
Loading…
Reference in New Issue