From 13617c42d896aa66178d914d744d2d42fb988248 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 2 Mar 1999 00:10:11 +0000 Subject: [PATCH] (to_oct): New parameter substitute, giving a substitute value to use when the original value is out of range. Do not append a space to the output; modern tars don't. When a value is out of range, specify the maximum value, not the number of bits. (GID_NOBODY, UID_NOBODY): New macros. (gid_to_oct, uid_to_oct): Use them as substitutes. (finish_header): Do not assume that UINTMAX_TO_OCT appends a space. (dump_file): Check whether the file changed as we read it. --- src/create.c | 79 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/src/create.c b/src/create.c index 8dec08b..0d7e67e 100644 --- a/src/create.c +++ b/src/create.c @@ -57,23 +57,23 @@ struct link *linklist = NULL; /* points to first link in list */ /*------------------------------------------------------------------------. -| Convert VALUE into a size-SIZE field at WHERE, including a | +| Convert VALUE (with substitute SUBSTITUTE if VALUE is out of range) | +| into a size-SIZE field at WHERE, including a | | trailing space. For example, 3 for SIZE means two digits and a space. | | | | We assume the trailing NUL is already there and don't fill it in. This | | fact is used by start_header and finish_header, so don't change it! | `------------------------------------------------------------------------*/ -/* This should be equivalent to: sprintf (WHERE, "%*lo ", SIZE - 1, VALUE); +/* This should be equivalent to: sprintf (WHERE, "%*lo", SIZE, VALUE); except that we don't assume VALUE fits in an unsigned long, and except that sprintf fills in the trailing NUL and we don't. */ static void -to_oct (uintmax_t value, char *where, size_t size, const char *type) +to_oct (uintmax_t value, uintmax_t substitute, char *where, size_t size, const char *type) { uintmax_t v = value; size_t i = size; - where[--i] = ' '; /* put in the space, though */ /* Produce the digits -- at least one. */ @@ -90,56 +90,78 @@ to_oct (uintmax_t value, char *where, size_t size, const char *type) if (v != 0) { - char buf[UINTMAX_STRSIZE_BOUND]; - ERROR ((0, 0, _("%s value %s is too large to fit in a %u-bit field"), - type, STRINGIFY_BIGINT (value, buf), - (unsigned) ((size - 1) * 3))); + int bits = size * 3; + uintmax_t maxval = (bits < sizeof (uintmax_t) * CHAR_BIT + ? ((uintmax_t) 1 << bits) - 1 + : (uintmax_t) -1); + char buf1[UINTMAX_STRSIZE_BOUND]; + char buf2[UINTMAX_STRSIZE_BOUND]; + char buf3[UINTMAX_STRSIZE_BOUND]; + char *value_string = STRINGIFY_BIGINT (value, buf1); + char *maxval_string = STRINGIFY_BIGINT (maxval, buf2); + if (substitute) + { + substitute &= maxval; + WARN ((0, 0, _("%s value %s too large (max=%s); substituting %s"), + type, value_string, maxval_string, + STRINGIFY_BIGINT (substitute, buf3))); + to_oct (substitute, (uintmax_t) 0, where, size, type); + } + else + ERROR ((0, 0, _("%s value %s too large (max=%s)"), + type, value_string, maxval_string)); } } +#ifndef GID_NOBODY +#define GID_NOBODY 0 +#endif void gid_to_oct (gid_t v, char *p, size_t s) { - to_oct ((uintmax_t) v, p, s, "gid_t"); + to_oct ((uintmax_t) v, (uintmax_t) GID_NOBODY, p, s, "gid_t"); } void major_to_oct (major_t v, char *p, size_t s) { - to_oct ((uintmax_t) v, p, s, "major_t"); + to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "major_t"); } void minor_to_oct (minor_t v, char *p, size_t s) { - to_oct ((uintmax_t) v, p, s, "minor_t"); + to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "minor_t"); } void mode_to_oct (mode_t v, char *p, size_t s) { - to_oct ((uintmax_t) v, p, s, "mode_t"); + to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "mode_t"); } void off_to_oct (off_t v, char *p, size_t s) { - to_oct ((uintmax_t) v, p, s, "off_t"); + to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "off_t"); } void size_to_oct (size_t v, char *p, size_t s) { - to_oct ((uintmax_t) v, p, s, "size_t"); + to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "size_t"); } void time_to_oct (time_t v, char *p, size_t s) { - to_oct ((uintmax_t) v, p, s, "time_t"); + to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "time_t"); } +#ifndef UID_NOBODY +#define UID_NOBODY 0 +#endif void uid_to_oct (uid_t v, char *p, size_t s) { - to_oct ((uintmax_t) v, p, s, "uid_t"); + to_oct ((uintmax_t) v, (uintmax_t) UID_NOBODY, p, s, "uid_t"); } void uintmax_to_oct (uintmax_t v, char *p, size_t s) { - to_oct (v, p, s, "uintmax_t"); + to_oct (v, (uintmax_t) 0, p, s, "uintmax_t"); } /* Writing routines. */ @@ -373,16 +395,16 @@ finish_header (union block *header) /* Fill in the checksum field. It's formatted differently from the other fields: it has [6] digits, a null, then a space -- rather than - digits, a space, then a null. We use to_oct then write the null in - over to_oct's space. The final space is already there, from - checksumming, and to_oct doesn't modify it. + digits, then a null. We use to_oct then write the null. + The final space is already there, from checksumming, + and to_oct doesn't modify it. This is a fast way to do: sprintf(header->header.chksum, "%6o", sum); */ - UINTMAX_TO_OCT ((uintmax_t) sum, header->header.chksum); - header->header.chksum[6] = '\0'; /* zap the space */ + uintmax_to_oct ((uintmax_t) sum, header->header.chksum, 6); + header->header.chksum[6] = '\0'; set_next_block_after (header); @@ -758,6 +780,7 @@ dump_file (char *p, dev_t parent_device, int top_level) union block *exhdr; char save_typeflag; struct utimbuf restore_times; + off_t restore_size; /* FIXME: `header' and `upperbound' might be used uninitialized in this function. Reported by Bruno Haible. */ @@ -769,7 +792,7 @@ dump_file (char *p, dev_t parent_device, int top_level) Otherwise, use lstat (which falls back to stat if no symbolic links). */ if (dereference_option != 0 -#ifdef STX_HIDDEN /* AIX */ +#if STX_HIDDEN && !_LARGE_FILES /* AIX */ ? statx (p, ¤t_stat, STATSIZE, STX_HIDDEN) : statx (p, ¤t_stat, STATSIZE, STX_HIDDEN | STX_LINK) #else @@ -785,6 +808,7 @@ dump_file (char *p, dev_t parent_device, int top_level) restore_times.actime = current_stat.st_atime; restore_times.modtime = current_stat.st_mtime; + restore_size = current_stat.st_size; #ifdef S_ISHIDDEN if (S_ISHIDDEN (current_stat.st_mode)) @@ -1176,7 +1200,14 @@ Read error at byte %s, reading %lu bytes, in file %s"), if (f >= 0) { - close (f); + struct stat final_stat; + if (fstat (f, &final_stat) != 0) + ERROR ((0, errno, "%s: fstat", p)); + else if (final_stat.st_mtime != restore_times.modtime + || final_stat.st_size != restore_size) + ERROR ((0, errno, _("%s: file changed as we read it"), p)); + if (close (f) != 0) + ERROR ((0, errno, _("%s: close"), p)); if (atime_preserve_option) utime (p, &restore_times); } -- 2.44.0