4
0
Эх сурвалжийг харах

(from_header): Do not issue a diagnostic if TYPE is zero.
However, check for error even for '-' or '+' case.

(print_header): Try parsing uids and gids as unsigned integers first,
and as a uid_t or gid_t only if that fails. This adds support for
listing positive uids and gids that are greater than UID_MAX and
GID_MAX.

Paul Eggert 23 жил өмнө
parent
commit
a52396de9b
1 өөрчлөгдсөн 99 нэмэгдсэн , 70 устгасан
  1. 99 70
      src/list.c

+ 99 - 70
src/list.c

@@ -1,5 +1,8 @@
 /* List a tar archive, with support routines for reading a tar archive.
 /* List a tar archive, with support routines for reading a tar archive.
-   Copyright 1988,92,93,94,96,97,98,99,2000,2001 Free Software Foundation, Inc.
+
+   Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
+   2001 Free Software Foundation, Inc.
+
    Written by John Gilmore, on 1985-08-26.
    Written by John Gilmore, on 1985-08-26.
 
 
    This program is free software; you can redistribute it and/or modify it
    This program is free software; you can redistribute it and/or modify it
@@ -484,7 +487,8 @@ decode_header (union block *header, struct stat *stat_info,
 /* Convert buffer at WHERE0 of size DIGS from external format to
 /* Convert buffer at WHERE0 of size DIGS from external format to
    uintmax_t.  The data is of type TYPE.  The buffer must represent a
    uintmax_t.  The data is of type TYPE.  The buffer must represent a
    value in the range -MINUS_MINVAL through MAXVAL.  DIGS must be
    value in the range -MINUS_MINVAL through MAXVAL.  DIGS must be
-   positive.  */
+   positive.  Return -1 on error, diagnosing the error if TYPE is
+   nonzero.  */
 static uintmax_t
 static uintmax_t
 from_header (char const *where0, size_t digs, char const *type,
 from_header (char const *where0, size_t digs, char const *type,
 	     uintmax_t minus_minval, uintmax_t maxval)
 	     uintmax_t minus_minval, uintmax_t maxval)
@@ -534,7 +538,7 @@ from_header (char const *where0, size_t digs, char const *type,
          nonzero digit is 1, we can't recover the original value
          nonzero digit is 1, we can't recover the original value
          reliably; so do this only if the digit is 2 or more.  This
          reliably; so do this only if the digit is 2 or more.  This
          catches the common case of 32-bit negative time stamps.  */
          catches the common case of 32-bit negative time stamps.  */
-      if ((overflow || maxval < value) && '2' <= *where1)
+      if ((overflow || maxval < value) && '2' <= *where1 && type)
 	{
 	{
 	  /* Compute the negative of the input value, assuming two's
 	  /* Compute the negative of the input value, assuming two's
 	     complement.  */
 	     complement.  */
@@ -566,79 +570,76 @@ from_header (char const *where0, size_t digs, char const *type,
 
 
       if (overflow)
       if (overflow)
 	{
 	{
-	  ERROR ((0, 0,
-		  _("Archive octal value %.*s is out of %s range"),
-		  (int) (where - where1), where1, type));
+	  if (type)
+	    ERROR ((0, 0,
+		    _("Archive octal value %.*s is out of %s range"),
+		    (int) (where - where1), where1, type));
 	  return -1;
 	  return -1;
 	}
 	}
     }
     }
-  else if (type)
+  else if (*where == '-' || *where == '+')
     {
     {
-      /* The following forms cannot appear as checksums, so we don't
-	 check for them if TYPE is null.  */
-
-      if (*where == '-' || *where == '+')
+      /* Parse base-64 output produced only by tar test versions
+	 1.13.6 (1999-08-11) through 1.13.11 (1999-08-23).
+	 Support for this will be withdrawn in future releases.  */
+      int dig;
+      static int warned_once;
+      if (! warned_once)
 	{
 	{
-	  /* Parse base-64 output produced only by tar test versions
-	     1.13.6 (1999-08-11) through 1.13.11 (1999-08-23).
-	     Support for this will be withdrawn in future releases.  */
-	  int dig;
-	  static int warned_once;
-	  if (! warned_once)
-	    {
-	      warned_once = 1;
-	      WARN ((0, 0,
-		     _("Archive contains obsolescent base-64 headers")));
-	    }
-	  negative = *where++ == '-';
-	  while (where != lim
-		 && (dig = base64_map[(unsigned char) *where]) < 64)
+	  warned_once = 1;
+	  WARN ((0, 0,
+		 _("Archive contains obsolescent base-64 headers")));
+	}
+      negative = *where++ == '-';
+      while (where != lim
+	     && (dig = base64_map[(unsigned char) *where]) < 64)
+	{
+	  if (value << LG_64 >> LG_64 != value)
 	    {
 	    {
-	      if (value << LG_64 >> LG_64 != value)
-		{
-		  char *string = alloca (digs + 1);
-		  memcpy (string, where0, digs);
-		  string[digs] = '\0';
-		  ERROR ((0, 0,
-			  _("Archive signed base-64 string %s is out of %s range"),
-			  quote (string), type));
-		  return -1;
-		}
-	      value = (value << LG_64) | dig;
-	      where++;
+	      char *string = alloca (digs + 1);
+	      memcpy (string, where0, digs);
+	      string[digs] = '\0';
+	      if (type)
+		ERROR ((0, 0,
+			_("Archive signed base-64 string %s is out of %s range"),
+			quote (string), type));
+	      return -1;
 	    }
 	    }
+	  value = (value << LG_64) | dig;
+	  where++;
 	}
 	}
-      else if (*where == '\200' /* positive base-256 */
-	       || *where == '\377' /* negative base-256 */)
+    }
+  else if (*where == '\200' /* positive base-256 */
+	   || *where == '\377' /* negative base-256 */)
+    {
+      /* Parse base-256 output.  A nonnegative number N is
+	 represented as (256**DIGS)/2 + N; a negative number -N is
+	 represented as (256**DIGS) - N, i.e. as two's complement.
+	 The representation guarantees that the leading bit is
+	 always on, so that we don't confuse this format with the
+	 others (assuming ASCII bytes of 8 bits or more).  */
+      int signbit = *where & (1 << (LG_256 - 2));
+      uintmax_t topbits = (((uintmax_t) - signbit)
+			   << (CHAR_BIT * sizeof (uintmax_t)
+			       - LG_256 - (LG_256 - 2)));
+      value = (*where++ & ((1 << (LG_256 - 2)) - 1)) - signbit;
+      for (;;)
 	{
 	{
-	  /* Parse base-256 output.  A nonnegative number N is
-	     represented as (256**DIGS)/2 + N; a negative number -N is
-	     represented as (256**DIGS) - N, i.e. as two's complement.
-	     The representation guarantees that the leading bit is
-	     always on, so that we don't confuse this format with the
-	     others (assuming ASCII bytes of 8 bits or more).  */
-	  int signbit = *where & (1 << (LG_256 - 2));
-	  uintmax_t topbits = (((uintmax_t) - signbit)
-			       << (CHAR_BIT * sizeof (uintmax_t)
-				   - LG_256 - (LG_256 - 2)));
-	  value = (*where++ & ((1 << (LG_256 - 2)) - 1)) - signbit;
-	  for (;;)
+	  value = (value << LG_256) + (unsigned char) *where++;
+	  if (where == lim)
+	    break;
+	  if (((value << LG_256 >> LG_256) | topbits) != value)
 	    {
 	    {
-	      value = (value << LG_256) + (unsigned char) *where++;
-	      if (where == lim)
-		break;
-	      if (((value << LG_256 >> LG_256) | topbits) != value)
-		{
-		  ERROR ((0, 0,
-			  _("Archive base-256 value is out of %s range"),
-			  type));
-		  return -1;
-		}
+	      if (type)
+		ERROR ((0, 0,
+			_("Archive base-256 value is out of %s range"),
+			type));
+	      return -1;
 	    }
 	    }
-	  negative = signbit;
-	  if (negative)
-	    value = -value;
 	}
 	}
+      negative = signbit;
+      if (negative)
+	value = -value;
     }
     }
 
 
   if (where != lim && *where && !ISSPACE ((unsigned char) *where))
   if (where != lim && *where && !ISSPACE ((unsigned char) *where))
@@ -947,17 +948,45 @@ print_header (void)
 	  && !numeric_owner_option)
 	  && !numeric_owner_option)
 	user = current_header->header.uname;
 	user = current_header->header.uname;
       else
       else
-	user = STRINGIFY_BIGINT (UINTMAX_FROM_HEADER
-				 (current_header->header.uid),
-				 uform);
+	{
+	  /* Try parsing it as an unsigned integer first, and as a
+	     uid_t if that fails.  This method can list positive user
+	     ids that are too large to fit in a uid_t.  */
+	  uintmax_t u = from_header (current_header->header.uid,
+				     sizeof current_header->header.uid, 0,
+				     (uintmax_t) 0,
+				     (uintmax_t) TYPE_MAXIMUM (uintmax_t));
+	  if (u != -1)
+	    user = STRINGIFY_BIGINT (u, uform);
+	  else
+	    {
+	      sprintf (uform, "%ld",
+		       (long) UID_FROM_HEADER (current_header->header.uid));
+	      user = uform;
+	    }
+	}
 
 
       if (*current_header->header.gname && current_format != V7_FORMAT
       if (*current_header->header.gname && current_format != V7_FORMAT
 	  && !numeric_owner_option)
 	  && !numeric_owner_option)
 	group = current_header->header.gname;
 	group = current_header->header.gname;
       else
       else
-	group = STRINGIFY_BIGINT (UINTMAX_FROM_HEADER
-				  (current_header->header.gid),
-				  gform);
+	{
+	  /* Try parsing it as an unsigned integer first, and as a
+	     gid_t if that fails.  This method can list positive group
+	     ids that are too large to fit in a gid_t.  */
+	  uintmax_t g = from_header (current_header->header.gid,
+				     sizeof current_header->header.gid, 0,
+				     (uintmax_t) 0,
+				     (uintmax_t) TYPE_MAXIMUM (uintmax_t));
+	  if (g != -1)
+	    group = STRINGIFY_BIGINT (g, gform);
+	  else
+	    {
+	      sprintf (gform, "%ld",
+		       (long) GID_FROM_HEADER (current_header->header.gid));
+	      group = gform;
+	    }
+	}
 
 
       /* Format the file size or major/minor device numbers.  */
       /* Format the file size or major/minor device numbers.  */