~sergei.glushchenko/percona-xtrabackup/xb-pprint

« back to all changes in this revision

Viewing changes to src/libarchive/libarchive/archive_write_set_compression_xz.c

merge parallel compression branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 2009 Michihiro NAKAJIMA
 
3
 * Copyright (c) 2003-2007 Tim Kientzle
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 * 1. Redistributions of source code must retain the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer.
 
11
 * 2. Redistributions in binary form must reproduce the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer in the
 
13
 *    documentation and/or other materials provided with the distribution.
 
14
 *
 
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 
16
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
17
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
18
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 
19
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
20
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
21
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
22
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
24
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
25
 */
 
26
 
 
27
#include "archive_platform.h"
 
28
 
 
29
__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_xz.c 201108 2009-12-28 03:28:21Z kientzle $");
 
30
 
 
31
#ifdef HAVE_ERRNO_H
 
32
#include <errno.h>
 
33
#endif
 
34
#ifdef HAVE_STDLIB_H
 
35
#include <stdlib.h>
 
36
#endif
 
37
#ifdef HAVE_STRING_H
 
38
#include <string.h>
 
39
#endif
 
40
#include <time.h>
 
41
#ifdef HAVE_LZMA_H
 
42
#include <lzma.h>
 
43
#endif
 
44
 
 
45
#include "archive.h"
 
46
#include "archive_private.h"
 
47
#include "archive_write_private.h"
 
48
 
 
49
#ifndef HAVE_LZMA_H
 
50
int
 
51
archive_write_set_compression_xz(struct archive *a)
 
52
{
 
53
        archive_set_error(a, ARCHIVE_ERRNO_MISC,
 
54
            "xz compression not supported on this platform");
 
55
        return (ARCHIVE_FATAL);
 
56
}
 
57
 
 
58
int
 
59
archive_write_set_compression_lzma(struct archive *a)
 
60
{
 
61
        archive_set_error(a, ARCHIVE_ERRNO_MISC,
 
62
            "lzma compression not supported on this platform");
 
63
        return (ARCHIVE_FATAL);
 
64
}
 
65
#else
 
66
/* Don't compile this if we don't have liblzma. */
 
67
 
 
68
struct private_data {
 
69
        lzma_stream      stream;
 
70
        lzma_filter      lzmafilters[2];
 
71
        lzma_options_lzma lzma_opt;
 
72
        int64_t          total_in;
 
73
        unsigned char   *compressed;
 
74
        size_t           compressed_buffer_size;
 
75
};
 
76
 
 
77
struct private_config {
 
78
        int              compression_level;
 
79
};
 
80
 
 
81
static int      archive_compressor_xz_init(struct archive_write *);
 
82
static int      archive_compressor_xz_options(struct archive_write *,
 
83
                    const char *, const char *);
 
84
static int      archive_compressor_xz_finish(struct archive_write *);
 
85
static int      archive_compressor_xz_write(struct archive_write *,
 
86
                    const void *, size_t);
 
87
static int      drive_compressor(struct archive_write *, struct private_data *,
 
88
                    int finishing);
 
89
 
 
90
 
 
91
/*
 
92
 * Allocate, initialize and return a archive object.
 
93
 */
 
94
int
 
95
archive_write_set_compression_xz(struct archive *_a)
 
96
{
 
97
        struct private_config *config;
 
98
        struct archive_write *a = (struct archive_write *)_a;
 
99
        __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 
100
            ARCHIVE_STATE_NEW, "archive_write_set_compression_xz");
 
101
        config = calloc(1, sizeof(*config));
 
102
        if (config == NULL) {
 
103
                archive_set_error(&a->archive, ENOMEM, "Out of memory");
 
104
                return (ARCHIVE_FATAL);
 
105
        }
 
106
        a->compressor.config = config;
 
107
        a->compressor.finish = archive_compressor_xz_finish;
 
108
        config->compression_level = LZMA_PRESET_DEFAULT;
 
109
        a->compressor.init = &archive_compressor_xz_init;
 
110
        a->compressor.options = &archive_compressor_xz_options;
 
111
        a->archive.compression_code = ARCHIVE_COMPRESSION_XZ;
 
112
        a->archive.compression_name = "xz";
 
113
        return (ARCHIVE_OK);
 
114
}
 
115
 
 
116
/* LZMA is handled identically, we just need a different compression
 
117
 * code set.  (The liblzma setup looks at the code to determine
 
118
 * the one place that XZ and LZMA require different handling.) */
 
119
int
 
120
archive_write_set_compression_lzma(struct archive *_a)
 
121
{
 
122
        struct archive_write *a = (struct archive_write *)_a;
 
123
        int r = archive_write_set_compression_xz(_a);
 
124
        if (r != ARCHIVE_OK)
 
125
                return (r);
 
126
        a->archive.compression_code = ARCHIVE_COMPRESSION_LZMA;
 
127
        a->archive.compression_name = "lzma";
 
128
        return (ARCHIVE_OK);
 
129
}
 
130
 
 
131
static int
 
132
archive_compressor_xz_init_stream(struct archive_write *a,
 
133
    struct private_data *state)
 
134
{
 
135
        int ret;
 
136
 
 
137
        state->stream = (lzma_stream)LZMA_STREAM_INIT;
 
138
        state->stream.next_out = state->compressed;
 
139
        state->stream.avail_out = state->compressed_buffer_size;
 
140
        if (a->archive.compression_code == ARCHIVE_COMPRESSION_XZ)
 
141
                ret = lzma_stream_encoder(&(state->stream),
 
142
                    state->lzmafilters, LZMA_CHECK_CRC64);
 
143
        else
 
144
                ret = lzma_alone_encoder(&(state->stream), &state->lzma_opt);
 
145
        if (ret == LZMA_OK)
 
146
                return (ARCHIVE_OK);
 
147
 
 
148
        switch (ret) {
 
149
        case LZMA_MEM_ERROR:
 
150
                archive_set_error(&a->archive, ENOMEM,
 
151
                    "Internal error initializing compression library: "
 
152
                    "Cannot allocate memory");
 
153
                break;
 
154
        default:
 
155
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 
156
                    "Internal error initializing compression library: "
 
157
                    "It's a bug in liblzma");
 
158
                break;
 
159
        }
 
160
        return (ARCHIVE_FATAL);
 
161
}
 
162
 
 
163
/*
 
164
 * Setup callback.
 
165
 */
 
166
static int
 
167
archive_compressor_xz_init(struct archive_write *a)
 
168
{
 
169
        int ret;
 
170
        struct private_data *state;
 
171
        struct private_config *config;
 
172
 
 
173
        if (a->client_opener != NULL) {
 
174
                ret = (a->client_opener)(&a->archive, a->client_data);
 
175
                if (ret != ARCHIVE_OK)
 
176
                        return (ret);
 
177
        }
 
178
 
 
179
        state = (struct private_data *)malloc(sizeof(*state));
 
180
        if (state == NULL) {
 
181
                archive_set_error(&a->archive, ENOMEM,
 
182
                    "Can't allocate data for compression");
 
183
                return (ARCHIVE_FATAL);
 
184
        }
 
185
        memset(state, 0, sizeof(*state));
 
186
        config = a->compressor.config;
 
187
 
 
188
        /*
 
189
         * See comment above.  We should set compressed_buffer_size to
 
190
         * max(bytes_per_block, 65536), but the code can't handle that yet.
 
191
         */
 
192
        state->compressed_buffer_size = a->bytes_per_block;
 
193
        state->compressed = (unsigned char *)malloc(state->compressed_buffer_size);
 
194
        if (state->compressed == NULL) {
 
195
                archive_set_error(&a->archive, ENOMEM,
 
196
                    "Can't allocate data for compression buffer");
 
197
                free(state);
 
198
                return (ARCHIVE_FATAL);
 
199
        }
 
200
        a->compressor.write = archive_compressor_xz_write;
 
201
 
 
202
        /* Initialize compression library. */
 
203
        if (lzma_lzma_preset(&state->lzma_opt, config->compression_level)) {
 
204
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 
205
                    "Internal error initializing compression library");
 
206
                free(state->compressed);
 
207
                free(state);
 
208
        }
 
209
        state->lzmafilters[0].id = LZMA_FILTER_LZMA2;
 
210
        state->lzmafilters[0].options = &state->lzma_opt;
 
211
        state->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
 
212
        ret = archive_compressor_xz_init_stream(a, state);
 
213
        if (ret == LZMA_OK) {
 
214
                a->compressor.data = state;
 
215
                return (0);
 
216
        }
 
217
        /* Library setup failed: clean up. */
 
218
        free(state->compressed);
 
219
        free(state);
 
220
 
 
221
        return (ARCHIVE_FATAL);
 
222
}
 
223
 
 
224
/*
 
225
 * Set write options.
 
226
 */
 
227
static int
 
228
archive_compressor_xz_options(struct archive_write *a, const char *key,
 
229
    const char *value)
 
230
{
 
231
        struct private_config *config;
 
232
 
 
233
        config = (struct private_config *)a->compressor.config;
 
234
        if (strcmp(key, "compression-level") == 0) {
 
235
                if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
 
236
                    value[1] != '\0')
 
237
                        return (ARCHIVE_WARN);
 
238
                config->compression_level = value[0] - '0';
 
239
                if (config->compression_level > 6)
 
240
                        config->compression_level = 6;
 
241
                return (ARCHIVE_OK);
 
242
        }
 
243
 
 
244
        return (ARCHIVE_WARN);
 
245
}
 
246
 
 
247
/*
 
248
 * Write data to the compressed stream.
 
249
 */
 
250
static int
 
251
archive_compressor_xz_write(struct archive_write *a, const void *buff,
 
252
    size_t length)
 
253
{
 
254
        struct private_data *state;
 
255
        int ret;
 
256
 
 
257
        state = (struct private_data *)a->compressor.data;
 
258
        if (a->client_writer == NULL) {
 
259
                archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
 
260
                    "No write callback is registered?  "
 
261
                    "This is probably an internal programming error.");
 
262
                return (ARCHIVE_FATAL);
 
263
        }
 
264
 
 
265
        /* Update statistics */
 
266
        state->total_in += length;
 
267
 
 
268
        /* Compress input data to output buffer */
 
269
        state->stream.next_in = buff;
 
270
        state->stream.avail_in = length;
 
271
        if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
 
272
                return (ret);
 
273
 
 
274
        a->archive.file_position += length;
 
275
        return (ARCHIVE_OK);
 
276
}
 
277
 
 
278
 
 
279
/*
 
280
 * Finish the compression...
 
281
 */
 
282
static int
 
283
archive_compressor_xz_finish(struct archive_write *a)
 
284
{
 
285
        ssize_t block_length, target_block_length, bytes_written;
 
286
        int ret;
 
287
        struct private_data *state;
 
288
        unsigned tocopy;
 
289
 
 
290
        ret = ARCHIVE_OK;
 
291
        state = (struct private_data *)a->compressor.data;
 
292
        if (state != NULL) {
 
293
                if (a->client_writer == NULL) {
 
294
                        archive_set_error(&a->archive,
 
295
                            ARCHIVE_ERRNO_PROGRAMMER,
 
296
                            "No write callback is registered?  "
 
297
                            "This is probably an internal programming error.");
 
298
                        ret = ARCHIVE_FATAL;
 
299
                        goto cleanup;
 
300
                }
 
301
 
 
302
                /* By default, always pad the uncompressed data. */
 
303
                if (a->pad_uncompressed) {
 
304
                        tocopy = a->bytes_per_block -
 
305
                            (state->total_in % a->bytes_per_block);
 
306
                        while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
 
307
                                state->stream.next_in = a->nulls;
 
308
                                state->stream.avail_in = tocopy < a->null_length ?
 
309
                                    tocopy : a->null_length;
 
310
                                state->total_in += state->stream.avail_in;
 
311
                                tocopy -= state->stream.avail_in;
 
312
                                ret = drive_compressor(a, state, 0);
 
313
                                if (ret != ARCHIVE_OK)
 
314
                                        goto cleanup;
 
315
                        }
 
316
                }
 
317
 
 
318
                /* Finish compression cycle */
 
319
                if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
 
320
                        goto cleanup;
 
321
 
 
322
                /* Optionally, pad the final compressed block. */
 
323
                block_length = state->stream.next_out - state->compressed;
 
324
 
 
325
                /* Tricky calculation to determine size of last block. */
 
326
                if (a->bytes_in_last_block <= 0)
 
327
                        /* Default or Zero: pad to full block */
 
328
                        target_block_length = a->bytes_per_block;
 
329
                else
 
330
                        /* Round length to next multiple of bytes_in_last_block. */
 
331
                        target_block_length = a->bytes_in_last_block *
 
332
                            ( (block_length + a->bytes_in_last_block - 1) /
 
333
                                a->bytes_in_last_block);
 
334
                if (target_block_length > a->bytes_per_block)
 
335
                        target_block_length = a->bytes_per_block;
 
336
                if (block_length < target_block_length) {
 
337
                        memset(state->stream.next_out, 0,
 
338
                            target_block_length - block_length);
 
339
                        block_length = target_block_length;
 
340
                }
 
341
 
 
342
                /* Write the last block */
 
343
                bytes_written = (a->client_writer)(&a->archive, a->client_data,
 
344
                    state->compressed, block_length);
 
345
                if (bytes_written <= 0) {
 
346
                        ret = ARCHIVE_FATAL;
 
347
                        goto cleanup;
 
348
                }
 
349
                a->archive.raw_position += bytes_written;
 
350
 
 
351
                /* Cleanup: shut down compressor, release memory, etc. */
 
352
        cleanup:
 
353
                lzma_end(&(state->stream));
 
354
                free(state->compressed);
 
355
                free(state);
 
356
        }
 
357
        free(a->compressor.config);
 
358
        a->compressor.config = NULL;
 
359
        return (ret);
 
360
}
 
361
 
 
362
/*
 
363
 * Utility function to push input data through compressor,
 
364
 * writing full output blocks as necessary.
 
365
 *
 
366
 * Note that this handles both the regular write case (finishing ==
 
367
 * false) and the end-of-archive case (finishing == true).
 
368
 */
 
369
static int
 
370
drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
 
371
{
 
372
        ssize_t bytes_written;
 
373
        int ret;
 
374
 
 
375
        for (;;) {
 
376
                if (state->stream.avail_out == 0) {
 
377
                        bytes_written = (a->client_writer)(&a->archive,
 
378
                            a->client_data, state->compressed,
 
379
                            state->compressed_buffer_size);
 
380
                        if (bytes_written <= 0) {
 
381
                                /* TODO: Handle this write failure */
 
382
                                return (ARCHIVE_FATAL);
 
383
                        } else if ((size_t)bytes_written < state->compressed_buffer_size) {
 
384
                                /* Short write: Move remaining to
 
385
                                 * front of block and keep filling */
 
386
                                memmove(state->compressed,
 
387
                                    state->compressed + bytes_written,
 
388
                                    state->compressed_buffer_size - bytes_written);
 
389
                        }
 
390
                        a->archive.raw_position += bytes_written;
 
391
                        state->stream.next_out
 
392
                            = state->compressed +
 
393
                            state->compressed_buffer_size - bytes_written;
 
394
                        state->stream.avail_out = bytes_written;
 
395
                }
 
396
 
 
397
                /* If there's nothing to do, we're done. */
 
398
                if (!finishing && state->stream.avail_in == 0)
 
399
                        return (ARCHIVE_OK);
 
400
 
 
401
                ret = lzma_code(&(state->stream),
 
402
                    finishing ? LZMA_FINISH : LZMA_RUN );
 
403
 
 
404
                switch (ret) {
 
405
                case LZMA_OK:
 
406
                        /* In non-finishing case, check if compressor
 
407
                         * consumed everything */
 
408
                        if (!finishing && state->stream.avail_in == 0)
 
409
                                return (ARCHIVE_OK);
 
410
                        /* In finishing case, this return always means
 
411
                         * there's more work */
 
412
                        break;
 
413
                case LZMA_STREAM_END:
 
414
                        /* This return can only occur in finishing case. */
 
415
                        if (finishing)
 
416
                                return (ARCHIVE_OK);
 
417
                        archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 
418
                            "lzma compression data error");
 
419
                        return (ARCHIVE_FATAL);
 
420
                case LZMA_MEMLIMIT_ERROR:
 
421
                        archive_set_error(&a->archive, ENOMEM,
 
422
                            "lzma compression error: "
 
423
                            "%ju MiB would have been needed",
 
424
                            (lzma_memusage(&(state->stream)) + 1024 * 1024 -1)
 
425
                            / (1024 * 1024));
 
426
                        return (ARCHIVE_FATAL);
 
427
                default:
 
428
                        /* Any other return value indicates an error. */
 
429
                        archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 
430
                            "lzma compression failed:"
 
431
                            " lzma_code() call returned status %d",
 
432
                            ret);
 
433
                        return (ARCHIVE_FATAL);
 
434
                }
 
435
        }
 
436
}
 
437
 
 
438
#endif /* HAVE_LZMA_H */