Skip to content

Commit 3653e51

Browse files
committed
Use base-256 encoding for files larger 68G
Reference: http://lists.busybox.net/pipermail/busybox/2011-May/075596.html
1 parent 8c24507 commit 3653e51

File tree

2 files changed

+49
-9
lines changed

2 files changed

+49
-9
lines changed

include/storage/tar.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,8 @@ checkMTarError(int error_code, const boost::filesystem::path &filepath, const st
2929
case MTAR_ESUCCESS:
3030
return;
3131
case MTAR_EFAILURE:
32-
throw util::RuntimeError(filepath.string() + " : " + name,
33-
ErrorCode::FileIOError,
34-
SOURCE_REF,
35-
std::strerror(errno));
32+
throw util::RuntimeError(
33+
filepath.string() + " : " + name, ErrorCode::FileIOError, SOURCE_REF);
3634
case MTAR_EOPENFAIL:
3735
throw util::RuntimeError(filepath.string() + " : " + name,
3836
ErrorCode::FileOpenError,

third_party/microtar/src/microtar.c

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ static int write_null_bytes(mtar_t *tar, int n) {
8989

9090
static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) {
9191
unsigned chksum1, chksum2;
92+
mtar_size_t filesize;
9293

9394
/* If the checksum starts with a null byte we assume the record is NULL */
9495
if (*rh->checksum == '\0') {
@@ -105,24 +106,68 @@ static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) {
105106
/* Load raw header into header */
106107
sscanf(rh->mode, "%o", &h->mode);
107108
sscanf(rh->owner, "%o", &h->owner);
108-
sscanf(rh->size, "%12lo", &h->size);
109109
sscanf(rh->mtime, "%o", &h->mtime);
110110
h->type = rh->type;
111111
strcpy(h->name, rh->name);
112112
strcpy(h->linkname, rh->linkname);
113113

114+
/* Load size field */
115+
if ((rh->size[0] & 0x80) == 0) {
116+
#ifdef _MSC_VER
117+
sscanf(rh->size, "%12llo", &h->size);
118+
#else
119+
sscanf(rh->size, "%12lo", &h->size);
120+
#endif
121+
} else {
122+
h->size = (rh->size[0] & 0x7f) | (rh->size[0] & 0x40 ? 0x80 : 0);
123+
uint8_t *p8 = (uint8_t *)&rh->size + 1;
124+
while (p8 != (uint8_t *)&rh->size + sizeof(rh->size)) {
125+
if (h->size >= ((mtar_size_t)1 << (sizeof(h->size) - 1) * 8)) {
126+
return MTAR_EFAILURE;
127+
}
128+
h->size = ((mtar_size_t)h->size << 8) + *p8++;
129+
}
130+
}
131+
114132
return MTAR_ESUCCESS;
115133
}
116134

117135

118136
static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) {
119137
unsigned chksum;
138+
mtar_size_t filesize = h->size;
120139

121140
/* Load header into raw header */
122141
memset(rh, 0, sizeof(*rh));
142+
143+
/* Store size in ASCII octal digits or base-256 formats */
144+
if (sizeof(mtar_size_t) <= 4 || filesize <= (mtar_size_t)0777777777777LL) {
145+
#ifdef _MSC_VER
146+
sprintf(rh->size, "%llo", h->size);
147+
#else
148+
sprintf(rh->size, "%lo", h->size);
149+
#endif
150+
} else if (sizeof(filesize) < sizeof(rh->size)) {
151+
/* GNU tar uses "base-256 encoding" for very large numbers.
152+
* Encoding is binary, with highest bit always set as a marker
153+
* and sign in next-highest bit:
154+
* 80 00 .. 00 - zero
155+
* bf ff .. ff - largest positive number
156+
* ff ff .. ff - minus 1
157+
* c0 00 .. 00 - smallest negative number
158+
*/
159+
uint8_t *p8 = (uint8_t *)&rh->size + sizeof(rh->size);
160+
do {
161+
*--p8 = (uint8_t)filesize;
162+
filesize >>= 8;
163+
} while (p8 != (uint8_t *)&rh->size);
164+
*p8 |= 0x80;
165+
} else {
166+
return MTAR_EFAILURE;
167+
}
168+
123169
sprintf(rh->mode, "%o", h->mode);
124170
sprintf(rh->owner, "%o", h->owner);
125-
sprintf(rh->size, "%lo", h->size);
126171
sprintf(rh->mtime, "%o", h->mtime);
127172
rh->type = h->type ? h->type : MTAR_TREG;
128173
strcpy(rh->name, h->name);
@@ -332,9 +377,6 @@ int mtar_write_header(mtar_t *tar, const mtar_header_t *h) {
332377

333378
int mtar_write_file_header(mtar_t *tar, const char *name, mtar_size_t size) {
334379
mtar_header_t h;
335-
if (size >= 0777777777777) {
336-
return MTAR_EFAILURE;
337-
}
338380
/* Build header */
339381
memset(&h, 0, sizeof(h));
340382
strcpy(h.name, name);

0 commit comments

Comments
 (0)