Home | History | Annotate | Line # | Download | only in libarchive
      1 /*-
      2  * Copyright (c) 2007 Joerg Sonnenberger
      3  * Copyright (c) 2012 Michihiro NAKAJIMA
      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 #ifdef HAVE_SYS_WAIT_H
     30 #  include <sys/wait.h>
     31 #endif
     32 #ifdef HAVE_ERRNO_H
     33 #  include <errno.h>
     34 #endif
     35 #ifdef HAVE_FCNTL_H
     36 #  include <fcntl.h>
     37 #endif
     38 #ifdef HAVE_STDLIB_H
     39 #  include <stdlib.h>
     40 #endif
     41 #ifdef HAVE_STRING_H
     42 #  include <string.h>
     43 #endif
     44 
     45 #include "archive.h"
     46 #include "archive_private.h"
     47 #include "archive_string.h"
     48 #include "archive_write_private.h"
     49 #include "filter_fork.h"
     50 
     51 #if ARCHIVE_VERSION_NUMBER < 4000000
     52 int
     53 archive_write_set_compression_program(struct archive *a, const char *cmd)
     54 {
     55 	__archive_write_filters_free(a);
     56 	return (archive_write_add_filter_program(a, cmd));
     57 }
     58 #endif
     59 
     60 struct archive_write_program_data {
     61 #if defined(_WIN32) && !defined(__CYGWIN__)
     62 	HANDLE		 child;
     63 #else
     64 	pid_t		 child;
     65 #endif
     66 	int		 child_stdin, child_stdout;
     67 
     68 	char		*child_buf;
     69 	size_t		 child_buf_len, child_buf_avail;
     70 	char		*program_name;
     71 };
     72 
     73 struct private_data {
     74 	struct archive_write_program_data *pdata;
     75 	struct archive_string description;
     76 	char		*cmd;
     77 };
     78 
     79 static int archive_compressor_program_open(struct archive_write_filter *);
     80 static int archive_compressor_program_write(struct archive_write_filter *,
     81 		    const void *, size_t);
     82 static int archive_compressor_program_close(struct archive_write_filter *);
     83 static int archive_compressor_program_free(struct archive_write_filter *);
     84 
     85 /*
     86  * Add a filter to this write handle that passes all data through an
     87  * external program.
     88  */
     89 int
     90 archive_write_add_filter_program(struct archive *_a, const char *cmd)
     91 {
     92 	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
     93 	struct private_data *data;
     94 	static const char prefix[] = "Program: ";
     95 
     96 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
     97 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_program");
     98 
     99 	f->data = calloc(1, sizeof(*data));
    100 	if (f->data == NULL)
    101 		goto memerr;
    102 	data = (struct private_data *)f->data;
    103 
    104 	data->cmd = strdup(cmd);
    105 	if (data->cmd == NULL)
    106 		goto memerr;
    107 
    108 	data->pdata = __archive_write_program_allocate(cmd);
    109 	if (data->pdata == NULL)
    110 		goto memerr;
    111 
    112 	/* Make up a description string. */
    113 	if (archive_string_ensure(&data->description,
    114 	    strlen(prefix) + strlen(cmd) + 1) == NULL)
    115 		goto memerr;
    116 	archive_strcpy(&data->description, prefix);
    117 	archive_strcat(&data->description, cmd);
    118 
    119 	f->name = data->description.s;
    120 	f->code = ARCHIVE_FILTER_PROGRAM;
    121 	f->open = archive_compressor_program_open;
    122 	f->write = archive_compressor_program_write;
    123 	f->close = archive_compressor_program_close;
    124 	f->free = archive_compressor_program_free;
    125 	return (ARCHIVE_OK);
    126 memerr:
    127 	archive_compressor_program_free(f);
    128 	archive_set_error(_a, ENOMEM,
    129 	    "Can't allocate memory for filter program");
    130 	return (ARCHIVE_FATAL);
    131 }
    132 
    133 static int
    134 archive_compressor_program_open(struct archive_write_filter *f)
    135 {
    136 	struct private_data *data = (struct private_data *)f->data;
    137 
    138 	return __archive_write_program_open(f, data->pdata, data->cmd);
    139 }
    140 
    141 static int
    142 archive_compressor_program_write(struct archive_write_filter *f,
    143     const void *buff, size_t length)
    144 {
    145 	struct private_data *data = (struct private_data *)f->data;
    146 
    147 	return __archive_write_program_write(f, data->pdata, buff, length);
    148 }
    149 
    150 static int
    151 archive_compressor_program_close(struct archive_write_filter *f)
    152 {
    153 	struct private_data *data = (struct private_data *)f->data;
    154 
    155 	return __archive_write_program_close(f, data->pdata);
    156 }
    157 
    158 static int
    159 archive_compressor_program_free(struct archive_write_filter *f)
    160 {
    161 	struct private_data *data = (struct private_data *)f->data;
    162 
    163 	if (data) {
    164 		free(data->cmd);
    165 		archive_string_free(&data->description);
    166 		__archive_write_program_free(data->pdata);
    167 		free(data);
    168 		f->data = NULL;
    169 	}
    170 	return (ARCHIVE_OK);
    171 }
    172 
    173 /*
    174  * Allocate resources for executing an external program.
    175  */
    176 struct archive_write_program_data *
    177 __archive_write_program_allocate(const char *program)
    178 {
    179 	struct archive_write_program_data *data;
    180 
    181 	data = calloc(1, sizeof(struct archive_write_program_data));
    182 	if (data == NULL)
    183 		return (data);
    184 	data->child_stdin = -1;
    185 	data->child_stdout = -1;
    186 	data->program_name = strdup(program);
    187 	return (data);
    188 }
    189 
    190 /*
    191  * Release the resources.
    192  */
    193 int
    194 __archive_write_program_free(struct archive_write_program_data *data)
    195 {
    196 
    197 	if (data) {
    198 		free(data->program_name);
    199 		free(data->child_buf);
    200 		free(data);
    201 	}
    202 	return (ARCHIVE_OK);
    203 }
    204 
    205 int
    206 __archive_write_program_open(struct archive_write_filter *f,
    207     struct archive_write_program_data *data, const char *cmd)
    208 {
    209 	int ret;
    210 
    211 	if (data->child_buf == NULL) {
    212 		data->child_buf_len = 65536;
    213 		data->child_buf_avail = 0;
    214 		data->child_buf = malloc(data->child_buf_len);
    215 
    216 		if (data->child_buf == NULL) {
    217 			archive_set_error(f->archive, ENOMEM,
    218 			    "Can't allocate compression buffer");
    219 			return (ARCHIVE_FATAL);
    220 		}
    221 	}
    222 
    223 	ret = __archive_create_child(cmd, &data->child_stdin,
    224 		    &data->child_stdout, &data->child);
    225 	if (ret != ARCHIVE_OK) {
    226 		archive_set_error(f->archive, EINVAL,
    227 		    "Can't launch external program: %s", cmd);
    228 		return (ARCHIVE_FATAL);
    229 	}
    230 	return (ARCHIVE_OK);
    231 }
    232 
    233 static ssize_t
    234 child_write(struct archive_write_filter *f,
    235     struct archive_write_program_data *data, const char *buf, size_t buf_len)
    236 {
    237 	ssize_t ret;
    238 
    239 	if (data->child_stdin == -1)
    240 		return (-1);
    241 
    242 	if (buf_len == 0)
    243 		return (-1);
    244 
    245 	for (;;) {
    246 		do {
    247 			ret = write(data->child_stdin, buf, buf_len);
    248 		} while (ret == -1 && errno == EINTR);
    249 
    250 		if (ret > 0)
    251 			return (ret);
    252 		if (ret == 0) {
    253 			close(data->child_stdin);
    254 			data->child_stdin = -1;
    255 			fcntl(data->child_stdout, F_SETFL, 0);
    256 			return (0);
    257 		}
    258 		if (ret == -1 && errno != EAGAIN)
    259 			return (-1);
    260 
    261 		if (data->child_stdout == -1) {
    262 			fcntl(data->child_stdin, F_SETFL, 0);
    263 			__archive_check_child(data->child_stdin,
    264 				data->child_stdout);
    265 			continue;
    266 		}
    267 
    268 		do {
    269 			ret = read(data->child_stdout,
    270 			    data->child_buf + data->child_buf_avail,
    271 			    data->child_buf_len - data->child_buf_avail);
    272 		} while (ret == -1 && errno == EINTR);
    273 
    274 		if (ret == 0 || (ret == -1 && errno == EPIPE)) {
    275 			close(data->child_stdout);
    276 			data->child_stdout = -1;
    277 			fcntl(data->child_stdin, F_SETFL, 0);
    278 			continue;
    279 		}
    280 		if (ret == -1 && errno == EAGAIN) {
    281 			__archive_check_child(data->child_stdin,
    282 				data->child_stdout);
    283 			continue;
    284 		}
    285 		if (ret == -1)
    286 			return (-1);
    287 
    288 		data->child_buf_avail += ret;
    289 
    290 		ret = __archive_write_filter(f->next_filter,
    291 		    data->child_buf, data->child_buf_avail);
    292 		if (ret != ARCHIVE_OK)
    293 			return (-1);
    294 		data->child_buf_avail = 0;
    295 	}
    296 }
    297 
    298 /*
    299  * Write data to the filter stream.
    300  */
    301 int
    302 __archive_write_program_write(struct archive_write_filter *f,
    303     struct archive_write_program_data *data, const void *buff, size_t length)
    304 {
    305 	ssize_t ret;
    306 	const char *buf;
    307 
    308 	if (data->child == 0)
    309 		return (ARCHIVE_OK);
    310 
    311 	buf = buff;
    312 	while (length > 0) {
    313 		ret = child_write(f, data, buf, length);
    314 		if (ret == -1 || ret == 0) {
    315 			archive_set_error(f->archive, EIO,
    316 			    "Can't write to program: %s", data->program_name);
    317 			return (ARCHIVE_FATAL);
    318 		}
    319 		length -= ret;
    320 		buf += ret;
    321 	}
    322 	return (ARCHIVE_OK);
    323 }
    324 
    325 /*
    326  * Finish the filtering...
    327  */
    328 int
    329 __archive_write_program_close(struct archive_write_filter *f,
    330     struct archive_write_program_data *data)
    331 {
    332 	int ret, status;
    333 	pid_t pid;
    334 	ssize_t bytes_read;
    335 
    336 	if (data->child == 0)
    337 		return ARCHIVE_OK;
    338 
    339 	ret = 0;
    340 	close(data->child_stdin);
    341 	data->child_stdin = -1;
    342 	fcntl(data->child_stdout, F_SETFL, 0);
    343 
    344 	for (;;) {
    345 		do {
    346 			bytes_read = read(data->child_stdout,
    347 			    data->child_buf + data->child_buf_avail,
    348 			    data->child_buf_len - data->child_buf_avail);
    349 		} while (bytes_read == -1 && errno == EINTR);
    350 
    351 		if (bytes_read == 0 || (bytes_read == -1 && errno == EPIPE))
    352 			break;
    353 
    354 		if (bytes_read == -1) {
    355 			archive_set_error(f->archive, errno,
    356 			    "Error reading from program: %s", data->program_name);
    357 			ret = ARCHIVE_FATAL;
    358 			goto cleanup;
    359 		}
    360 		data->child_buf_avail += bytes_read;
    361 
    362 		ret = __archive_write_filter(f->next_filter,
    363 		    data->child_buf, data->child_buf_avail);
    364 		if (ret != ARCHIVE_OK) {
    365 			ret = ARCHIVE_FATAL;
    366 			goto cleanup;
    367 		}
    368 		data->child_buf_avail = 0;
    369 	}
    370 
    371 cleanup:
    372 	/* Shut down the child. */
    373 	if (data->child_stdin != -1)
    374 		close(data->child_stdin);
    375 	if (data->child_stdout != -1)
    376 		close(data->child_stdout);
    377 	do {
    378 		pid = waitpid(data->child, &status, 0);
    379 	} while (pid == -1 && errno == EINTR);
    380 	data->child = 0;
    381 
    382 	if (pid < 0 || status != 0) {
    383 		archive_set_error(f->archive, EIO,
    384 		    "Error closing program: %s", data->program_name);
    385 		ret = ARCHIVE_FATAL;
    386 	}
    387 	return ret;
    388 }
    389 
    390