2011-03-08 22:32:14 +01:00
|
|
|
/*
|
2021-02-16 04:20:06 +01:00
|
|
|
Copyright (C) 2006-2016,2018,2021 Con Kolivas
|
2011-03-08 22:32:14 +01:00
|
|
|
Copyright (C) 2011 Peter Hyman
|
|
|
|
|
Copyright (C) 1998-2003 Andrew Tridgell
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-03-08 22:34:44 +01:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-03-08 22:36:55 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
#ifdef HAVE_SYS_STAT_H
|
|
|
|
|
# include <sys/stat.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <sys/statvfs.h>
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
|
# include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
#ifdef HAVE_ERRNO_H
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#endif
|
2011-03-18 00:37:09 +01:00
|
|
|
#include <sys/mman.h>
|
2011-03-11 13:29:56 +01:00
|
|
|
#include <sys/time.h>
|
2011-03-15 06:32:32 +01:00
|
|
|
#include <termios.h>
|
2011-03-21 21:57:32 +01:00
|
|
|
#ifdef HAVE_ENDIAN_H
|
|
|
|
|
# include <endian.h>
|
|
|
|
|
#elif HAVE_SYS_ENDIAN_H
|
|
|
|
|
# include <sys/endian.h>
|
|
|
|
|
#endif
|
2011-03-22 11:47:24 +01:00
|
|
|
#ifdef HAVE_ARPA_INET_H
|
|
|
|
|
# include <arpa/inet.h>
|
|
|
|
|
#endif
|
2011-08-11 05:57:20 +02:00
|
|
|
#include <math.h>
|
2012-03-07 14:15:58 +01:00
|
|
|
#include <utime.h>
|
2015-03-10 10:08:00 +01:00
|
|
|
#include <inttypes.h>
|
2011-03-08 22:36:55 +01:00
|
|
|
|
|
|
|
|
#include "md5.h"
|
2011-03-08 22:32:14 +01:00
|
|
|
#include "rzip.h"
|
2011-03-08 22:34:44 +01:00
|
|
|
#include "runzip.h"
|
|
|
|
|
#include "util.h"
|
2011-03-12 12:50:40 +01:00
|
|
|
#include "stream.h"
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-03-18 07:32:47 +01:00
|
|
|
#define MAGIC_LEN (24)
|
2011-03-12 09:56:08 +01:00
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
static void release_hashes(rzip_control *control);
|
|
|
|
|
|
2011-03-18 07:32:47 +01:00
|
|
|
static i64 fdout_seekto(rzip_control *control, i64 pos)
|
|
|
|
|
{
|
|
|
|
|
if (TMP_OUTBUF) {
|
|
|
|
|
pos -= control->out_relofs;
|
|
|
|
|
control->out_ofs = pos;
|
|
|
|
|
if (unlikely(pos > control->out_len || pos < 0)) {
|
|
|
|
|
print_err("Trying to seek to %lld outside tmp outbuf in fdout_seekto\n", pos);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return lseek(control->fd_out, pos, SEEK_SET);
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-11 05:57:20 +02:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
# include <sys/sysctl.h>
|
2012-07-07 13:44:00 +02:00
|
|
|
i64 get_ram(rzip_control *control)
|
2011-08-11 05:57:20 +02:00
|
|
|
{
|
|
|
|
|
int mib[2];
|
|
|
|
|
size_t len;
|
|
|
|
|
i64 *p, ramsize;
|
|
|
|
|
|
|
|
|
|
mib[0] = CTL_HW;
|
|
|
|
|
mib[1] = HW_MEMSIZE;
|
|
|
|
|
sysctl(mib, 2, NULL, &len, NULL, 0);
|
|
|
|
|
p = malloc(len);
|
|
|
|
|
sysctl(mib, 2, p, &len, NULL, 0);
|
|
|
|
|
ramsize = *p;
|
|
|
|
|
|
|
|
|
|
return ramsize;
|
|
|
|
|
}
|
|
|
|
|
#else /* __APPLE__ */
|
2012-03-07 02:42:42 +01:00
|
|
|
i64 get_ram(rzip_control *control)
|
2011-08-11 05:57:20 +02:00
|
|
|
{
|
|
|
|
|
i64 ramsize;
|
|
|
|
|
FILE *meminfo;
|
|
|
|
|
char aux[256];
|
|
|
|
|
|
|
|
|
|
ramsize = (i64)sysconf(_SC_PHYS_PAGES) * PAGE_SIZE;
|
|
|
|
|
if (ramsize > 0)
|
|
|
|
|
return ramsize;
|
|
|
|
|
|
|
|
|
|
/* Workaround for uclibc which doesn't properly support sysconf */
|
|
|
|
|
if(!(meminfo = fopen("/proc/meminfo", "r")))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("fopen\n"), -1);
|
2011-08-11 05:57:20 +02:00
|
|
|
|
2015-03-10 10:08:00 +01:00
|
|
|
while(!feof(meminfo) && !fscanf(meminfo, "MemTotal: %"PRId64" kB", &ramsize)) {
|
2011-08-12 08:43:42 +02:00
|
|
|
if (unlikely(fgets(aux, sizeof(aux), meminfo) == NULL)) {
|
|
|
|
|
fclose(meminfo);
|
|
|
|
|
fatal_return(("Failed to fgets in get_ram\n"), -1);
|
|
|
|
|
}
|
2011-08-11 05:57:20 +02:00
|
|
|
}
|
|
|
|
|
if (fclose(meminfo) == -1)
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("fclose"), -1);
|
2011-08-11 05:57:20 +02:00
|
|
|
ramsize *= 1000;
|
|
|
|
|
|
|
|
|
|
return ramsize;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
i64 nloops(i64 seconds, uchar *b1, uchar *b2)
|
|
|
|
|
{
|
|
|
|
|
i64 nloops;
|
|
|
|
|
int nbits;
|
|
|
|
|
|
|
|
|
|
nloops = ARBITRARY_AT_EPOCH * pow(MOORE_TIMES_PER_SECOND, seconds);
|
|
|
|
|
if (nloops < ARBITRARY)
|
|
|
|
|
nloops = ARBITRARY;
|
|
|
|
|
for (nbits = 0; nloops > 255; nbits ++)
|
|
|
|
|
nloops = nloops >> 1;
|
|
|
|
|
*b1 = nbits;
|
|
|
|
|
*b2 = nloops;
|
|
|
|
|
return nloops << nbits;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
bool write_magic(rzip_control *control)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
2011-12-05 15:23:54 +01:00
|
|
|
char magic[MAGIC_LEN] = {
|
|
|
|
|
'L', 'R', 'Z', 'I', LRZIP_MAJOR_VERSION, LRZIP_MINOR_VERSION
|
|
|
|
|
};
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-03-11 13:45:22 +01:00
|
|
|
/* File size is stored as zero for streaming STDOUT blocks when the
|
2011-03-18 07:32:47 +01:00
|
|
|
* file size is unknown. In encrypted files, the size is left unknown
|
|
|
|
|
* and instead the salt is stored here to preserve space. */
|
|
|
|
|
if (ENCRYPT)
|
|
|
|
|
memcpy(&magic[6], &control->salt, 8);
|
2011-03-20 06:16:38 +01:00
|
|
|
else if (!STDIN || !STDOUT || control->eof) {
|
2011-03-20 12:31:38 +01:00
|
|
|
i64 esize = htole64(control->st_size);
|
|
|
|
|
|
|
|
|
|
memcpy(&magic[6], &esize, 8);
|
2011-03-20 06:16:38 +01:00
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
/* save LZMA compression flags */
|
|
|
|
|
if (LZMA_COMPRESS) {
|
2011-03-12 04:13:28 +01:00
|
|
|
int i;
|
|
|
|
|
|
2011-03-08 22:32:14 +01:00
|
|
|
for (i = 0; i < 5; i++)
|
2011-03-22 10:49:51 +01:00
|
|
|
magic[i + 16] = (char)control->lzma_properties[i];
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is a flag that the archive contains an md5 sum at the end
|
|
|
|
|
* which can be used as an integrity check instead of crc check.
|
|
|
|
|
* crc is still stored for compatibility with 0.5 versions.
|
|
|
|
|
*/
|
2011-04-13 06:50:26 +02:00
|
|
|
if (!NO_MD5)
|
|
|
|
|
magic[21] = 1;
|
2011-03-15 05:04:58 +01:00
|
|
|
if (ENCRYPT)
|
2011-03-11 13:29:56 +01:00
|
|
|
magic[22] = 1;
|
|
|
|
|
|
2011-03-17 06:59:27 +01:00
|
|
|
if (unlikely(fdout_seekto(control, 0)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to seek to BOF to write Magic Header\n"), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-03-17 06:59:27 +01:00
|
|
|
if (unlikely(put_fdout(control, magic, MAGIC_LEN) != MAGIC_LEN))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to write magic header\n"), false);
|
2011-03-12 12:46:57 +01:00
|
|
|
control->magic_written = 1;
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-18 07:32:47 +01:00
|
|
|
}
|
2011-03-12 09:56:08 +01:00
|
|
|
|
2011-03-19 03:53:43 +01:00
|
|
|
static inline i64 enc_loops(uchar b1, uchar b2)
|
2011-03-18 07:32:47 +01:00
|
|
|
{
|
|
|
|
|
return (i64)b2 << (i64)b1;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
static bool get_magic(rzip_control *control, char *magic)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
2011-03-18 07:32:47 +01:00
|
|
|
int encrypted, md5, i;
|
2011-03-14 08:16:14 +01:00
|
|
|
i64 expected_size;
|
2011-03-08 22:32:14 +01:00
|
|
|
uint32_t v;
|
|
|
|
|
|
|
|
|
|
if (unlikely(strncmp(magic, "LRZI", 4)))
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("Not an lrzip file\n"), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
memcpy(&control->major_version, &magic[4], 1);
|
|
|
|
|
memcpy(&control->minor_version, &magic[5], 1);
|
|
|
|
|
|
2011-03-14 08:16:14 +01:00
|
|
|
print_verbose("Detected lrzip version %d.%d file.\n", control->major_version, control->minor_version);
|
|
|
|
|
if (control->major_version > LRZIP_MAJOR_VERSION ||
|
|
|
|
|
(control->major_version == LRZIP_MAJOR_VERSION && control->minor_version > LRZIP_MINOR_VERSION))
|
|
|
|
|
print_output("Attempting to work with file produced by newer lrzip version %d.%d file.\n", control->major_version, control->minor_version);
|
|
|
|
|
|
2011-03-08 22:32:14 +01:00
|
|
|
/* Support the convoluted way we described size in versions < 0.40 */
|
|
|
|
|
if (control->major_version == 0 && control->minor_version < 4) {
|
|
|
|
|
memcpy(&v, &magic[6], 4);
|
2011-03-14 08:16:14 +01:00
|
|
|
expected_size = ntohl(v);
|
2011-03-08 22:32:14 +01:00
|
|
|
memcpy(&v, &magic[10], 4);
|
2011-03-14 08:16:14 +01:00
|
|
|
expected_size |= ((i64)ntohl(v)) << 32;
|
2011-03-20 06:16:38 +01:00
|
|
|
} else {
|
2011-03-14 08:16:14 +01:00
|
|
|
memcpy(&expected_size, &magic[6], 8);
|
2011-03-20 06:16:38 +01:00
|
|
|
expected_size = le64toh(expected_size);
|
|
|
|
|
}
|
2011-03-14 08:16:14 +01:00
|
|
|
control->st_size = expected_size;
|
2011-05-07 15:36:55 +02:00
|
|
|
if (control->major_version == 0 && control->minor_version < 6)
|
|
|
|
|
control->eof = 1;
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
/* restore LZMA compression flags only if stored */
|
2011-03-22 10:49:51 +01:00
|
|
|
if ((int) magic[16]) {
|
2011-03-08 22:32:14 +01:00
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
|
control->lzma_properties[i] = magic[i + 16];
|
2021-02-15 15:20:29 +01:00
|
|
|
/* Cludge to allow us to read possibly corrupted archives */
|
|
|
|
|
if (!control->lzma_properties[0])
|
|
|
|
|
control->lzma_properties[0] = 93;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Whether this archive contains md5 data at the end or not */
|
|
|
|
|
md5 = magic[21];
|
2022-02-25 13:07:47 +01:00
|
|
|
if (md5) {
|
2011-03-18 07:32:47 +01:00
|
|
|
if (md5 == 1)
|
|
|
|
|
control->flags |= FLAG_MD5;
|
|
|
|
|
else
|
|
|
|
|
print_verbose("Unknown hash, falling back to CRC\n");
|
2011-03-15 11:18:29 +01:00
|
|
|
}
|
2011-03-18 07:32:47 +01:00
|
|
|
encrypted = magic[22];
|
|
|
|
|
if (encrypted) {
|
|
|
|
|
if (encrypted == 1)
|
|
|
|
|
control->flags |= FLAG_ENCRYPT;
|
|
|
|
|
else
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("Unknown encryption\n"), false);
|
2011-03-18 07:32:47 +01:00
|
|
|
/* In encrypted files, the size field is used to store the salt
|
|
|
|
|
* instead and the size is unknown, just like a STDOUT chunked
|
|
|
|
|
* file */
|
|
|
|
|
memcpy(&control->salt, &magic[6], 8);
|
|
|
|
|
control->st_size = expected_size = 0;
|
|
|
|
|
control->encloops = enc_loops(control->salt[0], control->salt[1]);
|
2011-03-15 05:04:58 +01:00
|
|
|
print_maxverbose("Encryption hash loops %lld\n", control->encloops);
|
2011-03-18 07:32:47 +01:00
|
|
|
} else if (ENCRYPT) {
|
|
|
|
|
print_output("Asked to decrypt a non-encrypted archive. Bypassing decryption.\n");
|
|
|
|
|
control->flags &= ~FLAG_ENCRYPT;
|
|
|
|
|
}
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-14 08:16:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
bool read_magic(rzip_control *control, int fd_in, i64 *expected_size)
|
2011-03-14 08:16:14 +01:00
|
|
|
{
|
|
|
|
|
char magic[MAGIC_LEN];
|
|
|
|
|
|
|
|
|
|
memset(magic, 0, sizeof(magic));
|
|
|
|
|
/* Initially read only <v0.6x header */
|
|
|
|
|
if (unlikely(read(fd_in, magic, 24) != 24))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to read magic header\n"), false);
|
2011-03-14 08:16:14 +01:00
|
|
|
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!get_magic(control, magic)))
|
|
|
|
|
return false;
|
2011-03-14 08:16:14 +01:00
|
|
|
*expected_size = control->st_size;
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* preserve ownership and permissions where possible */
|
2012-03-07 14:15:58 +01:00
|
|
|
static bool preserve_perms(rzip_control *control, int fd_in, int fd_out)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
|
|
if (unlikely(fstat(fd_in, &st)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to fstat input file\n"), false);
|
2011-05-07 17:28:34 +02:00
|
|
|
if (unlikely(fchmod(fd_out, (st.st_mode & 0666))))
|
2011-09-16 13:14:21 +02:00
|
|
|
print_verbose("Warning, unable to set permissions on %s\n", control->outfile);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
/* chown fail is not fatal_return(( */
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(fchown(fd_out, st.st_uid, st.st_gid)))
|
2011-09-16 13:14:21 +02:00
|
|
|
print_verbose("Warning, unable to set owner on %s\n", control->outfile);
|
2011-09-16 15:06:17 +02:00
|
|
|
return true;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2012-03-07 14:15:58 +01:00
|
|
|
static bool preserve_times(rzip_control *control, int fd_in)
|
|
|
|
|
{
|
|
|
|
|
struct utimbuf times;
|
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
|
|
if (unlikely(fstat(fd_in, &st)))
|
|
|
|
|
fatal_return(("Failed to fstat input file\n"), false);
|
|
|
|
|
times.actime = 0;
|
|
|
|
|
times.modtime = st.st_mtime;
|
|
|
|
|
if (unlikely(utime(control->outfile, ×)))
|
|
|
|
|
print_verbose("Warning, unable to set time on %s\n", control->outfile);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-08 22:32:14 +01:00
|
|
|
/* Open a temporary outputfile to emulate stdout */
|
|
|
|
|
int open_tmpoutfile(rzip_control *control)
|
|
|
|
|
{
|
|
|
|
|
int fd_out;
|
|
|
|
|
|
2011-03-08 22:36:55 +01:00
|
|
|
if (STDOUT && !TEST_ONLY)
|
2011-03-08 22:32:14 +01:00
|
|
|
print_verbose("Outputting to stdout.\n");
|
|
|
|
|
if (control->tmpdir) {
|
2011-03-08 22:36:55 +01:00
|
|
|
control->outfile = realloc(NULL, strlen(control->tmpdir) + 16);
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(!control->outfile))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to allocate outfile name\n"), -1);
|
2011-03-08 22:32:14 +01:00
|
|
|
strcpy(control->outfile, control->tmpdir);
|
|
|
|
|
strcat(control->outfile, "lrzipout.XXXXXX");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fd_out = mkstemp(control->outfile);
|
2015-03-10 02:05:55 +01:00
|
|
|
if (fd_out == -1) {
|
2022-02-27 08:35:10 +01:00
|
|
|
print_output("WARNING: Failed to create out tmpfile: %s, will fail if cannot perform %scompression entirely in ram\n",
|
2015-04-16 08:38:20 +02:00
|
|
|
control->outfile, DECOMPRESS ? "de" : "");
|
2015-03-10 02:05:55 +01:00
|
|
|
} else
|
|
|
|
|
register_outfile(control, control->outfile, TEST_ONLY || STDOUT || !KEEP_BROKEN);
|
2022-02-26 05:14:52 +01:00
|
|
|
print_maxverbose("Created temporary outfile %s\n", control->outfile);
|
2011-03-08 22:32:14 +01:00
|
|
|
return fd_out;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
static bool fwrite_stdout(rzip_control *control, void *buf, i64 len)
|
2011-03-12 12:46:57 +01:00
|
|
|
{
|
|
|
|
|
uchar *offset_buf = buf;
|
|
|
|
|
ssize_t ret;
|
|
|
|
|
i64 total;
|
|
|
|
|
|
|
|
|
|
total = 0;
|
|
|
|
|
while (len > 0) {
|
2020-11-11 13:19:29 +01:00
|
|
|
ssize_t wrote;
|
|
|
|
|
|
2022-02-26 00:58:52 +01:00
|
|
|
if (BITS32)
|
|
|
|
|
ret = MIN(len, one_g);
|
2011-03-12 12:46:57 +01:00
|
|
|
else
|
|
|
|
|
ret = len;
|
2020-11-11 13:19:29 +01:00
|
|
|
wrote = fwrite(offset_buf, 1, ret, control->outFILE);
|
|
|
|
|
if (unlikely(wrote != ret))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to fwrite in fwrite_stdout\n"), false);
|
2011-03-12 12:46:57 +01:00
|
|
|
len -= ret;
|
|
|
|
|
offset_buf += ret;
|
|
|
|
|
total += ret;
|
|
|
|
|
}
|
2011-08-13 08:21:45 +02:00
|
|
|
fflush(control->outFILE);
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-12 12:46:57 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
bool write_fdout(rzip_control *control, void *buf, i64 len)
|
2011-03-14 02:48:40 +01:00
|
|
|
{
|
|
|
|
|
uchar *offset_buf = buf;
|
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
|
|
while (len > 0) {
|
2022-02-26 00:58:52 +01:00
|
|
|
if (BITS32)
|
|
|
|
|
ret = MIN(len, one_g);
|
|
|
|
|
else
|
|
|
|
|
ret = len;
|
2011-03-14 02:48:40 +01:00
|
|
|
ret = write(control->fd_out, offset_buf, (size_t)ret);
|
|
|
|
|
if (unlikely(ret <= 0))
|
2015-03-10 02:05:55 +01:00
|
|
|
fatal_return(("Failed to write to fd_out in write_fdout\n"), false);
|
2011-03-14 02:48:40 +01:00
|
|
|
len -= ret;
|
|
|
|
|
offset_buf += ret;
|
|
|
|
|
}
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-14 02:48:40 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-26 05:14:52 +01:00
|
|
|
static bool flush_tmpoutbuf(rzip_control *control)
|
2011-03-12 09:56:08 +01:00
|
|
|
{
|
2011-03-14 08:16:14 +01:00
|
|
|
if (!TEST_ONLY) {
|
|
|
|
|
print_maxverbose("Dumping buffer to physical file.\n");
|
2011-08-12 08:43:42 +02:00
|
|
|
if (STDOUT) {
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!fwrite_stdout(control, control->tmp_outbuf, control->out_len)))
|
|
|
|
|
return false;
|
2011-08-12 08:43:42 +02:00
|
|
|
} else {
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!write_fdout(control, control->tmp_outbuf, control->out_len)))
|
|
|
|
|
return false;
|
2011-08-12 08:43:42 +02:00
|
|
|
}
|
2011-03-14 08:16:14 +01:00
|
|
|
}
|
2011-03-14 04:47:26 +01:00
|
|
|
control->out_relofs += control->out_len;
|
2011-03-12 12:46:57 +01:00
|
|
|
control->out_ofs = control->out_len = 0;
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-12 09:56:08 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-08 22:32:14 +01:00
|
|
|
/* Dump temporary outputfile to perform stdout */
|
2022-02-26 05:14:52 +01:00
|
|
|
static bool dump_tmpoutfile(rzip_control *control)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
2022-02-26 05:14:52 +01:00
|
|
|
int tmpchar, fd_out = control->fd_out;
|
2011-03-08 22:32:14 +01:00
|
|
|
FILE *tmpoutfp;
|
|
|
|
|
|
2015-03-10 02:05:55 +01:00
|
|
|
if (unlikely(fd_out == -1))
|
|
|
|
|
fatal_return(("Failed: No temporary outfile created, unable to do in ram\n"), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
/* flush anything not yet in the temporary file */
|
|
|
|
|
fsync(fd_out);
|
|
|
|
|
tmpoutfp = fdopen(fd_out, "r");
|
|
|
|
|
if (unlikely(tmpoutfp == NULL))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to fdopen out tmpfile\n"), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
rewind(tmpoutfp);
|
|
|
|
|
|
2011-03-08 22:36:55 +01:00
|
|
|
if (!TEST_ONLY) {
|
2011-08-13 08:21:45 +02:00
|
|
|
print_verbose("Dumping temporary file to control->outFILE.\n");
|
2011-03-08 22:36:55 +01:00
|
|
|
while ((tmpchar = fgetc(tmpoutfp)) != EOF)
|
|
|
|
|
putchar(tmpchar);
|
2011-08-13 08:21:45 +02:00
|
|
|
fflush(control->outFILE);
|
2011-03-08 22:36:55 +01:00
|
|
|
rewind(tmpoutfp);
|
|
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-03-08 22:36:55 +01:00
|
|
|
if (unlikely(ftruncate(fd_out, 0)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to ftruncate fd_out in dump_tmpoutfile\n"), false);
|
|
|
|
|
return true;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-26 05:14:52 +01:00
|
|
|
bool flush_tmpout(rzip_control *control)
|
|
|
|
|
{
|
|
|
|
|
if (!STDOUT)
|
|
|
|
|
return true;
|
|
|
|
|
if (TMP_OUTBUF)
|
|
|
|
|
return flush_tmpoutbuf(control);
|
|
|
|
|
return dump_tmpoutfile(control);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-14 10:22:45 +01:00
|
|
|
/* Used if we're unable to read STDIN into the temporary buffer, shunts data
|
|
|
|
|
* to temporary file */
|
2011-08-12 08:43:42 +02:00
|
|
|
bool write_fdin(rzip_control *control)
|
2011-03-14 10:22:45 +01:00
|
|
|
{
|
|
|
|
|
uchar *offset_buf = control->tmp_inbuf;
|
|
|
|
|
i64 len = control->in_len;
|
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
|
|
while (len > 0) {
|
2022-02-26 00:58:52 +01:00
|
|
|
if (BITS32)
|
|
|
|
|
ret = MIN(len, one_g);
|
|
|
|
|
else
|
|
|
|
|
ret = len;
|
2011-03-14 10:22:45 +01:00
|
|
|
ret = write(control->fd_in, offset_buf, (size_t)ret);
|
|
|
|
|
if (unlikely(ret <= 0))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to write to fd_in in write_fdin\n"), false);
|
2011-03-14 10:22:45 +01:00
|
|
|
len -= ret;
|
|
|
|
|
offset_buf += ret;
|
|
|
|
|
}
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-14 10:22:45 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-08 22:32:14 +01:00
|
|
|
/* Open a temporary inputfile to perform stdin decompression */
|
|
|
|
|
int open_tmpinfile(rzip_control *control)
|
|
|
|
|
{
|
2015-04-16 08:20:27 +02:00
|
|
|
int fd_in = -1;
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2015-04-16 08:20:27 +02:00
|
|
|
/* Use temporary directory if there is one */
|
2011-03-08 22:32:14 +01:00
|
|
|
if (control->tmpdir) {
|
2011-03-08 22:36:55 +01:00
|
|
|
control->infile = malloc(strlen(control->tmpdir) + 15);
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(!control->infile))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to allocate infile name\n"), -1);
|
2011-03-08 22:32:14 +01:00
|
|
|
strcpy(control->infile, control->tmpdir);
|
|
|
|
|
strcat(control->infile, "lrzipin.XXXXXX");
|
2015-04-16 08:20:27 +02:00
|
|
|
fd_in = mkstemp(control->infile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try the current directory */
|
|
|
|
|
if (fd_in == -1) {
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(control->infile);
|
2015-04-16 08:20:27 +02:00
|
|
|
control->infile = malloc(16);
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(!control->infile))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to allocate infile name\n"), -1);
|
2011-03-08 22:32:14 +01:00
|
|
|
strcpy(control->infile, "lrzipin.XXXXXX");
|
2015-04-16 08:20:27 +02:00
|
|
|
fd_in = mkstemp(control->infile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Use /tmp if nothing is writeable so far */
|
|
|
|
|
if (fd_in == -1) {
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(control->infile);
|
2015-04-16 08:20:27 +02:00
|
|
|
control->infile = malloc(20);
|
|
|
|
|
if (unlikely(!control->infile))
|
|
|
|
|
fatal_return(("Failed to allocate infile name\n"), -1);
|
|
|
|
|
strcpy(control->infile, "/tmp/lrzipin.XXXXXX");
|
|
|
|
|
fd_in = mkstemp(control->infile);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2015-04-16 08:38:20 +02:00
|
|
|
if (fd_in == -1) {
|
2022-02-27 08:35:10 +01:00
|
|
|
print_output("WARNING: Failed to create in tmpfile: %s, will fail if cannot perform %scompression entirely in ram\n",
|
2015-04-16 08:38:20 +02:00
|
|
|
control->infile, DECOMPRESS ? "de" : "");
|
|
|
|
|
} else {
|
|
|
|
|
register_infile(control, control->infile, (DECOMPRESS || TEST_ONLY) && STDIN);
|
|
|
|
|
/* Unlink temporary file immediately to minimise chance of files left
|
|
|
|
|
* lying around in cases of failure_return((. */
|
|
|
|
|
if (unlikely(unlink(control->infile))) {
|
|
|
|
|
fatal("Failed to unlink tmpfile: %s\n", control->infile);
|
|
|
|
|
close(fd_in);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-08-12 08:43:42 +02:00
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
return fd_in;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
static bool read_tmpinmagic(rzip_control *control)
|
2011-03-14 08:16:14 +01:00
|
|
|
{
|
|
|
|
|
char magic[MAGIC_LEN];
|
2011-03-18 00:37:09 +01:00
|
|
|
int i, tmpchar;
|
2011-03-14 08:16:14 +01:00
|
|
|
|
|
|
|
|
memset(magic, 0, sizeof(magic));
|
|
|
|
|
for (i = 0; i < 24; i++) {
|
|
|
|
|
tmpchar = getchar();
|
|
|
|
|
if (unlikely(tmpchar == EOF))
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("Reached end of file on STDIN prematurely on v05 magic read\n"), false);
|
2011-03-14 08:16:14 +01:00
|
|
|
magic[i] = (char)tmpchar;
|
|
|
|
|
}
|
2011-08-12 08:43:42 +02:00
|
|
|
return get_magic(control, magic);
|
2011-03-14 08:16:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-08 22:32:14 +01:00
|
|
|
/* Read data from stdin into temporary inputfile */
|
2011-08-12 08:43:42 +02:00
|
|
|
bool read_tmpinfile(rzip_control *control, int fd_in)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
|
|
|
|
FILE *tmpinfp;
|
|
|
|
|
int tmpchar;
|
|
|
|
|
|
2015-04-16 08:38:20 +02:00
|
|
|
if (fd_in == -1)
|
|
|
|
|
return false;
|
2011-03-08 22:32:14 +01:00
|
|
|
if (control->flags & FLAG_SHOW_PROGRESS)
|
|
|
|
|
fprintf(control->msgout, "Copying from stdin.\n");
|
|
|
|
|
tmpinfp = fdopen(fd_in, "w+");
|
|
|
|
|
if (unlikely(tmpinfp == NULL))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to fdopen in tmpfile\n"), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
while ((tmpchar = getchar()) != EOF)
|
|
|
|
|
fputc(tmpchar, tmpinfp);
|
|
|
|
|
|
|
|
|
|
fflush(tmpinfp);
|
|
|
|
|
rewind(tmpinfp);
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-14 00:07:51 +01:00
|
|
|
/* To perform STDOUT, we allocate a proportion of ram that is then used as
|
|
|
|
|
* a pseudo-temporary file */
|
2011-08-12 08:43:42 +02:00
|
|
|
static bool open_tmpoutbuf(rzip_control *control)
|
2011-03-14 00:07:51 +01:00
|
|
|
{
|
2016-06-09 02:51:55 +02:00
|
|
|
i64 maxlen = control->maxram;
|
|
|
|
|
void *buf;
|
|
|
|
|
|
|
|
|
|
while (42) {
|
|
|
|
|
round_to_page(&maxlen);
|
|
|
|
|
buf = malloc(maxlen);
|
|
|
|
|
if (buf) {
|
|
|
|
|
print_maxverbose("Malloced %"PRId64" for tmp_outbuf\n", maxlen);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
maxlen = maxlen / 3 * 2;
|
|
|
|
|
if (maxlen < 100000000)
|
|
|
|
|
fatal_return(("Unable to even malloc 100MB for tmp_outbuf\n"), false);
|
|
|
|
|
}
|
2011-03-14 00:07:51 +01:00
|
|
|
control->flags |= FLAG_TMP_OUTBUF;
|
2011-03-14 01:37:56 +01:00
|
|
|
/* Allocate slightly more so we can cope when the buffer overflows and
|
|
|
|
|
* fall back to a real temporary file */
|
2016-06-09 02:51:55 +02:00
|
|
|
control->out_maxlen = maxlen - control->page_size;
|
|
|
|
|
control->tmp_outbuf = buf;
|
2011-03-14 00:07:51 +01:00
|
|
|
if (!DECOMPRESS && !TEST_ONLY)
|
2011-08-12 08:43:42 +02:00
|
|
|
control->out_ofs = control->out_len = MAGIC_LEN;\
|
|
|
|
|
return true;
|
2011-03-14 00:07:51 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-03 04:15:09 +01:00
|
|
|
/* We've decided to use a temporary output file instead of trying to store
|
|
|
|
|
* all the output buffer in ram so we can free up the ram and increase the
|
|
|
|
|
* maximum sizes of ram we can allocate */
|
2011-03-14 02:48:40 +01:00
|
|
|
void close_tmpoutbuf(rzip_control *control)
|
|
|
|
|
{
|
|
|
|
|
control->flags &= ~FLAG_TMP_OUTBUF;
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(control->tmp_outbuf);
|
2015-03-03 04:15:09 +01:00
|
|
|
if (!BITS32)
|
|
|
|
|
control->usable_ram = control->maxram += control->ramsize / 18;
|
2011-03-14 02:48:40 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
static bool open_tmpinbuf(rzip_control *control)
|
2011-03-14 04:47:26 +01:00
|
|
|
{
|
|
|
|
|
control->flags |= FLAG_TMP_INBUF;
|
|
|
|
|
control->in_maxlen = control->maxram;
|
|
|
|
|
control->tmp_inbuf = malloc(control->maxram + control->page_size);
|
|
|
|
|
if (unlikely(!control->tmp_inbuf))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to malloc tmp_inbuf in open_tmpinbuf\n"), false);
|
|
|
|
|
return true;
|
2011-03-14 04:47:26 +01:00
|
|
|
}
|
|
|
|
|
|
2012-03-07 02:42:42 +01:00
|
|
|
void clear_tmpinbuf(rzip_control *control)
|
2011-03-14 12:03:13 +01:00
|
|
|
{
|
|
|
|
|
control->in_len = control->in_ofs = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
bool clear_tmpinfile(rzip_control *control)
|
2011-03-15 01:27:07 +01:00
|
|
|
{
|
|
|
|
|
if (unlikely(lseek(control->fd_in, 0, SEEK_SET)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to lseek on fd_in in clear_tmpinfile\n"), false);
|
2011-03-15 01:27:07 +01:00
|
|
|
if (unlikely(ftruncate(control->fd_in, 0)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to truncate fd_in in clear_tmpinfile\n"), false);
|
|
|
|
|
return true;
|
2011-03-15 01:27:07 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-03 04:15:09 +01:00
|
|
|
/* As per temporary output file but for input file */
|
2011-03-14 04:47:26 +01:00
|
|
|
void close_tmpinbuf(rzip_control *control)
|
|
|
|
|
{
|
|
|
|
|
control->flags &= ~FLAG_TMP_INBUF;
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(control->tmp_inbuf);
|
2015-03-03 04:15:09 +01:00
|
|
|
if (!BITS32)
|
|
|
|
|
control->usable_ram = control->maxram += control->ramsize / 18;
|
2011-03-14 04:47:26 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-11 09:06:32 +02:00
|
|
|
static int get_pass(rzip_control *control, char *s)
|
2011-03-16 21:03:40 +01:00
|
|
|
{
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
memset(s, 0, PASS_LEN - SALT_LEN);
|
2017-07-07 19:24:39 +02:00
|
|
|
if (control->passphrase)
|
|
|
|
|
strncpy(s, control->passphrase, PASS_LEN - SALT_LEN - 1);
|
|
|
|
|
else if (unlikely(fgets(s, PASS_LEN - SALT_LEN, stdin) == NULL))
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("Failed to retrieve passphrase\n"), -1);
|
2011-03-16 21:03:40 +01:00
|
|
|
len = strlen(s);
|
|
|
|
|
if (len > 0 && ('\r' == s[len - 1] || '\n' == s[len - 1]))
|
|
|
|
|
s[len - 1] = '\0';
|
|
|
|
|
if (len > 1 && ('\r' == s[len - 2] || '\n' == s[len - 2]))
|
|
|
|
|
s[len - 2] = '\0';
|
|
|
|
|
len = strlen(s);
|
|
|
|
|
if (unlikely(0 == len))
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("Empty passphrase\n"), -1);
|
2011-03-21 10:54:53 +01:00
|
|
|
return len;
|
2011-03-16 21:03:40 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
static bool get_hash(rzip_control *control, int make_hash)
|
2011-03-15 11:18:29 +01:00
|
|
|
{
|
|
|
|
|
char *passphrase, *testphrase;
|
|
|
|
|
struct termios termios_p;
|
2017-07-07 19:24:39 +02:00
|
|
|
int prompt = control->passphrase == NULL;
|
2011-03-15 11:18:29 +01:00
|
|
|
|
|
|
|
|
passphrase = calloc(PASS_LEN, 1);
|
|
|
|
|
testphrase = calloc(PASS_LEN, 1);
|
2011-03-21 10:54:53 +01:00
|
|
|
control->salt_pass = calloc(PASS_LEN, 1);
|
2011-03-15 11:18:29 +01:00
|
|
|
control->hash = calloc(HASH_LEN, 1);
|
2011-08-12 08:43:42 +02:00
|
|
|
if (unlikely(!passphrase || !testphrase || !control->salt_pass || !control->hash)) {
|
|
|
|
|
fatal("Failed to calloc encrypt buffers in compress_file\n");
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(testphrase);
|
|
|
|
|
dealloc(passphrase);
|
2011-08-12 08:43:42 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2011-03-15 11:18:29 +01:00
|
|
|
mlock(passphrase, PASS_LEN);
|
|
|
|
|
mlock(testphrase, PASS_LEN);
|
2011-03-21 10:54:53 +01:00
|
|
|
mlock(control->salt_pass, PASS_LEN);
|
2011-03-15 11:18:29 +01:00
|
|
|
mlock(control->hash, HASH_LEN);
|
|
|
|
|
|
2011-08-11 09:41:22 +02:00
|
|
|
if (control->pass_cb) {
|
2011-08-13 08:21:45 +02:00
|
|
|
control->pass_cb(control->pass_data, passphrase, PASS_LEN - SALT_LEN);
|
2011-08-12 08:43:42 +02:00
|
|
|
if (!passphrase[0]) {
|
|
|
|
|
fatal("Supplied password was null!");
|
|
|
|
|
munlock(passphrase, PASS_LEN);
|
|
|
|
|
munlock(testphrase, PASS_LEN);
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(testphrase);
|
|
|
|
|
dealloc(passphrase);
|
2011-08-12 08:43:42 +02:00
|
|
|
release_hashes(control);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-08-13 08:21:45 +02:00
|
|
|
control->salt_pass_len = strlen(passphrase) + SALT_LEN;
|
2011-08-11 09:41:22 +02:00
|
|
|
} else {
|
|
|
|
|
/* Disable stdin echo to screen */
|
|
|
|
|
tcgetattr(fileno(stdin), &termios_p);
|
|
|
|
|
termios_p.c_lflag &= ~ECHO;
|
|
|
|
|
tcsetattr(fileno(stdin), 0, &termios_p);
|
2011-03-15 11:18:29 +01:00
|
|
|
retry_pass:
|
2017-07-07 19:24:39 +02:00
|
|
|
if (prompt)
|
|
|
|
|
print_output("Enter passphrase: ");
|
2011-08-11 09:41:22 +02:00
|
|
|
control->salt_pass_len = get_pass(control, passphrase) + SALT_LEN;
|
2017-07-07 19:24:39 +02:00
|
|
|
if (prompt)
|
|
|
|
|
print_output("\n");
|
2011-08-11 09:41:22 +02:00
|
|
|
if (make_hash) {
|
2017-07-07 19:24:39 +02:00
|
|
|
if (prompt)
|
|
|
|
|
print_output("Re-enter passphrase: ");
|
2011-08-11 09:41:22 +02:00
|
|
|
get_pass(control, testphrase);
|
2017-07-07 19:24:39 +02:00
|
|
|
if (prompt)
|
|
|
|
|
print_output("\n");
|
2011-08-11 09:41:22 +02:00
|
|
|
if (strcmp(passphrase, testphrase)) {
|
|
|
|
|
print_output("Passwords do not match. Try again.\n");
|
|
|
|
|
goto retry_pass;
|
|
|
|
|
}
|
2011-03-15 11:18:29 +01:00
|
|
|
}
|
2011-08-11 09:41:22 +02:00
|
|
|
termios_p.c_lflag |= ECHO;
|
|
|
|
|
tcsetattr(fileno(stdin), 0, &termios_p);
|
|
|
|
|
memset(testphrase, 0, PASS_LEN);
|
2011-03-15 11:18:29 +01:00
|
|
|
}
|
2011-03-21 10:54:53 +01:00
|
|
|
memcpy(control->salt_pass, control->salt, SALT_LEN);
|
|
|
|
|
memcpy(control->salt_pass + SALT_LEN, passphrase, PASS_LEN - SALT_LEN);
|
|
|
|
|
lrz_stretch(control);
|
2011-03-16 02:38:10 +01:00
|
|
|
memset(passphrase, 0, PASS_LEN);
|
2011-03-15 11:18:29 +01:00
|
|
|
munlock(passphrase, PASS_LEN);
|
2011-08-11 09:41:22 +02:00
|
|
|
munlock(testphrase, PASS_LEN);
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(testphrase);
|
|
|
|
|
dealloc(passphrase);
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-15 11:18:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-17 06:00:57 +01:00
|
|
|
static void release_hashes(rzip_control *control)
|
|
|
|
|
{
|
2011-03-21 10:54:53 +01:00
|
|
|
memset(control->salt_pass, 0, PASS_LEN);
|
2011-03-17 06:00:57 +01:00
|
|
|
memset(control->hash, 0, SALT_LEN);
|
2011-04-11 13:51:53 +02:00
|
|
|
munlock(control->salt_pass, PASS_LEN);
|
|
|
|
|
munlock(control->hash, HASH_LEN);
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(control->salt_pass);
|
|
|
|
|
dealloc(control->hash);
|
2011-03-17 06:00:57 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-27 08:13:42 +01:00
|
|
|
static void clear_rulist(rzip_control *control)
|
|
|
|
|
{
|
|
|
|
|
while (control->ruhead) {
|
|
|
|
|
struct runzip_node *node = control->ruhead;
|
|
|
|
|
struct stream_info *sinfo = node->sinfo;
|
|
|
|
|
|
|
|
|
|
dealloc(sinfo->ucthreads);
|
|
|
|
|
dealloc(node->pthreads);
|
|
|
|
|
dealloc(sinfo->s);
|
|
|
|
|
dealloc(sinfo);
|
|
|
|
|
control->ruhead = node->prev;
|
|
|
|
|
dealloc(node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-08 22:32:14 +01:00
|
|
|
/*
|
|
|
|
|
decompress one file from the command line
|
|
|
|
|
*/
|
2011-08-12 08:43:42 +02:00
|
|
|
bool decompress_file(rzip_control *control)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
|
|
|
|
char *tmp, *tmpoutfile, *infilecopy = NULL;
|
|
|
|
|
int fd_in, fd_out = -1, fd_hist = -1;
|
2011-05-07 16:05:46 +02:00
|
|
|
i64 expected_size = 0, free_space;
|
2011-03-08 22:32:14 +01:00
|
|
|
struct statvfs fbuf;
|
|
|
|
|
|
2017-06-04 07:28:18 +02:00
|
|
|
if (!STDIN && !IS_FROM_FILE) {
|
2011-03-22 15:51:40 +01:00
|
|
|
struct stat fdin_stat;
|
2020-06-01 05:16:39 +02:00
|
|
|
|
|
|
|
|
stat(control->infile, &fdin_stat);
|
|
|
|
|
if (!S_ISREG(fdin_stat.st_mode) && (tmp = strrchr(control->infile, '.')) &&
|
|
|
|
|
strcmp(tmp,control->suffix)) {
|
|
|
|
|
/* make sure infile has an extension. If not, add it
|
|
|
|
|
* because manipulations may be made to input filename, set local ptr
|
|
|
|
|
*/
|
2011-08-12 08:43:42 +02:00
|
|
|
infilecopy = alloca(strlen(control->infile) + strlen(control->suffix) + 1);
|
|
|
|
|
strcpy(infilecopy, control->infile);
|
|
|
|
|
strcat(infilecopy, control->suffix);
|
2011-03-08 22:32:14 +01:00
|
|
|
} else
|
2011-08-12 08:43:42 +02:00
|
|
|
infilecopy = strdupa(control->infile);
|
2011-03-08 22:32:14 +01:00
|
|
|
/* regardless, infilecopy has the input filename */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!STDOUT && !TEST_ONLY) {
|
|
|
|
|
/* if output name already set, use it */
|
2020-06-01 05:16:39 +02:00
|
|
|
if (control->outname) {
|
2011-03-08 22:32:14 +01:00
|
|
|
control->outfile = strdup(control->outname);
|
2020-06-01 05:16:39 +02:00
|
|
|
} else {
|
2011-03-08 22:32:14 +01:00
|
|
|
/* default output name from infilecopy
|
|
|
|
|
* test if outdir specified. If so, strip path from filename of
|
|
|
|
|
* infilecopy, then remove suffix.
|
|
|
|
|
*/
|
|
|
|
|
if (control->outdir && (tmp = strrchr(infilecopy, '/')))
|
2011-08-12 08:43:42 +02:00
|
|
|
tmpoutfile = strdupa(tmp + 1);
|
2011-03-08 22:32:14 +01:00
|
|
|
else
|
2011-08-12 08:43:42 +02:00
|
|
|
tmpoutfile = strdupa(infilecopy);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
/* remove suffix to make outfile name */
|
|
|
|
|
if ((tmp = strrchr(tmpoutfile, '.')) && !strcmp(tmp, control->suffix))
|
|
|
|
|
*tmp='\0';
|
|
|
|
|
|
|
|
|
|
control->outfile = malloc((control->outdir == NULL? 0: strlen(control->outdir)) + strlen(tmpoutfile) + 1);
|
|
|
|
|
if (unlikely(!control->outfile))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to allocate outfile name\n"), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
if (control->outdir) { /* prepend control->outdir */
|
|
|
|
|
strcpy(control->outfile, control->outdir);
|
|
|
|
|
strcat(control->outfile, tmpoutfile);
|
|
|
|
|
} else
|
|
|
|
|
strcpy(control->outfile, tmpoutfile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!STDOUT)
|
2022-02-27 08:35:10 +01:00
|
|
|
print_output("Output filename is: %s\n", control->outfile);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2017-06-04 07:28:18 +02:00
|
|
|
if ( IS_FROM_FILE ) {
|
|
|
|
|
fd_in = fileno(control->inFILE);
|
|
|
|
|
}
|
|
|
|
|
else if (STDIN) {
|
2011-03-08 22:32:14 +01:00
|
|
|
fd_in = open_tmpinfile(control);
|
2011-03-14 08:16:14 +01:00
|
|
|
read_tmpinmagic(control);
|
2011-03-17 03:08:36 +01:00
|
|
|
if (ENCRYPT)
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("Cannot decompress encrypted file from STDIN\n"), false);
|
2011-03-14 08:16:14 +01:00
|
|
|
expected_size = control->st_size;
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!open_tmpinbuf(control)))
|
|
|
|
|
return false;
|
2011-03-08 22:32:14 +01:00
|
|
|
} else {
|
|
|
|
|
fd_in = open(infilecopy, O_RDONLY);
|
|
|
|
|
if (unlikely(fd_in == -1)) {
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to open %s\n", infilecopy), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
2011-03-14 04:58:41 +01:00
|
|
|
control->fd_in = fd_in;
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
if (!(TEST_ONLY | STDOUT)) {
|
2011-05-07 17:28:34 +02:00
|
|
|
fd_out = open(control->outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
2011-03-22 14:42:58 +01:00
|
|
|
if (FORCE_REPLACE && (-1 == fd_out) && (EEXIST == errno)) {
|
|
|
|
|
if (unlikely(unlink(control->outfile)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to unlink an existing file: %s\n", control->outfile), false);
|
2011-05-07 17:28:34 +02:00
|
|
|
fd_out = open(control->outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
2011-03-22 14:42:58 +01:00
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(fd_out == -1)) {
|
|
|
|
|
/* We must ensure we don't delete a file that already
|
|
|
|
|
* exists just because we tried to create a new one */
|
|
|
|
|
control->flags |= FLAG_KEEP_BROKEN;
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to create %s\n", control->outfile), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
2011-03-14 00:19:53 +01:00
|
|
|
fd_hist = open(control->outfile, O_RDONLY);
|
|
|
|
|
if (unlikely(fd_hist == -1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to open history file %s\n", control->outfile), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-04-10 03:03:45 +02:00
|
|
|
/* Can't copy permissions from STDIN */
|
|
|
|
|
if (!STDIN)
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!preserve_perms(control, fd_in, fd_out)))
|
|
|
|
|
return false;
|
2011-03-14 00:07:51 +01:00
|
|
|
} else {
|
2011-03-08 22:32:14 +01:00
|
|
|
fd_out = open_tmpoutfile(control);
|
2015-03-10 02:05:55 +01:00
|
|
|
if (fd_out == -1) {
|
|
|
|
|
fd_hist = -1;
|
|
|
|
|
} else {
|
|
|
|
|
fd_hist = open(control->outfile, O_RDONLY);
|
|
|
|
|
if (unlikely(fd_hist == -1))
|
|
|
|
|
fatal_return(("Failed to open history file %s\n", control->outfile), false);
|
|
|
|
|
/* Unlink temporary file as soon as possible */
|
|
|
|
|
if (unlikely(unlink(control->outfile)))
|
|
|
|
|
fatal_return(("Failed to unlink tmpfile: %s\n", control->outfile), false);
|
|
|
|
|
}
|
2011-03-14 00:07:51 +01:00
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2018-03-09 07:29:01 +01:00
|
|
|
if (STDOUT) {
|
|
|
|
|
if (unlikely(!open_tmpoutbuf(control)))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-03-14 02:48:40 +01:00
|
|
|
|
2016-06-09 10:18:14 +02:00
|
|
|
if (!STDIN) {
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!read_magic(control, fd_in, &expected_size)))
|
|
|
|
|
return false;
|
2018-05-25 05:12:54 +02:00
|
|
|
if (unlikely(expected_size < 0))
|
|
|
|
|
fatal_return(("Invalid expected size %lld\n", expected_size), false);
|
2016-06-09 10:18:14 +02:00
|
|
|
}
|
2011-03-13 08:12:05 +01:00
|
|
|
|
2015-03-10 02:05:55 +01:00
|
|
|
if (!STDOUT && !TEST_ONLY) {
|
2011-03-13 08:12:05 +01:00
|
|
|
/* Check if there's enough free space on the device chosen to fit the
|
|
|
|
|
* decompressed file. */
|
|
|
|
|
if (unlikely(fstatvfs(fd_out, &fbuf)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to fstatvfs in decompress_file\n"), false);
|
2011-03-14 00:21:10 +01:00
|
|
|
free_space = (i64)fbuf.f_bsize * (i64)fbuf.f_bavail;
|
2011-03-13 08:12:05 +01:00
|
|
|
if (free_space < expected_size) {
|
|
|
|
|
if (FORCE_REPLACE)
|
|
|
|
|
print_err("Warning, inadequate free space detected, but attempting to decompress due to -f option being used.\n");
|
|
|
|
|
else
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("Inadequate free space to decompress file, use -f to override.\n"), false);
|
2011-03-13 08:12:05 +01:00
|
|
|
}
|
|
|
|
|
}
|
2011-03-14 00:07:51 +01:00
|
|
|
control->fd_out = fd_out;
|
|
|
|
|
control->fd_hist = fd_hist;
|
2011-03-08 22:36:55 +01:00
|
|
|
|
2011-03-08 22:32:14 +01:00
|
|
|
if (NO_MD5)
|
|
|
|
|
print_verbose("Not performing MD5 hash check\n");
|
|
|
|
|
if (HAS_MD5)
|
|
|
|
|
print_verbose("MD5 ");
|
|
|
|
|
else
|
|
|
|
|
print_verbose("CRC32 ");
|
|
|
|
|
print_verbose("being used for integrity testing.\n");
|
|
|
|
|
|
2011-03-17 14:06:11 +01:00
|
|
|
if (ENCRYPT)
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!get_hash(control, 0)))
|
|
|
|
|
return false;
|
2011-03-15 11:18:29 +01:00
|
|
|
|
2022-02-27 08:35:10 +01:00
|
|
|
print_output("Decompressing...\n");
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2022-02-27 07:27:45 +01:00
|
|
|
if (unlikely(runzip_fd(control, fd_in, fd_hist, expected_size) < 0)) {
|
2022-02-26 00:11:49 +01:00
|
|
|
clear_rulist(control);
|
2012-03-07 12:04:24 +01:00
|
|
|
return false;
|
2022-02-26 00:11:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We can now safely delete sinfo and pthread data of all threads
|
|
|
|
|
* created. */
|
|
|
|
|
clear_rulist(control);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
/* if we get here, no fatal_return(( errors during decompression */
|
2011-03-08 22:32:14 +01:00
|
|
|
print_progress("\r");
|
|
|
|
|
if (!(STDOUT | TEST_ONLY))
|
2022-02-27 08:35:10 +01:00
|
|
|
print_output("Output filename is: %s: ", control->outfile);
|
2011-03-14 03:32:36 +01:00
|
|
|
if (!expected_size)
|
|
|
|
|
expected_size = control->st_size;
|
2011-03-20 07:01:33 +01:00
|
|
|
if (!ENCRYPT)
|
2022-02-27 08:35:10 +01:00
|
|
|
print_output("[OK] - %lld bytes \n", expected_size);
|
2011-03-20 07:01:33 +01:00
|
|
|
else
|
2022-02-27 08:35:10 +01:00
|
|
|
print_output("[OK] \n");
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2017-06-04 07:29:17 +02:00
|
|
|
if (TMP_OUTBUF)
|
|
|
|
|
close_tmpoutbuf(control);
|
|
|
|
|
|
2015-03-10 02:05:55 +01:00
|
|
|
if (fd_out > 0) {
|
|
|
|
|
if (unlikely(close(fd_hist) || close(fd_out)))
|
|
|
|
|
fatal_return(("Failed to close files\n"), false);
|
|
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2012-03-07 14:15:58 +01:00
|
|
|
if (unlikely(!STDIN && !STDOUT && !TEST_ONLY && !preserve_times(control, fd_in)))
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-06-04 07:28:18 +02:00
|
|
|
if ( ! IS_FROM_FILE ) {
|
|
|
|
|
close(fd_in);
|
|
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2015-04-16 07:31:23 +02:00
|
|
|
if (!KEEP_FILES && !STDIN) {
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(unlink(control->infile)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to unlink %s\n", infilecopy), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-17 06:00:57 +01:00
|
|
|
if (ENCRYPT)
|
|
|
|
|
release_hashes(control);
|
2011-03-15 11:18:29 +01:00
|
|
|
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(control->outfile);
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
bool get_header_info(rzip_control *control, int fd_in, uchar *ctype, i64 *c_len,
|
2011-03-18 13:18:36 +01:00
|
|
|
i64 *u_len, i64 *last_head, int chunk_bytes)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
|
|
|
|
if (unlikely(read(fd_in, ctype, 1) != 1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to read in get_header_info\n"), false);
|
2011-03-08 22:36:55 +01:00
|
|
|
|
2011-03-18 13:18:36 +01:00
|
|
|
*c_len = *u_len = *last_head = 0;
|
2011-03-08 22:32:14 +01:00
|
|
|
if (control->major_version == 0 && control->minor_version < 4) {
|
|
|
|
|
u32 c_len32, u_len32, last_head32;
|
|
|
|
|
|
|
|
|
|
if (unlikely(read(fd_in, &c_len32, 4) != 4))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to read in get_header_info"), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(read(fd_in, &u_len32, 4) != 4))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to read in get_header_info"), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(read(fd_in, &last_head32, 4) != 4))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to read in get_header_info"), false);
|
2011-03-21 11:35:25 +01:00
|
|
|
c_len32 = le32toh(c_len32);
|
|
|
|
|
u_len32 = le32toh(u_len32);
|
|
|
|
|
last_head32 = le32toh(last_head32);
|
2011-03-08 22:32:14 +01:00
|
|
|
*c_len = c_len32;
|
|
|
|
|
*u_len = u_len32;
|
|
|
|
|
*last_head = last_head32;
|
|
|
|
|
} else {
|
2011-03-18 13:18:36 +01:00
|
|
|
int read_len;
|
|
|
|
|
|
|
|
|
|
if (control->major_version == 0 && control->minor_version == 5)
|
|
|
|
|
read_len = 8;
|
|
|
|
|
else
|
|
|
|
|
read_len = chunk_bytes;
|
|
|
|
|
if (unlikely(read(fd_in, c_len, read_len) != read_len))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to read in get_header_info"), false);
|
2011-03-18 13:18:36 +01:00
|
|
|
if (unlikely(read(fd_in, u_len, read_len) != read_len))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to read in get_header_info"), false);
|
2011-03-18 13:18:36 +01:00
|
|
|
if (unlikely(read(fd_in, last_head, read_len) != read_len))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to read_i64 in get_header_info"), false);
|
2011-03-21 22:03:05 +01:00
|
|
|
*c_len = le64toh(*c_len);
|
|
|
|
|
*u_len = le64toh(*u_len);
|
|
|
|
|
*last_head = le64toh(*last_head);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-05-07 10:37:25 +02:00
|
|
|
static double percentage(i64 num, i64 den)
|
|
|
|
|
{
|
|
|
|
|
double d_num, d_den;
|
|
|
|
|
|
|
|
|
|
if (den < 100) {
|
|
|
|
|
d_num = num * 100;
|
2015-03-10 10:03:21 +01:00
|
|
|
d_den = den;
|
|
|
|
|
if (!d_den)
|
|
|
|
|
d_den = 1;
|
2011-05-07 10:37:25 +02:00
|
|
|
} else {
|
|
|
|
|
d_num = num;
|
|
|
|
|
d_den = den / 100;
|
|
|
|
|
}
|
|
|
|
|
return d_num / d_den;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
bool get_fileinfo(rzip_control *control)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
2018-05-17 07:21:40 +02:00
|
|
|
i64 u_len, c_len, second_last, last_head, utotal = 0, ctotal = 0, ofs = 25, stream_head[2];
|
2011-03-18 07:32:47 +01:00
|
|
|
i64 expected_size, infile_size, chunk_size = 0, chunk_total = 0;
|
2011-03-18 13:18:36 +01:00
|
|
|
int header_length, stream = 0, chunk = 0;
|
2011-03-13 07:31:30 +01:00
|
|
|
char *tmp, *infilecopy = NULL;
|
2011-03-11 11:26:42 +01:00
|
|
|
char chunk_byte = 0;
|
2011-03-08 22:32:14 +01:00
|
|
|
long double cratio;
|
|
|
|
|
uchar ctype = 0;
|
2019-11-03 22:12:50 +01:00
|
|
|
uchar save_ctype = 255;
|
2011-03-08 22:32:14 +01:00
|
|
|
struct stat st;
|
2011-03-22 22:16:07 +01:00
|
|
|
int fd_in;
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
if (!STDIN) {
|
2011-03-22 15:51:40 +01:00
|
|
|
struct stat fdin_stat;
|
|
|
|
|
|
|
|
|
|
stat(control->infile, &fdin_stat);
|
|
|
|
|
if (!S_ISREG(fdin_stat.st_mode) && (tmp = strrchr(control->infile, '.')) &&
|
|
|
|
|
strcmp(tmp,control->suffix)) {
|
2011-08-12 08:43:42 +02:00
|
|
|
infilecopy = alloca(strlen(control->infile) + strlen(control->suffix) + 1);
|
|
|
|
|
strcpy(infilecopy, control->infile);
|
|
|
|
|
strcat(infilecopy, control->suffix);
|
2011-03-08 22:32:14 +01:00
|
|
|
} else
|
2011-08-12 08:43:42 +02:00
|
|
|
infilecopy = strdupa(control->infile);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2017-06-04 07:28:18 +02:00
|
|
|
if ( IS_FROM_FILE )
|
|
|
|
|
fd_in = fileno(control->inFILE);
|
|
|
|
|
else if (STDIN)
|
2011-03-08 22:32:14 +01:00
|
|
|
fd_in = 0;
|
|
|
|
|
else {
|
|
|
|
|
fd_in = open(infilecopy, O_RDONLY);
|
|
|
|
|
if (unlikely(fd_in == -1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to open %s\n", infilecopy), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get file size */
|
|
|
|
|
if (unlikely(fstat(fd_in, &st)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("bad magic file descriptor!?\n"), error);
|
2011-03-21 22:19:21 +01:00
|
|
|
infile_size = st.st_size;
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
/* Get decompressed size */
|
2016-06-09 10:18:14 +02:00
|
|
|
if (unlikely(!read_magic(control, fd_in, &expected_size)))
|
|
|
|
|
goto error;
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-03-20 05:45:44 +01:00
|
|
|
if (ENCRYPT) {
|
|
|
|
|
print_output("Encrypted lrzip archive. No further information available\n");
|
2017-06-04 07:28:18 +02:00
|
|
|
if (!STDIN && !IS_FROM_FILE)
|
|
|
|
|
close(fd_in);
|
2011-03-20 05:45:44 +01:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-11 11:26:42 +01:00
|
|
|
if (control->major_version == 0 && control->minor_version > 4) {
|
|
|
|
|
if (unlikely(read(fd_in, &chunk_byte, 1) != 1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to read chunk_byte in get_fileinfo\n"), error);
|
2018-05-16 09:12:50 +02:00
|
|
|
if (unlikely(chunk_byte < 1 || chunk_byte > 8))
|
|
|
|
|
fatal_goto(("Invalid chunk bytes %d\n", chunk_byte), error);
|
2011-03-12 01:40:51 +01:00
|
|
|
if (control->major_version == 0 && control->minor_version > 5) {
|
|
|
|
|
if (unlikely(read(fd_in, &control->eof, 1) != 1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to read eof in get_fileinfo\n"), error);
|
2011-03-22 21:59:04 +01:00
|
|
|
if (unlikely(read(fd_in, &chunk_size, chunk_byte) != chunk_byte))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to read chunk_size in get_fileinfo\n"), error);
|
2011-03-22 21:59:04 +01:00
|
|
|
chunk_size = le64toh(chunk_size);
|
2021-02-15 15:10:01 +01:00
|
|
|
if (unlikely(chunk_size < 0))
|
2018-05-16 09:12:50 +02:00
|
|
|
fatal_goto(("Invalid chunk size %lld\n", chunk_size), error);
|
2011-03-12 01:40:51 +01:00
|
|
|
}
|
2011-03-11 11:26:42 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-13 07:31:30 +01:00
|
|
|
if (control->major_version == 0 && control->minor_version < 4) {
|
|
|
|
|
ofs = 24;
|
|
|
|
|
header_length = 13;
|
2011-03-18 13:18:36 +01:00
|
|
|
} else if (control->major_version == 0 && control->minor_version == 4) {
|
2011-03-13 07:31:30 +01:00
|
|
|
ofs = 24;
|
2011-03-18 13:18:36 +01:00
|
|
|
header_length = 25;
|
|
|
|
|
} else if (control->major_version == 0 && control->minor_version == 5) {
|
2011-03-13 07:31:30 +01:00
|
|
|
ofs = 25;
|
2011-03-18 13:18:36 +01:00
|
|
|
header_length = 25;
|
|
|
|
|
} else {
|
2011-03-22 21:59:04 +01:00
|
|
|
ofs = 26 + chunk_byte;
|
2011-03-18 13:18:36 +01:00
|
|
|
header_length = 1 + (chunk_byte * 3);
|
|
|
|
|
}
|
2011-05-07 15:58:38 +02:00
|
|
|
if (control->major_version == 0 && control->minor_version < 6 &&
|
|
|
|
|
!expected_size)
|
|
|
|
|
goto done;
|
2011-03-13 07:31:30 +01:00
|
|
|
next_chunk:
|
|
|
|
|
stream = 0;
|
|
|
|
|
stream_head[0] = 0;
|
|
|
|
|
stream_head[1] = stream_head[0] + header_length;
|
|
|
|
|
|
2021-12-01 14:49:45 +01:00
|
|
|
print_verbose("Rzip chunk: %d\n", ++chunk);
|
2011-03-13 07:31:30 +01:00
|
|
|
if (chunk_byte)
|
|
|
|
|
print_verbose("Chunk byte width: %d\n", chunk_byte);
|
|
|
|
|
if (chunk_size) {
|
|
|
|
|
chunk_total += chunk_size;
|
2021-12-01 14:49:45 +01:00
|
|
|
print_verbose("Chunk size: %'"PRId64"\n", chunk_size);
|
2011-03-13 07:31:30 +01:00
|
|
|
}
|
2018-05-16 09:20:26 +02:00
|
|
|
if (unlikely(chunk_byte && (chunk_byte > 8 || chunk_size < 0)))
|
2018-05-16 08:44:50 +02:00
|
|
|
failure("Invalid chunk data\n");
|
2011-03-13 07:31:30 +01:00
|
|
|
while (stream < NUM_STREAMS) {
|
|
|
|
|
int block = 1;
|
|
|
|
|
|
2018-05-17 07:21:40 +02:00
|
|
|
second_last = 0;
|
2015-02-01 08:05:27 +01:00
|
|
|
if (unlikely(lseek(fd_in, stream_head[stream] + ofs, SEEK_SET) == -1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to seek to header data in get_fileinfo\n"), error);
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!get_header_info(control, fd_in, &ctype, &c_len, &u_len, &last_head, chunk_byte)))
|
|
|
|
|
return false;
|
2011-03-13 07:31:30 +01:00
|
|
|
|
|
|
|
|
print_verbose("Stream: %d\n", stream);
|
2021-12-01 14:49:45 +01:00
|
|
|
print_maxverbose("Offset: %'"PRId64"\n", stream_head[stream] + ofs);
|
|
|
|
|
print_verbose("%s\t%s\t%s\t%16s / %14s", "Block","Comp","Percent","Comp Size", "UComp Size");
|
|
|
|
|
print_maxverbose("%18s : %14s", "Offset", "Head");
|
|
|
|
|
print_verbose("\n");
|
2011-03-13 07:31:30 +01:00
|
|
|
do {
|
|
|
|
|
i64 head_off;
|
|
|
|
|
|
2018-05-17 07:21:40 +02:00
|
|
|
if (unlikely(last_head && last_head < second_last))
|
|
|
|
|
failure_goto(("Invalid earlier last_head position, corrupt archive.\n"), error);
|
|
|
|
|
second_last = last_head;
|
2011-03-13 07:31:30 +01:00
|
|
|
if (unlikely(last_head + ofs > infile_size))
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_goto(("Offset greater than archive size, likely corrupted/truncated archive.\n"), error);
|
2020-11-14 22:32:32 +01:00
|
|
|
if (unlikely((head_off = lseek(fd_in, last_head + ofs, SEEK_SET)) == -1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to seek to header data in get_fileinfo\n"), error);
|
|
|
|
|
if (unlikely(!get_header_info(control, fd_in, &ctype, &c_len, &u_len,
|
2012-03-07 12:04:24 +01:00
|
|
|
&last_head, chunk_byte)))
|
|
|
|
|
return false;
|
2011-03-13 07:31:30 +01:00
|
|
|
if (unlikely(last_head < 0 || c_len < 0 || u_len < 0))
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_goto(("Entry negative, likely corrupted archive.\n"), error);
|
2011-03-13 07:31:30 +01:00
|
|
|
print_verbose("%d\t", block);
|
|
|
|
|
if (ctype == CTYPE_NONE)
|
|
|
|
|
print_verbose("none");
|
|
|
|
|
else if (ctype == CTYPE_BZIP2)
|
|
|
|
|
print_verbose("bzip2");
|
|
|
|
|
else if (ctype == CTYPE_LZO)
|
|
|
|
|
print_verbose("lzo");
|
|
|
|
|
else if (ctype == CTYPE_LZMA)
|
|
|
|
|
print_verbose("lzma");
|
|
|
|
|
else if (ctype == CTYPE_GZIP)
|
|
|
|
|
print_verbose("gzip");
|
|
|
|
|
else if (ctype == CTYPE_ZPAQ)
|
|
|
|
|
print_verbose("zpaq");
|
|
|
|
|
else
|
|
|
|
|
print_verbose("Dunno wtf");
|
2019-11-03 22:12:50 +01:00
|
|
|
if (save_ctype == 255)
|
|
|
|
|
save_ctype = ctype; /* need this for lzma when some chunks could have no compression
|
|
|
|
|
* and info will show rzip + none on info display if last chunk
|
|
|
|
|
* is not compressed. Adjust for all types in case it's used in
|
|
|
|
|
* the future */
|
2011-03-13 07:31:30 +01:00
|
|
|
utotal += u_len;
|
|
|
|
|
ctotal += c_len;
|
2021-12-01 14:49:45 +01:00
|
|
|
print_verbose("\t%5.1f%%\t%'16"PRId64" / %'14"PRId64"", percentage(c_len, u_len), c_len, u_len);
|
|
|
|
|
print_maxverbose("%'18"PRId64" : %'14"PRId64"", head_off, last_head);
|
2011-03-13 07:31:30 +01:00
|
|
|
print_verbose("\n");
|
|
|
|
|
block++;
|
|
|
|
|
} while (last_head);
|
|
|
|
|
++stream;
|
|
|
|
|
}
|
2011-03-17 14:06:11 +01:00
|
|
|
|
2011-03-20 05:45:44 +01:00
|
|
|
if (unlikely((ofs = lseek(fd_in, c_len, SEEK_CUR)) == -1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to lseek c_len in get_fileinfo\n"), error);
|
2011-03-17 14:06:11 +01:00
|
|
|
|
2011-03-18 13:18:36 +01:00
|
|
|
if (ofs >= infile_size - (HAS_MD5 ? MD5_DIGEST_SIZE : 0))
|
|
|
|
|
goto done;
|
2011-03-13 07:31:30 +01:00
|
|
|
/* Chunk byte entry */
|
|
|
|
|
if (control->major_version == 0 && control->minor_version > 4) {
|
|
|
|
|
if (unlikely(read(fd_in, &chunk_byte, 1) != 1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to read chunk_byte in get_fileinfo\n"), error);
|
2018-05-16 09:20:26 +02:00
|
|
|
if (unlikely(chunk_byte < 1 || chunk_byte > 8))
|
|
|
|
|
fatal_goto(("Invalid chunk bytes %d\n", chunk_byte), error);
|
2011-03-13 07:31:30 +01:00
|
|
|
ofs++;
|
|
|
|
|
if (control->major_version == 0 && control->minor_version > 5) {
|
|
|
|
|
if (unlikely(read(fd_in, &control->eof, 1) != 1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to read eof in get_fileinfo\n"), error);
|
2011-03-22 21:59:04 +01:00
|
|
|
if (unlikely(read(fd_in, &chunk_size, chunk_byte) != chunk_byte))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to read chunk_size in get_fileinfo\n"), error);
|
2011-03-22 21:59:04 +01:00
|
|
|
chunk_size = le64toh(chunk_size);
|
2018-05-16 09:20:26 +02:00
|
|
|
if (unlikely(chunk_size < 0))
|
|
|
|
|
fatal_goto(("Invalid chunk size %lld\n", chunk_size), error);
|
2011-03-22 21:59:04 +01:00
|
|
|
ofs += 1 + chunk_byte;
|
2011-03-18 13:18:36 +01:00
|
|
|
header_length = 1 + (chunk_byte * 3);
|
2011-03-13 07:31:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
2011-03-18 13:18:36 +01:00
|
|
|
goto next_chunk;
|
|
|
|
|
done:
|
2021-12-01 14:49:45 +01:00
|
|
|
cratio = (long double)expected_size / (long double)infile_size;
|
2011-03-13 07:31:30 +01:00
|
|
|
if (unlikely(ofs > infile_size))
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_goto(("Offset greater than archive size, likely corrupted/truncated archive.\n"), error);
|
2021-12-01 14:49:45 +01:00
|
|
|
print_output("\nSummary\n=======\n");
|
|
|
|
|
print_output("File: %s\nlrzip version: %'d.%'d \n\n", infilecopy,
|
|
|
|
|
control->major_version, control->minor_version);
|
2011-03-13 07:31:30 +01:00
|
|
|
|
2021-12-01 14:49:45 +01:00
|
|
|
if (!expected_size)
|
|
|
|
|
print_output("Due to %s, expected decompression size not available\n", "Compression to STDOUT");
|
|
|
|
|
print_verbose(" Stats Percent Compressed / Uncompressed\n -------------------------------------------------------\n");
|
|
|
|
|
/* If we can't show expected size, tailor output for it */
|
|
|
|
|
if (expected_size) {
|
|
|
|
|
print_verbose(" Rzip: %5.1f%%\t%'16"PRId64" / %'14"PRId64"\n",
|
|
|
|
|
percentage (utotal, expected_size),
|
|
|
|
|
utotal, expected_size);
|
|
|
|
|
print_verbose(" Back end: %5.1f%%\t%'16"PRId64" / %'14"PRId64"\n",
|
|
|
|
|
percentage(ctotal, utotal),
|
|
|
|
|
ctotal, utotal);
|
|
|
|
|
print_verbose(" Overall: %5.1f%%\t%'16"PRId64" / %'14"PRId64"\n",
|
|
|
|
|
percentage(ctotal, expected_size),
|
|
|
|
|
ctotal, expected_size);
|
|
|
|
|
} else {
|
|
|
|
|
print_verbose(" Rzip: Unavailable\n");
|
|
|
|
|
print_verbose(" Back end: %5.1f%%\t%'16"PRId64" / %'14"PRId64"\n", percentage(ctotal, utotal), ctotal, utotal);
|
|
|
|
|
print_verbose(" Overall: Unavailable\n");
|
|
|
|
|
}
|
|
|
|
|
print_verbose("\n");
|
2011-03-08 22:36:55 +01:00
|
|
|
|
2021-12-01 14:49:45 +01:00
|
|
|
print_output(" Compression Method: ");
|
2011-03-12 01:55:15 +01:00
|
|
|
|
2019-11-03 22:12:50 +01:00
|
|
|
if (save_ctype == CTYPE_NONE)
|
2011-03-08 22:32:14 +01:00
|
|
|
print_output("rzip alone\n");
|
2019-11-03 22:12:50 +01:00
|
|
|
else if (save_ctype == CTYPE_BZIP2)
|
2011-03-08 22:32:14 +01:00
|
|
|
print_output("rzip + bzip2\n");
|
2019-11-03 22:12:50 +01:00
|
|
|
else if (save_ctype == CTYPE_LZO)
|
2011-03-08 22:32:14 +01:00
|
|
|
print_output("rzip + lzo\n");
|
2019-11-03 22:12:50 +01:00
|
|
|
else if (save_ctype == CTYPE_LZMA)
|
2011-03-08 22:32:14 +01:00
|
|
|
print_output("rzip + lzma\n");
|
2019-11-03 22:12:50 +01:00
|
|
|
else if (save_ctype == CTYPE_GZIP)
|
2011-03-08 22:32:14 +01:00
|
|
|
print_output("rzip + gzip\n");
|
2019-11-03 22:12:50 +01:00
|
|
|
else if (save_ctype == CTYPE_ZPAQ)
|
2011-03-08 22:32:14 +01:00
|
|
|
print_output("rzip + zpaq\n");
|
|
|
|
|
else
|
|
|
|
|
print_output("Dunno wtf\n");
|
|
|
|
|
|
2021-12-01 14:49:45 +01:00
|
|
|
print_output("\n");
|
|
|
|
|
|
|
|
|
|
if (expected_size) {
|
|
|
|
|
print_output(" Decompressed file size: %'14"PRIu64"\n", expected_size);
|
|
|
|
|
print_output(" Compressed file size: %'14"PRIu64"\n", infile_size);
|
|
|
|
|
print_output(" Compression ratio: %14.3Lfx\n", cratio);
|
|
|
|
|
} else {
|
|
|
|
|
print_output(" Decompressed file size: Unavailable\n");
|
|
|
|
|
print_output(" Compressed file size: %'14"PRIu64"\n", infile_size);
|
|
|
|
|
print_output(" Compression ratio: Unavailable\n");
|
|
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
if (HAS_MD5) {
|
|
|
|
|
char md5_stored[MD5_DIGEST_SIZE];
|
|
|
|
|
int i;
|
|
|
|
|
|
2015-02-01 08:05:27 +01:00
|
|
|
if (unlikely(lseek(fd_in, -MD5_DIGEST_SIZE, SEEK_END) == -1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to seek to md5 data in runzip_fd\n"), error);
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(read(fd_in, md5_stored, MD5_DIGEST_SIZE) != MD5_DIGEST_SIZE))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to read md5 data in runzip_fd\n"), error);
|
2021-12-01 14:49:45 +01:00
|
|
|
print_output("\n MD5 Checksum: ");
|
2011-03-20 05:45:44 +01:00
|
|
|
for (i = 0; i < MD5_DIGEST_SIZE; i++)
|
|
|
|
|
print_output("%02x", md5_stored[i] & 0xFF);
|
2011-03-08 22:32:14 +01:00
|
|
|
print_output("\n");
|
|
|
|
|
} else
|
2021-12-01 14:49:45 +01:00
|
|
|
print_output("\n CRC32 used for integrity testing\n");
|
2017-06-04 07:28:18 +02:00
|
|
|
if ( !IS_FROM_FILE )
|
|
|
|
|
if (unlikely(close(fd_in)))
|
|
|
|
|
fatal_return(("Failed to close fd_in in get_fileinfo\n"), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-03-20 05:45:44 +01:00
|
|
|
out:
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(control->outfile);
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
|
|
|
|
error:
|
2017-06-04 07:28:18 +02:00
|
|
|
if (!STDIN && ! IS_FROM_FILE) close(fd_in);
|
2011-08-12 08:43:42 +02:00
|
|
|
return false;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
compress one file from the command line
|
|
|
|
|
*/
|
2011-08-12 08:43:42 +02:00
|
|
|
bool compress_file(rzip_control *control)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
|
|
|
|
const char *tmp, *tmpinfile; /* we're just using this as a proxy for control->infile.
|
|
|
|
|
* Spares a compiler warning
|
|
|
|
|
*/
|
2011-08-12 08:43:42 +02:00
|
|
|
int fd_in = -1, fd_out = -1;
|
2011-03-12 09:56:08 +01:00
|
|
|
char header[MAGIC_LEN];
|
2011-03-15 06:32:32 +01:00
|
|
|
|
2022-02-25 13:07:47 +01:00
|
|
|
control->flags |= FLAG_MD5;
|
2011-03-17 14:06:11 +01:00
|
|
|
if (ENCRYPT)
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!get_hash(control, 1)))
|
|
|
|
|
return false;
|
2011-03-08 22:32:14 +01:00
|
|
|
memset(header, 0, sizeof(header));
|
|
|
|
|
|
2017-06-04 07:28:18 +02:00
|
|
|
if ( IS_FROM_FILE )
|
|
|
|
|
fd_in = fileno(control->inFILE);
|
|
|
|
|
else if (!STDIN) {
|
|
|
|
|
/* is extension at end of infile? */
|
2011-03-08 22:32:14 +01:00
|
|
|
if ((tmp = strrchr(control->infile, '.')) && !strcmp(tmp, control->suffix)) {
|
|
|
|
|
print_err("%s: already has %s suffix. Skipping...\n", control->infile, control->suffix);
|
2011-08-12 08:43:42 +02:00
|
|
|
return false;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2017-06-04 07:28:18 +02:00
|
|
|
fd_in = open(control->infile, O_RDONLY);
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(fd_in == -1))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to open %s\n", control->infile), false);
|
2017-06-04 07:28:18 +02:00
|
|
|
}
|
|
|
|
|
else
|
2011-03-08 22:32:14 +01:00
|
|
|
fd_in = 0;
|
|
|
|
|
|
|
|
|
|
if (!STDOUT) {
|
|
|
|
|
if (control->outname) {
|
|
|
|
|
/* check if outname has control->suffix */
|
|
|
|
|
if (*(control->suffix) == '\0') /* suffix is empty string */
|
|
|
|
|
control->outfile = strdup(control->outname);
|
|
|
|
|
else if ((tmp=strrchr(control->outname, '.')) && strcmp(tmp, control->suffix)) {
|
|
|
|
|
control->outfile = malloc(strlen(control->outname) + strlen(control->suffix) + 1);
|
|
|
|
|
if (unlikely(!control->outfile))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to allocate outfile name\n"), error);
|
2011-03-08 22:32:14 +01:00
|
|
|
strcpy(control->outfile, control->outname);
|
|
|
|
|
strcat(control->outfile, control->suffix);
|
|
|
|
|
print_output("Suffix added to %s.\nFull pathname is: %s\n", control->outname, control->outfile);
|
|
|
|
|
} else /* no, already has suffix */
|
|
|
|
|
control->outfile = strdup(control->outname);
|
|
|
|
|
} else {
|
|
|
|
|
/* default output name from control->infile
|
|
|
|
|
* test if outdir specified. If so, strip path from filename of
|
|
|
|
|
* control->infile
|
|
|
|
|
*/
|
|
|
|
|
if (control->outdir && (tmp = strrchr(control->infile, '/')))
|
|
|
|
|
tmpinfile = tmp + 1;
|
|
|
|
|
else
|
|
|
|
|
tmpinfile = control->infile;
|
|
|
|
|
|
|
|
|
|
control->outfile = malloc((control->outdir == NULL? 0: strlen(control->outdir)) + strlen(tmpinfile) + strlen(control->suffix) + 1);
|
|
|
|
|
if (unlikely(!control->outfile))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to allocate outfile name\n"), error);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
if (control->outdir) { /* prepend control->outdir */
|
|
|
|
|
strcpy(control->outfile, control->outdir);
|
|
|
|
|
strcat(control->outfile, tmpinfile);
|
|
|
|
|
} else
|
|
|
|
|
strcpy(control->outfile, tmpinfile);
|
|
|
|
|
strcat(control->outfile, control->suffix);
|
2022-02-27 08:35:10 +01:00
|
|
|
print_output("Output filename is: %s\n", control->outfile);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-05-07 17:28:34 +02:00
|
|
|
fd_out = open(control->outfile, O_RDWR | O_CREAT | O_EXCL, 0666);
|
2011-03-22 14:42:58 +01:00
|
|
|
if (FORCE_REPLACE && (-1 == fd_out) && (EEXIST == errno)) {
|
|
|
|
|
if (unlikely(unlink(control->outfile)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to unlink an existing file: %s\n", control->outfile), error);
|
2011-05-07 17:28:34 +02:00
|
|
|
fd_out = open(control->outfile, O_RDWR | O_CREAT | O_EXCL, 0666);
|
2011-03-22 14:42:58 +01:00
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(fd_out == -1)) {
|
|
|
|
|
/* We must ensure we don't delete a file that already
|
|
|
|
|
* exists just because we tried to create a new one */
|
|
|
|
|
control->flags |= FLAG_KEEP_BROKEN;
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Failed to create %s\n", control->outfile), error);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
2011-03-12 12:46:57 +01:00
|
|
|
control->fd_out = fd_out;
|
2016-06-09 10:18:14 +02:00
|
|
|
if (!STDIN) {
|
|
|
|
|
if (unlikely(!preserve_perms(control, fd_in, fd_out)))
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-02-26 05:14:52 +01:00
|
|
|
control->fd_out = fd_out = open_tmpoutfile(control);
|
|
|
|
|
if (likely(fd_out != -1)) {
|
|
|
|
|
/* Unlink temporary file as soon as possible */
|
|
|
|
|
if (unlikely(unlink(control->outfile)))
|
|
|
|
|
fatal_return(("Failed to unlink tmpfile: %s\n", control->outfile), false);
|
|
|
|
|
}
|
2016-06-09 10:18:14 +02:00
|
|
|
if (unlikely(!open_tmpoutbuf(control)))
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-03-12 01:17:11 +01:00
|
|
|
/* Write zeroes to header at beginning of file */
|
2011-03-12 04:13:28 +01:00
|
|
|
if (unlikely(!STDOUT && write(fd_out, header, sizeof(header)) != sizeof(header)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_goto(("Cannot write file header\n"), error);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
|
|
|
|
rzip_fd(control, fd_in, fd_out);
|
|
|
|
|
|
2022-02-26 05:14:52 +01:00
|
|
|
/* Write magic at end b/c lzma does not tell us properties until it is done */
|
2016-06-09 10:18:14 +02:00
|
|
|
if (!STDOUT) {
|
|
|
|
|
if (unlikely(!write_magic(control)))
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2011-03-17 06:00:57 +01:00
|
|
|
if (ENCRYPT)
|
|
|
|
|
release_hashes(control);
|
2011-03-15 11:18:29 +01:00
|
|
|
|
2016-10-17 12:25:36 +02:00
|
|
|
if (unlikely(!STDIN && !STDOUT && !preserve_times(control, fd_in))) {
|
|
|
|
|
fatal("Failed to preserve times on output file\n");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
if (unlikely(close(fd_in))) {
|
|
|
|
|
fatal("Failed to close fd_in\n");
|
|
|
|
|
fd_in = -1;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
2011-03-12 04:13:28 +01:00
|
|
|
if (unlikely(!STDOUT && close(fd_out)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to close fd_out\n"), false);
|
2011-03-12 22:34:06 +01:00
|
|
|
if (TMP_OUTBUF)
|
2011-03-14 02:48:40 +01:00
|
|
|
close_tmpoutbuf(control);
|
2011-03-08 22:32:14 +01:00
|
|
|
|
2015-04-16 07:28:01 +02:00
|
|
|
if (!KEEP_FILES && !STDIN) {
|
2011-03-08 22:32:14 +01:00
|
|
|
if (unlikely(unlink(control->infile)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to unlink %s\n", control->infile), false);
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2018-05-16 06:12:22 +02:00
|
|
|
dealloc(control->outfile);
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
|
|
|
|
error:
|
2017-06-04 07:28:18 +02:00
|
|
|
if (! IS_FROM_FILE && STDIN && (fd_in > 0))
|
2016-10-17 12:25:36 +02:00
|
|
|
close(fd_in);
|
|
|
|
|
if ((!STDOUT) && (fd_out > 0))
|
|
|
|
|
close(fd_out);
|
2011-08-12 08:43:42 +02:00
|
|
|
return false;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
2011-08-11 06:41:21 +02:00
|
|
|
|
2015-03-03 04:15:09 +01:00
|
|
|
bool initialise_control(rzip_control *control)
|
2011-08-11 06:41:21 +02:00
|
|
|
{
|
2016-06-14 05:47:38 +02:00
|
|
|
time_t now_t, tdiff;
|
2018-05-16 06:03:14 +02:00
|
|
|
char localeptr[] = "./", *eptr; /* for environment */
|
|
|
|
|
size_t len;
|
2011-08-11 06:41:21 +02:00
|
|
|
|
|
|
|
|
memset(control, 0, sizeof(rzip_control));
|
|
|
|
|
control->msgout = stderr;
|
2011-08-13 08:21:45 +02:00
|
|
|
control->msgerr = stderr;
|
2011-08-11 09:06:32 +02:00
|
|
|
register_outputfile(control, control->msgout);
|
2011-08-11 06:41:21 +02:00
|
|
|
control->flags = FLAG_SHOW_PROGRESS | FLAG_KEEP_FILES | FLAG_THRESHOLD;
|
2022-02-25 23:21:45 +01:00
|
|
|
control->suffix = ".lrz";
|
2011-08-11 06:41:21 +02:00
|
|
|
control->compression_level = 7;
|
2011-08-11 09:06:32 +02:00
|
|
|
control->ramsize = get_ram(control);
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(control->ramsize == -1))
|
|
|
|
|
return false;
|
2011-08-11 06:41:21 +02:00
|
|
|
/* for testing single CPU */
|
|
|
|
|
control->threads = PROCESSORS; /* get CPUs for LZMA */
|
|
|
|
|
control->page_size = PAGE_SIZE;
|
|
|
|
|
control->nice_val = 19;
|
|
|
|
|
|
|
|
|
|
/* The first 5 bytes of the salt is the time in seconds.
|
|
|
|
|
* The next 2 bytes encode how many times to hash the password.
|
|
|
|
|
* The last 9 bytes are random data, making 16 bytes of salt */
|
2016-06-14 05:47:38 +02:00
|
|
|
if (unlikely((now_t = time(NULL)) == ((time_t)-1)))
|
|
|
|
|
fatal_return(("Failed to call time in main\n"), false);
|
|
|
|
|
if (unlikely(now_t < T_ZERO)) {
|
|
|
|
|
print_output("Warning your time reads before the year 2011, check your system clock\n");
|
|
|
|
|
now_t = T_ZERO;
|
|
|
|
|
}
|
|
|
|
|
/* Workaround for CPUs no longer keeping up with Moore's law!
|
|
|
|
|
* This way we keep the magic header format unchanged. */
|
|
|
|
|
tdiff = (now_t - T_ZERO) / 4;
|
|
|
|
|
now_t = T_ZERO + tdiff;
|
|
|
|
|
control->secs = now_t;
|
2011-08-11 06:41:21 +02:00
|
|
|
control->encloops = nloops(control->secs, control->salt, control->salt + 1);
|
2012-03-07 12:04:24 +01:00
|
|
|
if (unlikely(!get_rand(control, control->salt + 2, 6)))
|
|
|
|
|
return false;
|
2011-08-11 06:41:21 +02:00
|
|
|
|
2015-03-10 02:10:50 +01:00
|
|
|
/* Get Temp Dir. Try variations on canonical unix environment variable */
|
|
|
|
|
eptr = getenv("TMPDIR");
|
|
|
|
|
if (!eptr)
|
|
|
|
|
eptr = getenv("TMP");
|
|
|
|
|
if (!eptr)
|
|
|
|
|
eptr = getenv("TEMPDIR");
|
|
|
|
|
if (!eptr)
|
|
|
|
|
eptr = getenv("TEMP");
|
2018-05-16 06:03:14 +02:00
|
|
|
if (!eptr)
|
|
|
|
|
eptr = localeptr;
|
|
|
|
|
len = strlen(eptr);
|
2015-03-10 04:36:19 +01:00
|
|
|
|
2015-04-16 07:47:31 +02:00
|
|
|
control->tmpdir = malloc(len + 2);
|
2015-03-10 04:36:19 +01:00
|
|
|
if (control->tmpdir == NULL)
|
|
|
|
|
fatal_return(("Failed to allocate for tmpdir\n"), false);
|
|
|
|
|
strcpy(control->tmpdir, eptr);
|
2015-04-16 07:47:31 +02:00
|
|
|
if (control->tmpdir[len - 1] != '/') {
|
2015-03-10 04:36:19 +01:00
|
|
|
control->tmpdir[len] = '/'; /* need a trailing slash */
|
2015-04-16 07:47:31 +02:00
|
|
|
control->tmpdir[len + 1] = '\0';
|
2015-03-10 19:30:37 +01:00
|
|
|
}
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-08-11 06:41:21 +02:00
|
|
|
}
|