From 875894245a3fc8a065260f5eecb0232e0308e529 Mon Sep 17 00:00:00 2001 From: Erik Skultety Date: Tue, 7 Feb 2017 10:19:06 +0100 Subject: [PATCH] util: Introduce virFileComparePaths So rather than comparing 2 paths (strings) as they are, which can very easily lead to unnecessary errors (e.g. in storage driver) that the paths are not the same when in fact they'd be e.g. just symlinks to the same location, we should put our best effort into resolving any symlinks and canonicalizing the path and only then compare the 2 paths for equality. Signed-off-by: Erik Skultety --- src/libvirt_private.syms | 1 + src/util/virfile.c | 44 ++++++++++++++++++++++++++++++++++++++++ src/util/virfile.h | 2 ++ 3 files changed, 47 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0a7de9a8ee..6bbb36b4e6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1575,6 +1575,7 @@ virFileActivateDirOverride; virFileBindMountDevice; virFileBuildPath; virFileClose; +virFileComparePaths; virFileCopyACLs; virFileDeleteTree; virFileDirectFdFlag; diff --git a/src/util/virfile.c b/src/util/virfile.c index 49ea1d1f00..6ba67bfbd3 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -3749,3 +3749,47 @@ virFileCopyACLs(const char *src, virFileFreeACLs(&acl); return ret; } + +/* + * virFileComparePaths: + * @p1: source path 1 + * @p2: source path 2 + * + * Compares two paths for equality. To do so, it first canonicalizes both paths + * to resolve all symlinks and discard relative path components. If symlinks + * resolution or path canonicalization fails, plain string equality of @p1 + * and @p2 is performed. + * + * Returns: + * 1 : Equal + * 0 : Non-Equal + * -1 : Error + */ +int +virFileComparePaths(const char *p1, const char *p2) +{ + int ret = -1; + char *res1, *res2; + + res1 = res2 = NULL; + + /* Assume p1 and p2 are symlinks, so try to resolve and canonicalize them. + * Canonicalization fails for example on file systems names like 'proc' or + * 'sysfs', since they're no real paths so fallback to plain string + * comparison. + */ + ignore_value(virFileResolveLink(p1, &res1)); + if (!res1 && VIR_STRDUP(res1, p1) < 0) + goto cleanup; + + ignore_value(virFileResolveLink(p2, &res2)); + if (!res2 && VIR_STRDUP(res2, p2) < 0) + goto cleanup; + + ret = STREQ_NULLABLE(res1, res2); + + cleanup: + VIR_FREE(res1); + VIR_FREE(res2); + return ret; +} diff --git a/src/util/virfile.h b/src/util/virfile.h index 232c1d66e1..f2a3faa158 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -334,4 +334,6 @@ void virFileFreeACLs(void **acl); int virFileCopyACLs(const char *src, const char *dst); + +int virFileComparePaths(const char *p1, const char *p2); #endif /* __VIR_FILE_H */