1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27229592Smm__FBSDID("$FreeBSD$"); 28228753Smm 29228753Smm#ifdef HAVE_ERRNO_H 30228753Smm#include <errno.h> 31228753Smm#endif 32228753Smm#ifdef HAVE_STDLIB_H 33228753Smm#include <stdlib.h> 34228753Smm#endif 35228753Smm#ifdef HAVE_STRING_H 36228753Smm#include <string.h> 37228753Smm#endif 38228753Smm 39228753Smm#include "archive.h" 40228753Smm#include "archive_private.h" 41228753Smm#include "archive_write_private.h" 42228753Smm 43228753Smmstatic int archive_compressor_none_finish(struct archive_write *a); 44228753Smmstatic int archive_compressor_none_init(struct archive_write *); 45228753Smmstatic int archive_compressor_none_write(struct archive_write *, 46228753Smm const void *, size_t); 47228753Smm 48228753Smmstruct archive_none { 49228753Smm char *buffer; 50228753Smm ssize_t buffer_size; 51228753Smm char *next; /* Current insert location */ 52228753Smm ssize_t avail; /* Free space left in buffer */ 53228753Smm}; 54228753Smm 55228753Smmint 56228753Smmarchive_write_set_compression_none(struct archive *_a) 57228753Smm{ 58228753Smm struct archive_write *a = (struct archive_write *)_a; 59228753Smm __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, 60228753Smm ARCHIVE_STATE_NEW, "archive_write_set_compression_none"); 61228753Smm a->compressor.init = &archive_compressor_none_init; 62228753Smm return (0); 63228753Smm} 64228753Smm 65228753Smm/* 66228753Smm * Setup callback. 67228753Smm */ 68228753Smmstatic int 69228753Smmarchive_compressor_none_init(struct archive_write *a) 70228753Smm{ 71228753Smm int ret; 72228753Smm struct archive_none *state; 73228753Smm 74228753Smm a->archive.compression_code = ARCHIVE_COMPRESSION_NONE; 75228753Smm a->archive.compression_name = "none"; 76228753Smm 77228753Smm if (a->client_opener != NULL) { 78228753Smm ret = (a->client_opener)(&a->archive, a->client_data); 79228753Smm if (ret != 0) 80228753Smm return (ret); 81228753Smm } 82228753Smm 83228753Smm state = (struct archive_none *)malloc(sizeof(*state)); 84228753Smm if (state == NULL) { 85228753Smm archive_set_error(&a->archive, ENOMEM, 86228753Smm "Can't allocate data for output buffering"); 87228753Smm return (ARCHIVE_FATAL); 88228753Smm } 89228753Smm memset(state, 0, sizeof(*state)); 90228753Smm 91228753Smm state->buffer_size = a->bytes_per_block; 92228753Smm if (state->buffer_size != 0) { 93228753Smm state->buffer = (char *)malloc(state->buffer_size); 94228753Smm if (state->buffer == NULL) { 95228753Smm archive_set_error(&a->archive, ENOMEM, 96228753Smm "Can't allocate output buffer"); 97228753Smm free(state); 98228753Smm return (ARCHIVE_FATAL); 99228753Smm } 100228753Smm } 101228753Smm 102228753Smm state->next = state->buffer; 103228753Smm state->avail = state->buffer_size; 104228753Smm 105228753Smm a->compressor.data = state; 106228753Smm a->compressor.write = archive_compressor_none_write; 107228753Smm a->compressor.finish = archive_compressor_none_finish; 108228753Smm return (ARCHIVE_OK); 109228753Smm} 110228753Smm 111228753Smm/* 112228753Smm * Write data to the stream. 113228753Smm */ 114228753Smmstatic int 115228753Smmarchive_compressor_none_write(struct archive_write *a, const void *vbuff, 116228753Smm size_t length) 117228753Smm{ 118228753Smm const char *buff; 119228753Smm ssize_t remaining, to_copy; 120228753Smm ssize_t bytes_written; 121228753Smm struct archive_none *state; 122228753Smm 123228753Smm state = (struct archive_none *)a->compressor.data; 124228753Smm buff = (const char *)vbuff; 125228753Smm if (a->client_writer == NULL) { 126228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, 127228753Smm "No write callback is registered? " 128228753Smm "This is probably an internal programming error."); 129228753Smm return (ARCHIVE_FATAL); 130228753Smm } 131228753Smm 132228753Smm remaining = length; 133228753Smm 134228753Smm /* 135228753Smm * If there is no buffer for blocking, just pass the data 136228753Smm * straight through to the client write callback. In 137228753Smm * particular, this supports "no write delay" operation for 138228753Smm * special applications. Just set the block size to zero. 139228753Smm */ 140228753Smm if (state->buffer_size == 0) { 141228753Smm while (remaining > 0) { 142228753Smm bytes_written = (a->client_writer)(&a->archive, 143228753Smm a->client_data, buff, remaining); 144228753Smm if (bytes_written <= 0) 145228753Smm return (ARCHIVE_FATAL); 146228753Smm a->archive.raw_position += bytes_written; 147228753Smm remaining -= bytes_written; 148228753Smm buff += bytes_written; 149228753Smm } 150228753Smm a->archive.file_position += length; 151228753Smm return (ARCHIVE_OK); 152228753Smm } 153228753Smm 154228753Smm /* If the copy buffer isn't empty, try to fill it. */ 155228753Smm if (state->avail < state->buffer_size) { 156228753Smm /* If buffer is not empty... */ 157228753Smm /* ... copy data into buffer ... */ 158228753Smm to_copy = (remaining > state->avail) ? 159228753Smm state->avail : remaining; 160228753Smm memcpy(state->next, buff, to_copy); 161228753Smm state->next += to_copy; 162228753Smm state->avail -= to_copy; 163228753Smm buff += to_copy; 164228753Smm remaining -= to_copy; 165228753Smm /* ... if it's full, write it out. */ 166228753Smm if (state->avail == 0) { 167228753Smm bytes_written = (a->client_writer)(&a->archive, 168228753Smm a->client_data, state->buffer, state->buffer_size); 169228753Smm if (bytes_written <= 0) 170228753Smm return (ARCHIVE_FATAL); 171228753Smm /* XXX TODO: if bytes_written < state->buffer_size */ 172228753Smm a->archive.raw_position += bytes_written; 173228753Smm state->next = state->buffer; 174228753Smm state->avail = state->buffer_size; 175228753Smm } 176228753Smm } 177228753Smm 178228753Smm while (remaining > state->buffer_size) { 179228753Smm /* Write out full blocks directly to client. */ 180228753Smm bytes_written = (a->client_writer)(&a->archive, 181228753Smm a->client_data, buff, state->buffer_size); 182228753Smm if (bytes_written <= 0) 183228753Smm return (ARCHIVE_FATAL); 184228753Smm a->archive.raw_position += bytes_written; 185228753Smm buff += bytes_written; 186228753Smm remaining -= bytes_written; 187228753Smm } 188228753Smm 189228753Smm if (remaining > 0) { 190228753Smm /* Copy last bit into copy buffer. */ 191228753Smm memcpy(state->next, buff, remaining); 192228753Smm state->next += remaining; 193228753Smm state->avail -= remaining; 194228753Smm } 195228753Smm 196228753Smm a->archive.file_position += length; 197228753Smm return (ARCHIVE_OK); 198228753Smm} 199228753Smm 200228753Smm 201228753Smm/* 202228753Smm * Finish the compression. 203228753Smm */ 204228753Smmstatic int 205228753Smmarchive_compressor_none_finish(struct archive_write *a) 206228753Smm{ 207228753Smm ssize_t block_length; 208228753Smm ssize_t target_block_length; 209228753Smm ssize_t bytes_written; 210228753Smm int ret; 211228753Smm struct archive_none *state; 212228753Smm 213228753Smm state = (struct archive_none *)a->compressor.data; 214228753Smm ret = ARCHIVE_OK; 215228753Smm if (a->client_writer == NULL) { 216228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, 217228753Smm "No write callback is registered? " 218228753Smm "This is probably an internal programming error."); 219228753Smm return (ARCHIVE_FATAL); 220228753Smm } 221228753Smm 222228753Smm /* If there's pending data, pad and write the last block */ 223228753Smm if (state->next != state->buffer) { 224228753Smm block_length = state->buffer_size - state->avail; 225228753Smm 226228753Smm /* Tricky calculation to determine size of last block */ 227228753Smm if (a->bytes_in_last_block <= 0) 228228753Smm /* Default or Zero: pad to full block */ 229228753Smm target_block_length = a->bytes_per_block; 230228753Smm else 231228753Smm /* Round to next multiple of bytes_in_last_block. */ 232228753Smm target_block_length = a->bytes_in_last_block * 233228753Smm ( (block_length + a->bytes_in_last_block - 1) / 234228753Smm a->bytes_in_last_block); 235228753Smm if (target_block_length > a->bytes_per_block) 236228753Smm target_block_length = a->bytes_per_block; 237228753Smm if (block_length < target_block_length) { 238228753Smm memset(state->next, 0, 239228753Smm target_block_length - block_length); 240228753Smm block_length = target_block_length; 241228753Smm } 242228753Smm bytes_written = (a->client_writer)(&a->archive, 243228753Smm a->client_data, state->buffer, block_length); 244228753Smm if (bytes_written <= 0) 245228753Smm ret = ARCHIVE_FATAL; 246228753Smm else { 247228753Smm a->archive.raw_position += bytes_written; 248228753Smm ret = ARCHIVE_OK; 249228753Smm } 250228753Smm } 251228753Smm if (state->buffer) 252228753Smm free(state->buffer); 253228753Smm free(state); 254228753Smm a->compressor.data = NULL; 255228753Smm 256228753Smm return (ret); 257228753Smm} 258