archive_write_set_compression_none.c revision 229592
1/*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "archive_platform.h" 27__FBSDID("$FreeBSD: stable/9/contrib/libarchive/libarchive/archive_write_set_compression_none.c 229592 2012-01-05 12:06:54Z mm $"); 28 29#ifdef HAVE_ERRNO_H 30#include <errno.h> 31#endif 32#ifdef HAVE_STDLIB_H 33#include <stdlib.h> 34#endif 35#ifdef HAVE_STRING_H 36#include <string.h> 37#endif 38 39#include "archive.h" 40#include "archive_private.h" 41#include "archive_write_private.h" 42 43static int archive_compressor_none_finish(struct archive_write *a); 44static int archive_compressor_none_init(struct archive_write *); 45static int archive_compressor_none_write(struct archive_write *, 46 const void *, size_t); 47 48struct archive_none { 49 char *buffer; 50 ssize_t buffer_size; 51 char *next; /* Current insert location */ 52 ssize_t avail; /* Free space left in buffer */ 53}; 54 55int 56archive_write_set_compression_none(struct archive *_a) 57{ 58 struct archive_write *a = (struct archive_write *)_a; 59 __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, 60 ARCHIVE_STATE_NEW, "archive_write_set_compression_none"); 61 a->compressor.init = &archive_compressor_none_init; 62 return (0); 63} 64 65/* 66 * Setup callback. 67 */ 68static int 69archive_compressor_none_init(struct archive_write *a) 70{ 71 int ret; 72 struct archive_none *state; 73 74 a->archive.compression_code = ARCHIVE_COMPRESSION_NONE; 75 a->archive.compression_name = "none"; 76 77 if (a->client_opener != NULL) { 78 ret = (a->client_opener)(&a->archive, a->client_data); 79 if (ret != 0) 80 return (ret); 81 } 82 83 state = (struct archive_none *)malloc(sizeof(*state)); 84 if (state == NULL) { 85 archive_set_error(&a->archive, ENOMEM, 86 "Can't allocate data for output buffering"); 87 return (ARCHIVE_FATAL); 88 } 89 memset(state, 0, sizeof(*state)); 90 91 state->buffer_size = a->bytes_per_block; 92 if (state->buffer_size != 0) { 93 state->buffer = (char *)malloc(state->buffer_size); 94 if (state->buffer == NULL) { 95 archive_set_error(&a->archive, ENOMEM, 96 "Can't allocate output buffer"); 97 free(state); 98 return (ARCHIVE_FATAL); 99 } 100 } 101 102 state->next = state->buffer; 103 state->avail = state->buffer_size; 104 105 a->compressor.data = state; 106 a->compressor.write = archive_compressor_none_write; 107 a->compressor.finish = archive_compressor_none_finish; 108 return (ARCHIVE_OK); 109} 110 111/* 112 * Write data to the stream. 113 */ 114static int 115archive_compressor_none_write(struct archive_write *a, const void *vbuff, 116 size_t length) 117{ 118 const char *buff; 119 ssize_t remaining, to_copy; 120 ssize_t bytes_written; 121 struct archive_none *state; 122 123 state = (struct archive_none *)a->compressor.data; 124 buff = (const char *)vbuff; 125 if (a->client_writer == NULL) { 126 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, 127 "No write callback is registered? " 128 "This is probably an internal programming error."); 129 return (ARCHIVE_FATAL); 130 } 131 132 remaining = length; 133 134 /* 135 * If there is no buffer for blocking, just pass the data 136 * straight through to the client write callback. In 137 * particular, this supports "no write delay" operation for 138 * special applications. Just set the block size to zero. 139 */ 140 if (state->buffer_size == 0) { 141 while (remaining > 0) { 142 bytes_written = (a->client_writer)(&a->archive, 143 a->client_data, buff, remaining); 144 if (bytes_written <= 0) 145 return (ARCHIVE_FATAL); 146 a->archive.raw_position += bytes_written; 147 remaining -= bytes_written; 148 buff += bytes_written; 149 } 150 a->archive.file_position += length; 151 return (ARCHIVE_OK); 152 } 153 154 /* If the copy buffer isn't empty, try to fill it. */ 155 if (state->avail < state->buffer_size) { 156 /* If buffer is not empty... */ 157 /* ... copy data into buffer ... */ 158 to_copy = (remaining > state->avail) ? 159 state->avail : remaining; 160 memcpy(state->next, buff, to_copy); 161 state->next += to_copy; 162 state->avail -= to_copy; 163 buff += to_copy; 164 remaining -= to_copy; 165 /* ... if it's full, write it out. */ 166 if (state->avail == 0) { 167 bytes_written = (a->client_writer)(&a->archive, 168 a->client_data, state->buffer, state->buffer_size); 169 if (bytes_written <= 0) 170 return (ARCHIVE_FATAL); 171 /* XXX TODO: if bytes_written < state->buffer_size */ 172 a->archive.raw_position += bytes_written; 173 state->next = state->buffer; 174 state->avail = state->buffer_size; 175 } 176 } 177 178 while (remaining > state->buffer_size) { 179 /* Write out full blocks directly to client. */ 180 bytes_written = (a->client_writer)(&a->archive, 181 a->client_data, buff, state->buffer_size); 182 if (bytes_written <= 0) 183 return (ARCHIVE_FATAL); 184 a->archive.raw_position += bytes_written; 185 buff += bytes_written; 186 remaining -= bytes_written; 187 } 188 189 if (remaining > 0) { 190 /* Copy last bit into copy buffer. */ 191 memcpy(state->next, buff, remaining); 192 state->next += remaining; 193 state->avail -= remaining; 194 } 195 196 a->archive.file_position += length; 197 return (ARCHIVE_OK); 198} 199 200 201/* 202 * Finish the compression. 203 */ 204static int 205archive_compressor_none_finish(struct archive_write *a) 206{ 207 ssize_t block_length; 208 ssize_t target_block_length; 209 ssize_t bytes_written; 210 int ret; 211 struct archive_none *state; 212 213 state = (struct archive_none *)a->compressor.data; 214 ret = ARCHIVE_OK; 215 if (a->client_writer == NULL) { 216 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, 217 "No write callback is registered? " 218 "This is probably an internal programming error."); 219 return (ARCHIVE_FATAL); 220 } 221 222 /* If there's pending data, pad and write the last block */ 223 if (state->next != state->buffer) { 224 block_length = state->buffer_size - state->avail; 225 226 /* Tricky calculation to determine size of last block */ 227 if (a->bytes_in_last_block <= 0) 228 /* Default or Zero: pad to full block */ 229 target_block_length = a->bytes_per_block; 230 else 231 /* Round to next multiple of bytes_in_last_block. */ 232 target_block_length = a->bytes_in_last_block * 233 ( (block_length + a->bytes_in_last_block - 1) / 234 a->bytes_in_last_block); 235 if (target_block_length > a->bytes_per_block) 236 target_block_length = a->bytes_per_block; 237 if (block_length < target_block_length) { 238 memset(state->next, 0, 239 target_block_length - block_length); 240 block_length = target_block_length; 241 } 242 bytes_written = (a->client_writer)(&a->archive, 243 a->client_data, state->buffer, block_length); 244 if (bytes_written <= 0) 245 ret = ARCHIVE_FATAL; 246 else { 247 a->archive.raw_position += bytes_written; 248 ret = ARCHIVE_OK; 249 } 250 } 251 if (state->buffer) 252 free(state->buffer); 253 free(state); 254 a->compressor.data = NULL; 255 256 return (ret); 257} 258