
On 05/30/2014 02:37 AM, Peter Krempa wrote:
As gnulib's canonicalize_filename_mode isn't LGPL and relative snapshot resolution code will need to clean paths with relative path components
s/components/components,/
this patch adds a libvirt's own implementation of that functionality and
s/adds a/adds/
tests to make sure everything works well. --- src/util/virstoragefile.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virstoragefile.h | 2 + tests/virstoragetest.c | 83 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+)
+static char * +virStorageFileExportPath(char **components, + size_t ncomponents, + bool beginSlash) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + size_t i; + char *ret = NULL; + + if (beginSlash) + virBufferAddLit(&buf, "/"); + + for (i = 0; i < ncomponents; i++) { + if (i != 0) + virBufferAddLit(&buf, "/");
I find it slightly fewer lines of code to just blindly add a trailing '/' always...
+ + virBufferAdd(&buf, components[i], -1); + }
...then use virBufferTrim() to remove the last unneeded one. But that's aesthetic; what you have works.
+ + /* if the output string is empty ... wel just return an empty string */
Did you mean "well" or "we'll"? Either way, it still reads okay (and shorter) as: s/wel//
+virStorageFileSimplifyPath(const char *path, + bool allow_relative) +{ + bool beginSlash = false; + char **components = NULL; + size_t ncomponents = 0; + size_t i; + char *ret = NULL; + + /* special cases are "" and "//", return them as they are */ + if (STREQ(path, "") || STREQ(path, "//")) { + ignore_value(VIR_STRDUP(ret, path));
It's more than just "//" that is special; also special is anything with a leading double slash ("//foo" should not be simplified to "/foo", even though "/bar//foo" can be simplified. Other corner cases: "//foo//bar" should be simplified to "//foo/bar", "//../blah" can be simplified to "//blah"). Maybe this means checking if path[0]=='/' && path[1]=='/' && path[2]!='/'.
+++ b/tests/virstoragetest.c @@ -512,12 +512,61 @@ testStorageLookup(const void *args) return ret; }
+ +struct testPathSimplifyData +{ + const char *path; + const char *exp_abs; + const char *exp_rel; +}; +
Thanks; adding the test makes it more obvious what the code intends to do :)
static int mymain(void) { int ret; virCommandPtr cmd = NULL; struct testChainData data; + struct testPathSimplifyData data3;
data followed by data3 looks a bit odd :)
+ + /* PATH, absolute simplification, relative simplification */ + TEST_SIMPLIFY(1, "/", "/", "/"); + TEST_SIMPLIFY(2, "/path", "/path", "/path"); + TEST_SIMPLIFY(3, "/path/to/blah", "/path/to/blah", "/path/to/blah"); + TEST_SIMPLIFY(4, "/path/", "/path", "/path"); + TEST_SIMPLIFY(5, "///////", "/", "/"); + TEST_SIMPLIFY(6, "//", "//", "//"); + TEST_SIMPLIFY(7, "", "", ""); + TEST_SIMPLIFY(8, "../", "", ".."); + TEST_SIMPLIFY(9, "../../", "", "../.."); + TEST_SIMPLIFY(10, "../../blah", "blah", "../../blah"); + TEST_SIMPLIFY(11, "/./././blah", "/blah", "/blah"); + TEST_SIMPLIFY(12, ".././../././../blah", "blah", "../../../blah"); + TEST_SIMPLIFY(13, "/././", "/", "/"); + TEST_SIMPLIFY(14, "./././", "", "");
Turning "." into empty looks a bit odd (POSIX requires "" to fail while "." is the current directory). Not sure if that needs tweaking. Also, maybe it's worth a test of plain "." after test 7 (so that we are separating test of "." behavior from test 14's coverage of multiple "/." behavior).
+ TEST_SIMPLIFY(15, "blah/../foo", "foo", "foo");
This is not always true. It is wrong if blah/ is not a (symlink to a) directory; and if blah IS a symlink, it can still be wrong if it is a symlink to somewhere else in the hierarchy. While I'm in favor of simplifying /./ and a//b, I'm less certain about the benefits of reducing '..' without actually stat'ing the underlying filesystem.
+ TEST_SIMPLIFY(16, "foo/bar/../blah", "foo/blah", "foo/blah"); + TEST_SIMPLIFY(17, "foo/bar/.././blah", "foo/blah", "foo/blah"); + TEST_SIMPLIFY(18, "/path/to/foo/bar/../../../../../../../../baz", "/baz", "/baz"); + TEST_SIMPLIFY(19, "path/to/foo/bar/../../../../../../../../baz", "baz", "../../../../baz"); + TEST_SIMPLIFY(20, "path/to/foo/bar", "path/to/foo/bar", "path/to/foo/bar"); + TEST_SIMPLIFY(21, "some/path/to/image.qcow/../image2.qcow/../image3.qcow/", + "some/path/to/image3.qcow", "some/path/to/image3.qcow");
Yep, the more I look at this, the more I worry that simplifying '..' is wrong. :( -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org