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 */