diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2019-09-03 17:08:10 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2019-09-03 17:11:12 -0400 |
commit | e2f526768e1d91893dc2772962be8155205b9c50 (patch) | |
tree | 257133be87499976dcb99803cced2798b88fd7e8 | |
parent | f7f1e3cfa25cf95e15bac30e6934d5a534ceca08 (diff) | |
download | bfs-e2f526768e1d91893dc2772962be8155205b9c50.tar.xz |
color: Fix directory coloring when resolving symlinks at the root
-rw-r--r-- | color.c | 69 | ||||
-rwxr-xr-x | tests.sh | 25 | ||||
-rw-r--r-- | tests/test_color_ls.out | 6 |
3 files changed, 73 insertions, 27 deletions
@@ -716,49 +716,61 @@ static int print_colored(const struct colors *colors, const char *esc, const cha /** Find the offset of the first broken path component. */ static ssize_t first_broken_offset(const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flag flags, size_t max) { + ssize_t ret = max; + if (bftw_typeflag(ftwbuf, flags) != BFTW_ERROR) { - return max; + goto out; } + char *at_path; int at_fd; - if (path != ftwbuf->path) { - // We're in print_link_target(), so resolve relative to the parent directory - at_fd = ftwbuf->at_fd; - } else if (ftwbuf->depth == 0) { - at_fd = AT_FDCWD; + if (path == ftwbuf->path) { + if (ftwbuf->depth == 0) { + at_fd = AT_FDCWD; + at_path = dstrndup(path, max); + } else { + // The parent must have existed to get here + goto out; + } } else { - // The parent must have existed to get here - return max; + // We're in print_link_target(), so resolve relative to the link's parent directory + at_fd = AT_FDCWD; + if (at_fd == AT_FDCWD && path[0] != '/') { + at_path = dstrndup(ftwbuf->path, ftwbuf->nameoff); + if (at_path && dstrncat(&at_path, path, max) != 0) { + ret = -1; + goto out_path; + } + } else { + at_path = dstrndup(path, max); + } } - char *copy = dstralloc(max); - if (!copy) { - return 0; + if (!at_path) { + ret = -1; + goto out; } - size_t i = 0; - while (i < max) { - size_t j = i; - while (path[j] != '/') { - ++j; - } - while (path[j] == '/') { - ++j; - } - - if (dstrncat(©, path + i, j - i) != 0) { + while (ret > 0) { + if (xfaccessat(at_fd, at_path, F_OK) == 0) { break; } - if (xfaccessat(at_fd, copy, F_OK) != 0) { - break; + size_t len = dstrlen(at_path); + while (ret && at_path[len - 1] == '/') { + --len, --ret; + } + while (ret && at_path[len - 1] != '/') { + --len, --ret; } - i = j; + dstresize(&at_path, len); } - dstrfree(copy); - return i; +out_path: + dstrfree(at_path); +out: + return ret; } /** Print the directories leading up to a file. */ @@ -767,6 +779,9 @@ static int print_dirs_colored(CFILE *cfile, const char *path, const struct BFTW FILE *file = cfile->file; size_t broken = first_broken_offset(path, ftwbuf, flags, nameoff); + if (broken < 0) { + return -1; + } if (broken > 0) { if (print_colored(colors, colors->directory, path, broken, file) != 0) { @@ -618,6 +618,7 @@ bfs_tests=( test_color_no_stat test_color_L_no_stat test_color_star + test_color_ls test_execdir_plus @@ -2105,6 +2106,30 @@ function test_color_star() { LS_COLORS="*" bfs_diff rainbow -color } +function test_color_ls() { + rm -rf scratch/* + touchp scratch/foo/bar/baz + ln -s foo/bar/baz scratch/link + ln -s foo/bar/nowhere scratch/broken + ln -s foo/bar/nowhere/nothing scratch/nested + ln -s foo/bar/baz/qux scratch/notdir + ln -s scratch/foo/bar scratch/relative + ln -s /__bfs__/nowhere scratch/absolute + + local EXPECTED="$TESTS/${FUNCNAME[0]}.out" + if [ "$UPDATE" ]; then + local ACTUAL="$EXPECTED" + else + local ACTUAL="$TMP/${FUNCNAME[0]}.out" + fi + + LS_COLORS="or=01;31:" invoke_bfs scratch/{link,broken,nested,notdir,relative,absolute} -color -ls | sed 's/.* -> //' >"$ACTUAL" + + if [ ! "$UPDATE" ]; then + diff -u "$EXPECTED" "$ACTUAL" + fi +} + function test_deep() { closefrom 4 diff --git a/tests/test_color_ls.out b/tests/test_color_ls.out new file mode 100644 index 0000000..59a791a --- /dev/null +++ b/tests/test_color_ls.out @@ -0,0 +1,6 @@ +[01;34mfoo/bar/[0mbaz +[01;34mfoo/bar/[0m[01;31mnowhere[0m +[01;34mfoo/bar/[0m[01;31mnowhere/[0m[01;31mnothing[0m +[01;34mfoo/bar/[0m[01;31mbaz/[0m[01;31mqux[0m +[01;31mscratch/foo/[0m[01;31mbar[0m +[01;34m/[0m[01;31m__bfs__/[0m[01;31mnowhere[0m |