2013-12-01 18:57:24 +00:00
|
|
|
/*
|
2015-10-22 05:13:26 +00:00
|
|
|
* Apple // emulator for *ix
|
2013-12-01 18:57:24 +00:00
|
|
|
*
|
|
|
|
* This software package is subject to the GNU General Public License
|
2015-10-22 05:13:26 +00:00
|
|
|
* version 3 or later (your choice) as published by the Free Software
|
2013-12-01 18:57:24 +00:00
|
|
|
* Foundation.
|
|
|
|
*
|
2017-05-21 21:58:55 +00:00
|
|
|
* Copyright 2013-2017 Aaron Culliney
|
2013-12-01 18:57:24 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-01-23 04:42:34 +00:00
|
|
|
#include "common.h"
|
2013-12-01 18:57:24 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
typedef enum a2gzip_t {
|
|
|
|
A2GZT_ERR = -1,
|
|
|
|
A2GZT_NOT_GZ = 0,
|
|
|
|
A2GZT_MAYBE_GZ = 1,
|
|
|
|
} a2gzip_t;
|
2013-12-01 18:57:24 +00:00
|
|
|
|
|
|
|
/* report a zlib or i/o error */
|
2015-10-16 03:55:15 +00:00
|
|
|
static const char* const _gzerr(gzFile gzf) {
|
|
|
|
if (gzf == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-12-22 20:37:01 +00:00
|
|
|
int err_num = 0;
|
|
|
|
const char *reason = gzerror(gzf, &err_num);
|
|
|
|
if (err_num == Z_ERRNO) {
|
|
|
|
return strerror(err_num);
|
|
|
|
} else {
|
|
|
|
return reason;
|
2013-12-01 18:57:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-22 00:30:09 +00:00
|
|
|
static int _gzread_data(gzFile gzsource, uint8_t *buf, const unsigned int expected_bytescount) {
|
2017-05-21 21:58:55 +00:00
|
|
|
int bytescount = 0;
|
|
|
|
|
|
|
|
int maxtries = 10;
|
|
|
|
do {
|
|
|
|
int bytesread = gzread(gzsource, buf+bytescount, expected_bytescount-bytescount);
|
|
|
|
if (bytesread <= 0) {
|
|
|
|
if (--maxtries == 0) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, giving up on gzread() ...");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, gzread() ...");
|
2017-05-21 21:58:55 +00:00
|
|
|
usleep(100);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytescount += bytesread;
|
|
|
|
|
|
|
|
if (bytescount >= expected_bytescount) {
|
|
|
|
bytescount = expected_bytescount;
|
|
|
|
break; // DONE
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
return bytescount;
|
|
|
|
}
|
|
|
|
|
2017-09-22 00:30:09 +00:00
|
|
|
static ssize_t _read_data(int fd_own, uint8_t *buf, const off_t expected_bytescount) {
|
|
|
|
ssize_t bytescount = 0;
|
2017-05-21 21:58:55 +00:00
|
|
|
|
|
|
|
int maxtries = 10;
|
|
|
|
do {
|
2017-09-22 00:30:09 +00:00
|
|
|
ssize_t bytesread = 0;
|
2018-01-21 21:18:49 +00:00
|
|
|
off_t len0 = expected_bytescount-bytescount;
|
|
|
|
unsigned int len = (unsigned int)len0;
|
|
|
|
if (UNLIKELY(len0 > UINT_MAX || len0 < 0)) {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEMP_FAILURE_RETRY(bytesread = read(fd_own, buf+bytescount, len));
|
2017-05-21 21:58:55 +00:00
|
|
|
if (bytesread <= 0) {
|
|
|
|
if (--maxtries == 0) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, giving up on read() ...");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, read() ...");
|
2017-05-21 21:58:55 +00:00
|
|
|
usleep(100);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytescount += bytesread;
|
|
|
|
|
|
|
|
if (bytescount >= expected_bytescount) {
|
2017-09-22 00:30:09 +00:00
|
|
|
bytescount = (int)expected_bytescount;
|
2017-05-21 21:58:55 +00:00
|
|
|
break; // DONE
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
return bytescount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-22 00:30:09 +00:00
|
|
|
static ssize_t _write_data(int fd_own, uint8_t *buf, const unsigned int expected_bytescount) {
|
|
|
|
ssize_t bytescount = 0;
|
2017-05-21 21:58:55 +00:00
|
|
|
|
|
|
|
int maxtries = 10;
|
|
|
|
do {
|
|
|
|
ssize_t byteswritten = 0;
|
|
|
|
TEMP_FAILURE_RETRY(byteswritten = write(fd_own, buf+bytescount, expected_bytescount-bytescount));
|
|
|
|
|
|
|
|
if (byteswritten <= 0) {
|
|
|
|
if (--maxtries == 0) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, giving up on write() ...");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, write ...");
|
2017-05-21 21:58:55 +00:00
|
|
|
usleep(100);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytescount += byteswritten;
|
|
|
|
|
|
|
|
if (bytescount >= expected_bytescount) {
|
|
|
|
bytescount = expected_bytescount;
|
|
|
|
break; // DONE
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
return bytescount;
|
|
|
|
}
|
|
|
|
|
2017-09-22 00:30:09 +00:00
|
|
|
static a2gzip_t _check_gzip_magick(int fd_own, const unsigned int expected_bytescount) {
|
2017-05-21 21:58:55 +00:00
|
|
|
|
|
|
|
a2gzip_t ret = A2GZT_ERR;
|
|
|
|
|
|
|
|
do {
|
2017-06-03 12:38:24 +00:00
|
|
|
uint8_t stkbuf[2];
|
2017-09-22 00:30:09 +00:00
|
|
|
off_t bytescount = _read_data(fd_own, &stkbuf[0], sizeof(stkbuf));
|
2017-05-21 21:58:55 +00:00
|
|
|
if (bytescount != sizeof(stkbuf)) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, could not read file magick for file descriptor");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytescount = lseek(fd_own, 0L, SEEK_END);
|
|
|
|
if (bytescount == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot seek to end of file descriptor!");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stkbuf[0] == 0x1f && stkbuf[1] == 0x8b) {
|
|
|
|
// heuristics : gzip magick matches, but could possibly be a disk image file that begins with those bytes ...
|
|
|
|
ret = A2GZT_MAYBE_GZ;
|
|
|
|
if (bytescount >= expected_bytescount) {
|
|
|
|
// most gzipped disk images are *likely* to compress smaller, but we shouldn't assume ...
|
|
|
|
LOG("OMG, found a large apparently gzipped disk image!");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// did not see the gzip magick, so this is not a gzip file, but we should check file length ...
|
|
|
|
if (bytescount >= expected_bytescount) {
|
|
|
|
ret = A2GZT_NOT_GZ;
|
|
|
|
} else {
|
2017-09-22 00:30:09 +00:00
|
|
|
LOG("OOPS, did not find gzip magick, and file is %lld bytes, not expected size of %u", (long long)bytescount, expected_bytescount);
|
2017-05-21 21:58:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Inflate/uncompress file descriptor to buffer.
|
2015-11-29 21:31:17 +00:00
|
|
|
*
|
|
|
|
* Return NULL on success, or error string (possibly from zlib) on failure.
|
|
|
|
*/
|
2017-09-22 00:30:09 +00:00
|
|
|
const char *zlib_inflate_to_buffer(int fd, const unsigned int expected_bytescount, uint8_t *buf) {
|
2017-05-21 21:58:55 +00:00
|
|
|
gzFile gzsource = NULL;
|
|
|
|
int fd_own = -1;
|
2013-12-01 18:57:24 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
assert(buf != NULL);
|
|
|
|
assert(expected_bytescount > 0);
|
2013-12-01 18:57:24 +00:00
|
|
|
|
2017-09-22 00:30:09 +00:00
|
|
|
ssize_t bytescount = 0;
|
2015-10-16 03:55:15 +00:00
|
|
|
char *err = NULL;
|
2013-12-01 18:57:24 +00:00
|
|
|
do {
|
2017-05-21 21:58:55 +00:00
|
|
|
|
|
|
|
TEMP_FAILURE_RETRY(fd_own = dup(fd)); // balance gzclose() behavior
|
|
|
|
if (fd_own == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, could not dup() file descriptor %d", fd);
|
2013-12-01 18:57:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-05-21 21:58:55 +00:00
|
|
|
fd = -1;
|
2013-12-01 18:57:24 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
// check gzip magick ...
|
|
|
|
a2gzip_t val = _check_gzip_magick(fd_own, expected_bytescount);
|
|
|
|
if (val == A2GZT_ERR) {
|
|
|
|
break;
|
|
|
|
}
|
2013-12-01 18:57:24 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
if (lseek(fd_own, 0L, SEEK_SET) == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot seek to start of file descriptor!");
|
2013-12-01 18:57:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
if (val == A2GZT_NOT_GZ) {
|
|
|
|
// definitively not gzipped and expected size, all good!
|
|
|
|
bytescount = _read_data(fd_own, buf, expected_bytescount);
|
2013-12-22 20:37:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
// attempt inflate ...
|
|
|
|
|
|
|
|
gzsource = gzdopen(fd_own, "r");
|
|
|
|
if (gzsource == NULL) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot open file descriptor for reading");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytescount = _gzread_data(gzsource, buf, expected_bytescount);
|
|
|
|
if (bytescount != expected_bytescount) {
|
|
|
|
// could not gzread(), maybe it's not actually a gzip stream? ...
|
2017-09-22 00:30:09 +00:00
|
|
|
LOG("OOPS, did not gzread() expected_bytescount of %u ... apparently read %zd ... checking file length heuristic ...", expected_bytescount, bytescount);
|
2013-12-22 20:37:01 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
if (lseek(fd_own, 0L, SEEK_SET) == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot seek to start of file descriptor!");
|
2013-12-22 20:37:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
bytescount = _read_data(fd_own, buf, expected_bytescount);
|
|
|
|
|
|
|
|
if (bytescount < expected_bytescount) {
|
|
|
|
LOG("OOPS, apparently corrupt gzipped file...");
|
|
|
|
} else {
|
|
|
|
LOG("File appears to be non-gzipped, proceeding to load ...");
|
|
|
|
bytescount = expected_bytescount;
|
2013-12-22 20:37:01 +00:00
|
|
|
}
|
2017-05-21 21:58:55 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2013-12-22 20:37:01 +00:00
|
|
|
|
2013-12-01 18:57:24 +00:00
|
|
|
} while (0);
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
if (bytescount != expected_bytescount) {
|
2017-09-22 00:30:09 +00:00
|
|
|
LOG("OOPS did not read expected_bytescount of %u ... apparently read %zd", expected_bytescount, bytescount);
|
2017-05-21 21:58:55 +00:00
|
|
|
if (gzsource) {
|
|
|
|
err = (char *)_gzerr(gzsource);
|
2015-10-16 03:55:15 +00:00
|
|
|
}
|
|
|
|
if (!err) {
|
|
|
|
err = ZERR_UNKNOWN;
|
|
|
|
}
|
2013-12-22 20:37:01 +00:00
|
|
|
}
|
2013-12-01 18:57:24 +00:00
|
|
|
|
|
|
|
// clean up
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
if (gzsource) {
|
|
|
|
gzclose(gzsource);
|
|
|
|
// TEMP_FAILURE_RETRY(close(fd_own)); -- NOTE gzdopen() API with gzclose() above also closes the dup()'d fd
|
|
|
|
} else if (fd_own > 0) {
|
|
|
|
TEMP_FAILURE_RETRY(close(fd_own));
|
2015-10-16 03:55:15 +00:00
|
|
|
}
|
|
|
|
|
2013-12-01 18:57:24 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
/* Inline inflate/uncompress buffer to file descriptor
|
2015-11-29 21:31:17 +00:00
|
|
|
*
|
|
|
|
* Return NULL on success, or error string (possibly from zlib) on failure.
|
|
|
|
*/
|
2017-09-22 00:30:09 +00:00
|
|
|
const char *zlib_inflate_inplace(int fd, const unsigned int expected_bytescount, bool *is_gzipped) {
|
2013-12-22 20:37:01 +00:00
|
|
|
gzFile gzsource = NULL;
|
2017-05-21 21:58:55 +00:00
|
|
|
int fd_own = -1;
|
2017-06-03 12:38:24 +00:00
|
|
|
uint8_t *buf = NULL;
|
2013-12-01 18:57:24 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
*is_gzipped = false;
|
2013-12-01 18:57:24 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
assert(expected_bytescount > 2);
|
|
|
|
|
2017-09-22 00:30:09 +00:00
|
|
|
off_t bytescount = 0;
|
2013-12-01 18:57:24 +00:00
|
|
|
do {
|
2017-05-21 21:58:55 +00:00
|
|
|
|
|
|
|
TEMP_FAILURE_RETRY(fd_own = dup(fd)); // balance gzclose()
|
|
|
|
if (fd_own == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, could not dup() file descriptor %d", fd);
|
2013-12-01 18:57:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-05-21 21:58:55 +00:00
|
|
|
fd = -1;
|
2013-12-01 18:57:24 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
// check gzip magick ...
|
|
|
|
a2gzip_t val = _check_gzip_magick(fd_own, expected_bytescount);
|
|
|
|
if (val == A2GZT_ERR) {
|
|
|
|
break;
|
|
|
|
} else if (val == A2GZT_NOT_GZ) {
|
|
|
|
// definitively not gzipped and expected size, all good!
|
|
|
|
bytescount = expected_bytescount;
|
2013-12-01 20:36:43 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-12-01 18:57:24 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
// attempt inflate ...
|
|
|
|
|
|
|
|
buf = MALLOC(expected_bytescount);
|
|
|
|
if (buf == NULL) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, failed allocation of %d bytes", expected_bytescount);
|
2013-12-01 18:57:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
if (lseek(fd_own, 0L, SEEK_SET) == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot seek to start of file descriptor!");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gzsource = gzdopen(fd_own, "r");
|
|
|
|
if (gzsource == NULL) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot open file file descriptor for reading");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytescount = _gzread_data(gzsource, buf, expected_bytescount);
|
|
|
|
if (bytescount != expected_bytescount) {
|
|
|
|
// could not gzread(), maybe it's not actually a gzip stream? ...
|
2017-09-22 00:30:09 +00:00
|
|
|
LOG("OOPS, did not in-place gzread() expected_bytescount of %u ... apparently read %lld ... checking file length heuristic ...", expected_bytescount, (long long)bytescount);
|
2017-05-21 21:58:55 +00:00
|
|
|
|
|
|
|
bytescount = lseek(fd_own, 0L, SEEK_END);
|
|
|
|
if (bytescount == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot seek to end of file descriptor!");
|
2013-12-22 20:37:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
if (bytescount < expected_bytescount) {
|
|
|
|
LOG("OOPS, apparently corrupt gzipped file...");
|
|
|
|
} else {
|
|
|
|
LOG("File appears to be non-gzipped, proceeding to load ...");
|
|
|
|
bytescount = expected_bytescount;
|
2013-12-22 20:37:01 +00:00
|
|
|
}
|
2015-10-16 03:55:15 +00:00
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// successfully read gzipped file ...
|
|
|
|
*is_gzipped = true;
|
|
|
|
|
|
|
|
// inplace write file
|
|
|
|
|
|
|
|
if (lseek(fd_own, 0L, SEEK_SET) == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot seek to start of file descriptor!");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytescount = _write_data(fd_own, buf, expected_bytescount);
|
|
|
|
|
|
|
|
if (bytescount == expected_bytescount) {
|
|
|
|
int ret = -1;
|
|
|
|
TEMP_FAILURE_RETRY(ret = ftruncate(fd_own, expected_bytescount));
|
|
|
|
if (ret == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, ftruncate file descriptor failed");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-12-01 18:57:24 +00:00
|
|
|
|
|
|
|
} while (0);
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
char *err = NULL;
|
|
|
|
if (bytescount != expected_bytescount) {
|
2017-09-22 00:30:09 +00:00
|
|
|
LOG("OOPS, did not write expected_bytescount of %u ... apparently wrote %lld", expected_bytescount, (long long)bytescount);
|
2015-10-16 03:55:15 +00:00
|
|
|
if (gzsource) {
|
|
|
|
err = (char *)_gzerr(gzsource);
|
|
|
|
}
|
|
|
|
if (!err) {
|
|
|
|
err = ZERR_UNKNOWN;
|
|
|
|
}
|
2013-12-22 20:37:01 +00:00
|
|
|
}
|
2013-12-01 18:57:24 +00:00
|
|
|
|
|
|
|
// clean up
|
|
|
|
|
2013-12-22 20:37:01 +00:00
|
|
|
if (gzsource) {
|
|
|
|
gzclose(gzsource);
|
2017-05-21 21:58:55 +00:00
|
|
|
// TEMP_FAILURE_RETRY(close(fd_own)); -- NOTE gzdopen() API with gzclose() above also closes the dup()'d fd
|
|
|
|
} else if (fd_own > 0) {
|
|
|
|
TEMP_FAILURE_RETRY(close(fd_own));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buf) {
|
|
|
|
FREE(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deflate/compress source buffer to destination buffer.
|
|
|
|
*
|
|
|
|
* Return NULL on success, or error string (possibly from zlib) on failure.
|
|
|
|
*/
|
2017-09-22 00:30:09 +00:00
|
|
|
const char *zlib_deflate_buffer(const uint8_t *src, const unsigned int src_bytescount, uint8_t *dst, OUTPARM off_t *dst_size) {
|
2017-05-21 21:58:55 +00:00
|
|
|
char *gzPath = NULL;
|
|
|
|
gzFile gzdest = NULL;
|
|
|
|
int fd_own = -1;
|
|
|
|
|
2017-09-22 00:30:09 +00:00
|
|
|
off_t expected_bytescount = src_bytescount;
|
2017-05-21 21:58:55 +00:00
|
|
|
|
|
|
|
*dst_size = -1;
|
|
|
|
|
2017-09-22 00:30:09 +00:00
|
|
|
off_t bytescount = 0;
|
2017-05-21 21:58:55 +00:00
|
|
|
char *err = NULL;
|
|
|
|
do {
|
|
|
|
ASPRINTF(&gzPath, "%s/tmp.img", data_dir);
|
|
|
|
assert(gzPath != NULL);
|
|
|
|
|
2017-08-28 05:17:32 +00:00
|
|
|
TEMP_FAILURE_RETRY(fd_own = open(gzPath, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR));
|
2017-05-21 21:58:55 +00:00
|
|
|
if (fd_own == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS could not open temp image path : %s", gzPath);
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gzdest = gzdopen(fd_own, "w");
|
|
|
|
if (gzdest == NULL) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot open file descriptor for writing");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2018-01-21 21:18:49 +00:00
|
|
|
off_t len0 = expected_bytescount-bytescount;
|
2017-09-22 00:30:09 +00:00
|
|
|
unsigned int len = (unsigned int)len0;
|
|
|
|
if (UNLIKELY(len0 > UINT_MAX || len0 < 0)) {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
int byteswritten = gzwrite(gzdest, src+bytescount, len);
|
2017-05-21 21:58:55 +00:00
|
|
|
if (byteswritten <= 0) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, gzwrite() returned %d", byteswritten);
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytescount += byteswritten;
|
|
|
|
if (bytescount >= expected_bytescount) {
|
|
|
|
bytescount = expected_bytescount;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// do short writes happen? ...
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
if (bytescount != expected_bytescount) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gzflush(gzdest, Z_FINISH) != Z_OK) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("Error flushing compressed output : %s", err);
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now read compressed data into buffer ...
|
|
|
|
|
|
|
|
{
|
2017-09-22 00:30:09 +00:00
|
|
|
off_t compressed_size = lseek(fd_own, 0L, SEEK_CUR);
|
2017-05-21 21:58:55 +00:00
|
|
|
assert(compressed_size > 0 && compressed_size < expected_bytescount);
|
|
|
|
expected_bytescount = compressed_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lseek(fd_own, 0L, SEEK_SET) == -1) {
|
2017-07-16 00:34:43 +00:00
|
|
|
LOG("OOPS, cannot seek to start of file descriptor!");
|
2017-05-21 21:58:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytescount = _read_data(fd_own, dst, expected_bytescount);
|
|
|
|
if (bytescount != expected_bytescount) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*dst_size = expected_bytescount;
|
|
|
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
if (bytescount != expected_bytescount) {
|
2017-09-22 00:30:09 +00:00
|
|
|
LOG("OOPS, did not write/read expected number of bytes of %lld ... apparently wrote %lld", (long long)expected_bytescount, (long long)bytescount);
|
2017-05-21 21:58:55 +00:00
|
|
|
if (gzdest) {
|
|
|
|
err = (char *)_gzerr(gzdest);
|
|
|
|
}
|
|
|
|
if (!err) {
|
|
|
|
err = ZERR_UNKNOWN;
|
|
|
|
}
|
2013-12-01 18:57:24 +00:00
|
|
|
}
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
// clean up
|
|
|
|
|
|
|
|
if (gzdest) {
|
|
|
|
gzclose(gzdest);
|
|
|
|
// TEMP_FAILURE_RETRY(close(fd_own)); -- NOTE gzdopen() API with gzclose() above also closes the open()'d fd
|
|
|
|
} else if (fd_own > 0) {
|
|
|
|
TEMP_FAILURE_RETRY(close(fd_own));
|
2015-10-16 03:55:15 +00:00
|
|
|
}
|
|
|
|
|
2017-05-21 21:58:55 +00:00
|
|
|
if (gzPath) {
|
|
|
|
unlink(gzPath);
|
|
|
|
FREE(gzPath);
|
2013-12-01 18:57:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|