Pádraig Brady wrote: > Jim Meyering wrote: >> Nearly missed this one. >> ls initializes a struct stat to all NUL bytes. >> It calls stat or lstat on a dangling symlink, and that fails. >> ls then tests stat.st_ino. >> >> Sometimes, it's 0, but sometimes it's the inode of the symlink, >> possibly depending on how the package was configured/built or >> the environment. >> I haven't determined precisely what makes the difference, >> but ls (from coreutils-7.6) built some way prints 0 as the inode >> number, and other ways, it prints the inode of the dangling symlink. >> >> >>>From f7db178fdff1ebb113841035b55b103e074b5f6f Mon Sep 17 00:00:00 2001 >> From: Jim Meyering <meyer...@redhat.com> >> Date: Tue, 29 Sep 2009 07:28:01 +0200 >> Subject: [PATCH] ls: don't use an undefined struct stat after failed >> stat/lstat >> >> * src/ls.c (gobble_file): After a failed stat/lstat call, >> clear the f->stat buffer, since the syscall may have modified it, >> and we may need to know that stat.st_ino is zero. > > Well spotted. By the same token is this useful?
Well spotted yourself! I should have remembered to use the stat_ok member. I'll merge something like this into my patch. Thanks! diff --git a/src/ls.c b/src/ls.c index dc2f86e..03ef9b0 100644 --- a/src/ls.c +++ b/src/ls.c @@ -2777,11 +2777,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode, if (err != 0) { - /* The failed stat/lstat may have modified f->stat. Clear it, - since we may use at least its st_ino member, e.g., - when trying to print the inode of dangling symlink: - mkdir d; ln -s no-such d/s; ls -Li d */ - memset (&f->stat, 0, sizeof (f->stat)); + f->stat.st_ino = 22; /* Failure to stat a command line argument leads to an exit status of 2. For other files, stat failure @@ -3569,9 +3565,9 @@ static char * format_inode (char *buf, size_t buflen, const struct fileinfo *f) { assert (INT_BUFSIZE_BOUND (uintmax_t) <= buflen); - return (f->stat.st_ino == NOT_AN_INODE_NUMBER - ? (char *) "?" - : umaxtostr (f->stat.st_ino, buf)); + return (f->stat_ok && f->stat.st_ino != NOT_AN_INODE_NUMBER + ? umaxtostr (f->stat.st_ino, buf) + : (char *) "?"); } /* Print information about F in long format. */