aboutsummaryrefslogtreecommitdiff
path: root/archival
diff options
context:
space:
mode:
Diffstat (limited to 'archival')
-rw-r--r--archival/tar.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/archival/tar.c b/archival/tar.c
index 01b83d5e2..ebaa183b4 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -264,7 +264,8 @@ static int writeTarHeader(struct TarBallInfo *tbInfo,
264 PUT_OCTAL(header.uid, statbuf->st_uid); 264 PUT_OCTAL(header.uid, statbuf->st_uid);
265 PUT_OCTAL(header.gid, statbuf->st_gid); 265 PUT_OCTAL(header.gid, statbuf->st_gid);
266 memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */ 266 memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
267 PUT_OCTAL(header.mtime, statbuf->st_mtime); 267 /* users report that files with negative st_mtime cause trouble, so: */
268 PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0);
268 269
269 /* Enter the user and group names */ 270 /* Enter the user and group names */
270 safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname)); 271 safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
@@ -316,15 +317,42 @@ static int writeTarHeader(struct TarBallInfo *tbInfo,
316 } else if (S_ISFIFO(statbuf->st_mode)) { 317 } else if (S_ISFIFO(statbuf->st_mode)) {
317 header.typeflag = FIFOTYPE; 318 header.typeflag = FIFOTYPE;
318 } else if (S_ISREG(statbuf->st_mode)) { 319 } else if (S_ISREG(statbuf->st_mode)) {
319 if (sizeof(statbuf->st_size) > 4 320 /* header.size field is 12 bytes long */
320 && statbuf->st_size > (off_t)0777777777777LL 321 /* Does octal-encoded size fit? */
322 uoff_t filesize = statbuf->st_size;
323 if (sizeof(filesize) <= 4
324 || filesize <= (uoff_t)0777777777777LL
321 ) { 325 ) {
326 PUT_OCTAL(header.size, filesize);
327 }
328 /* Does base256-encoded size fit?
329 * It always does unless off_t is wider than 64 bits.
330 */
331 else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS
332#if ULLONG_MAX > 0xffffffffffffffffLL /* 2^64-1 */
333 && (filesize <= 0x3fffffffffffffffffffffffLL)
334#endif
335 ) {
336 /* GNU tar uses "base-256 encoding" for very large numbers.
337 * Encoding is binary, with highest bit always set as a marker
338 * and sign in next-highest bit:
339 * 80 00 .. 00 - zero
340 * bf ff .. ff - largest positive number
341 * ff ff .. ff - minus 1
342 * c0 00 .. 00 - smallest negative number
343 */
344 char *p8 = header.size + sizeof(header.size);
345 do {
346 *--p8 = (uint8_t)filesize;
347 filesize >>= 8;
348 } while (p8 != header.size);
349 *p8 |= 0x80;
350 } else {
322 bb_error_msg_and_die("can't store file '%s' " 351 bb_error_msg_and_die("can't store file '%s' "
323 "of size %"OFF_FMT"u, aborting", 352 "of size %"OFF_FMT"u, aborting",
324 fileName, statbuf->st_size); 353 fileName, statbuf->st_size);
325 } 354 }
326 header.typeflag = REGTYPE; 355 header.typeflag = REGTYPE;
327 PUT_OCTAL(header.size, statbuf->st_size);
328 } else { 356 } else {
329 bb_error_msg("%s: unknown file type", fileName); 357 bb_error_msg("%s: unknown file type", fileName);
330 return FALSE; 358 return FALSE;