
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