diff options
author | Jim Meyering <jim@meyering.net> | 2003-01-15 11:59:07 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2003-01-15 11:59:07 +0000 |
commit | 800f3a1e77d6185038d3d553b4188ea138a08881 (patch) | |
tree | c0d6d6bddd8fb3478da2c1273814d27eec43c346 | |
parent | b1ebf2a3838cb7c673a641884fd4a64833d99258 (diff) | |
download | coreutils-800f3a1e77d6185038d3d553b4188ea138a08881.tar.xz |
(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.
-rw-r--r-- | src/ls.c | 36 |
1 files changed, 31 insertions, 5 deletions
@@ -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; |