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 <eskultet@redhat.com>
This commit is contained in:
Erik Skultety 2017-02-07 10:19:06 +01:00
parent 8fcf6330b6
commit 875894245a
3 changed files with 47 additions and 0 deletions

View File

@ -1575,6 +1575,7 @@ virFileActivateDirOverride;
virFileBindMountDevice;
virFileBuildPath;
virFileClose;
virFileComparePaths;
virFileCopyACLs;
virFileDeleteTree;
virFileDirectFdFlag;

View File

@ -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;
}

View File

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