From 28c787b0dcbae9e6c7dfc0013bdaff25d0a2f009 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 2 Jan 2019 22:12:36 -0500 Subject: color: Fix more incompatibilities with GNU ls --- RELEASES.md | 7 +++- color.c | 31 +++++++------- tests.sh | 83 ++++++++++++++++++++++++++++++++++++-- tests/test_color.out | 15 +++++++ tests/test_color_ext.out | 15 +++++++ tests/test_color_ext0.out | 15 +++++++ tests/test_color_mh.out | 15 +++++++ tests/test_color_mh0.out | 15 +++++++ tests/test_color_mi.out | 15 +++++++ tests/test_color_missing_colon.out | 15 +++++++ tests/test_color_or.out | 15 +++++++ tests/test_color_or0_mi.out | 15 +++++++ tests/test_color_or_mi.out | 15 +++++++ tests/test_color_or_mi0.out | 15 +++++++ tests/test_colors.out | 12 ------ 15 files changed, 267 insertions(+), 31 deletions(-) create mode 100644 tests/test_color.out create mode 100644 tests/test_color_ext.out create mode 100644 tests/test_color_ext0.out create mode 100644 tests/test_color_mh.out create mode 100644 tests/test_color_mh0.out create mode 100644 tests/test_color_mi.out create mode 100644 tests/test_color_missing_colon.out create mode 100644 tests/test_color_or.out create mode 100644 tests/test_color_or0_mi.out create mode 100644 tests/test_color_or_mi.out create mode 100644 tests/test_color_or_mi0.out delete mode 100644 tests/test_colors.out diff --git a/RELEASES.md b/RELEASES.md index 2275cf8..f8f3c3c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -15,7 +15,12 @@ New features: Fixes: -- Extension colors from `LS_COLORS` are now case-insensitive like GNU `ls` +- `LS_COLORS` handling has been improved: + - Extension colors are now case-insensitive like GNU `ls` + - `or` (orphan) and `mi` (missing) files are now treated differently + - Default colors can be unset with `di=00` or similar + - Specific colors fall back to more general colors when unspecified in more places + - `LS_COLORS` no longer needs a trailing colon - `-ls`/`-fls` now prints the major/minor numbers for device nodes - `-exec ;` is rejected rather than segfaulting - `bfs` now builds on old Linux versions that require `-lrt` for POSIX timers diff --git a/color.c b/color.c index 5807184..a877ff7 100644 --- a/color.c +++ b/color.c @@ -184,25 +184,20 @@ struct colors *parse_colors(const char *ls_colors) { } char *start = colors->data; - char *end; + size_t colon; struct ext_color *ext; - for (end = strchr(start, ':'); *start && end; start = end + 1, end = strchr(start, ':')) { + for (colon = strcspn(start, ":"); *start; start += colon + 1, colon = strcspn(start, ":")) { + start[colon] = '\0'; + char *equals = strchr(start, '='); if (!equals) { continue; } - *equals = '\0'; - *end = '\0'; const char *key = start; const char *value = equals + 1; - // Ignore all-zero values - if (strspn(value, "0") == strlen(value)) { - continue; - } - if (key[0] == '*') { ext = malloc(sizeof(struct ext_color)); if (ext) { @@ -213,6 +208,11 @@ struct colors *parse_colors(const char *ls_colors) { colors->ext_list = ext; } } else { + // All-zero values should be treated like NULL, to fall + // back on any other relevant coloring for that file + if (strcmp(key, "rs") != 0 && strspn(value, "0") == strlen(value)) { + value = NULL; + } set_color(colors, key, value); } } @@ -307,7 +307,11 @@ static const char *ext_color(const struct colors *colors, const char *filename) static const char *file_color(const struct colors *colors, const char *filename, const struct BFTW *ftwbuf) { const struct bfs_stat *sb = ftwbuf->statbuf; if (!sb) { - return colors->orphan; + if (colors->missing) { + return colors->missing; + } else { + return colors->orphan; + } } const char *color = NULL; @@ -318,7 +322,7 @@ static const char *file_color(const struct colors *colors, const char *filename, color = colors->setuid; } else if (sb->mode & S_ISGID) { color = colors->setgid; - } else if (bfs_check_capabilities(ftwbuf)) { + } else if (colors->capable && bfs_check_capabilities(ftwbuf)) { color = colors->capable; } else if (sb->mode & 0111) { color = colors->exec; @@ -356,9 +360,8 @@ static const char *file_color(const struct colors *colors, const char *filename, break; case S_IFLNK: - if (xfaccessat(ftwbuf->at_fd, ftwbuf->at_path, F_OK) == 0) { - color = colors->link; - } else { + color = colors->link; + if (colors->orphan && xfaccessat(ftwbuf->at_fd, ftwbuf->at_path, F_OK) != 0) { color = colors->orphan; } break; diff --git a/tests.sh b/tests.sh index 0e86904..0b2678d 100755 --- a/tests.sh +++ b/tests.sh @@ -53,7 +53,9 @@ function installp() { # Like a mythical touch -p function touchp() { - installp -m644 /dev/null "$1" + for arg; do + installp -m644 /dev/null "$arg" + done } # Creates a simple file+directory structure for tests @@ -164,6 +166,29 @@ function make_deep() { } make_deep "$TMP/deep" +# Creates a directory structure with many different types, and therefore colors +function make_rainbow() { + touchp "$1/file.txt" + touchp "$1/file.dat" + ln -s file.txt "$1/link.txt" + touchp "$1/mh1" + ln "$1/mh1" "$1/mh2" + mkfifo "$1/pipe" + # XXX: block + # XXX: chardev + ln -s nowhere "$1/broken" + # XXX: socket + touchp "$1"/s{u,g,ug}id + chmod u+s "$1"/su{,g}id + chmod g+s "$1"/s{u,}gid + mkdir "$1/ow" "$1"/sticky{,_ow} + chmod o+w "$1"/*ow + chmod +t "$1"/sticky* + touchp "$1"/exec.sh + chmod +x "$1"/exec.sh +} +make_rainbow "$TMP/rainbow" + # Creates a scratch directory that tests can modify function make_scratch() { mkdir -p "$1" @@ -582,7 +607,17 @@ bfs_tests=( # Primaries - test_colors + test_color + test_color_mh + test_color_mh0 + test_color_or + test_color_mi + test_color_or_mi + test_color_or0_mi + test_color_or_mi0 + test_color_ext + test_color_ext0 + test_color_missing_colon test_execdir_plus @@ -1741,8 +1776,48 @@ function test_precedence() { bfs_diff basic \( -name foo -type d -o -name bar -a -type f \) -print , \! -empty -type f -print } -function test_colors() { - LS_COLORS= bfs_diff links -color +function test_color() { + LS_COLORS= bfs_diff rainbow -color +} + +function test_color_mh() { + LS_COLORS="mh=01:" bfs_diff rainbow -color +} + +function test_color_mh0() { + LS_COLORS="mh=00:" bfs_diff rainbow -color +} + +function test_color_or() { + LS_COLORS="or=01:" bfs_diff rainbow -color +} + +function test_color_mi() { + LS_COLORS="mi=01:" bfs_diff rainbow -color +} + +function test_color_or_mi() { + LS_COLORS="or=01;31:mi=01;33:" bfs_diff rainbow -color +} + +function test_color_or0_mi() { + LS_COLORS="or=00:mi=01;33:" bfs_diff rainbow -color +} + +function test_color_or_mi0() { + LS_COLORS="or=01;31:mi=00:" bfs_diff rainbow -color +} + +function test_color_ext() { + LS_COLORS="*.txt=01:" bfs_diff rainbow -color +} + +function test_color_ext0() { + LS_COLORS="*.txt=00:" bfs_diff rainbow -color +} + +function test_color_missing_colon() { + LS_COLORS="*.txt=01" bfs_diff rainbow -color } function test_deep() { diff --git a/tests/test_color.out b/tests/test_color.out new file mode 100644 index 0000000..e267da8 --- /dev/null +++ b/tests/test_color.out @@ -0,0 +1,15 @@ +rainbow +rainbow/exec.sh +rainbow/link.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/broken +rainbow/pipe +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_color_ext.out b/tests/test_color_ext.out new file mode 100644 index 0000000..d2e2a70 --- /dev/null +++ b/tests/test_color_ext.out @@ -0,0 +1,15 @@ +rainbow +rainbow/exec.sh +rainbow/link.txt +rainbow/file.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/broken +rainbow/pipe +rainbow/file.dat +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_color_ext0.out b/tests/test_color_ext0.out new file mode 100644 index 0000000..3bc8dc1 --- /dev/null +++ b/tests/test_color_ext0.out @@ -0,0 +1,15 @@ +rainbow +rainbow/file.txt +rainbow/exec.sh +rainbow/link.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/broken +rainbow/pipe +rainbow/file.dat +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_color_mh.out b/tests/test_color_mh.out new file mode 100644 index 0000000..600451e --- /dev/null +++ b/tests/test_color_mh.out @@ -0,0 +1,15 @@ +rainbow +rainbow/exec.sh +rainbow/link.txt +rainbow/mh1 +rainbow/mh2 +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/broken +rainbow/pipe +rainbow/file.dat +rainbow/file.txt diff --git a/tests/test_color_mh0.out b/tests/test_color_mh0.out new file mode 100644 index 0000000..e267da8 --- /dev/null +++ b/tests/test_color_mh0.out @@ -0,0 +1,15 @@ +rainbow +rainbow/exec.sh +rainbow/link.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/broken +rainbow/pipe +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_color_mi.out b/tests/test_color_mi.out new file mode 100644 index 0000000..e267da8 --- /dev/null +++ b/tests/test_color_mi.out @@ -0,0 +1,15 @@ +rainbow +rainbow/exec.sh +rainbow/link.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/broken +rainbow/pipe +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_color_missing_colon.out b/tests/test_color_missing_colon.out new file mode 100644 index 0000000..d2e2a70 --- /dev/null +++ b/tests/test_color_missing_colon.out @@ -0,0 +1,15 @@ +rainbow +rainbow/exec.sh +rainbow/link.txt +rainbow/file.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/broken +rainbow/pipe +rainbow/file.dat +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_color_or.out b/tests/test_color_or.out new file mode 100644 index 0000000..6e94bc6 --- /dev/null +++ b/tests/test_color_or.out @@ -0,0 +1,15 @@ +rainbow +rainbow/exec.sh +rainbow/link.txt +rainbow/broken +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/pipe +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_color_or0_mi.out b/tests/test_color_or0_mi.out new file mode 100644 index 0000000..cafa798 --- /dev/null +++ b/tests/test_color_or0_mi.out @@ -0,0 +1,15 @@ +rainbow +rainbow/exec.sh +rainbow/broken +rainbow/link.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/pipe +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_color_or_mi.out b/tests/test_color_or_mi.out new file mode 100644 index 0000000..7e57688 --- /dev/null +++ b/tests/test_color_or_mi.out @@ -0,0 +1,15 @@ +rainbow +rainbow/broken +rainbow/exec.sh +rainbow/link.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/pipe +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_color_or_mi0.out b/tests/test_color_or_mi0.out new file mode 100644 index 0000000..7e57688 --- /dev/null +++ b/tests/test_color_or_mi0.out @@ -0,0 +1,15 @@ +rainbow +rainbow/broken +rainbow/exec.sh +rainbow/link.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/pipe +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 diff --git a/tests/test_colors.out b/tests/test_colors.out deleted file mode 100644 index dbdeafa..0000000 --- a/tests/test_colors.out +++ /dev/null @@ -1,12 +0,0 @@ -links -links/deeply -links/skip -links/symlink -links/broken -links/notdir -links/file -links/hardlink -links/deeply/nested -links/deeply/nested/dir -links/deeply/nested/link -links/deeply/nested/file -- cgit v1.2.3