X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fcreate.c;h=a7d134495caba826d63b15dd5d82d8ee42183b87;hb=6600451136831cb42ddf08938dc9ead04e3ea723;hp=0d7e67e0a719cde68a42949e6ba28b4c958e9637;hpb=13617c42d896aa66178d914d744d2d42fb988248;p=chaz%2Ftar diff --git a/src/create.c b/src/create.c index 0d7e67e..a7d1344 100644 --- a/src/create.c +++ b/src/create.c @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., - 59 Place - Suite 330, Boston, MA 02111-1307, USA. */ + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "system.h" @@ -65,9 +65,11 @@ struct link *linklist = NULL; /* points to first link in list */ | fact is used by start_header and finish_header, so don't change it! | `------------------------------------------------------------------------*/ -/* 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. */ +/* Output VALUE in octal, using SUBSTITUTE if value won't fit. + Output to buffer WHERE with size SIZE. + TYPE is the kind of value being output (useful for diagnostics). + Prefer SIZE - 1 octal digits (with leading '0's), followed by '\0'; + but if SIZE octal digits would fit, omit the '\0'. */ static void to_oct (uintmax_t value, uintmax_t substitute, char *where, size_t size, const char *type) @@ -75,6 +77,15 @@ to_oct (uintmax_t value, uintmax_t substitute, char *where, size_t size, const c uintmax_t v = value; size_t i = size; +# define MAX_OCTAL_VAL_WITH_DIGITS(digits) \ + ((digits) * 3 < sizeof (uintmax_t) * CHAR_BIT \ + ? ((uintmax_t) 1 << ((digits) * 3)) - 1 \ + : (uintmax_t) -1) + + /* Output a trailing NUL unless the value is too large. */ + if (value <= MAX_OCTAL_VAL_WITH_DIGITS (size - 1)) + where[--i] = '\0'; + /* Produce the digits -- at least one. */ do @@ -84,16 +95,13 @@ to_oct (uintmax_t value, uintmax_t substitute, char *where, size_t size, const c } while (i != 0 && v != 0); - /* Leading spaces, if necessary. */ + /* Leading zeros, if necessary. */ while (i != 0) - where[--i] = ' '; + where[--i] = '0'; if (v != 0) { - int bits = size * 3; - uintmax_t maxval = (bits < sizeof (uintmax_t) * CHAR_BIT - ? ((uintmax_t) 1 << bits) - 1 - : (uintmax_t) -1); + uintmax_t maxval = MAX_OCTAL_VAL_WITH_DIGITS (size); char buf1[UINTMAX_STRSIZE_BOUND]; char buf2[UINTMAX_STRSIZE_BOUND]; char buf3[UINTMAX_STRSIZE_BOUND]; @@ -133,7 +141,29 @@ minor_to_oct (minor_t v, char *p, size_t s) void mode_to_oct (mode_t v, char *p, size_t s) { - to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "mode_t"); + /* In the common case where the internal and external mode bits are the same, + propagate all unknown bits to the external mode. + This matches historical practice. + Otherwise, just copy the bits we know about. */ + uintmax_t u = + ((S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX + && S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC + && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC + && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC) + ? v + : ((v & S_ISUID ? TSUID : 0) + | (v & S_ISGID ? TSGID : 0) + | (v & S_ISVTX ? TSVTX : 0) + | (v & S_IRUSR ? TUREAD : 0) + | (v & S_IWUSR ? TUWRITE : 0) + | (v & S_IXUSR ? TUEXEC : 0) + | (v & S_IRGRP ? TGREAD : 0) + | (v & S_IWGRP ? TGWRITE : 0) + | (v & S_IXGRP ? TGEXEC : 0) + | (v & S_IROTH ? TOREAD : 0) + | (v & S_IWOTH ? TOWRITE : 0) + | (v & S_IXOTH ? TOEXEC : 0))); + to_oct (u, (uintmax_t) 0, p, s, "mode_t"); } void off_to_oct (off_t v, char *p, size_t s) @@ -297,7 +327,7 @@ Removing leading `/' from absolute path names in the archive"))); if (group_option != (gid_t) -1) st->st_gid = group_option; if (mode_option) - st->st_mode = ((st->st_mode & S_IFMT) + st->st_mode = ((st->st_mode & ~MODE_ALL) | mode_adjust (st->st_mode, mode_option)); /* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a) @@ -324,7 +354,7 @@ Removing leading `/' from absolute path names in the archive"))); acceptor for Paul's test. */ if (archive_format == V7_FORMAT) - MODE_TO_OCT (st->st_mode & 07777, header->header.mode); + MODE_TO_OCT (st->st_mode & MODE_ALL, header->header.mode); else MODE_TO_OCT (st->st_mode, header->header.mode); @@ -395,16 +425,15 @@ 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, 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. + digits, then a null. We use to_oct. + 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, 6); - header->header.chksum[6] = '\0'; + uintmax_to_oct ((uintmax_t) sum, header->header.chksum, 7); set_next_block_after (header); @@ -511,7 +540,7 @@ deal_with_sparse (char *name, union block *header) init_sparsearray (); clear_buffer (buffer); - while (count = read (file, buffer, sizeof buffer), count != 0) + while (count = safe_read (file, buffer, sizeof buffer), count != 0) { /* Realloc the scratch area as necessary. FIXME: should reallocate only at beginning of a new instance of non-zero data. */ @@ -613,7 +642,7 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name) break; } - if (lseek (file, sparsearray[sparse_index++].offset, 0) < 0) + if (lseek (file, sparsearray[sparse_index++].offset, SEEK_SET) < 0) { char buf[UINTMAX_STRSIZE_BOUND]; ERROR ((0, errno, _("lseek error at byte %s in file %s"), @@ -630,8 +659,8 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name) #if 0 if (amount_read) { - count = read (file, start->buffer + amount_read, - BLOCKSIZE - amount_read); + count = safe_read (file, start->buffer + amount_read, + BLOCKSIZE - amount_read); bufsize -= BLOCKSIZE - amount_read; amount_read = 0; set_next_block_after (start); @@ -641,7 +670,7 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name) #endif /* Store the data. */ - count = read (file, start->buffer, BLOCKSIZE); + count = safe_read (file, start->buffer, BLOCKSIZE); if (count < 0) { char buf[UINTMAX_STRSIZE_BOUND]; @@ -662,7 +691,7 @@ Read error at byte %s, reading %lu bytes, in file %s"), char buffer[BLOCKSIZE]; clear_buffer (buffer); - count = read (file, buffer, bufsize); + count = safe_read (file, buffer, bufsize); memcpy (start->buffer, buffer, BLOCKSIZE); } @@ -726,7 +755,8 @@ create_archive (void) collect_and_sort_names (); while (p = name_from_list (), p) - dump_file (p, (dev_t) -1, 1); + if (!excluded_pathname (excluded, p)) + dump_file (p, (dev_t) -1, 1); blank_name_list (); while (p = name_from_list (), p) @@ -751,7 +781,8 @@ create_archive (void) else { while (p = name_next (1), p) - dump_file (p, (dev_t) -1, 1); + if (!excluded_pathname (excluded, p)) + dump_file (p, (dev_t) -1, 1); } write_eot (); @@ -1054,7 +1085,8 @@ Removing leading `/' from absolute links"))); files when archive is meant for /dev/null. */ if (dev_null_output - || (sizeleft == 0 && 0444 == (0444 & current_stat.st_mode))) + || (sizeleft == 0 + && MODE_R == (MODE_R & current_stat.st_mode))) f = -1; else { @@ -1137,7 +1169,8 @@ Removing leading `/' from absolute links"))); } if (save_typeflag == GNUTYPE_SPARSE) { - if (finish_sparse_file (f, &sizeleft, current_stat.st_size, p)) + if (f < 0 + || finish_sparse_file (f, &sizeleft, current_stat.st_size, p)) goto padit; } else @@ -1166,7 +1199,7 @@ Removing leading `/' from absolute links"))); if (f < 0) count = bufsize; else - count = read (f, start->buffer, bufsize); + count = safe_read (f, start->buffer, bufsize); if (count < 0) { char buf[UINTMAX_STRSIZE_BOUND]; @@ -1447,9 +1480,10 @@ Read error at byte %s, reading %lu bytes, in file %s"), while (entry = readdir (directory), entry) { - /* Skip `.' and `..'. */ + /* Skip `.', `..', and excluded file names. */ - if (is_dot_or_dotdot (entry->d_name)) + if (is_dot_or_dotdot (entry->d_name) + || excluded_filename (excluded, entry->d_name)) continue; if ((int) NAMLEN (entry) + len >= buflen) @@ -1464,8 +1498,6 @@ Read error at byte %s, reading %lu bytes, in file %s"), #endif } strcpy (namebuf + len, entry->d_name); - if (exclude_option && check_exclude (namebuf)) - continue; dump_file (namebuf, our_device, 0); } @@ -1486,9 +1518,7 @@ Read error at byte %s, reading %lu bytes, in file %s"), type = BLKTYPE; #endif - /* Avoid screwy apollo lossage where S_IFIFO == S_IFSOCK. */ - -#if (_ISP__M68K == 0) && (_ISP__A88K == 0) && defined(S_ISFIFO) +#ifdef S_ISFIFO else if (S_ISFIFO (current_stat.st_mode)) type = FIFOTYPE; #endif @@ -1514,7 +1544,7 @@ Read error at byte %s, reading %lu bytes, in file %s"), header->header.typeflag = type; -#if defined(S_IFBLK) || defined(S_IFCHR) +#if defined S_ISBLK || defined S_ISCHR if (type != FIFOTYPE) { MAJOR_TO_OCT (major (current_stat.st_rdev), header->header.devmajor);