From beca31d26734b32d0ba211c529ed2cea5e455673 Mon Sep 17 00:00:00 2001 From: Joerg Sonnenberger Date: Thu, 31 Jul 2008 03:33:17 -0400 Subject: [PATCH] Restore sparse file handling from before 146023: Don't write to the last block if the filesystem implements the XSI extension for ftruncate. While here, flush the the stat cache again after the write in the fallback case. SVN-Revision: 173 --- libarchive/archive_write_disk.c | 36 ++++++---- .../archive_write_set_compression_compress.c | 68 ++++++++----------- 2 files changed, 51 insertions(+), 53 deletions(-) diff --git a/libarchive/archive_write_disk.c b/libarchive/archive_write_disk.c index bc5f3e052..5685a1cc2 100644 --- a/libarchive/archive_write_disk.c +++ b/libarchive/archive_write_disk.c @@ -622,23 +622,33 @@ _archive_write_finish_entry(struct archive *_a) /* Last write ended at exactly the filesize; we're done. */ /* Hopefully, this is the common case. */ } else { - /* - * The write handlers truncate long writes, so we - * never have to shorten a file here. Some systems - * can lengthen files with ftruncate(), but this is - * more portable: - */ - const char nul = '\0'; - if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) { - archive_set_error(&a->archive, errno, "Seek failed"); - return (ARCHIVE_FAILED); - } - if (write(a->fd, &nul, 1) < 0) { + if (ftruncate(a->fd, a->filesize) == -1 && + a->filesize == 0) { archive_set_error(&a->archive, errno, - "Write to restore size failed"); + "File size could not be restored"); return (ARCHIVE_FAILED); } + /* + * Explicitly stat the file as some platforms might not + * implement the XSI option to extend files via ftruncate. + */ a->pst = NULL; + if ((ret = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK) + return (ret); + if (a->st.st_size != a->filesize) { + const char nul = '\0'; + if (lseek(a->fd, a->st.st_size - 1, SEEK_SET) < 0) { + archive_set_error(&a->archive, errno, + "Seek failed"); + return (ARCHIVE_FATAL); + } + if (write(a->fd, &nul, 1) < 0) { + archive_set_error(&a->archive, errno, + "Write to restore size failed"); + return (ARCHIVE_FATAL); + } + a->pst = NULL; + } } /* Restore metadata. */ diff --git a/libarchive/archive_write_set_compression_compress.c b/libarchive/archive_write_set_compression_compress.c index f913a23c5..b62d6fe25 100644 --- a/libarchive/archive_write_set_compression_compress.c +++ b/libarchive/archive_write_set_compression_compress.c @@ -74,8 +74,6 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_compress.c, #include "archive_private.h" #include "archive_write_private.h" -#define HSIZE 69001 /* 95% occupancy */ -#define HSHIFT 8 /* 8 - trunc(log2(HSIZE / 65536)) */ #define CHECK_GAP 10000 /* Ratio check interval. */ #define MAXCODE(bits) ((1 << (bits)) - 1) @@ -93,12 +91,10 @@ struct private_data { int code_len; /* Number of bits/code. */ int cur_maxcode; /* Maximum code, given n_bits. */ int max_maxcode; /* Should NEVER generate this code. */ - int hashtab [HSIZE]; - unsigned short codetab [HSIZE]; int first_free; /* First unused entry. */ int compress_ratio; - int cur_code, cur_fcode; + size_t cur_code; int bit_offset; unsigned char bit_buf; @@ -106,6 +102,10 @@ struct private_data { unsigned char *compressed; size_t compressed_buffer_size; size_t compressed_offset; + + uint8_t code_next[65536]; + uint16_t code_link[65536]; + uint16_t code_state[65536]; }; static int archive_compressor_compress_finish(struct archive_write *); @@ -158,7 +158,6 @@ archive_compressor_compress_init(struct archive_write *a) "Can't allocate data for compression"); return (ARCHIVE_FATAL); } - memset(state, 0, sizeof(*state)); state->compressed_buffer_size = a->bytes_per_block; state->compressed = malloc(state->compressed_buffer_size); @@ -173,18 +172,23 @@ archive_compressor_compress_init(struct archive_write *a) a->compressor.write = archive_compressor_compress_write; a->compressor.finish = archive_compressor_compress_finish; + state->in_count = 0; + state->out_count = 0; + state->checkpoint = 0; + state->max_maxcode = 0x10000; /* Should NEVER generate this code. */ - state->in_count = 0; /* Length of input. */ state->bit_buf = 0; state->bit_offset = 0; state->out_count = 3; /* Includes 3-byte header mojo. */ state->compress_ratio = 0; state->checkpoint = CHECK_GAP; state->code_len = 9; + state->cur_code = 256; state->cur_maxcode = MAXCODE(state->code_len); state->first_free = FIRST; - memset(state->hashtab, 0xff, sizeof(state->hashtab)); + state->first_higher = 0; + memset(state->code_lower, 0, sizeof(state->code_lower)); /* Prime output buffer with a gzip header. */ state->compressed[0] = 0x1f; /* Compress */ @@ -211,9 +215,6 @@ archive_compressor_compress_init(struct archive_write *a) * code in turn. When the buffer fills up empty it and start over. */ -static unsigned char rmask[9] = - {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; - static int output_byte(struct archive_write *a, unsigned char c) { @@ -263,7 +264,7 @@ output_code(struct archive_write *a, int ocode) } /* Last bits. */ state->bit_offset += state->code_len; - state->bit_buf = ocode & rmask[bits]; + state->bit_buf = ocode & ((1 << bits) - 1); if (state->bit_offset == state->code_len * 8) state->bit_offset = 0; @@ -291,6 +292,8 @@ output_code(struct archive_write *a, int ocode) if (clear_flg) { state->code_len = 9; state->cur_maxcode = MAXCODE(state->code_len); + state->first_higher = 0; + memset(state->code_lower, 0, sizeof(state->code_lower)); } else { state->code_len++; if (state->code_len == 16) @@ -330,8 +333,9 @@ archive_compressor_compress_write(struct archive_write *a, const void *buff, struct private_data *state; int i; int ratio; - int c, disp, ret; + int ret; const unsigned char *bp; + size_t c, next1, next2; state = (struct private_data *)a->compressor.data; if (a->client_writer == NULL) { @@ -355,40 +359,26 @@ archive_compressor_compress_write(struct archive_write *a, const void *buff, while (length--) { c = *bp++; state->in_count++; - state->cur_fcode = (c << 16) + state->cur_code; - i = ((c << HSHIFT) ^ state->cur_code); /* Xor hashing. */ - - if (state->hashtab[i] == state->cur_fcode) { - state->cur_code = state->codetab[i]; - continue; - } - if (state->hashtab[i] < 0) /* Empty slot. */ - goto nomatch; - /* Secondary hash (after G. Knott). */ - if (i == 0) - disp = 1; - else - disp = HSIZE - i; - probe: - if ((i -= disp) < 0) - i += HSIZE; - if (state->hashtab[i] == state->cur_fcode) { - state->cur_code = state->codetab[i]; + if ((next1 = state->code_lower[state->cur_code * 16 + c / 16]) != 0 && + (next2 = state->code_higher[next1 * 16 + c % 16]) != 0) { + state->cur_code = next2; continue; } - if (state->hashtab[i] >= 0) - goto probe; - nomatch: ret = output_code(a, state->cur_code); if (ret != ARCHIVE_OK) return ret; - state->cur_code = c; if (state->first_free < state->max_maxcode) { - state->codetab[i] = state->first_free++; /* code -> hashtable */ - state->hashtab[i] = state->cur_fcode; + if (next1 == 0) { + next1 = ++state->first_higher; + state->code_lower[state->cur_code * 16 + c / 16] = next1; + memset(state->code_higher + next1 * 16, 0, 32); + } + state->code_higher[next1 * 16 + c % 16] = state->first_free++; + state->cur_code = c; continue; } + state->cur_code = c; if (state->in_count < state->checkpoint) continue; @@ -405,7 +395,6 @@ archive_compressor_compress_write(struct archive_write *a, const void *buff, state->compress_ratio = ratio; else { state->compress_ratio = 0; - memset(state->hashtab, 0xff, sizeof(state->hashtab)); state->first_free = FIRST; ret = output_code(a, CLEAR); if (ret != ARCHIVE_OK) @@ -416,7 +405,6 @@ archive_compressor_compress_write(struct archive_write *a, const void *buff, return (ARCHIVE_OK); } - /* * Finish the compression... */ -- 2.47.3