[libvirt] [PATCHv3 16/36] util: storage: Add helper to resolve relative path difference

Eric Blake eblake at redhat.com
Mon Jun 2 23:09:38 UTC 2014


On 05/30/2014 02:37 AM, Peter Krempa wrote:
> This patch introduces a function that will allow us to resolve a
> relative difference between two elements of a disk backing chain. This
> fucntion will be used to allow relative block commit and block pull

s/fucntion/function/

> where we need to specify the new relative name of the image to qemu.
> 
> This patch also adds unit tests for the function to verify that it works
> correctly.
> ---
>  src/libvirt_private.syms  |   1 +
>  src/util/virstoragefile.c |  45 +++++++++++++++++++++
>  src/util/virstoragefile.h |   4 ++
>  tests/virstoragetest.c    | 101 ++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 151 insertions(+)
> 

> +int
> +virStorageFileGetRelativeBackingPath(virStorageSourcePtr from,
> +                                     virStorageSourcePtr to,
> +                                     char **relpath)

Missing documentation on what this function is intended to do.

> +{
> +    virBuffer buf = VIR_BUFFER_INITIALIZER;
> +    virStorageSourcePtr next;
> +    char *tmp = NULL;
> +    char ret = -1;
> +
> +    *relpath = NULL;
> +
> +    for (next = from; next; next = next->backingStore) {
> +        if (!next->backingRelative || !next->relPath) {
> +            ret = 1;
> +            goto cleanup;
> +        }
> +
> +        if (next != from)
> +            virBufferAddLit(&buf, "/../");
> +
> +        virBufferAdd(&buf, next->relPath, -1);
> +
> +        if (next == to)
> +            break;
> +    }
> +
> +    if (next != to)
> +        goto cleanup;
> +
> +    if (!(tmp = virBufferContentAndReset(&buf)))
> +        goto cleanup;
> +
> +    if (!(*relpath = virStorageFileSimplifyPath(tmp, true)))

Ouch.  Playing fast and loose with 'path/to/file/../otherfile' as a way
to simplify to 'path/to/otherfile' is very risky.  Instead of doing
'path/to/file'+'/../'+'otherfile', I'd feel better doing
mdirname('path/to/file')+'/'+'otherfile' == 'path/to'+'/'+'otherfile'.
Don't we already have a helper function in util/virfile.h that can
concatenate a relative filename in relation to the containing directory
of another filename?

/me re-reads virFileBuildPath...

nope, not quite what we need.


> 
> +virStorageSource backingchain[9];
> +
> +static void
> +testPathRelativePrepare(void)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < ARRAY_CARDINALITY(backingchain) - 1; i++) {
> +        backingchain[i].backingStore = &backingchain[i+1];
> +    }
> +
> +    backingchain[0].relPath = (char *) "/path/to/some/img";
> +    backingchain[0].backingRelative = false;
> +
> +    backingchain[1].relPath = (char *) "asdf";
> +    backingchain[1].backingRelative = true;
> +
> +    backingchain[2].relPath = (char *) "test";
> +    backingchain[2].backingRelative = true;
> +
> +    backingchain[3].relPath = (char *) "blah";
> +    backingchain[3].backingRelative = true;

1 through 3 are relative to the directory containing img in 0, but that
is '/path/to/some/blah' and not a simplification of
'/path/to/some/img/../blah' since 'img/..' doesn't resolve via POSIX
functions.

> +
> +    backingchain[4].relPath = (char *) "/path/to/some/other/img";
> +    backingchain[4].backingRelative = false;

As a non-relative image, the search for relative starts over again.

> +
> +    backingchain[5].relPath = (char *) "../relative/in/other/path";
> +    backingchain[5].backingRelative = true;

Here, the answer has to be
"/path/to/some/other/../relative/in/other/path", unless we did a stat
test to ensure that '/path/to/some/other/..' resolves to the same
location as '/path/to/some'.

> +
> +    backingchain[6].relPath = (char *) "test";
> +    backingchain[6].backingRelative = true;
> +
> +    backingchain[7].relPath = (char *) "../../../../../below";
> +    backingchain[7].backingRelative = true;

I see that you are trying to test that you can't escape past /...

> +
> +    backingchain[8].relPath = (char *) "a/little/more/upwards";
> +    backingchain[8].backingRelative = true;

but that still doesn't make me feel good about simplifying .. without
actual stat tests.

> +    testPathRelativePrepare();
> +
> +    TEST_RELATIVE_BACKING(1, backingchain[0], backingchain[1], NULL);

I'm trying to wrap my head around this test and the expected results,
and merely got confused.  I need something that describes what we are
doing visually, something like:

Given the chain { "base" <- "intermediate" <- "active" }, we plan to
commit "intermediate" into "base" and need to rewrite the backing file
stored in "active" to point to "base".  TEST_RELATIVE_BACKING(, active,
intermediate, expected) then gives the expected string to write into active.

Except that my formulation doesn't work with what your code expects, or
I'm getting lost somewhere.  backingchain[0] is the active image (living
at "/path/to/some/file", and with backing element currently at the
relative "asdf"); and we are committing backingchain[1] (file at "asdf",
 whose backing is currently "test").  Doesn't that mean that we want to
determine a relative name for "test" that we can store in the metadata
for "/path/to/some/file"?  If so, isn't the answer "asdf", not NULL?

I need more help understanding your goal here.  :(

> +    TEST_RELATIVE_BACKING(2, backingchain[1], backingchain[2], "test");
> +    TEST_RELATIVE_BACKING(3, backingchain[2], backingchain[3], "blah");
> +    TEST_RELATIVE_BACKING(4, backingchain[1], backingchain[3], "blah");
> +    TEST_RELATIVE_BACKING(5, backingchain[1], backingchain[4], NULL);
> +    TEST_RELATIVE_BACKING(6, backingchain[5], backingchain[6], "../relative/in/other/test");
> +    TEST_RELATIVE_BACKING(7, backingchain[5], backingchain[7], "../../../below");
> +    TEST_RELATIVE_BACKING(8, backingchain[5], backingchain[8], "../../../a/little/more/upwards");

and to reiterate, I'm not sure we can elide any 'foo/../' pairs in our
simplification, without actually stat'ing the local filesystem or using
the equivalent libgfapi or other network driver calls.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 604 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20140602/3bea6cfc/attachment-0001.sig>


More information about the libvir-list mailing list