/* * Write the appropriate header. */ static int _archive_write_header(struct archive *_a, struct archive_entry *entry) { struct archive_write *a = (struct archive_write *)_a; int ret, r2; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_DATA | ARCHIVE_STATE_HEADER, "archive_write_header"); tk_archive_clear_error(&a->archive); /* In particular, "retry" and "fatal" get returned immediately. */ ret = tk_archive_write_finish_entry(&a->archive); if (ret < ARCHIVE_OK && ret != ARCHIVE_WARN) return (ret); if (a->skip_file_dev != 0 && tk_archive_entry_dev(entry) == a->skip_file_dev && a->skip_file_ino != 0 && tk_archive_entry_ino64(entry) == a->skip_file_ino) { tk_archive_set_error(&a->archive, 0, "Can't add archive to itself"); return (ARCHIVE_FAILED); } /* Format and write header. */ r2 = ((a->format_write_header)(a, entry)); if (r2 < ret) ret = r2; a->archive.state = ARCHIVE_STATE_DATA; return (ret); }
/* * Skip over all remaining data in this entry. */ int archive_read_data_skip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; int r; const void *buff; size_t size; off_t offset; __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_skip"); if (a->format->read_data_skip != NULL) r = (a->format->read_data_skip)(a); else { while ((r = archive_read_data_block(&a->archive, &buff, &size, &offset)) == ARCHIVE_OK) ; } if (r == ARCHIVE_EOF) r = ARCHIVE_OK; a->archive.state = ARCHIVE_STATE_HEADER; return (r); }
/* * Release memory and other resources. */ static int _archive_read_finish(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; int i; int slots; int r = ARCHIVE_OK; __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_finish"); if (a->archive.state != ARCHIVE_STATE_CLOSED) r = archive_read_close(&a->archive); /* Cleanup format-specific data. */ slots = sizeof(a->formats) / sizeof(a->formats[0]); for (i = 0; i < slots; i++) { a->format = &(a->formats[i]); if (a->formats[i].cleanup) (a->formats[i].cleanup)(a); } archive_string_free(&a->archive.error_string); if (a->entry) archive_entry_free(a->entry); a->archive.magic = 0; free(a); #if ARCHIVE_API_VERSION > 1 return (r); #endif }
/* * Return the value set above. -1 indicates it has not been set. */ int tk_archive_write_get_bytes_in_last_block(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_get_bytes_in_last_block"); return (a->bytes_in_last_block); }
/* * Return the file offset (within the uncompressed data stream) where * the last header started. */ int64_t archive_read_header_position(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_header_position"); return (a->header_position); }
/* * Record the do-not-extract-to file. This belongs in archive_read_extract.c. */ void archive_read_extract_set_skip_file(struct archive *_a, dev_t d, ino_t i) { struct archive_read *a = (struct archive_read *)_a; __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file"); a->skip_file_dev = d; a->skip_file_ino = i; }
/* * Set the block size. Returns 0 if successful. */ int archive_write_set_bytes_per_block(struct archive *_a, int bytes_per_block) { struct archive_write *a = (struct archive_write *)_a; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block"); a->bytes_per_block = bytes_per_block; return (ARCHIVE_OK); }
/* * Note that the compressor is responsible for blocking. */ static ssize_t _archive_write_data(struct archive *_a, const void *buff, size_t s) { struct archive_write *a = (struct archive_write *)_a; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_DATA, "archive_write_data"); tk_archive_clear_error(&a->archive); return ((a->format_write_data)(a, buff, s)); }
int archive_write_set_compression_none(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_none"); a->compressor.init = &archive_compressor_none_init; return (0); }
/* * Set the size for the last block. * Returns 0 if successful. */ int tk_archive_write_set_bytes_in_last_block(struct archive *_a, int bytes) { struct archive_write *a = (struct archive_write *)_a; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block"); a->bytes_in_last_block = bytes; return (ARCHIVE_OK); }
/* * Set read options for the format. */ int archive_read_set_format_options(struct archive *_a, const char *s) { struct archive_read *a; struct archive_format_descriptor *format; char key[64], val[64]; char *valp; size_t i; int len, r; __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_format_options"); if (s == NULL || *s == '\0') return (ARCHIVE_OK); a = (struct archive_read *)_a; __archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_format_options"); len = 0; for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) { format = &a->formats[i]; if (format == NULL || format->options == NULL || format->name == NULL) /* This format does not support option. */ continue; while ((len = __archive_parse_options(s, format->name, sizeof(key), key, sizeof(val), val)) > 0) { valp = val[0] == '\0' ? NULL : val; a->format = format; r = format->options(a, key, valp); a->format = NULL; if (r == ARCHIVE_FATAL) return (r); s += len; } } if (len < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Illegal format options."); return (ARCHIVE_WARN); } return (ARCHIVE_OK); }
int archive_read_open2(struct archive *_a, void *client_data, archive_open_callback *client_opener, archive_read_callback *client_reader, archive_skip_callback *client_skipper, archive_close_callback *client_closer) { struct archive_read *a = (struct archive_read *)_a; struct archive_read_filter *filter; int e; __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open"); archive_clear_error(&a->archive); if (client_reader == NULL) __archive_errx(1, "No reader function provided to archive_read_open"); /* Open data source. */ if (client_opener != NULL) { e =(client_opener)(&a->archive, client_data); if (e != 0) { /* If the open failed, call the closer to clean up. */ if (client_closer) (client_closer)(&a->archive, client_data); return (e); } } /* Save the client functions and mock up the initial source. */ a->client.reader = client_reader; a->client.skipper = client_skipper; a->client.closer = client_closer; filter = calloc(1, sizeof(*filter)); if (filter == NULL) return (ARCHIVE_FATAL); filter->bidder = NULL; filter->upstream = NULL; filter->archive = a; filter->data = client_data; filter->read = client_read_proxy; filter->skip = client_skip_proxy; filter->close = client_close_proxy; filter->name = "none"; filter->code = ARCHIVE_COMPRESSION_NONE; a->filter = filter; /* Build out the input pipeline. */ e = build_stream(a); if (e == ARCHIVE_OK) a->archive.state = ARCHIVE_STATE_HEADER; return (e); }
/* * dev/ino of a file to be rejected. Used to prevent adding * an archive to itself recursively. */ int tk_archive_write_set_skip_file(struct archive *_a, dev_t d, ino_t i) { struct archive_write *a = (struct archive_write *)_a; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_set_skip_file"); a->skip_file_dev = d; a->skip_file_ino = i; return (ARCHIVE_OK); }
/* * Set read options for the filter. */ int archive_read_set_filter_options(struct archive *_a, const char *s) { struct archive_read *a; struct archive_read_filter *filter; struct archive_read_filter_bidder *bidder; char key[64], val[64]; int len, r; __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_filter_options"); if (s == NULL || *s == '\0') return (ARCHIVE_OK); a = (struct archive_read *)_a; __archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_filter_options"); len = 0; for (filter = a->filter; filter != NULL; filter = filter->upstream) { bidder = filter->bidder; if (bidder == NULL) continue; if (bidder->options == NULL) /* This bidder does not support option */ continue; while ((len = __archive_parse_options(s, filter->name, sizeof(key), key, sizeof(val), val)) > 0) { if (val[0] == '\0') r = bidder->options(bidder, key, NULL); else r = bidder->options(bidder, key, val); if (r == ARCHIVE_FATAL) return (r); s += len; } } if (len < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Illegal format options."); return (ARCHIVE_WARN); } return (ARCHIVE_OK); }
/* * Allocate, initialize and return a archive object. */ int archive_write_set_compression_program(struct archive *_a, const char *cmd) { struct archive_write *a = (struct archive_write *)_a; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_program"); a->compressor.init = &archive_compressor_program_init; a->compressor.config = strdup(cmd); return (ARCHIVE_OK); }
/* * Record the do-not-extract-to file. This belongs in archive_read_extract.c. */ void archive_read_extract_set_skip_file(struct archive *_a, int64_t d, int64_t i) { struct archive_read *a = (struct archive_read *)_a; if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file")) return; a->skip_file_set = 1; a->skip_file_dev = d; a->skip_file_ino = i; }
static int _archive_write_finish_entry(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; int ret = ARCHIVE_OK; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_write_finish_entry"); if (a->archive.state & ARCHIVE_STATE_DATA) ret = (a->format_finish_entry)(a); a->archive.state = ARCHIVE_STATE_HEADER; return (ret); }
/* * This implementation minimizes copying of data and is sparse-file aware. */ int archive_read_data_into_fd(struct archive *a, int fd) { int r; const void *buff; size_t size, bytes_to_write; ssize_t bytes_written, total_written; off_t offset; off_t output_offset; __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_into_fd"); total_written = 0; output_offset = 0; while ((r = archive_read_data_block(a, &buff, &size, &offset)) == ARCHIVE_OK) { const char *p = buff; if (offset > output_offset) { output_offset = lseek(fd, offset - output_offset, SEEK_CUR); if (output_offset != offset) { archive_set_error(a, errno, "Seek error"); return (ARCHIVE_FATAL); } } while (size > 0) { bytes_to_write = size; if (bytes_to_write > MAX_WRITE) bytes_to_write = MAX_WRITE; bytes_written = write(fd, p, bytes_to_write); if (bytes_written < 0) { archive_set_error(a, errno, "Write error"); return (ARCHIVE_FATAL); } output_offset += bytes_written; total_written += bytes_written; p += bytes_written; size -= bytes_written; } } if (r != ARCHIVE_EOF) return (r); return (ARCHIVE_OK); }
/* * Set read options for the format and the filter. */ int archive_read_set_options(struct archive *_a, const char *s) { int r; __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_options"); archive_clear_error(_a); r = archive_read_set_format_options(_a, s); if (r != ARCHIVE_OK) return (r); r = archive_read_set_filter_options(_a, s); if (r != ARCHIVE_OK) return (r); return (ARCHIVE_OK); }
/* * Read the next block of entry data from the archive. * This is a zero-copy interface; the client receives a pointer, * size, and file offset of the next available block of data. * * Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if * the end of entry is encountered. */ int archive_read_data_block(struct archive *_a, const void **buff, size_t *size, off_t *offset) { struct archive_read *a = (struct archive_read *)_a; __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_block"); if (a->format->read_data == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Internal error: " "No format_read_data_block function registered"); return (ARCHIVE_FATAL); } return (a->format->read_data)(a, buff, size, offset); }
/* * Destroy the archive structure. */ static int _archive_write_finish(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; int r = ARCHIVE_OK; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_finish"); if (a->archive.state != ARCHIVE_STATE_CLOSED) r = tk_archive_write_close(&a->archive); /* Release various dynamic buffers. */ free((void *)(uintptr_t)(const void *)a->nulls); tk_archive_string_free(&a->archive.error_string); a->archive.magic = 0; free(a); return (r); }
/* * Close out the archive. * * Be careful: user might just call write_new and then write_finish. * Don't assume we actually wrote anything or performed any non-trivial * initialization. */ static int _archive_write_close(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; int r = ARCHIVE_OK, r1 = ARCHIVE_OK; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_close"); /* Finish the last entry. */ if (a->archive.state & ARCHIVE_STATE_DATA) r = ((a->format_finish_entry)(a)); /* Finish off the archive. */ if (a->format_finish != NULL) { r1 = (a->format_finish)(a); if (r1 < r) r = r1; } /* Release format resources. */ if (a->format_destroy != NULL) { r1 = (a->format_destroy)(a); if (r1 < r) r = r1; } /* Finish the compression and close the stream. */ if (a->compressor.finish != NULL) { r1 = (a->compressor.finish)(a); if (r1 < r) r = r1; } /* Close out the client stream. */ if (a->client_closer != NULL) { r1 = (a->client_closer)(&a->archive, a->client_data); if (r1 < r) r = r1; } a->archive.state = ARCHIVE_STATE_CLOSED; return (r); }
/* * Set write options for the compressor. Returns 0 if successful. */ int tk_archive_write_set_compressor_options(struct archive *_a, const char *s) { struct archive_write *a = (struct archive_write *)_a; char key[64], val[64]; int len, r; int ret = ARCHIVE_OK; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compressor_options"); tk_archive_clear_error(&a->archive); if (s == NULL || *s == '\0') return (ARCHIVE_OK); if (a->compressor.options == NULL) { tk_archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Unsupported option ``%s''", s); /* This compressor does not support option. */ return (ARCHIVE_WARN); } while ((len = __archive_parse_options(s, a->archive.compression_name, sizeof(key), key, sizeof(val), val)) > 0) { if (val[0] == '\0') r = a->compressor.options(a, key, NULL); else r = a->compressor.options(a, key, val); if (r == ARCHIVE_FATAL) return (r); if (r < ARCHIVE_OK) { tk_archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Unsupported option ``%s''", key); ret = ARCHIVE_WARN; } s += len; } if (len < 0) { tk_archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Illegal format options."); return (ARCHIVE_WARN); } return (ret); }
/* * Allocate, initialize and return an archive object. */ int archive_write_set_compression_bzip2(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; struct private_config *config; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2"); config = malloc(sizeof(*config)); if (config == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } a->compressor.config = config; a->compressor.finish = archive_compressor_bzip2_finish; config->compression_level = 9; /* default */ a->compressor.init = &archive_compressor_bzip2_init; a->compressor.options = &archive_compressor_bzip2_options; a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2; a->archive.compression_name = "bzip2"; return (ARCHIVE_OK); }
/* * Allocate, initialize and return a archive object. */ int archive_write_set_compression_xz(struct archive *_a) { struct private_config *config; struct archive_write *a = (struct archive_write *)_a; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_xz"); config = calloc(1, sizeof(*config)); if (config == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } a->compressor.config = config; a->compressor.finish = archive_compressor_xz_finish; config->compression_level = LZMA_PRESET_DEFAULT; a->compressor.init = &archive_compressor_xz_init; a->compressor.options = &archive_compressor_xz_options; a->archive.compression_code = ARCHIVE_COMPRESSION_XZ; a->archive.compression_name = "xz"; return (ARCHIVE_OK); }
/* * Open the archive using the current settings. */ int tk_archive_write_open(struct archive *_a, void *client_data, tk_archive_open_callback *opener, tk_archive_write_callback *writer, tk_archive_close_callback *closer) { struct archive_write *a = (struct archive_write *)_a; int ret; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_open"); tk_archive_clear_error(&a->archive); a->archive.state = ARCHIVE_STATE_HEADER; a->client_data = client_data; a->client_writer = writer; a->client_opener = opener; a->client_closer = closer; ret = (a->compressor.init)(a); if (a->format_init && ret == ARCHIVE_OK) ret = (a->format_init)(a); return (ret); }
/* * Used internally by decompression routines to register their bid and * initialization functions. */ struct archive_read_filter_bidder * __archive_read_get_bidder(struct archive_read *a) { int i, number_slots; __archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_get_bidder"); number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]); for (i = 0; i < number_slots; i++) { if (a->bidders[i].bid == NULL) { memset(a->bidders + i, 0, sizeof(a->bidders[0])); return (a->bidders + i); } } __archive_errx(1, "Not enough slots for compression registration"); return (NULL); /* Never actually executed. */ }
/* * Set write options for the format. Returns 0 if successful. */ int tk_archive_write_set_format_options(struct archive *_a, const char *s) { struct archive_write *a = (struct archive_write *)_a; char key[64], val[64]; int len, r, ret = ARCHIVE_OK; __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_format_options"); tk_archive_clear_error(&a->archive); if (s == NULL || *s == '\0') return (ARCHIVE_OK); if (a->format_options == NULL) /* This format does not support option. */ return (ARCHIVE_OK); while ((len = __archive_parse_options(s, a->format_name, sizeof(key), key, sizeof(val), val)) > 0) { if (val[0] == '\0') r = a->format_options(a, key, NULL); else r = a->format_options(a, key, val); if (r == ARCHIVE_FATAL) return (r); if (r < ARCHIVE_OK) { /* This key was not handled. */ tk_archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Unsupported option ``%s''", key); ret = ARCHIVE_WARN; } s += len; } if (len < 0) { tk_archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Malformed options string."); return (ARCHIVE_WARN); } return (ret); }
/* * Used internally by read format handlers to register their bid and * initialization functions. */ int __archive_read_register_format(struct archive_read *a, void *format_data, const char *name, int (*bid)(struct archive_read *), int (*options)(struct archive_read *, const char *, const char *), int (*read_header)(struct archive_read *, struct archive_entry *), int (*read_data)(struct archive_read *, const void **, size_t *, off_t *), int (*read_data_skip)(struct archive_read *), int (*cleanup)(struct archive_read *)) { int i, number_slots; __archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_format"); number_slots = sizeof(a->formats) / sizeof(a->formats[0]); for (i = 0; i < number_slots; i++) { if (a->formats[i].bid == bid) return (ARCHIVE_WARN); /* We've already installed */ if (a->formats[i].bid == NULL) { a->formats[i].bid = bid; a->formats[i].options = options; a->formats[i].read_header = read_header; a->formats[i].read_data = read_data; a->formats[i].read_data_skip = read_data_skip; a->formats[i].cleanup = cleanup; a->formats[i].data = format_data; a->formats[i].name = name; return (ARCHIVE_OK); } } __archive_errx(1, "Not enough slots for format registration"); return (ARCHIVE_FATAL); /* Never actually called. */ }
/* * Close the file and release most resources. * * Be careful: client might just call read_new and then read_finish. * Don't assume we actually read anything or performed any non-trivial * initialization. */ static int _archive_read_close(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; int r = ARCHIVE_OK, r1 = ARCHIVE_OK; size_t i, n; __archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_close"); archive_clear_error(&a->archive); a->archive.state = ARCHIVE_STATE_CLOSED; /* Call cleanup functions registered by optional components. */ if (a->cleanup_archive_extract != NULL) r = (a->cleanup_archive_extract)(a); /* TODO: Clean up the formatters. */ /* Release the filter objects. */ r1 = cleanup_filters(a); if (r1 < r) r = r1; /* Release the bidder objects. */ n = sizeof(a->bidders)/sizeof(a->bidders[0]); for (i = 0; i < n; i++) { if (a->bidders[i].free != NULL) { r1 = (a->bidders[i].free)(&a->bidders[i]); if (r1 < r) r = r1; } } return (r); }