From 982aa263a0cef10ee4f4c06084a87af736c449ac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Dec 2010 21:54:39 +0100 Subject: [PATCH] ls: add support for -H Signed-off-by: Denys Vlasenko --- coreutils/ls.c | 159 ++++++++++++++++++++++++++----------------------- 1 file changed, 86 insertions(+), 73 deletions(-) diff --git a/coreutils/ls.c b/coreutils/ls.c index eadd6cee7..d27c36ddc 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -32,7 +32,7 @@ //usage:#define ls_trivial_usage //usage: "[-1AaCxd" -//usage: IF_FEATURE_LS_FOLLOWLINKS("L") +//usage: IF_FEATURE_LS_FOLLOWLINKS("LH") //usage: IF_FEATURE_LS_RECURSIVE("R") //usage: IF_FEATURE_LS_FILETYPES("Fp") "lins" //usage: IF_FEATURE_LS_TIMESTAMPS("e") @@ -51,7 +51,8 @@ //usage: "\n -x List by lines" //usage: "\n -d List directory entries instead of contents" //usage: IF_FEATURE_LS_FOLLOWLINKS( -//usage: "\n -L List entries pointed to by symlinks" +//usage: "\n -L Follow symlinks" +//usage: "\n -H Follow symlinks on command line only" //usage: ) //usage: IF_FEATURE_LS_RECURSIVE( //usage: "\n -R Recurse" @@ -118,11 +119,11 @@ enum { TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ -/* what is the overall style of the listing */ -STYLE_COLUMNAR = 1 << 21, /* many records per line */ -STYLE_LONG = 2 << 21, /* one record per line, extended info */ -STYLE_SINGLE = 3 << 21, /* one record per line */ -STYLE_MASK = STYLE_SINGLE, +SPLIT_DIR = 1, +SPLIT_FILE = 0, +SPLIT_SUBDIR = 2, + +/* Bits in all_fmt: */ /* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */ /* what file information will be listed */ @@ -152,44 +153,41 @@ DISP_RECURSIVE = 1 << 19, /* show directory and everything below it */ DISP_ROWS = 1 << 20, /* print across rows */ DISP_MASK = ((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1), -/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */ -SORT_FORWARD = 0, /* sort in reverse order */ -SORT_REVERSE = 1 << 27, /* sort in reverse order */ - -SORT_NAME = 0, /* sort by file name */ -SORT_SIZE = 1 << 28, /* sort by file size */ -SORT_ATIME = 2 << 28, /* sort by last access time */ -SORT_CTIME = 3 << 28, /* sort by last change time */ -SORT_MTIME = 4 << 28, /* sort by last modification time */ -SORT_VERSION = 5 << 28, /* sort by version */ -SORT_EXT = 6 << 28, /* sort by file name extension */ -SORT_DIR = 7 << 28, /* sort by file or directory */ -SORT_MASK = (7 << 28) * ENABLE_FEATURE_LS_SORTFILES, +/* what is the overall style of the listing */ +STYLE_COLUMNAR = 1 << 21, /* many records per line */ +STYLE_LONG = 2 << 21, /* one record per line, extended info */ +STYLE_SINGLE = 3 << 21, /* one record per line */ +STYLE_MASK = STYLE_SINGLE, /* which of the three times will be used */ TIME_CHANGE = (1 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, TIME_ACCESS = (1 << 24) * ENABLE_FEATURE_LS_TIMESTAMPS, TIME_MASK = (3 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, -FOLLOW_LINKS = (1 << 25) * ENABLE_FEATURE_LS_FOLLOWLINKS, +/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */ +SORT_REVERSE = 1 << 25, -LS_DISP_HR = (1 << 26) * ENABLE_FEATURE_HUMAN_READABLE, +SORT_NAME = 0, /* sort by file name */ +SORT_SIZE = 1 << 26, /* sort by file size */ +SORT_ATIME = 2 << 26, /* sort by last access time */ +SORT_CTIME = 3 << 26, /* sort by last change time */ +SORT_MTIME = 4 << 26, /* sort by last modification time */ +SORT_VERSION = 5 << 26, /* sort by version */ +SORT_EXT = 6 << 26, /* sort by file name extension */ +SORT_DIR = 7 << 26, /* sort by file or directory */ +SORT_MASK = (7 << 26) * ENABLE_FEATURE_LS_SORTFILES, LIST_SHORT = LIST_FILENAME, LIST_LONG = LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \ LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK, - -SPLIT_DIR = 1, -SPLIT_FILE = 0, -SPLIT_SUBDIR = 2, }; /* -Cadil1 Std options, busybox always supports */ /* -gnsxA Std options, busybox always supports */ -/* -Q GNU option? busybox always supports */ +/* -Q GNU option, busybox always supports */ /* -k SELinux option, busybox always supports (ignores if !SELinux) */ /* Std has -k which means "show sizes in kbytes" */ -/* -FLRctur Std options, busybox optionally supports */ +/* -FLHRctur Std options, busybox optionally supports */ /* -p Std option, busybox optionally supports */ /* Not fully compatible - we show not only '/' but other chars too */ /* -SXvhTw GNU options, busybox optionally supports */ @@ -199,15 +197,15 @@ SPLIT_SUBDIR = 2, /* Std opts we do not support: */ /* -H Follow the links on command line only */ static const char ls_options[] ALIGN1 = - "Cadil1gnsxQAk" /* 13 opts, total 13 */ + "Cadil1gnsxQAk" /* 13 opts, total 13 */ IF_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */ IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 21 */ IF_FEATURE_LS_FILETYPES("Fp") /* 2, 23 */ - IF_FEATURE_LS_FOLLOWLINKS("L") /* 1, 24 */ - IF_FEATURE_LS_RECURSIVE("R") /* 1, 25 */ - IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ - IF_SELINUX("KZ") /* 2, 28 */ - IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */ + IF_FEATURE_LS_RECURSIVE("R") /* 1, 24 */ + IF_SELINUX("KZ") /* 2, 26 */ + IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 28 */ + IF_FEATURE_HUMAN_READABLE("h") /* 1, 29 */ + IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 31 */ ; enum { //OPT_C = (1 << 0), @@ -223,27 +221,55 @@ enum { OPT_Q = (1 << 10), //OPT_A = (1 << 11), //OPT_k = (1 << 12), - OPTBIT_F = 13 - + 4 * ENABLE_FEATURE_LS_TIMESTAMPS - + 4 * ENABLE_FEATURE_LS_SORTFILES, - OPTBIT_color = OPTBIT_F - + 2 * ENABLE_FEATURE_LS_FILETYPES - + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS - + 1 * ENABLE_FEATURE_LS_RECURSIVE - + 1 * ENABLE_FEATURE_HUMAN_READABLE - + 2 * ENABLE_SELINUX - + 2 * ENABLE_FEATURE_AUTOWIDTH, - OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, - OPT_color = (1 << OPTBIT_color), + + OPTBIT_c = 13, + OPTBIT_e, + OPTBIT_t, + OPTBIT_u, + OPTBIT_S = OPTBIT_c + 4 * ENABLE_FEATURE_LS_TIMESTAMPS, + OPTBIT_X, /* 18 */ + OPTBIT_r, + OPTBIT_v, + OPTBIT_F = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, + OPTBIT_p, /* 22 */ + OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, + OPTBIT_K = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, + OPTBIT_Z, /* 25 */ + OPTBIT_L = OPTBIT_K + 2 * ENABLE_SELINUX, + OPTBIT_H, /* 27 */ + OPTBIT_h = OPTBIT_L + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPTBIT_T = OPTBIT_h + 2 * ENABLE_FEATURE_HUMAN_READABLE, + OPTBIT_w, /* 30 */ + OPTBIT_color = OPTBIT_T + 2 * ENABLE_FEATURE_AUTOWIDTH, + + OPT_c = (1 << OPTBIT_c) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_e = (1 << OPTBIT_e) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_t = (1 << OPTBIT_t) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_u = (1 << OPTBIT_u) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_S = (1 << OPTBIT_S) * ENABLE_FEATURE_LS_SORTFILES, + OPT_X = (1 << OPTBIT_X) * ENABLE_FEATURE_LS_SORTFILES, + OPT_r = (1 << OPTBIT_r) * ENABLE_FEATURE_LS_SORTFILES, + OPT_v = (1 << OPTBIT_v) * ENABLE_FEATURE_LS_SORTFILES, + OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, + OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, + OPT_R = (1 << OPTBIT_R) * ENABLE_FEATURE_LS_RECURSIVE, + OPT_K = (1 << OPTBIT_K) * ENABLE_SELINUX, + OPT_Z = (1 << OPTBIT_Z) * ENABLE_SELINUX, + OPT_L = (1 << OPTBIT_L) * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPT_H = (1 << OPTBIT_H) * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPT_h = (1 << OPTBIT_h) * ENABLE_FEATURE_HUMAN_READABLE, + OPT_T = (1 << OPTBIT_T) * ENABLE_FEATURE_AUTOWIDTH, + OPT_w = (1 << OPTBIT_w) * ENABLE_FEATURE_AUTOWIDTH, + OPT_color = (1 << OPTBIT_color) * ENABLE_FEATURE_LS_COLOR, }; /* TODO: simple toggles may be stored as OPT_xxx bits instead */ -static const unsigned opt_flags[] = { +static const uint32_t opt_flags[] = { LIST_SHORT | STYLE_COLUMNAR, /* C */ DISP_HIDDEN | DISP_DOT, /* a */ DISP_NOLIST, /* d */ LIST_INO, /* i */ - LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */ + LIST_LONG | STYLE_LONG, /* l */ LIST_SHORT | STYLE_SINGLE, /* 1 */ 0, /* g (don't show owner) - handled via OPT_g */ LIST_ID_NUMERIC, /* n */ @@ -268,23 +294,15 @@ static const unsigned opt_flags[] = { LIST_FILETYPE | LIST_EXEC, /* F */ LIST_FILETYPE, /* p */ #endif -#if ENABLE_FEATURE_LS_FOLLOWLINKS - FOLLOW_LINKS, /* L */ -#endif #if ENABLE_FEATURE_LS_RECURSIVE DISP_RECURSIVE, /* R */ #endif -#if ENABLE_FEATURE_HUMAN_READABLE - LS_DISP_HR, /* h */ -#endif #if ENABLE_SELINUX LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ #endif - (1U<<31) - /* options after Z are not processed through opt_flags: - * T, w - ignored - */ + (1U << 31) + /* options after Z are not processed through opt_flags */ }; @@ -344,7 +362,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f struct dnode *cur; IF_SELINUX(security_context_t sid = NULL;) - if ((all_fmt & FOLLOW_LINKS) || force_follow) { + if ((option_mask32 & OPT_L) || force_follow) { #if ENABLE_SELINUX if (is_selinux_enabled()) { getfilecon(fullname, &sid); @@ -699,7 +717,7 @@ static NOINLINE unsigned list_single(const struct dnode *dn) (int) major(dn->dstat.st_rdev), (int) minor(dn->dstat.st_rdev)); } else { - if (all_fmt & LS_DISP_HR) { + if (option_mask32 & OPT_h) { column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ", /* print st_size, show one fractional, use suffixes */ make_human_readable_str(dn->dstat.st_size, 1, 0) @@ -887,12 +905,6 @@ static void showdirs(struct dnode **dn, int first) struct dnode **subdnp; struct dnode **dnd; - /* Never happens: - if (dn == NULL || ndirs < 1) { - return; - } - */ - for (; *dn; dn++) { if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) { if (!first) @@ -1031,8 +1043,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) init_unicode(); - all_fmt = LIST_SHORT | - (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD)); + all_fmt = LIST_SHORT | (ENABLE_FEATURE_LS_SORTFILES * SORT_NAME); #if ENABLE_FEATURE_AUTOWIDTH /* obtain the terminal width */ @@ -1050,8 +1061,8 @@ int ls_main(int argc UNUSED_PARAM, char **argv) * in some pairs of opts, only last one takes effect: */ IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES(":t-S:S-t")) /* time/size */ - // ":H-L:L-H:" - we don't have -H - // ":m-l:l-m:" - we don't have -m + // ":m-l:l-m" - we don't have -m + IF_FEATURE_LS_FOLLOWLINKS(":H-L:L-H") ":C-xl:x-Cl:l-xC" /* bycols/bylines/long */ ":C-1:1-C" /* bycols/oneline */ ":x-1:1-x" /* bylines/oneline (not in SuS, but in GNU coreutils 8.4) */ @@ -1062,9 +1073,9 @@ int ls_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_AUTOWIDTH(, NULL, &terminal_width) IF_FEATURE_LS_COLOR(, &color_opt) ); - for (i = 0; opt_flags[i] != (1U<<31); i++) { + for (i = 0; opt_flags[i] != (1U << 31); i++) { if (opt & (1 << i)) { - unsigned flags = opt_flags[i]; + uint32_t flags = opt_flags[i]; if (flags & STYLE_MASK) all_fmt &= ~STYLE_MASK; @@ -1134,9 +1145,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv) dn = NULL; nfiles = 0; do { - /* NB: follow links on command line unless -l, -s or -F */ cur = my_stat(*argv, *argv, + /* follow links on command line unless -l, -s or -F: */ !((all_fmt & (STYLE_LONG|LIST_BLOCKS)) || (option_mask32 & OPT_F)) + /* ... or if -H: */ + || (option_mask32 & OPT_H) ); argv++; if (!cur)