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_SYS_STAT_H 30228753Smm#include <sys/stat.h> 31228753Smm#endif 32228753Smm#ifdef HAVE_ERRNO_H 33228753Smm#include <errno.h> 34228753Smm#endif 35228753Smm#ifdef HAVE_FCNTL_H 36228753Smm#include <fcntl.h> 37228753Smm#endif 38228753Smm#ifdef HAVE_STDLIB_H 39228753Smm#include <stdlib.h> 40228753Smm#endif 41228753Smm#ifdef HAVE_STRING_H 42228753Smm#include <string.h> 43228753Smm#endif 44228753Smm#ifdef HAVE_UNISTD_H 45228753Smm#include <unistd.h> 46228753Smm#endif 47228753Smm 48228753Smm#include "archive.h" 49228753Smm 50228753Smm#ifndef O_BINARY 51228753Smm#define O_BINARY 0 52228753Smm#endif 53228753Smm 54228753Smmstruct write_file_data { 55228753Smm int fd; 56228753Smm char filename[1]; 57228753Smm}; 58228753Smm 59228753Smmstatic int file_close(struct archive *, void *); 60228753Smmstatic int file_open(struct archive *, void *); 61228753Smmstatic ssize_t file_write(struct archive *, void *, const void *buff, size_t); 62228753Smm 63228753Smmint 64228753Smmarchive_write_open_file(struct archive *a, const char *filename) 65228753Smm{ 66228753Smm return (archive_write_open_filename(a, filename)); 67228753Smm} 68228753Smm 69228753Smmint 70228753Smmarchive_write_open_filename(struct archive *a, const char *filename) 71228753Smm{ 72228753Smm struct write_file_data *mine; 73228753Smm 74228753Smm if (filename == NULL || filename[0] == '\0') 75228753Smm return (archive_write_open_fd(a, 1)); 76228753Smm 77228753Smm mine = (struct write_file_data *)malloc(sizeof(*mine) + strlen(filename)); 78228753Smm if (mine == NULL) { 79228753Smm archive_set_error(a, ENOMEM, "No memory"); 80228753Smm return (ARCHIVE_FATAL); 81228753Smm } 82228753Smm strcpy(mine->filename, filename); 83228753Smm mine->fd = -1; 84228753Smm return (archive_write_open(a, mine, 85228753Smm file_open, file_write, file_close)); 86228753Smm} 87228753Smm 88228753Smmstatic int 89228753Smmfile_open(struct archive *a, void *client_data) 90228753Smm{ 91228753Smm int flags; 92228753Smm struct write_file_data *mine; 93228753Smm struct stat st; 94228753Smm 95228753Smm mine = (struct write_file_data *)client_data; 96228753Smm flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; 97228753Smm 98228753Smm /* 99228753Smm * Open the file. 100228753Smm */ 101228753Smm mine->fd = open(mine->filename, flags, 0666); 102228753Smm if (mine->fd < 0) { 103228753Smm archive_set_error(a, errno, "Failed to open '%s'", 104228753Smm mine->filename); 105228753Smm return (ARCHIVE_FATAL); 106228753Smm } 107228753Smm 108228753Smm if (fstat(mine->fd, &st) != 0) { 109228753Smm archive_set_error(a, errno, "Couldn't stat '%s'", 110228753Smm mine->filename); 111228753Smm return (ARCHIVE_FATAL); 112228753Smm } 113228753Smm 114228753Smm /* 115228753Smm * Set up default last block handling. 116228753Smm */ 117228753Smm if (archive_write_get_bytes_in_last_block(a) < 0) { 118228753Smm if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || 119228753Smm S_ISFIFO(st.st_mode)) 120228753Smm /* Pad last block when writing to device or FIFO. */ 121228753Smm archive_write_set_bytes_in_last_block(a, 0); 122228753Smm else 123228753Smm /* Don't pad last block otherwise. */ 124228753Smm archive_write_set_bytes_in_last_block(a, 1); 125228753Smm } 126228753Smm 127228753Smm /* 128228753Smm * If the output file is a regular file, don't add it to 129228753Smm * itself. If it's a device file, it's okay to add the device 130228753Smm * entry to the output archive. 131228753Smm */ 132228753Smm if (S_ISREG(st.st_mode)) 133228753Smm archive_write_set_skip_file(a, st.st_dev, st.st_ino); 134228753Smm 135228753Smm return (ARCHIVE_OK); 136228753Smm} 137228753Smm 138228753Smmstatic ssize_t 139228753Smmfile_write(struct archive *a, void *client_data, const void *buff, size_t length) 140228753Smm{ 141228753Smm struct write_file_data *mine; 142228753Smm ssize_t bytesWritten; 143228753Smm 144228753Smm mine = (struct write_file_data *)client_data; 145228753Smm for (;;) { 146228753Smm bytesWritten = write(mine->fd, buff, length); 147228753Smm if (bytesWritten <= 0) { 148228753Smm if (errno == EINTR) 149228753Smm continue; 150228753Smm archive_set_error(a, errno, "Write error"); 151228753Smm return (-1); 152228753Smm } 153228753Smm return (bytesWritten); 154228753Smm } 155228753Smm} 156228753Smm 157228753Smmstatic int 158228753Smmfile_close(struct archive *a, void *client_data) 159228753Smm{ 160228753Smm struct write_file_data *mine = (struct write_file_data *)client_data; 161228753Smm 162228753Smm (void)a; /* UNUSED */ 163228753Smm close(mine->fd); 164228753Smm free(mine); 165228753Smm return (ARCHIVE_OK); 166228753Smm} 167