bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: more ls changes: stat-failed


From: Paul Eggert
Subject: Re: more ls changes: stat-failed
Date: Tue, 25 Jul 2006 16:41:03 -0700
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.4 (gnu/linux)

Jim Meyering <address@hidden> writes:

>   ?--------- ? ?    ?    ?            ? cwd

How about outputting something like this instead?

    d????????? ? ?    ?    ?            ? cwd

The file type is typically known, so it can be listed as "d" instead
of "?".  Also, this example doesn't show it, but the inode number is
also known typically, so it shouldn't be listed as "?".

Conversely, the file mode bits are not known, so they should be listed
as "?" rather than as the (misleading) "-".

I hacked on a patch along these lines but did not have time to finish
it; it fails the tests due to problems with file name colors.  However,
if you like the idea I can work on cleaning this up.

2006-07-25  Paul Eggert  <address@hidden>

        * src/ls.c (DT_INIT): Remove.  All uses removed.
        (enum filetype): Use an ordinary enum rather than trying to keep
        the values in sync with DT_FIFO etc.  That way, we don't have
        to make special assumptions about them.  All uses changed.
        (whiteout): New constant member of enum filetype.
        (filetype_letter): New constant, for use with enum filetype.
        (struct fileinfo): Rename stat_failed to stat_ok, since stat
        might not necessarily have failed if this value is (now) false.
        All uses changed.
        (format_user, format_group, print_name_with_quoting): Likewise.
        (print_color_indicator): Likewise.
        (print_dir): Add case for DT_WHT.
        (gobble_file): If stat fails, don't discard information from
        readdir; instead, preserve it so it can be printed.
        (print_long_format): Fall back on readdir result if stat info
        is not available.  Use "?" to denote each unknown mode char,
        instead of an overall "?", since we now know some of the mode
        typically.
        [... changelog not finished, alas ....]

Index: doc/coreutils.texi
===================================================================
RCS file: /fetish/cu/doc/coreutils.texi,v
retrieving revision 1.341
diff -p -u -r1.341 coreutils.texi
--- doc/coreutils.texi  23 Jul 2006 01:26:56 -0000      1.341
+++ doc/coreutils.texi  25 Jul 2006 23:36:28 -0000
@@ -5795,7 +5795,8 @@ uniquely identifies each file within a p
 In addition to the name of each file, print the file type, file mode bits,
 number of hard links, owner name, group name, size, and
 timestamp (@pxref{Formatting file timestamps}), normally
-the modification time.
+the modification time.  Print question marks for information that
+cannot be determined.
 
 Normally the size is printed as a byte count without punctuation, but
 this can be overridden (@pxref{Block size}).  For example, @option{-h}
@@ -5852,7 +5853,7 @@ socket
 @c @item w
 @c whiteout (4.4BSD; not implemented)
 @item ?
-some other file type
+unknown file type
 @end table
 
 @cindex permissions, output by @command{ls}
Index: src/ls.c
===================================================================
RCS file: /fetish/cu/src/ls.c,v
retrieving revision 1.430
diff -p -u -r1.430 ls.c
--- src/ls.c    25 Jul 2006 16:35:59 -0000      1.430
+++ src/ls.c    25 Jul 2006 23:36:29 -0000
@@ -142,37 +142,43 @@ int wcwidth ();
    Subtracting doesn't always work, due to overflow.  */
 #define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b))
 
-#if HAVE_STRUCT_DIRENT_D_TYPE && defined DTTOIF
-# define DT_INIT(Val) = Val
-#else
-# define DT_INIT(Val) /* empty */
-#endif
-
 #if ! HAVE_STRUCT_STAT_ST_AUTHOR
 # define st_author st_uid
 #endif
 
 enum filetype
   {
-    unknown DT_INIT (DT_UNKNOWN),
-    fifo DT_INIT (DT_FIFO),
-    chardev DT_INIT (DT_CHR),
-    directory DT_INIT (DT_DIR),
-    blockdev DT_INIT (DT_BLK),
-    normal DT_INIT (DT_REG),
-    symbolic_link DT_INIT (DT_LNK),
-    sock DT_INIT (DT_SOCK),
-    arg_directory DT_INIT (2 * (DT_UNKNOWN | DT_FIFO | DT_CHR | DT_DIR | DT_BLK
-                               | DT_REG | DT_LNK | DT_SOCK))
+    unknown,
+    fifo,
+    chardev,
+    directory,
+    blockdev,
+    normal,
+    symbolic_link,
+    sock,
+    whiteout,
+    arg_directory
   };
 
+/* Display letters and indicators for each filetype.
+   Keep these in sync with enum filetype.  */
+
+static char const filetype_letter[] = "?pcdb-lswd";
+
+#define FILETYPE_INDICATORS                            \
+  {                                                    \
+    C_ORPHAN, C_FIFO, C_CHR, C_DIR, C_BLK, C_FILE,     \
+    C_LINK, C_SOCK, C_FILE, C_DIR                      \
+  }
+
+
 struct fileinfo
   {
     /* The file name.  */
     char *name;
 
     struct stat stat;
-    bool stat_failed;
+    bool stat_ok;
 
     /* For symbolic link, name of the file linked to, otherwise zero.  */
     char *linkname;
@@ -228,7 +234,7 @@ static uintmax_t gobble_file (char const
                              ino_t inode, bool command_line_arg,
                              char const *dirname);
 static void print_color_indicator (const char *name, mode_t mode, int linkok,
-                                  bool stat_failed);
+                                  bool stat_ok, enum filetype type);
 static void put_indicator (const struct bin_str *ind);
 static void add_ignore_pattern (const char *pattern);
 static void attach (char *dest, const char *dirname, const char *name);
@@ -249,10 +255,12 @@ static int format_group_width (gid_t g);
 static void print_long_format (const struct fileinfo *f);
 static void print_many_per_line (void);
 static void print_name_with_quoting (const char *p, mode_t mode,
-                                    int linkok, bool stat_failed,
+                                    int linkok, bool stat_ok,
+                                    enum filetype type,
                                     struct obstack *stack);
 static void prep_non_filename_text (void);
-static void print_type_indicator (mode_t mode);
+static void print_type_indicator (bool stat_ok, mode_t mode,
+                                 enum filetype type);
 static void print_with_commas (void);
 static void queue_directory (char const *name, char const *realname,
                             bool command_line_arg);
@@ -2361,14 +2369,19 @@ print_dir (char const *name, char const 
              enum filetype type = unknown;
 
 #if HAVE_STRUCT_DIRENT_D_TYPE
-             if (next->d_type == DT_BLK
-                 || next->d_type == DT_CHR
-                 || next->d_type == DT_DIR
-                 || next->d_type == DT_FIFO
-                 || next->d_type == DT_LNK
-                 || next->d_type == DT_REG
-                 || next->d_type == DT_SOCK)
-               type = next->d_type;
+             switch (next->d_type)
+               {
+               case DT_BLK:  type = blockdev;          break;
+               case DT_CHR:  type = chardev;           break;
+               case DT_DIR:  type = directory;         break;
+               case DT_FIFO: type = fifo;              break;
+               case DT_LNK:  type = symbolic_link;     break;
+               case DT_REG:  type = normal;            break;
+               case DT_SOCK: type = sock;              break;
+# ifdef DT_WHT
+               case DT_WHT:  type = whiteout;          break;
+# endif
+               }
 #endif
              total_blocks += gobble_file (next->d_name, type, D_INO (next),
                                           false, name);
@@ -2519,7 +2532,7 @@ static uintmax_t
 gobble_file (char const *name, enum filetype type, ino_t inode,
             bool command_line_arg, char const *dirname)
 {
-  uintmax_t blocks;
+  uintmax_t blocks = 0;
   struct fileinfo *f;
 
   /* An inode value prior to gobble_file necessarily came from readdir,
@@ -2533,9 +2546,9 @@ gobble_file (char const *name, enum file
     }
 
   f = &files[files_index];
-  f->linkname = NULL;
-  f->linkmode = 0;
-  f->linkok = false;
+  memset (f, '\0', sizeof *f);
+  f->stat.st_ino = inode;
+  f->filetype = type;
 
   if (command_line_arg
       || format_needs_stat
@@ -2608,8 +2621,7 @@ gobble_file (char const *name, enum file
          break;
        }
 
-      f->stat_failed = (err < 0);
-      if (f->stat_failed)
+      if (err != 0)
        {
          /* Failure to stat a command line argument leads to
             an exit status of 2.  For other files, stat failure
@@ -2619,18 +2631,14 @@ gobble_file (char const *name, enum file
          if (command_line_arg)
            return 0;
 
-         f->filetype = type;
-         memset (&f->stat, '\0', sizeof (f->stat));
-
-#if USE_ACL
-         f->have_acl = false;
-#endif
          f->name = xstrdup (name);
          files_index++;
 
          return 0;
        }
 
+      f->stat_ok = true;
+
 #if USE_ACL
       if (format == long_format)
        {
@@ -2668,7 +2676,6 @@ gobble_file (char const *name, enum file
                  /* Get the linked-to file's mode for the filetype indicator
                     in long listings.  */
                  f->linkmode = linkstats.st_mode;
-                 f->linkok = true;
                }
            }
          free (linkname);
@@ -2748,15 +2755,6 @@ gobble_file (char const *name, enum file
            file_size_width = len;
        }
     }
-  else
-    {
-      f->filetype = type;
-      f->stat.st_ino = inode;
-#if HAVE_STRUCT_DIRENT_D_TYPE && defined DTTOIF
-      f->stat.st_mode = DTTOIF (type);
-#endif
-      blocks = 0;
-    }
 
   if (print_inode)
       {
@@ -3290,18 +3288,18 @@ format_user_or_group (char const *name, 
    WIDTH.  */
 
 static void
-format_user (uid_t u, int width, bool stat_failed)
+format_user (uid_t u, int width, bool stat_ok)
 {
-  format_user_or_group (stat_failed ? "?" :
+  format_user_or_group (! stat_ok ? "?" :
                        (numeric_ids ? NULL : getuser (u)), u, width);
 }
 
 /* Likewise, for groups.  */
 
 static void
-format_group (gid_t g, int width, bool stat_failed)
+format_group (gid_t g, int width, bool stat_ok)
 {
-  format_user_or_group (stat_failed ? "?" :
+  format_user_or_group (! stat_ok ? "?" :
                        (numeric_ids ? NULL : getgroup (g)), g, width);
 }
 
@@ -3364,7 +3362,14 @@ print_long_format (const struct fileinfo
 
   /* Compute the mode string, except remove the trailing space if no
      files in this directory have ACLs.  */
-  filemodestring (&f->stat, modebuf);
+  if (f->stat_ok)
+    filemodestring (&f->stat, modebuf);
+  else
+    {
+      modebuf[0] = filetype_letter[f->filetype];
+      memset (modebuf + 1, '?', 10);
+      modebuf[11] = '\0';
+    }
   if (! any_has_acl)
     modebuf[10] = '\0';
   else if (FILE_HAS_ACL (f))
@@ -3394,7 +3399,9 @@ print_long_format (const struct fileinfo
     {
       char hbuf[INT_BUFSIZE_BOUND (uintmax_t)];
       sprintf (p, "%*s ", inode_number_width,
-              f->stat_failed ? "?" : umaxtostr (f->stat.st_ino, hbuf));
+              (f->stat.st_ino == NOT_AN_INODE_NUMBER
+               ? "?"
+               : umaxtostr (f->stat.st_ino, hbuf)));
       /* Increment by strlen (p) here, rather than by inode_number_width + 1.
         The latter is wrong when inode_number_width is zero.  */
       p += strlen (p);
@@ -3404,7 +3411,7 @@ print_long_format (const struct fileinfo
     {
       char hbuf[LONGEST_HUMAN_READABLE + 1];
       char const *blocks =
-       (f->stat_failed
+       (! f->stat_ok
         ? "?"
         : human_readable (ST_NBLOCKS (f->stat), hbuf, human_output_opts,
                           ST_NBLOCKSIZE, output_block_size));
@@ -3421,7 +3428,7 @@ print_long_format (const struct fileinfo
   {
     char hbuf[INT_BUFSIZE_BOUND (uintmax_t)];
     sprintf (p, "%s %*s ", modebuf, nlink_width,
-            f->stat_failed ? "?" : umaxtostr (f->stat.st_nlink, hbuf));
+            ! f->stat_ok ? "?" : umaxtostr (f->stat.st_nlink, hbuf));
   }
   /* Increment by strlen (p) here, rather than by, e.g.,
      sizeof modebuf - 2 + any_has_acl + 1 + nlink_width + 1.
@@ -3435,18 +3442,18 @@ print_long_format (const struct fileinfo
       DIRED_FPUTS (buf, stdout, p - buf);
 
       if (print_owner)
-       format_user (f->stat.st_uid, owner_width, f->stat_failed);
+       format_user (f->stat.st_uid, owner_width, f->stat_ok);
 
       if (print_group)
-       format_group (f->stat.st_gid, group_width, f->stat_failed);
+       format_group (f->stat.st_gid, group_width, f->stat_ok);
 
       if (print_author)
-       format_user (f->stat.st_author, author_width, f->stat_failed);
+       format_user (f->stat.st_author, author_width, f->stat_ok);
 
       p = buf;
     }
 
-  if (!f->stat_failed
+  if (f->stat_ok
       && (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)))
     {
       char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
@@ -3465,7 +3472,7 @@ print_long_format (const struct fileinfo
     {
       char hbuf[LONGEST_HUMAN_READABLE + 1];
       char const *size =
-       (f->stat_failed
+       (! f->stat_ok
         ? "?"
         : human_readable (unsigned_file_size (f->stat.st_size),
                           hbuf, human_output_opts, 1, file_output_block_size));
@@ -3481,7 +3488,7 @@ print_long_format (const struct fileinfo
   s = 0;
   *p = '\1';
 
-  if (!f->stat_failed && when_local)
+  if (f->stat_ok && when_local)
     {
       time_t six_months_ago;
       bool recent;
@@ -3528,7 +3535,7 @@ print_long_format (const struct fileinfo
         print it as a huge integer number of seconds.  */
       char hbuf[INT_BUFSIZE_BOUND (intmax_t)];
       sprintf (p, "%*s ", long_time_expected_width (),
-              (f->stat_failed
+              (! f->stat_ok
                ? "?"
                : (TYPE_SIGNED (time_t)
                   ? imaxtostr (when, hbuf)
@@ -3538,7 +3545,7 @@ print_long_format (const struct fileinfo
 
   DIRED_FPUTS (buf, stdout, p - buf);
   print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok,
-                          f->stat_failed, &dired_obstack);
+                          f->stat_ok, f->filetype, &dired_obstack);
 
   if (f->filetype == symbolic_link)
     {
@@ -3546,13 +3553,13 @@ print_long_format (const struct fileinfo
        {
          DIRED_FPUTS_LITERAL (" -> ", stdout);
          print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1,
-                                  f->stat_failed, NULL);
+                                  f->stat_ok, f->filetype, NULL);
          if (indicator_style != none)
-           print_type_indicator (f->linkmode);
+           print_type_indicator (true, f->linkmode, unknown);
        }
     }
   else if (indicator_style != none)
-    print_type_indicator (f->stat.st_mode);
+    print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype);
 }
 
 /* Output to OUT a quoted representation of the file name NAME,
@@ -3728,10 +3735,11 @@ quote_name (FILE *out, const char *name,
 
 static void
 print_name_with_quoting (const char *p, mode_t mode, int linkok,
-                        bool stat_failed, struct obstack *stack)
+                        bool stat_ok, enum filetype type,
+                        struct obstack *stack)
 {
   if (print_with_color)
-    print_color_indicator (p, mode, linkok, stat_failed);
+    print_color_indicator (p, mode, linkok, stat_ok, type);
 
   if (stack)
     PUSH_CURRENT_DIRED_POS (stack);
@@ -3780,37 +3788,37 @@ print_file_name_and_frills (const struct
                            ST_NBLOCKSIZE, output_block_size));
 
   print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok,
-                          f->stat_failed, NULL);
+                          f->stat_ok, f->filetype, NULL);
 
   if (indicator_style != none)
-    print_type_indicator (f->stat.st_mode);
+    print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype);
 }
 
 static void
-print_type_indicator (mode_t mode)
+print_type_indicator (bool stat_ok, mode_t mode, enum filetype type)
 {
   char c;
 
-  if (S_ISREG (mode))
+  if (stat_ok ? S_ISREG (mode) : type == normal)
     {
-      if (indicator_style == classify && (mode & S_IXUGO))
+      if (stat_ok && indicator_style == classify && (mode & S_IXUGO))
        c = '*';
       else
        c = 0;
     }
   else
     {
-      if (S_ISDIR (mode))
+      if (stat_ok ? S_ISDIR (mode) : type == directory || type == 
arg_directory)
        c = '/';
       else if (indicator_style == slash)
        c = 0;
-      else if (S_ISLNK (mode))
+      else if (stat_ok ? S_ISLNK (mode) : type == symbolic_link)
        c = '@';
-      else if (S_ISFIFO (mode))
+      else if (stat_ok ? S_ISFIFO (mode) : type == fifo)
        c = '|';
-      else if (S_ISSOCK (mode))
+      else if (stat_ok ? S_ISSOCK (mode) : type == sock)
        c = '=';
-      else if (S_ISDOOR (mode))
+      else if (stat_ok && S_ISDOOR (mode))
        c = '>';
       else
        c = 0;
@@ -3822,7 +3830,7 @@ print_type_indicator (mode_t mode)
 
 static void
 print_color_indicator (const char *name, mode_t mode, int linkok,
-                      bool stat_failed)
+                      bool stat_ok, enum filetype filetype)
 {
   int type = C_FILE;
   struct color_ext_type *ext;  /* Color extension */
@@ -3831,9 +3839,11 @@ print_color_indicator (const char *name,
   /* Is this a nonexistent file?  If so, linkok == -1.  */
 
   if (linkok == -1 && color_indicator[C_MISSING].string != NULL)
+    type = C_MISSING;
+  else if (! stat_ok)
     {
-      ext = NULL;
-      type = C_MISSING;
+      static enum indicator_no filetype_indicator[] = FILETYPE_INDICATORS;
+      type = filetype_indicator[filetype];
     }
   else
     {
@@ -3861,7 +3871,7 @@ print_color_indicator (const char *name,
        type = C_CHR;
       else if (S_ISDOOR (mode))
        type = C_DOOR;
-      else if (stat_failed)
+      else
        type = C_ORPHAN;
 
       if (type == C_FILE)
@@ -3873,22 +3883,22 @@ print_color_indicator (const char *name,
          else if ((mode & S_IXUGO) != 0)
            type = C_EXEC;
        }
+    }
 
-      /* Check the file's suffix only if still classified as C_FILE.  */
-      ext = NULL;
-      if (type == C_FILE)
-       {
-         /* Test if NAME has a recognized suffix.  */
+  /* Check the file's suffix only if still classified as C_FILE.  */
+  ext = NULL;
+  if (type == C_FILE)
+    {
+      /* Test if NAME has a recognized suffix.  */
 
-         len = strlen (name);
-         name += len;          /* Pointer to final \0.  */
-         for (ext = color_ext_list; ext != NULL; ext = ext->next)
-           {
-             if (ext->ext.len <= len
-                 && strncmp (name - ext->ext.len, ext->ext.string,
-                             ext->ext.len) == 0)
-               break;
-           }
+      len = strlen (name);
+      name += len;             /* Pointer to final \0.  */
+      for (ext = color_ext_list; ext != NULL; ext = ext->next)
+       {
+         if (ext->ext.len <= len
+             && strncmp (name - ext->ext.len, ext->ext.string,
+                         ext->ext.len) == 0)
+           break;
        }
     }
 
Index: tests/ls/stat-failed
===================================================================
RCS file: /fetish/cu/tests/ls/stat-failed,v
retrieving revision 1.3
diff -p -u -r1.3 stat-failed
--- tests/ls/stat-failed        25 Jul 2006 16:36:00 -0000      1.3
+++ tests/ls/stat-failed        25 Jul 2006 23:36:29 -0000
@@ -35,24 +35,24 @@ test $? = 1 || fail=1
 
 cat <<\EOF > exp || fail=1
 total 0
-?--------- ? ?            ? s
+?????????? ? ?            ? s
 EOF
 
-cmp out exp || fail=1
+sed 's/^l/?/' out | cmp - exp || fail=1
 test $fail = 1 && diff out exp 2> /dev/null
 
 # Ensure that the offsets in --dired output are accurate.
 rm -f out exp
-ls --dired -il d > out 2> /dev/null && fail=1
+ls --dired -l d > out 2> /dev/null && fail=1
 
 cat <<\EOF > exp || fail=1
   total 0
-  ? ?--------- ? ? ? ?            ? s
-//DIRED// 46 47
+  ?????????? ? ? ? ?            ? s
+//DIRED// 44 45
 //DIRED-OPTIONS// --quoting-style=literal
 EOF
 
-cmp out exp || fail=1
+sed 's/^  l/  ?/' out | cmp - exp || fail=1
 test $fail = 1 && diff out exp 2> /dev/null
 
 (exit $fail); exit $fail




reply via email to

[Prev in Thread] Current Thread [Next in Thread]