diff --git a/lrzip.c b/lrzip.c index 3434585..2c59c94 100644 --- a/lrzip.c +++ b/lrzip.c @@ -42,19 +42,20 @@ #include "util.h" #include "liblrzip.h" /* flag defines */ -void write_magic(rzip_control *control, int fd_in, int fd_out) +char *make_magic(rzip_control *control, int fd_in) { struct timeval tv; struct stat st; - char magic[39]; - int i; + char *magic; - memset(magic, 0, sizeof(magic)); + magic = calloc(39, 1); + if (unlikely(!magic)) + fatal("Failed to calloc magic in make_magic\n"); strcpy(magic, "LRZI"); magic[4] = LRZIP_MAJOR_VERSION; magic[5] = LRZIP_MINOR_VERSION; - if (unlikely(fstat(fd_in, &st))) + if (unlikely(!STDIN && fstat(fd_in, &st))) fatal("bad magic file descriptor!?\n"); /* File size is stored as zero for streaming STDOUT blocks when the @@ -64,6 +65,8 @@ void write_magic(rzip_control *control, int fd_in, int fd_out) /* save LZMA compression flags */ if (LZMA_COMPRESS) { + int i; + for (i = 0; i < 5; i++) magic[i + 16] = (char)control->lzma_properties[i]; } @@ -83,10 +86,17 @@ void write_magic(rzip_control *control, int fd_in, int fd_out) memcpy(&magic[23], &control->secs, 8); memcpy(&magic[31], &control->usecs, 8); + return magic; +} + +static void write_magic(rzip_control *control, int fd_in, int fd_out) +{ + char *magic = make_magic(control, fd_in); + if (unlikely(lseek(fd_out, 0, SEEK_SET))) fatal("Failed to seek to BOF to write Magic Header\n"); - if (unlikely(write(fd_out, magic, sizeof(magic)) != sizeof(magic))) + if (unlikely(write(fd_out, magic, 39) != 39)) fatal("Failed to write magic header\n"); } @@ -651,6 +661,14 @@ next_chunk: free(infilecopy); } +static void open_tmpoutbuf(rzip_control *control) +{ + control->tmp_outbuf = malloc(control->maxram); + if (unlikely(!control->tmp_outbuf)) + fatal("Failed to malloc tmp_outbuf in open_tmpoutbuf\n"); + control->out_ofs = 39; +} + /* compress one file from the command line */ @@ -734,19 +752,19 @@ void compress_file(rzip_control *control) preserve_perms(control, fd_in, fd_out); /* Write zeroes to header at beginning of file */ - if (unlikely(write(fd_out, header, sizeof(header)) != sizeof(header))) + if (unlikely(!STDOUT && write(fd_out, header, sizeof(header)) != sizeof(header))) fatal("Cannot write file header\n"); rzip_fd(control, fd_in, fd_out); /* Wwrite magic at end b/c lzma does not tell us properties until it is done */ - write_magic(control, fd_in, fd_out); + if (!STDOUT) + write_magic(control, fd_in, fd_out); - if (STDOUT) - dump_tmpoutfile(control, fd_out); - - if (unlikely(close(fd_in) || close(fd_out))) - fatal("Failed to close files\n"); + if (unlikely(close(fd_in))) + fatal("Failed to close fd_in\n"); + if (unlikely(!STDOUT && close(fd_out))) + fatal("Failed to close fd_out\n"); if (!KEEP_FILES) { if (unlikely(unlink(control->infile))) diff --git a/lrzip.h b/lrzip.h index 730a3d6..e98a9ef 100644 --- a/lrzip.h +++ b/lrzip.h @@ -32,4 +32,5 @@ void decompress_file(rzip_control *control); void get_header_info(rzip_control *control, int fd_in, uchar *ctype, i64 *c_len, i64 *u_len, i64 *last_head); void get_fileinfo(rzip_control *control); void compress_file(rzip_control *control); +char *make_magic(rzip_control *control, int fd_in); #endif diff --git a/lrzip_private.h b/lrzip_private.h index 1fca208..83d06cc 100644 --- a/lrzip_private.h +++ b/lrzip_private.h @@ -159,6 +159,8 @@ struct rzip_control { char *outfile; char *outdir; char *tmpdir; // when stdin, stdout, or test used + char *tmp_outbuf; // Temporary file storage for stdout + i64 out_ofs; // Output offset when tmp_outbuf in use FILE *msgout; //stream for output messages const char *suffix; int compression_level; diff --git a/runzip.c b/runzip.c index 5270447..d7cb763 100644 --- a/runzip.c +++ b/runzip.c @@ -100,7 +100,7 @@ static i64 unzip_literal(rzip_control *control, void *ss, i64 len, int fd_out, u if (unlikely(stream_read == -1 )) fatal("Failed to read_stream in unzip_literal\n"); - if (unlikely(write_1g(fd_out, buf, (size_t)stream_read) != (ssize_t)stream_read)) + if (unlikely(write_1g(control, fd_out, buf, (size_t)stream_read) != (ssize_t)stream_read)) fatal("Failed to write literal buffer of size %lld\n", stream_read); if (!HAS_MD5) @@ -142,7 +142,7 @@ static i64 unzip_match(rzip_control *control, void *ss, i64 len, int fd_out, int if (unlikely(read_1g(fd_hist, off_buf, (size_t)n) != (ssize_t)n)) fatal("Failed to read %d bytes in unzip_match\n", n); - if (unlikely(write_1g(fd_out, off_buf, (size_t)n) != (ssize_t)n)) + if (unlikely(write_1g(control, fd_out, off_buf, (size_t)n) != (ssize_t)n)) fatal("Failed to write %d bytes in unzip_match\n", n); if (!HAS_MD5) diff --git a/stream.c b/stream.c index a4f6889..b373f2e 100644 --- a/stream.c +++ b/stream.c @@ -635,10 +635,19 @@ out: const i64 one_g = 1000 * 1024 * 1024; +ssize_t put_fdout(rzip_control *control, int fd, void *offset_buf, ssize_t ret) +{ + if (!STDOUT) + return write(fd, offset_buf, (size_t)ret); + memcpy(control->tmp_outbuf, offset_buf, ret); + control->out_ofs += ret; + return ret; +} + /* This is a custom version of write() which writes in 1GB chunks to avoid the overflows at the >= 2GB mark thanks to 32bit fuckage. This should help even on the rare occasion write() fails to write 1GB as well. */ -ssize_t write_1g(int fd, void *buf, i64 len) +ssize_t write_1g(rzip_control *control, int fd, void *buf, i64 len) { uchar *offset_buf = buf; ssize_t ret; @@ -650,7 +659,7 @@ ssize_t write_1g(int fd, void *buf, i64 len) ret = one_g; else ret = len; - ret = write(fd, offset_buf, (size_t)ret); + ret = put_fdout(control, fd, offset_buf, (size_t)ret); if (unlikely(ret <= 0)) return ret; len -= ret; @@ -684,11 +693,11 @@ ssize_t read_1g(int fd, void *buf, i64 len) } /* write to a file, return 0 on success and -1 on failure */ -static int write_buf(int f, uchar *p, i64 len) +static int write_buf(rzip_control *control, int f, uchar *p, i64 len) { ssize_t ret; - ret = write_1g(f, p, (size_t)len); + ret = write_1g(control, f, p, (size_t)len); if (unlikely(ret == -1)) { print_err("Write of length %lld failed - %s\n", len, strerror(errno)); return -1; @@ -701,15 +710,15 @@ static int write_buf(int f, uchar *p, i64 len) } /* write a byte */ -static int write_u8(int f, uchar v) +static int write_u8(rzip_control *control, int f, uchar v) { - return write_buf(f, &v, 1); + return write_buf(control, f, &v, 1); } /* write a i64 */ -static int write_i64(int f, i64 v) +static int write_i64(rzip_control *control, int f, i64 v) { - if (unlikely(write_buf(f, (uchar *)&v, 8))) + if (unlikely(write_buf(control, f, (uchar *)&v, 8))) return -1; return 0; @@ -1072,22 +1081,22 @@ retry: int j; /* Write chunk bytes of this block */ - write_u8(ctis->fd, ctis->chunk_bytes); + write_u8(control, ctis->fd, ctis->chunk_bytes); /* Write whether this is the last chunk, followed by the size * of this chunk */ - write_u8(ctis->fd, control->eof); - write_i64(ctis->fd, ctis->size); + write_u8(control, ctis->fd, control->eof); + write_i64(control, ctis->fd, ctis->size); /* First chunk of this stream, write headers */ ctis->initial_pos = lseek(ctis->fd, 0, SEEK_CUR); for (j = 0; j < ctis->num_streams; j++) { ctis->s[j].last_head = ctis->cur_pos + 17; - write_u8(ctis->fd, CTYPE_NONE); - write_i64(ctis->fd, 0); - write_i64(ctis->fd, 0); - write_i64(ctis->fd, 0); + write_u8(control, ctis->fd, CTYPE_NONE); + write_i64(control, ctis->fd, 0); + write_i64(control, ctis->fd, 0); + write_i64(control, ctis->fd, 0); ctis->cur_pos += 25; } } @@ -1095,7 +1104,7 @@ retry: if (unlikely(seekto(ctis, ctis->s[cti->streamno].last_head))) fatal("Failed to seekto in compthread %d\n", i); - if (unlikely(write_i64(ctis->fd, ctis->cur_pos))) + if (unlikely(write_i64(control, ctis->fd, ctis->cur_pos))) fatal("Failed to write_i64 in compthread %d\n", i); ctis->s[cti->streamno].last_head = ctis->cur_pos + 17; @@ -1103,15 +1112,15 @@ retry: fatal("Failed to seekto cur_pos in compthread %d\n", i); print_maxverbose("Thread %ld writing %lld compressed bytes from stream %d\n", i, cti->c_len, cti->streamno); - if (unlikely(write_u8(ctis->fd, cti->c_type) || - write_i64(ctis->fd, cti->c_len) || - write_i64(ctis->fd, cti->s_len) || - write_i64(ctis->fd, 0))) { + if (unlikely(write_u8(control, ctis->fd, cti->c_type) || + write_i64(control, ctis->fd, cti->c_len) || + write_i64(control, ctis->fd, cti->s_len) || + write_i64(control, ctis->fd, 0))) { fatal("Failed write in compthread %d\n", i); } ctis->cur_pos += 25; - if (unlikely(write_buf(ctis->fd, cti->s_buf, cti->c_len))) + if (unlikely(write_buf(control, ctis->fd, cti->s_buf, cti->c_len))) fatal("Failed to write_buf in compthread %d\n", i); ctis->cur_pos += cti->c_len; diff --git a/stream.h b/stream.h index 959d2e3..b26dde2 100644 --- a/stream.h +++ b/stream.h @@ -26,7 +26,7 @@ void create_pthread(pthread_t *thread, pthread_attr_t *attr, void * (*start_routine)(void *), void *arg); void join_pthread(pthread_t th, void **thread_return); -ssize_t write_1g(int fd, void *buf, i64 len); +ssize_t write_1g(rzip_control *control, int fd, void *buf, i64 len); ssize_t read_1g(int fd, void *buf, i64 len); void prepare_streamout_threads(rzip_control *control); void close_streamout_threads(rzip_control *control);