... | ... |
@@ -124,8 +124,10 @@ cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx) |
124 | 124 |
int size = 0, ret, fout=-1; |
125 | 125 |
int in_block = 0; |
126 | 126 |
int last_header_bad = 0; |
127 |
+ int limitnear = 0; |
|
127 | 128 |
unsigned int files = 0; |
128 | 129 |
char fullname[NAME_MAX + 1]; |
130 |
+ size_t currsize = 0; |
|
129 | 131 |
|
130 | 132 |
cli_dbgmsg("In untar(%s, %d)\n", dir, desc); |
131 | 133 |
|
... | ... |
@@ -149,6 +151,7 @@ cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx) |
149 | 149 |
int directory, skipEntry = 0; |
150 | 150 |
int checksum = -1; |
151 | 151 |
char magic[7], name[101], osize[TARSIZELEN + 1]; |
152 |
+ currsize = 0; |
|
152 | 153 |
|
153 | 154 |
if(fout>=0) { |
154 | 155 |
lseek(fout, 0, SEEK_SET); |
... | ... |
@@ -243,8 +246,20 @@ cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx) |
243 | 243 |
skipEntry++; |
244 | 244 |
} else { |
245 | 245 |
cli_dbgmsg("cli_untar: size = %d\n", size); |
246 |
- if((ret=cli_checklimits("cli_untar", ctx, size, 0, 0))!=CL_CLEAN) |
|
247 |
- skipEntry++; |
|
246 |
+ ret = cli_checklimits("cli_untar", ctx, size, 0, 0); |
|
247 |
+ switch(ret) { |
|
248 |
+ case CL_EMAXFILES: // Scan no more files |
|
249 |
+ skipEntry++; |
|
250 |
+ limitnear = 0; |
|
251 |
+ break; |
|
252 |
+ case CL_EMAXSIZE: // Either single file limit or total byte limit would be exceeded |
|
253 |
+ cli_dbgmsg("cli_untar: would exceed limit, will try up to max"); |
|
254 |
+ limitnear = 1; |
|
255 |
+ break; |
|
256 |
+ default: // Ok based on reported content size |
|
257 |
+ limitnear = 0; |
|
258 |
+ break; |
|
259 |
+ } |
|
248 | 260 |
} |
249 | 261 |
|
250 | 262 |
if(skipEntry) { |
... | ... |
@@ -278,16 +293,40 @@ cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx) |
278 | 278 |
|
279 | 279 |
in_block = 1; |
280 | 280 |
} else { /* write or continue writing file contents */ |
281 |
- const int nbytes = size>512? 512:size; |
|
282 |
- const int nwritten = (int)write(fout, block, (size_t)nbytes); |
|
281 |
+ int nbytes, nwritten; |
|
282 |
+ int skipwrite = 0; |
|
283 |
+ char err[128]; |
|
284 |
+ |
|
285 |
+ nbytes = size>512? 512:size; |
|
286 |
+ if (nread && nread < nbytes) |
|
287 |
+ nbytes = nread; |
|
288 |
+ |
|
289 |
+ if (limitnear > 0) { |
|
290 |
+ currsize += nbytes; |
|
291 |
+ cli_dbgmsg("cli_untar: Approaching limit...\n"); |
|
292 |
+ if (cli_checklimits("cli_untar", ctx, (unsigned long)currsize, 0, 0) != CL_SUCCESS) { |
|
293 |
+ // Limit would be exceeded by this file, suppress writing beyond limit |
|
294 |
+ // Need to keep reading to get to end of file chunk |
|
295 |
+ skipwrite++; |
|
296 |
+ } |
|
297 |
+ } |
|
283 | 298 |
|
284 |
- if(nwritten != nbytes) { |
|
285 |
- cli_errmsg("cli_untar: only wrote %d bytes to file %s (out of disc space?)\n", |
|
286 |
- nwritten, fullname); |
|
287 |
- close(fout); |
|
288 |
- return CL_EWRITE; |
|
299 |
+ if (skipwrite == 0) { |
|
300 |
+ nwritten = (int)write(fout, block, (size_t)nbytes); |
|
301 |
+ |
|
302 |
+ if(nwritten != nbytes) { |
|
303 |
+ cli_errmsg("cli_untar: only wrote %d bytes to file %s (out of disc space?)\n", |
|
304 |
+ nwritten, fullname); |
|
305 |
+ close(fout); |
|
306 |
+ return CL_EWRITE; |
|
307 |
+ } |
|
289 | 308 |
} |
290 | 309 |
size -= nbytes; |
310 |
+ if ((size != 0) && (nread == 0)) { |
|
311 |
+ // Truncated tar file, so end file content like tar behavior |
|
312 |
+ cli_dbgmsg("cli_untar: No bytes read! Forcing end of file content.\n"); |
|
313 |
+ size = 0; |
|
314 |
+ } |
|
291 | 315 |
} |
292 | 316 |
if (size == 0) |
293 | 317 |
in_block = 0; |