From 892f59bdc1830443f87ad3aaeddaab2eeefb5937 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 22 Nov 2012 11:42:25 +1030 Subject: [PATCH] tal/path: new module Signed-off-by: Rusty Russell Header from folded patch 'path-talloc-take.patch': tal/path: accept take() for arguments. Signed-off-by: Rusty Russell --- Makefile-ccan | 1 + ccan/tal/path/LICENSE | 1 + ccan/tal/path/_info | 62 ++++ ccan/tal/path/path.c | 560 ++++++++++++++++++++++++++++++ ccan/tal/path/path.h | 167 +++++++++ ccan/tal/path/test/run-basename.c | 58 ++++ ccan/tal/path/test/run-canon.c | 53 +++ ccan/tal/path/test/run-cwd.c | 37 ++ ccan/tal/path/test/run-dirname.c | 58 ++++ ccan/tal/path/test/run-ext_off.c | 19 + ccan/tal/path/test/run-is_abs.c | 16 + ccan/tal/path/test/run-is_dir.c | 41 +++ ccan/tal/path/test/run-is_file.c | 42 +++ ccan/tal/path/test/run-join.c | 91 +++++ ccan/tal/path/test/run-pushd.c | 75 ++++ ccan/tal/path/test/run-readlink.c | 46 +++ ccan/tal/path/test/run-rel.c | 69 ++++ ccan/tal/path/test/run-simplify.c | 244 +++++++++++++ ccan/tal/path/test/run-split.c | 105 ++++++ 19 files changed, 1745 insertions(+) create mode 120000 ccan/tal/path/LICENSE create mode 100644 ccan/tal/path/_info create mode 100644 ccan/tal/path/path.c create mode 100644 ccan/tal/path/path.h create mode 100644 ccan/tal/path/test/run-basename.c create mode 100644 ccan/tal/path/test/run-canon.c create mode 100644 ccan/tal/path/test/run-cwd.c create mode 100644 ccan/tal/path/test/run-dirname.c create mode 100644 ccan/tal/path/test/run-ext_off.c create mode 100644 ccan/tal/path/test/run-is_abs.c create mode 100644 ccan/tal/path/test/run-is_dir.c create mode 100644 ccan/tal/path/test/run-is_file.c create mode 100644 ccan/tal/path/test/run-join.c create mode 100644 ccan/tal/path/test/run-pushd.c create mode 100644 ccan/tal/path/test/run-readlink.c create mode 100644 ccan/tal/path/test/run-rel.c create mode 100644 ccan/tal/path/test/run-simplify.c create mode 100644 ccan/tal/path/test/run-split.c diff --git a/Makefile-ccan b/Makefile-ccan index e16c87a8..39467383 100644 --- a/Makefile-ccan +++ b/Makefile-ccan @@ -72,6 +72,7 @@ MODS_NORMAL_WITH_SRC := antithread \ str_talloc \ take \ tal \ + tal/path \ tal/str \ talloc \ talloc_link \ diff --git a/ccan/tal/path/LICENSE b/ccan/tal/path/LICENSE new file mode 120000 index 00000000..2b1feca5 --- /dev/null +++ b/ccan/tal/path/LICENSE @@ -0,0 +1 @@ +../../../licenses/BSD-MIT \ No newline at end of file diff --git a/ccan/tal/path/_info b/ccan/tal/path/_info new file mode 100644 index 00000000..24b9e468 --- /dev/null +++ b/ccan/tal/path/_info @@ -0,0 +1,62 @@ +#include +#include "config.h" + +/** + * tal/path - routines to manipulate paths + * + * This code helps manage paths. + * + * License: BSD-MIT + * Author: Rusty Russell + * + * Example: + * // Program to print out full path names, recursively. + * #include + * #include + * #include + * #include + * #include + * + * static void dump(const char *dir) + * { + * struct dirent *di; + * DIR *d = opendir(dir); + * if (!d) { + * warn("Failed to open %s", dir); + * return; + * } + * printf("%s\n", dir); + * while ((di = readdir(d)) != NULL) { + * char *path; + * if (streq(di->d_name, ".") || streq(di->d_name, "..")) + * continue; + * path = path_join(NULL, dir, di->d_name); + * if (path_is_dir(path)) + * dump(path); + * tal_free(path); + * } + * closedir(d); + * } + * + * int main(void) + * { + * dump(path_cwd(NULL)); + * return 0; + * } + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + printf("ccan/str\n"); + printf("ccan/take\n"); + printf("ccan/tal\n"); + printf("ccan/tal/str\n"); + return 0; + } + + return 1; +} diff --git a/ccan/tal/path/path.c b/ccan/tal/path/path.c new file mode 100644 index 00000000..0ad168c8 --- /dev/null +++ b/ccan/tal/path/path.c @@ -0,0 +1,560 @@ +/* Licensed under BSD-MIT - see LICENSE file for details */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PATH_SEP_STR "/" +#define PATH_SEP (PATH_SEP_STR[0]) + +char *path_cwd(const tal_t *ctx) +{ + size_t len = 64; + char *cwd; + + /* *This* is why people hate C. */ + cwd = tal_arr(ctx, char, len); + while (cwd && !getcwd(cwd, len)) { + if (errno != ERANGE || !tal_resize(&cwd, len *= 2)) + cwd = tal_free(cwd); + } + return cwd; +} + +char *path_join(const tal_t *ctx, const char *base, const char *a) +{ + char *ret = NULL; + size_t len; + + if (unlikely(!a) && taken(a)) { + if (taken(base)) + tal_free(base); + return NULL; + } + + if (a[0] == PATH_SEP) { + if (taken(base)) + tal_free(base); + return tal_strdup(ctx, a); + } + + if (unlikely(!base) && taken(base)) + goto out; + + len = strlen(base); + ret = tal_dup(ctx, char, base, len, 1 + strlen(a) + 1); + if (!ret) + goto out; + if (ret[len-1] != PATH_SEP) + ret[len++] = PATH_SEP; + strcpy(ret + len, a); + +out: + if (taken(a)) + tal_free(a); + return ret; +} + +#if HAVE_FCHDIR +struct path_pushd { + int fd; +}; + +static void pushd_destroy(struct path_pushd *pushd) +{ + close(pushd->fd); +} + +struct path_pushd *path_pushd(const tal_t *ctx, const char *dir) +{ + struct path_pushd *old = tal(ctx, struct path_pushd); + + if (!old) + return NULL; + + if (unlikely(!dir) && taken(dir)) + return tal_free(old); + + if (!tal_add_destructor(old, pushd_destroy)) + old = tal_free(old); + else { + old->fd = open(".", O_RDONLY); + if (old->fd < 0) + old = tal_free(old); + else if (chdir(dir) != 0) + old = tal_free(old); + } + + if (taken(dir)) + tal_free(dir); + return old; +} + +bool path_popd(struct path_pushd *olddir) +{ + bool ok = (fchdir(olddir->fd) == 0); + + tal_free(olddir); + return ok; +} +#else +struct path_pushd { + const char *olddir; +}; + +struct path_pushd *path_pushd(const tal_t *ctx, const char *dir) +{ + struct path_pushd *old = tal(ctx, struct path_pushd); + + if (!old) + return NULL; + + old->olddir = path_cwd(old); + if (unlikely(!old->olddir)) + old = tal_free(old); + else if (unlikely(!dir) && is_taken(dir)) + old = tal_free(old); + else if (chdir(dir) != 0) + old = tal_free(old); + + if (taken(dir)) + tal_free(dir); + + return old; +} + +bool path_popd(struct path_pushd *olddir) +{ + bool ok = (chdir(olddir->olddir) == 0); + + tal_free(olddir); + return ok; +} +#endif /* !HAVE_FCHDIR */ + +char *path_canon(const tal_t *ctx, const char *a) +{ +#if 0 + char *oldcwd, *path, *p; + void *tmpctx; + size_t len; + struct path_pushd *olddir; + + /* A good guess as to size. */ + len = strlen(a) + 1; + if (a[0] != PATH_SEP) { + tmpctx = oldcwd = path_cwd(ctx); + if (!oldcwd) + return NULL; + len += strlen(oldcwd) + strlen(PATH_SEP_STR); + + path = tal_array(tmpctx, char, len); + if (!path) + goto out; + + len = strlen(oldcwd); + memcpy(path, oldcwd, len); + path[len++] = PATH_SEP; + } else { + tmpctx = path = tal_array(ctx, char, len); + if (!path) + return NULL; + len = 0; + } + strcpy(path + len, a); + + p = strrchr(path, PATH_SEP); + *p = '\0'; + + olddir = path_pushd(tmpctx, path); + if (!olddir) + goto out; + + /* Make OS canonicalize path for us. */ + path = path_cwd(tmpctx); + if (!path) + goto out; + + /* Append rest of old path. */ + len = strlen(p+1); + if (len) { + size_t oldlen = tal_array_length(path); + if (path[oldlen-1] != PATH_SEP) { + /* Include / to append. */ + *p = PATH_SEP; + p--; + len++; + } + path = tal_realloc(NULL, path, char, oldlen+len+1); + if (!path) + goto out; + memcpy(path + oldlen, p, len+1); + } + + path = tal_steal(ctx, path); +out: + /* This can happen if old cwd is deleted. */ + if (!path_popd(olddir)) + path = tal_free(path); + + tal_free(tmpctx); + return path; +#else + char *path; + if (unlikely(!a) && is_taken(a)) + path = NULL; + else { + path = tal_arr(ctx, char, PATH_MAX); + if (path && !realpath(a, path)) + path = tal_free(path); + } + if (taken(a)) + tal_free(a); + return path; +#endif +} + +/* Symlinks make this hard! */ +char *path_rel(const tal_t *ctx, const char *from, const char *to) +{ + char *cfrom, *cto, *ret, *p; + tal_t *tmpctx; + size_t common, num_back, i, postlen; + + /* This frees from if we're supposed to take it. */ + tmpctx = cfrom = path_canon(ctx, from); + if (!cfrom) + goto fail_take_to; + + /* From is a directory, so we append / to it. */ + if (!streq(cfrom, PATH_SEP_STR)) { + if (!tal_resize(&cfrom, strlen(cfrom)+2)) + goto fail_take_to; + tmpctx = cfrom; + strcat(cfrom, PATH_SEP_STR); + } + + /* This frees to if we're supposed to take it. */ + cto = path_canon(tmpctx, to); + if (!cto) + goto out; + + /* How much is in common? */ + for (common = i = 0; cfrom[i] && cto[i]; i++) { + if (cfrom[i] != cto[i]) + break; + if (cfrom[i] == PATH_SEP) + common = i + 1; + } + + /* Skip over / if matches end of other path. */ + if (!cfrom[i] && cto[i] == PATH_SEP) { + cto++; + common = i; + } else if (!cto[i] && cfrom[i] == PATH_SEP) { + cfrom++; + common = i; + } + + /* Normalize so strings point past common area. */ + cfrom += common; + cto += common; + + /* One .. for every path element remaining in 'from', to get + * back to common prefix. Then the rest of 'to'. */ + num_back = strcount(cfrom, PATH_SEP_STR); + postlen = strlen(cto) + 1; + + /* Nothing left? That's ".". */ + if (num_back == 0 && postlen == 1) { + ret = tal_strdup(ctx, "."); + goto out; + } + + ret = tal_arr(ctx, char, + strlen(".." PATH_SEP_STR) * num_back + postlen); + if (!ret) + goto out; + + for (i = 0, p = ret; i < num_back; i++, p += strlen(".." PATH_SEP_STR)) + memcpy(p, ".." PATH_SEP_STR, strlen(".." PATH_SEP_STR)); + /* Nothing to append? Trim the final / */ + if (postlen == 1) + p--; + memcpy(p, cto, postlen); + +out: + tal_free(tmpctx); + return ret; + +fail_take_to: + if (taken(to)) + tal_free(to); + ret = NULL; + goto out; +} + + char *path_readlink(const tal_t *ctx, const char *linkname) + { + ssize_t len, maxlen = 64; /* good first guess. */ + char *ret = NULL; + + if (unlikely(!linkname) && is_taken(linkname)) + goto fail; + + ret = tal_arr(ctx, char, maxlen + 1); + + while (ret) { + len = readlink(linkname, ret, maxlen); + if (len < 0) + goto fail; + if (len < maxlen) + break; + + if (!tal_resize(&ret, maxlen *= 2 + 1)) + goto fail; + } + + ret[len] = '\0'; +out: + if (taken(linkname)) + tal_free(linkname); + + return ret; + +fail: + ret = tal_free(ret); + goto out; +} + +char *path_simplify(const tal_t *ctx, const char *path) +{ + size_t i, j, start, len; + char *ret; + bool ended = false; + + ret = tal_strdup(ctx, path); + if (!ret) + return NULL; + + /* Always need first / if there is one. */ + if (ret[0] == PATH_SEP) + start = 1; + else + start = 0; + + for (i = j = start; !ended; i += len) { + /* Get length of this segment, including terminator. */ + for (len = 0; ret[i+len] != PATH_SEP; len++) { + if (!ret[i+len]) { + ended = true; + break; + } + } + len++; + + /* Empty segment is //; ignore first one. */ + if (len == 1) + continue; + + /* Always ignore slashdot. */ + if (len == 2 && ret[i] == '.') + continue; + + /* .. => remove previous if there is one, unless symlink. */ + if (len == 3 && ret[i] == '.' && ret[i+1] == '.') { + struct stat st; + + if (j > start) { + /* eg. /foo/, foo/ or foo/bar/ */ + assert(ret[j-1] == PATH_SEP); + ret[j-1] = '\0'; + + /* Avoid stepping back over ..! */ + if (streq(ret, "..") + || strends(ret, PATH_SEP_STR"..")) { + ret[j-1] = PATH_SEP; + goto copy; + } + + if (lstat(ret, &st) == 0 + && !S_ISLNK(st.st_mode)) { + char *sep = strrchr(ret, PATH_SEP); + if (sep) + j = sep - ret + 1; + else + j = 0; + } + continue; + } else if (start) { + /* /.. => / */ + j = 1; + /* nul term in case we're at end */ + ret[1] = '\0'; + continue; + } + } + + copy: + memmove(ret + j, ret + i, len); + /* Don't count nul terminator. */ + j += len - ended; + } + + /* Empty string created by ../ elimination. */ + if (j == 0) { + ret[0] = '.'; + ret[1] = '\0'; + } else if (j > 1 && ret[j-1] == PATH_SEP) { + ret[j-1] = '\0'; + } else + ret[j] = '\0'; + + return ret; +} + +char *path_basename(const tal_t *ctx, const char *path) +{ + const char *sep; + char *ret; + + if (unlikely(!path) && taken(path)) + return NULL; + + sep = strrchr(path, PATH_SEP); + if (!sep) + return tal_strdup(ctx, path); + + /* Trailing slashes need to be trimmed. */ + if (!sep[1]) { + const char *end; + + for (end = sep; end != path; end--) + if (*end != PATH_SEP) + break; + + /* Find *previous* / */ + for (sep = end; sep >= path && *sep != PATH_SEP; sep--); + + /* All /? Just return / */ + if (end == sep) + ret = tal_strdup(ctx, PATH_SEP_STR); + else + ret = tal_strndup(ctx, sep+1, end - sep); + } else + ret = tal_strdup(ctx, sep + 1); + + if (taken(path)) + tal_free(path); + return ret; +} + +/* This reuses str if we're to take it. */ +static char *fixed_string(const tal_t *ctx, + const char *str, const char *path) +{ + char *ret = tal_dup(ctx, char, path, 0, strlen(str)+1); + if (ret) + strcpy(ret, str); + return ret; +} + +char *path_dirname(const tal_t *ctx, const char *path) +{ + const char *sep; + + if (unlikely(!path) && taken(path)) + return NULL; + + sep = strrchr(path, PATH_SEP); + if (!sep) + return fixed_string(ctx, ".", path); + + /* Trailing slashes need to be trimmed. */ + if (!sep[1]) { + const char *end; + + for (end = sep; end != path; end--) + if (*end != PATH_SEP) + break; + + /* Find *previous* / */ + for (sep = end; sep > path && *sep != PATH_SEP; sep--); + } + + /* In case there are multiple / in a row. */ + while (sep > path && sep[-1] == PATH_SEP) + sep--; + + if (sep == path) { + if (path_is_abs(path)) + return tal_strndup(ctx, path, 1); + else + return fixed_string(ctx, ".", path); + } + return tal_strndup(ctx, path, sep - path); +} + +bool path_is_abs(const char *path) +{ + return path[0] == PATH_SEP; +} + +bool path_is_file(const char *path) +{ + struct stat st; + + return stat(path, &st) == 0 && S_ISREG(st.st_mode); +} + +bool path_is_dir(const char *path) +{ + struct stat st; + + return stat(path, &st) == 0 && S_ISDIR(st.st_mode); +} + +char **path_split(const tal_t *ctx, const char *path) +{ + bool empty = path && !path[0]; + char **ret = strsplit(ctx, path, PATH_SEP_STR, STR_NO_EMPTY); + + /* Handle the "/" case */ + if (ret && !empty && !ret[0]) { + if (!tal_resize(&ret, 2)) + ret = tal_free(ret); + else { + ret[1] = NULL; + ret[0] = tal_strdup(ret, PATH_SEP_STR); + if (!ret[0]) + ret = tal_free(ret); + } + } + + return ret; +} + +size_t path_ext_off(const char *path) +{ + const char *dot, *base; + + dot = strrchr(path, '.'); + if (dot) { + base = strrchr(path, PATH_SEP); + if (!base) + base = path; + else + base++; + if (dot > base) + return dot - path; + } + return strlen(path); +} diff --git a/ccan/tal/path/path.h b/ccan/tal/path/path.h new file mode 100644 index 00000000..65d539c1 --- /dev/null +++ b/ccan/tal/path/path.h @@ -0,0 +1,167 @@ +/* Licensed under BSD-MIT - see LICENSE file for details */ +#ifndef CCAN_PATH_H +#define CCAN_PATH_H +#include +#include + +/** + * path_cwd - get current directory. + * @ctx: the context to tal from + * + * Returns NULL and sets errno on error. + */ +char *path_cwd(const tal_t *ctx); + +/** + * path_readlink - get a symbolic link contents + * @ctx: the context to tal the result from + * @link: the link to read (can be take()) + * + * Returns NULL and sets errno on error, otherwise returns nul-terminated + * link contents. + */ +char *path_readlink(const tal_t *ctx, const char *link); + +/** + * path_canon - return the canonical absolute pathname. + * @ctx: the context to tal the result from. + * @a: path to canonicalize (can be take()) + * + * Returns NULL and sets errno on error, otherwise returns an absolute + * path with no symbolic links and no extra separators (ie. as per + * realpath). + */ +char *path_canon(const tal_t *ctx, const char *a); + +/** + * path_simplify - remove double-/, ./ and some ../, plus trailing /. + * @ctx: the context to tal the result from + * @a: path to simplify (can be take()) + * + * Unlike path_canon(), this routine does not convert a path to absolute + * terms or remove symlinks, but it does neaten it by removing extraneous + * parts. + */ +char *path_simplify(const tal_t *ctx, const char *a); + +/** + * path_join - attach one path to another. + * @ctx: the context to tal the result from + * @base: the path to start at (can be take()) + * @a: the path to head from there (can be take()) + * + * If @a is an absolute path, return a copy of it. Otherwise, attach + * @a to @base. + */ +char *path_join(const tal_t *ctx, const char *base, const char *a); + +/** + * path_pushd - save old dir and change to a new one. + * @ctx: the context to tal the result from + * @dir: the directory to return to (can be take()) + */ +struct path_pushd *path_pushd(const tal_t *ctx, const char *dir); + +/** + * path_popd - return to old, path_pushd dir. + * @olddir: the return from a previous path_pushd. + * + * Returns false and sets errno if it fails. + */ +bool path_popd(struct path_pushd *olddir); + +/** + * path_rel - get relative path from a to b. + * @ctx: the context to tal the result from. + * @fromdir: the starting location (can be take()) + * @to: the destination location (can be take()) + * + * This returns a relative path which leads from @fromdir (assumed to be a + * directory) to @to. If @ctx it TAL_TAKE, frees both @fromdir and @to. + * + * Example: + * char *path = path_rel(NULL, "/tmp", "/"); + * assert(strcmp(path, "..") == 0); + */ +char *path_rel(const tal_t *ctx, const char *fromdir, const char *to); + +/** + * path_basename - get trailing filename part of path + * @ctx: the context to tal the result from + * @path: the path (can be take()) + * + * This follows SUSv2: + * path dirname basename + * "/usr/lib" "/usr" "lib" + * "/usr/" "/" "usr" + * "usr" "." "usr" + * "/" "/" "/" + * "." "." "." + * ".." "." ".." + * + * See Also: + * path_dirname() + */ +char *path_basename(const tal_t *ctx, const char *path); + +/** + * path_dirname - get the directory part of path + * @ctx: the context to tal the result from. + * @path: the path (can be take()) + * + * This follows SUSv2. + * + * See Also: + * path_basename() + */ +char *path_dirname(const tal_t *ctx, const char *path); + +/** + * path_is_abs - is a path absolute? + * @path: the path to examine. + */ +bool path_is_abs(const char *path); + +/** + * path_is_file - is a path an existing file (or long to one)? + * @path: the path to examine. + */ +bool path_is_file(const char *path); + +/** + * path_is_file - is a path an existing directory (or long to one)? + * @path: the path to examine. + */ +bool path_is_dir(const char *path); + +/** + * path_split - split a path into its pathname components + * @ctx: the context to tal the result from + * @path: the path (can be take()) + * + * This returns the sections of a path, such that joining them with / + * will restore the original path. This means that the resulting + * strings will never contain / unless the input path was entirely one + * or more "/" characters. + * + * The final char * in the array will be NULL. + * + * See Also: + * strjoin() + */ +char **path_split(const tal_t *ctx, const char *path); + +/** + * path_ext_off - get offset of the extension within a pathname. + * @path: the path + * + * This returns the offset of the final . in the pathname (ie. + * path[path_ext_off(path)] == '.') or the length of the string + * if there is no extension. + * + * Note that if the only . in the basename is at the start + * (eg. /home/person/.bashrc), that is not considered an extension! + */ +size_t path_ext_off(const char *path); + +#endif /* CCAN_PATH_H */ diff --git a/ccan/tal/path/test/run-basename.c b/ccan/tal/path/test/run-basename.c new file mode 100644 index 00000000..c99353a4 --- /dev/null +++ b/ccan/tal/path/test/run-basename.c @@ -0,0 +1,58 @@ +#include +#include +#include + +int main(void) +{ + char *path, *ctx = tal_strdup(NULL, "ctx"); + + plan_tests(26); + + path = path_basename(ctx, "/usr/lib"); + ok1(streq(path, "lib")); + ok1(tal_parent(path) == ctx); + path = path_basename(ctx, "/usr/"); + ok1(streq(path, "usr")); + ok1(tal_parent(path) == ctx); + path = path_basename(ctx, "/usr//"); + ok1(streq(path, "usr")); + ok1(tal_parent(path) == ctx); + path = path_basename(ctx, "usr"); + ok1(streq(path, "usr")); + ok1(tal_parent(path) == ctx); + path = path_basename(ctx, "/"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + path = path_basename(ctx, "//"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + path = path_basename(ctx, "."); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + path = path_basename(ctx, "./"); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + path = path_basename(ctx, ".."); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + path = path_basename(ctx, "../"); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + tal_free(ctx); + + ctx = tal_strdup(NULL, "ctx"); + ok1(!tal_first(ctx)); + + /* Test take */ + path = path_basename(ctx, take(tal_strdup(ctx, ".."))); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + ok1(tal_first(ctx) == path && !tal_next(ctx, path)); + tal_free(path); + ok1(path_basename(ctx, take(NULL)) == NULL); + ok1(!tal_first(ctx)); + + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-canon.c b/ccan/tal/path/test/run-canon.c new file mode 100644 index 00000000..e01567bf --- /dev/null +++ b/ccan/tal/path/test/run-canon.c @@ -0,0 +1,53 @@ +#include +#include +#include + +int main(void) +{ + char cwd[1024], *path, *path2, *ctx = tal_strdup(NULL, "ctx"); + + plan_tests(15); + + if (!getcwd(cwd, sizeof(cwd))) + abort(); + + unlink("run-canon-link"); + rmdir("run-canon-foo"); + if (mkdir("run-canon-foo", 0700) != 0) + abort(); + if (symlink("run-canon-foo", "run-canon-link") != 0) + abort(); + + path = path_canon(ctx, "run-canon-foo"); + ok1(tal_parent(path) == ctx); + ok1(strends(path, "run-canon-foo")); + ok1(strstarts(path, cwd)); + ok1(path[strlen(cwd)] == PATH_SEP); + ok1(strlen(path) == strlen(cwd) + 1 + strlen("run-canon-foo")); + tal_free(path); + + ok1(!path_canon(ctx, take(NULL))); + ok1(tal_first(ctx) == NULL); + + /* Test take doesn't leak. */ + ok1(tal_first(ctx) == NULL); + path = path_canon(ctx, take(tal_strdup(ctx, "run-canon-foo"))); + ok1(strends(path, "run-canon-foo")); + ok1(strstarts(path, cwd)); + ok1(path[strlen(cwd)] == PATH_SEP); + ok1(strlen(path) == strlen(cwd) + 1 + strlen("run-canon-foo")); + ok1(tal_first(ctx) == path && tal_next(ctx, path) == NULL); + path2 = path_canon(ctx, "run-canon-link"); + ok1(streq(path2, path)); + + unlink("run-canon-link"); + if (symlink(".", "run-canon-link") != 0) + abort(); + + path = path_canon(ctx, "run-canon-link"); + ok1(streq(path, cwd)); + + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-cwd.c b/ccan/tal/path/test/run-cwd.c new file mode 100644 index 00000000..d751774b --- /dev/null +++ b/ccan/tal/path/test/run-cwd.c @@ -0,0 +1,37 @@ +#include +#include +#include + +int main(void) +{ + char path1[1024], *cwd, *ctx = tal_strdup(NULL, "ctx"); + + /* This is how many tests you plan to run */ + plan_tests(5); + + if (!getcwd(path1, sizeof(path1))) + abort(); + + cwd = path_cwd(ctx); + ok1(cwd); + ok1(tal_parent(cwd) == ctx); + tal_free(cwd); + + rmdir("run-cwd-long-long-long-name/bar-long-long-long-long-name"); + rmdir("run-cwd-long-long-long-name"); + if (mkdir("run-cwd-long-long-long-name", 0700) != 0) + abort(); + if (mkdir("run-cwd-long-long-long-name/bar-long-long-long-long-name", 0700) != 0) + abort(); + if (chdir("run-cwd-long-long-long-name/bar-long-long-long-long-name") != 0) + abort(); + + cwd = path_cwd(ctx); + ok1(cwd); + ok1(tal_parent(cwd) == ctx); + ok1(strends(cwd, + "run-cwd-long-long-long-name/bar-long-long-long-long-name")); + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-dirname.c b/ccan/tal/path/test/run-dirname.c new file mode 100644 index 00000000..46589aef --- /dev/null +++ b/ccan/tal/path/test/run-dirname.c @@ -0,0 +1,58 @@ +#include +#include +#include + +int main(void) +{ + char *path, *ctx = tal_strdup(NULL, "ctx"); + + plan_tests(26); + + path = path_dirname(ctx, "/usr/lib"); + ok1(streq(path, "/usr")); + ok1(tal_parent(path) == ctx); + path = path_dirname(ctx, "/usr/"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + path = path_dirname(ctx, "/usr//"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + path = path_dirname(ctx, "usr"); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + path = path_dirname(ctx, "/"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + path = path_dirname(ctx, "//"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + path = path_dirname(ctx, "."); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + path = path_dirname(ctx, "./"); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + path = path_dirname(ctx, ".."); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + path = path_dirname(ctx, "../"); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + tal_free(ctx); + + ctx = tal_strdup(NULL, "ctx"); + ok1(!tal_first(ctx)); + + /* Test take */ + path = path_dirname(ctx, take(tal_strdup(ctx, ".."))); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + ok1(tal_first(ctx) == path && !tal_next(ctx, path)); + tal_free(path); + ok1(path_dirname(ctx, take(NULL)) == NULL); + ok1(!tal_first(ctx)); + + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-ext_off.c b/ccan/tal/path/test/run-ext_off.c new file mode 100644 index 00000000..ab0d0a53 --- /dev/null +++ b/ccan/tal/path/test/run-ext_off.c @@ -0,0 +1,19 @@ +#include +#include +#include + +int main(void) +{ + plan_tests(9); + + ok1(path_ext_off("foo") == 3); + ok1(path_ext_off(".foo") == 4); + ok1(path_ext_off("bar.foo") == 3); + ok1(path_ext_off("bar/foo") == 7); + ok1(path_ext_off("bar/.foo") == 8); + ok1(path_ext_off(".bar/foo") == 8); + ok1(path_ext_off("foo.bar/foo") == 11); + ok1(path_ext_off("foo.bar/foo.") == 11); + ok1(path_ext_off("foo.bar/foo..") == 12); + return exit_status(); +} diff --git a/ccan/tal/path/test/run-is_abs.c b/ccan/tal/path/test/run-is_abs.c new file mode 100644 index 00000000..8cb0a1d8 --- /dev/null +++ b/ccan/tal/path/test/run-is_abs.c @@ -0,0 +1,16 @@ +#include +#include +#include + +int main(void) +{ + plan_tests(5); + + ok1(path_is_abs(PATH_SEP_STR "foo")); + ok1(!path_is_abs("foo")); + ok1(!path_is_abs("foo" PATH_SEP_STR)); + + ok1(path_is_abs(PATH_SEP_STR "foo" PATH_SEP_STR)); + ok1(path_is_abs(PATH_SEP_STR ".")); + return exit_status(); +} diff --git a/ccan/tal/path/test/run-is_dir.c b/ccan/tal/path/test/run-is_dir.c new file mode 100644 index 00000000..15b0c4df --- /dev/null +++ b/ccan/tal/path/test/run-is_dir.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include + +int main(void) +{ + char cwd[1024], *path, *ctx = tal_strdup(NULL, "ctx"); + + plan_tests(6); + + if (!getcwd(cwd, sizeof(cwd))) + abort(); + + unlink("run-is_dir-dir-link"); + unlink("run-is_dir-file-link"); + unlink("run-is_dir-dir/file"); + rmdir("run-is_dir-dir"); + if (mkdir("run-is_dir-dir", 0700) != 0) + abort(); + if (symlink("run-is_dir-dir", "run-is_dir-dir-link") != 0) + abort(); + if (symlink("run-is_dir-dir/file", "run-is_dir-file-link") != 0) + abort(); + close(open("run-is_dir-dir/file", O_WRONLY|O_CREAT, 0600)); + + ok1(path_is_dir("run-is_dir-dir-link")); + ok1(!path_is_dir("run-is_dir-file-link")); + ok1(!path_is_dir("run-is_dir-dir/file")); + ok1(path_is_dir("run-is_dir-dir")); + + path = path_join(ctx, cwd, "run-is_dir-dir/file"); + ok1(!path_is_dir(path)); + ok1(path_is_dir(cwd)); + + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-is_file.c b/ccan/tal/path/test/run-is_file.c new file mode 100644 index 00000000..fc3c7d30 --- /dev/null +++ b/ccan/tal/path/test/run-is_file.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include + +int main(void) +{ + char cwd[1024], *path, *ctx = tal_strdup(NULL, "ctx"); + + plan_tests(7); + + if (!getcwd(cwd, sizeof(cwd))) + abort(); + + unlink("run-is_file-dir-link"); + unlink("run-is_file-file-link"); + unlink("run-is_file-dir/file"); + rmdir("run-is_file-dir"); + if (mkdir("run-is_file-dir", 0700) != 0) + abort(); + if (symlink("run-is_file-dir", "run-is_file-dir-link") != 0) + abort(); + if (symlink("run-is_file-dir/file", "run-is_file-file-link") != 0) + abort(); + close(open("run-is_file-dir/file", O_WRONLY|O_CREAT, 0600)); + + ok1(!path_is_file("run-is_file-dir-link")); + ok1(path_is_file("run-is_file-file-link")); + ok1(path_is_file("run-is_file-dir/file")); + ok1(!path_is_file("run-is_file-dir")); + ok1(!path_is_file("run-is_file-nonexist")); + + path = path_join(ctx, cwd, "run-is_file-dir/file"); + ok1(path_is_file(path)); + ok1(!path_is_file(cwd)); + + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-join.c b/ccan/tal/path/test/run-join.c new file mode 100644 index 00000000..a4f63b31 --- /dev/null +++ b/ccan/tal/path/test/run-join.c @@ -0,0 +1,91 @@ +#include +#include +#include + +int main(void) +{ + char *path, *ctx = tal_strdup(NULL, "ctx"); + + plan_tests(34); + + path = path_join(ctx, "foo", "bar"); + ok1(streq(path, "foo/bar")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_join(ctx, "foo/", "bar"); + ok1(streq(path, "foo/bar")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_join(ctx, "foo/", "/bar"); + ok1(streq(path, "/bar")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_join(ctx, "foo", "/bar"); + ok1(streq(path, "/bar")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + /* Test take */ + path = path_join(ctx, "foo", take(tal_strdup(ctx, "bar"))); + ok1(streq(path, "foo/bar")); + ok1(tal_parent(path) == ctx); + ok1(tal_first(ctx) == path && tal_next(ctx, path) == NULL); + tal_free(path); + + path = path_join(ctx, "foo", take(tal_strdup(ctx, "/bar"))); + ok1(streq(path, "/bar")); + ok1(tal_parent(path) == ctx); + ok1(tal_first(ctx) == path && tal_next(ctx, path) == NULL); + tal_free(path); + + path = path_join(ctx, take(tal_strdup(ctx, "foo")), "bar"); + ok1(streq(path, "foo/bar")); + ok1(tal_parent(path) == ctx); + ok1(tal_first(ctx) == path && tal_next(ctx, path) == NULL); + tal_free(path); + + path = path_join(ctx, take(tal_strdup(ctx, "foo")), "/bar"); + ok1(streq(path, "/bar")); + ok1(tal_parent(path) == ctx); + ok1(tal_first(ctx) == path && tal_next(ctx, path) == NULL); + tal_free(path); + + path = path_join(ctx, take(tal_strdup(ctx, "foo")), + take(tal_strdup(ctx, "bar"))); + ok1(streq(path, "foo/bar")); + ok1(tal_parent(path) == ctx); + ok1(tal_first(ctx) == path && tal_next(ctx, path) == NULL); + tal_free(path); + + path = path_join(ctx, take(tal_strdup(ctx, "foo")), + take(tal_strdup(ctx, "/bar"))); + ok1(streq(path, "/bar")); + ok1(tal_parent(path) == ctx); + ok1(tal_first(ctx) == path && tal_next(ctx, path) == NULL); + tal_free(path); + + path = path_join(ctx, take(NULL), "bar"); + ok1(!path); + ok1(!tal_first(ctx)); + + /* This is allowed to succeed, as first arg unneeded. */ + path = path_join(ctx, take(NULL), "/bar"); + ok1(!path || streq(path, "/bar")); + tal_free(path); + ok1(!tal_first(ctx)); + + path = path_join(ctx, "foo", take(NULL)); + ok1(!path); + ok1(!tal_first(ctx)); + + path = path_join(ctx, take(NULL), take(NULL)); + ok1(!path); + ok1(!tal_first(ctx)); + + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-pushd.c b/ccan/tal/path/test/run-pushd.c new file mode 100644 index 00000000..dc3f2eae --- /dev/null +++ b/ccan/tal/path/test/run-pushd.c @@ -0,0 +1,75 @@ +#include +#include +#include + +int main(void) +{ + struct path_pushd *pd; + char path1[1024], path2[1024], *ctx = tal_strdup(NULL, "ctx"); + + /* This is how many tests you plan to run */ + plan_tests(19); + + /* Test pushd/popd */ + if (!getcwd(path1, sizeof(path1))) + abort(); + + pd = path_pushd(NULL, "non-existent-dir"); + ok1(errno == ENOENT); + ok1(!pd); + + errno = -100; + pd = path_pushd(ctx, take(tal_strdup(ctx, "non-existent-dir"))); + ok1(errno == ENOENT); + ok1(!pd); + ok1(!tal_first(ctx)); + + errno = -100; + pd = path_pushd(ctx, take(NULL)); + ok1(!pd); + ok1(!tal_first(ctx)); + ok1(errno == -100); + + pd = path_pushd(ctx, "/tmp"); + ok1(pd); + ok1(tal_parent(pd) == ctx); + + if (!getcwd(path2, sizeof(path2))) + abort(); + + ok1(streq(path2, "/tmp")); + path_popd(pd); + + if (!getcwd(path2, sizeof(path2))) + abort(); + ok1(streq(path2, path1)); + + pd = path_pushd(ctx, take(tal_strdup(ctx, "/tmp"))); + ok1(pd); + ok1(tal_parent(pd) == ctx); + path_popd(pd); + if (!getcwd(path2, sizeof(path2))) + abort(); + ok1(streq(path2, path1)); + ok1(!tal_first(ctx)); + + /* Without fchdir, we can't push a path which no longer exists. */ + if (mkdir("run-pushd-dir", 0700) != 0) + abort(); + if (chdir("run-pushd-dir") != 0) + abort(); + if (rmdir("../run-pushd-dir") != 0) + abort(); + + pd = path_pushd(ctx, path1); +#if HAVE_FCHDIR + ok1(pd); + ok1(path_popd(pd)); +#else + ok1(errno == ENOENT); + ok1(!pd); +#endif + ok1(!tal_first(ctx)); + tal_free(ctx); + return exit_status(); +} diff --git a/ccan/tal/path/test/run-readlink.c b/ccan/tal/path/test/run-readlink.c new file mode 100644 index 00000000..28dcf87e --- /dev/null +++ b/ccan/tal/path/test/run-readlink.c @@ -0,0 +1,46 @@ +#include +#include +#include + +int main(void) +{ + char *link, *ctx = tal_strdup(NULL, "ctx"); + + plan_tests(12); + + unlink("run-readlink-link"); + + link = path_readlink(ctx, "run-readlink-link"); + ok1(errno == ENOENT); + ok1(!link); + + link = path_readlink(ctx, take(tal_strdup(ctx, "run-readlink-link"))); + ok1(errno == ENOENT); + ok1(!link); + ok1(tal_first(ctx) == NULL); + + if (symlink("/tmp", "run-readlink-link") != 0) + abort(); + + link = path_readlink(ctx, "run-readlink-link"); + ok1(tal_parent(link) == ctx); + ok1(streq(link, "/tmp")); + tal_free(link); + + link = path_readlink(ctx, take(tal_strdup(ctx, "run-readlink-link"))); + ok1(tal_parent(link) == ctx); + ok1(streq(link, "/tmp")); + ok1(tal_first(ctx) == link && tal_next(ctx, link) == NULL); + + unlink("run-readlink-link"); + + if (symlink("some-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-long-name", "run-readlink-link") != 0) + abort(); + + link = path_readlink(ctx, "run-readlink-link"); + ok1(tal_parent(link) == ctx); + ok1(streq(link, "some-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-long-name")); + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-rel.c b/ccan/tal/path/test/run-rel.c new file mode 100644 index 00000000..7083c4bd --- /dev/null +++ b/ccan/tal/path/test/run-rel.c @@ -0,0 +1,69 @@ +#include +#include +#include + +int main(void) +{ + char cwd[1024], *path, *ctx = tal_strdup(NULL, "ctx"); + + plan_tests(19); + + if (!getcwd(cwd, sizeof(cwd))) + abort(); + + unlink("run-rel-link"); + rmdir("run-rel-foo"); + if (mkdir("run-rel-foo", 0700) != 0) + abort(); + if (symlink("run-rel-foo", "run-rel-link") != 0) + abort(); + + path = path_rel(ctx, ".", "run-rel-foo"); + ok1(streq(path, "run-rel-foo")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_rel(ctx, "run-rel-foo", "."); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_rel(ctx, ".", "run-rel-link"); + /* This doesn't specify whether it preserves links. */ + ok1(streq(path, "run-rel-link") || streq(path, "run-rel-foo")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_rel(ctx, "/", "."); + ok1(streq(path, cwd + 1)); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_rel(ctx, "run-rel-foo", "run-rel-foo"); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_rel(ctx, take(tal_strdup(ctx, ".")), "run-rel-foo"); + ok1(streq(path, "run-rel-foo")); + ok1(tal_parent(path) == ctx); + tal_free(path); + ok1(tal_first(ctx) == NULL); + + path = path_rel(ctx, ".", take(tal_strdup(ctx, "run-rel-foo"))); + ok1(streq(path, "run-rel-foo")); + ok1(tal_parent(path) == ctx); + tal_free(path); + ok1(tal_first(ctx) == NULL); + + path = path_rel(ctx, take(tal_strdup(ctx, ".")), + take(tal_strdup(ctx, "run-rel-foo"))); + ok1(streq(path, "run-rel-foo")); + ok1(tal_parent(path) == ctx); + tal_free(path); + ok1(tal_first(ctx) == NULL); + + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-simplify.c b/ccan/tal/path/test/run-simplify.c new file mode 100644 index 00000000..3d1b3514 --- /dev/null +++ b/ccan/tal/path/test/run-simplify.c @@ -0,0 +1,244 @@ +#include +#include +#include + +int main(void) +{ + char cwd[1024], *path, *ctx = tal_strdup(NULL, "ctx"); + + plan_tests(87); + + if (!getcwd(cwd, sizeof(cwd))) + abort(); + + rmdir("run-simplify-foo"); + unlink("run-simplify-link"); + if (mkdir("run-simplify-foo", 0700) != 0) + abort(); + if (symlink("run-simplify-foo", "run-simplify-link") != 0) + abort(); + + /* Handling of . and .. */ + path = path_simplify(ctx, "."); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./"); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, ".."); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "../"); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./.."); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./../"); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./../."); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./.././"); + ok1(streq(path, "..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./../.."); + ok1(streq(path, "../..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./../../"); + ok1(streq(path, "../..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + /* Handling of /. and /.. */ + path = path_simplify(ctx, "/"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "//"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/."); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/./"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/.."); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/../"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/./.."); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/./../"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/./../."); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/./.././"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/./../.."); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/./../../"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + /* Don't trace back over a symlink link */ + path = path_simplify(ctx, "run-simplify-foo"); + ok1(streq(path, "run-simplify-foo")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./run-simplify-foo"); + ok1(streq(path, "run-simplify-foo")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./run-simplify-foo/."); + ok1(streq(path, "run-simplify-foo")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "run-simplify-link"); + ok1(streq(path, "run-simplify-link")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./run-simplify-link"); + ok1(streq(path, "run-simplify-link")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "./run-simplify-link/."); + ok1(streq(path, "run-simplify-link")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "run-simplify-foo/.."); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "run-simplify-foo//.."); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "run-simplify-foo//../"); + ok1(streq(path, ".")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + /* This is expected to be a real directory. */ + path = path_simplify(ctx, "/tmp"); + ok1(streq(path, "/tmp")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/tmp/"); + ok1(streq(path, "/tmp")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/tmp/."); + ok1(streq(path, "/tmp")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/./tmp/."); + ok1(streq(path, "/tmp")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/../tmp/."); + ok1(streq(path, "/tmp")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/tmp/.."); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/tmp/../"); + ok1(streq(path, "/")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/tmp/../tmp"); + ok1(streq(path, "/tmp")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/tmp/../tmp/"); + ok1(streq(path, "/tmp")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "/tmp/../tmp/."); + ok1(streq(path, "/tmp")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + /* take tests */ + path = path_simplify(ctx, take(tal_strdup(ctx, "/tmp/../tmp/."))); + ok1(streq(path, "/tmp")); + ok1(tal_parent(path) == ctx); + tal_free(path); + ok1(tal_first(ctx) == NULL); + + path = path_simplify(ctx, take(NULL)); + ok1(!path); + ok1(tal_first(ctx) == NULL); + + tal_free(ctx); + + return exit_status(); +} diff --git a/ccan/tal/path/test/run-split.c b/ccan/tal/path/test/run-split.c new file mode 100644 index 00000000..732333c3 --- /dev/null +++ b/ccan/tal/path/test/run-split.c @@ -0,0 +1,105 @@ +#include +#include +#include + +int main(void) +{ + char *ctx = tal_strdup(NULL, "ctx"), **split; + + plan_tests(46); + + split = path_split(ctx, "foo" PATH_SEP_STR "bar"); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(streq(split[1], "bar")); + ok1(split[2] == NULL); + tal_free(split); + + split = path_split(ctx, "foo" PATH_SEP_STR "bar" PATH_SEP_STR); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(streq(split[1], "bar")); + ok1(split[2] == NULL); + tal_free(split); + + split = path_split(ctx, PATH_SEP_STR "foo" + PATH_SEP_STR "bar" PATH_SEP_STR); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(streq(split[1], "bar")); + ok1(split[2] == NULL); + tal_free(split); + + split = path_split(ctx, PATH_SEP_STR PATH_SEP_STR "foo" + PATH_SEP_STR PATH_SEP_STR "bar" + PATH_SEP_STR PATH_SEP_STR); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(streq(split[1], "bar")); + ok1(split[2] == NULL); + tal_free(split); + + split = path_split(ctx, "foo"); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(split[1] == NULL); + tal_free(split); + + split = path_split(ctx, PATH_SEP_STR "foo"); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(split[1] == NULL); + tal_free(split); + + split = path_split(ctx, PATH_SEP_STR PATH_SEP_STR "foo"); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(split[1] == NULL); + tal_free(split); + + split = path_split(ctx, "foo" PATH_SEP_STR); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(split[1] == NULL); + tal_free(split); + + split = path_split(ctx, "foo" PATH_SEP_STR PATH_SEP_STR); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(split[1] == NULL); + tal_free(split); + + split = path_split(ctx, PATH_SEP_STR "foo" PATH_SEP_STR); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], "foo")); + ok1(split[1] == NULL); + tal_free(split); + + split = path_split(ctx, ""); + ok1(tal_parent(split) == ctx); + ok1(split[0] == NULL); + tal_free(split); + + split = path_split(ctx, PATH_SEP_STR); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], PATH_SEP_STR)); + ok1(split[1] == NULL); + tal_free(split); + + /* Test take */ + split = path_split(ctx, take(tal_strdup(ctx, PATH_SEP_STR))); + ok1(tal_parent(split) == ctx); + ok1(streq(split[0], PATH_SEP_STR)); + ok1(split[1] == NULL); + tal_free(split); + ok1(tal_first(ctx) == NULL); + + split = path_split(ctx, take(NULL)); + ok1(!split); + ok1(tal_first(ctx) == NULL); + + ok1(tal_first(NULL) == ctx && tal_next(NULL, ctx) == NULL); + tal_free(ctx); + + return exit_status(); +} -- 2.39.2