From 800f3a1e77d6185038d3d553b4188ea138a08881 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Wed, 15 Jan 2003 11:59:07 +0000 Subject: [PATCH] (gobble_file): Fall back on using lstat when required: when --dereference (-L) is not specified, and - when operating on a dangling symlink - when operating on command-line-symlink-to-directories This fixes numerous problems. Here are examples: - `ls dangling-symlink' would fail with `no such file...' Now it prints `dangling-symlink'. - `ls -i symlink' would mistakenly print the inode of the referent. Now it prints the inode of the symlink. Likewise for --size (-s). Based on a patch from Michael Stone. Reported by Deepak Goel as Debian bug #173793. --- src/ls.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/ls.c b/src/ls.c index bbd1dd034..e15d5cfa9 100644 --- a/src/ls.c +++ b/src/ls.c @@ -2337,7 +2337,7 @@ gobble_file (const char *name, enum filetype type, int explicit_arg, { /* `path' is the absolute pathname of this file. */ - int val; + int err; if (name[0] == '/' || dirname[0] == 0) path = (char *) name; @@ -2347,11 +2347,37 @@ gobble_file (const char *name, enum filetype type, int explicit_arg, attach (path, dirname, name); } - val = (DEREF_ALWAYS <= dereference + explicit_arg - ? stat (path, &files[files_index].stat) - : lstat (path, &files[files_index].stat)); + switch (dereference) + { + case DEREF_ALWAYS: + err = stat (path, &files[files_index].stat); + break; + + case DEREF_COMMAND_LINE_SYMLINK_TO_DIR: + if (explicit_arg) + { + int need_lstat; + err = stat (path, &files[files_index].stat); + /* If stat failed because of ENOENT (maybe indicating a + dangling symlink), or if it succeeded and PATH refers + to a non-directory (hence PATH may be a symlink to a + non-directory and we may not dereference it), fall + through so that we call lstat instead. */ + need_lstat = (err < 0 + ? errno == ENOENT + : ! S_ISDIR (files[files_index].stat.st_mode)); + if (!need_lstat) + break; + } + + /* fall through. */ + + default: /* DEREF_NEVER */ + err = lstat (path, &files[files_index].stat); + break; + } - if (val < 0) + if (err < 0) { error (0, errno, "%s", quotearg_colon (path)); exit_status = 1; -- 2.34.1