diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-04 21:14:12 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-04 21:14:12 +0200 |
commit | 9180c6045e8b2465b3e18a22eb08ee8438ae8544 (patch) | |
tree | 154bd3a352b89e73098e7923941bb76393dcf604 | |
parent | 882062915d52581fb754e5721addca72aa789ab7 (diff) | |
download | busybox-w32-9180c6045e8b2465b3e18a22eb08ee8438ae8544.tar.gz busybox-w32-9180c6045e8b2465b3e18a22eb08ee8438ae8544.tar.bz2 busybox-w32-9180c6045e8b2465b3e18a22eb08ee8438ae8544.zip |
tar: store negative mtime as 0; pack very large files using base-256 encoding
function old new delta
writeTarHeader 841 979 +138
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | archival/tar.c | 36 | ||||
-rw-r--r-- | include/archive.h | 2 |
2 files changed, 33 insertions, 5 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; |
diff --git a/include/archive.h b/include/archive.h index b139dc5be..9e176d335 100644 --- a/include/archive.h +++ b/include/archive.h | |||
@@ -125,7 +125,7 @@ typedef struct archive_handle_t { | |||
125 | #define TAR_BLOCK_SIZE 512 | 125 | #define TAR_BLOCK_SIZE 512 |
126 | #define NAME_SIZE 100 | 126 | #define NAME_SIZE 100 |
127 | #define NAME_SIZE_STR "100" | 127 | #define NAME_SIZE_STR "100" |
128 | typedef struct tar_header_t { /* byte offset */ | 128 | typedef struct tar_header_t { /* byte offset */ |
129 | char name[NAME_SIZE]; /* 0-99 */ | 129 | char name[NAME_SIZE]; /* 0-99 */ |
130 | char mode[8]; /* 100-107 */ | 130 | char mode[8]; /* 100-107 */ |
131 | char uid[8]; /* 108-115 */ | 131 | char uid[8]; /* 108-115 */ |