This commit adds a new function (ovs_realpath) to perform the role of realpath on various operating systems. The purpose is to ensure that a given path to file exists, and to return a completely resolved path (sans '.' and '..').
Signed-off-by: Aaron Conole <acon...@redhat.com> --- v11: * Added configure.ac | 2 +- lib/util.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/util.h | 1 + tests/library.at | 5 +++++ tests/test-util.c | 23 +++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 05d80d5..a490260 100644 --- a/configure.ac +++ b/configure.ac @@ -105,7 +105,7 @@ AC_CHECK_DECLS([sys_siglist], [], [], [[#include <signal.h>]]) AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec], [], [], [[#include <sys/stat.h>]]) AC_CHECK_MEMBERS([struct ifreq.ifr_flagshigh], [], [], [[#include <net/if.h>]]) -AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r]) +AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r realpath]) AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h stdatomic.h]) AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include <sys/types.h> #include <net/if.h>]]) diff --git a/lib/util.c b/lib/util.c index 94311ac..6bb6d9e 100644 --- a/lib/util.c +++ b/lib/util.c @@ -2098,6 +2098,58 @@ is_stdout_a_tty(void) return (isatty(STDOUT_FILENO) && t && strcmp(t, "dumb") != 0); } +/* Derives, from the pathname pointed to by path, an absolute pathname that + * names the same file, whose resolution does not involve '.', '..' or + * symbolic links. If path is null or does not exist, returns NULL. + */ +char * +ovs_realpath(const char *path) +{ + if (!path) { + return NULL; + } + char *realpath_res = NULL; + +#ifdef HAVE_REALPATH + realpath_res = realpath(path, NULL); + if (realpath_res == NULL) { + goto error; + } + struct stat s; + int err = stat(realpath_res, &s); + if (err) { + goto error; + } + return realpath_res; +#elif defined(_WIN32) + realpath_res = xstrdup(path); + DWORD ret = GetFullPathName(path, strlen(realpath_res), realpath_res, + NULL); + if (ret == 0) { + goto error; + } else if (ret > strlen(realpath_res)) { + DWORD new_ret; + char *new_path = (char *)xrealloc(realpath_res, ret); + if (new_path == NULL) { + goto error; + } + realpath_res = new_path; + new_ret = GetFullPathName(path, strlen(realpath_res), realpath_res, + NULL); + if (new_ret == 0 || new_ret != ret ) { + goto error; + } + } + return realpath_res; +#else +#error Need realpath() on this platform +#endif + +error: + free(realpath_res); + return NULL; +} + #ifdef _WIN32 char * diff --git a/lib/util.h b/lib/util.h index 41c5ea6..8d7f335 100644 --- a/lib/util.h +++ b/lib/util.h @@ -220,6 +220,7 @@ char *dir_name(const char *file_name); char *base_name(const char *file_name); #endif char *abs_file_name(const char *dir, const char *file_name); +char *ovs_realpath(const char *path); char *follow_symlinks(const char *filename); diff --git a/tests/library.at b/tests/library.at index e1bac92..b6561e5 100644 --- a/tests/library.at +++ b/tests/library.at @@ -234,3 +234,8 @@ AT_CLEANUP AT_SETUP([test rcu]) AT_CHECK([ovstest test-rcu-quiesce], [0], []) AT_CLEANUP + +AT_SETUP([test ovs_realpath]) +AT_CHECK([ovstest test-util realpath \ +/tmp/../tmp/../usr/bin/.//../share:/usr/share /tmpNOEXISTS:], [0], []) +AT_CLEANUP diff --git a/tests/test-util.c b/tests/test-util.c index ef45903..2755200 100644 --- a/tests/test-util.c +++ b/tests/test-util.c @@ -1128,6 +1128,28 @@ test_snprintf(struct ovs_cmdl_context *ctx OVS_UNUSED) ovs_assert(snprintf(NULL, 0, "abcde") == 5); } +static void +test_ovs_realpath(struct ovs_cmdl_context *ctx) +{ + int i; + for (i = 1; i < ctx->argc; i++) { + char *str_toks = NULL; + char *path = strtok_r(ctx->argv[i], ":", &str_toks); + ovs_assert(path != NULL); + + char *check = strtok_r(NULL, ":", &str_toks); + char *rpath = ovs_realpath(path); + + if (check) { + ovs_assert(rpath != NULL); + ovs_assert(!strcmp(check, rpath)); + free(rpath); + } else { + ovs_assert(rpath == NULL); + } + } +} + #ifndef _WIN32 static void test_file_name(struct ovs_cmdl_context *ctx) @@ -1164,6 +1186,7 @@ static const struct ovs_cmdl_command commands[] = { {"assert", NULL, 0, 0, test_assert}, {"ovs_scan", NULL, 0, 0, test_ovs_scan}, {"snprintf", NULL, 0, 0, test_snprintf}, + {"realpath", NULL, 1, INT_MAX, test_ovs_realpath}, #ifndef _WIN32 {"file_name", NULL, 1, INT_MAX, test_file_name}, #endif -- 2.5.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev