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" 27228763Smm__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" 49248616Smm#include "archive_private.h" 50232153Smm#include "archive_string.h" 51228753Smm 52228753Smm#ifndef O_BINARY 53228753Smm#define O_BINARY 0 54228753Smm#endif 55248616Smm#ifndef O_CLOEXEC 56248616Smm#define O_CLOEXEC 0 57248616Smm#endif 58228753Smm 59228753Smmstruct write_file_data { 60228753Smm int fd; 61238856Smm struct archive_mstring filename; 62228753Smm}; 63228753Smm 64228753Smmstatic int file_close(struct archive *, void *); 65228753Smmstatic int file_open(struct archive *, void *); 66228753Smmstatic ssize_t file_write(struct archive *, void *, const void *buff, size_t); 67238856Smmstatic int open_filename(struct archive *, int, const void *); 68228753Smm 69228753Smmint 70228753Smmarchive_write_open_file(struct archive *a, const char *filename) 71228753Smm{ 72228753Smm return (archive_write_open_filename(a, filename)); 73228753Smm} 74228753Smm 75228753Smmint 76228753Smmarchive_write_open_filename(struct archive *a, const char *filename) 77228753Smm{ 78228753Smm 79228753Smm if (filename == NULL || filename[0] == '\0') 80228753Smm return (archive_write_open_fd(a, 1)); 81228753Smm 82238856Smm return (open_filename(a, 1, filename)); 83228753Smm} 84228753Smm 85232153Smmint 86232153Smmarchive_write_open_filename_w(struct archive *a, const wchar_t *filename) 87232153Smm{ 88232153Smm 89232153Smm if (filename == NULL || filename[0] == L'\0') 90232153Smm return (archive_write_open_fd(a, 1)); 91232153Smm 92238856Smm return (open_filename(a, 0, filename)); 93238856Smm} 94238856Smm 95238856Smmstatic int 96238856Smmopen_filename(struct archive *a, int mbs_fn, const void *filename) 97238856Smm{ 98238856Smm struct write_file_data *mine; 99238856Smm int r; 100238856Smm 101238856Smm mine = (struct write_file_data *)calloc(1, sizeof(*mine)); 102232153Smm if (mine == NULL) { 103232153Smm archive_set_error(a, ENOMEM, "No memory"); 104232153Smm return (ARCHIVE_FATAL); 105232153Smm } 106238856Smm if (mbs_fn) 107238856Smm r = archive_mstring_copy_mbs(&mine->filename, filename); 108238856Smm else 109238856Smm r = archive_mstring_copy_wcs(&mine->filename, filename); 110238856Smm if (r < 0) { 111238856Smm if (errno == ENOMEM) { 112238856Smm archive_set_error(a, ENOMEM, "No memory"); 113238856Smm return (ARCHIVE_FATAL); 114238856Smm } 115238856Smm if (mbs_fn) 116238856Smm archive_set_error(a, ARCHIVE_ERRNO_MISC, 117238856Smm "Can't convert '%s' to WCS", 118238856Smm (const char *)filename); 119238856Smm else 120238856Smm archive_set_error(a, ARCHIVE_ERRNO_MISC, 121238856Smm "Can't convert '%S' to MBS", 122238856Smm (const wchar_t *)filename); 123238856Smm return (ARCHIVE_FAILED); 124238856Smm } 125232153Smm mine->fd = -1; 126232153Smm return (archive_write_open(a, mine, 127232153Smm file_open, file_write, file_close)); 128232153Smm} 129232153Smm 130228753Smmstatic int 131228753Smmfile_open(struct archive *a, void *client_data) 132228753Smm{ 133228753Smm int flags; 134228753Smm struct write_file_data *mine; 135228753Smm struct stat st; 136238856Smm#if defined(_WIN32) && !defined(__CYGWIN__) 137238856Smm wchar_t *fullpath; 138238856Smm#endif 139238856Smm const wchar_t *wcs; 140238856Smm const char *mbs; 141228753Smm 142228753Smm mine = (struct write_file_data *)client_data; 143248616Smm flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC; 144228753Smm 145228753Smm /* 146228753Smm * Open the file. 147228753Smm */ 148238856Smm mbs = NULL; wcs = NULL; 149232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 150238856Smm if (archive_mstring_get_wcs(a, &mine->filename, &wcs) != 0) { 151238856Smm if (errno == ENOMEM) 152238856Smm archive_set_error(a, errno, "No memory"); 153238856Smm else { 154238856Smm archive_mstring_get_mbs(a, &mine->filename, &mbs); 155238856Smm archive_set_error(a, errno, 156238856Smm "Can't convert '%s' to WCS", mbs); 157232153Smm } 158238856Smm return (ARCHIVE_FATAL); 159238856Smm } 160238856Smm fullpath = __la_win_permissive_name_w(wcs); 161238856Smm if (fullpath != NULL) { 162238856Smm mine->fd = _wopen(fullpath, flags, 0666); 163238856Smm free(fullpath); 164238856Smm } else 165238856Smm mine->fd = _wopen(wcs, flags, 0666); 166238856Smm#else 167238856Smm if (archive_mstring_get_mbs(a, &mine->filename, &mbs) != 0) { 168238856Smm if (errno == ENOMEM) 169238856Smm archive_set_error(a, errno, "No memory"); 170238856Smm else { 171238856Smm archive_mstring_get_wcs(a, &mine->filename, &wcs); 172238856Smm archive_set_error(a, errno, 173238856Smm "Can't convert '%S' to MBS", wcs); 174232153Smm } 175228753Smm return (ARCHIVE_FATAL); 176238856Smm } 177238856Smm mine->fd = open(mbs, flags, 0666); 178248616Smm __archive_ensure_cloexec_flag(mine->fd); 179232153Smm#endif 180238856Smm if (mine->fd < 0) { 181238856Smm if (mbs != NULL) 182238856Smm archive_set_error(a, errno, "Failed to open '%s'", mbs); 183238856Smm else 184238856Smm archive_set_error(a, errno, "Failed to open '%S'", wcs); 185238856Smm return (ARCHIVE_FATAL); 186228753Smm } 187228753Smm 188238856Smm if (fstat(mine->fd, &st) != 0) { 189238856Smm if (mbs != NULL) 190238856Smm archive_set_error(a, errno, "Couldn't stat '%s'", mbs); 191238856Smm else 192238856Smm archive_set_error(a, errno, "Couldn't stat '%S'", wcs); 193238856Smm return (ARCHIVE_FATAL); 194238856Smm } 195238856Smm 196228753Smm /* 197228753Smm * Set up default last block handling. 198228753Smm */ 199228753Smm if (archive_write_get_bytes_in_last_block(a) < 0) { 200228753Smm if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || 201228753Smm S_ISFIFO(st.st_mode)) 202228753Smm /* Pad last block when writing to device or FIFO. */ 203228753Smm archive_write_set_bytes_in_last_block(a, 0); 204228753Smm else 205228753Smm /* Don't pad last block otherwise. */ 206228753Smm archive_write_set_bytes_in_last_block(a, 1); 207228753Smm } 208228753Smm 209228753Smm /* 210228753Smm * If the output file is a regular file, don't add it to 211228753Smm * itself. If it's a device file, it's okay to add the device 212228753Smm * entry to the output archive. 213228753Smm */ 214228753Smm if (S_ISREG(st.st_mode)) 215228753Smm archive_write_set_skip_file(a, st.st_dev, st.st_ino); 216228753Smm 217228753Smm return (ARCHIVE_OK); 218228753Smm} 219228753Smm 220228753Smmstatic ssize_t 221238856Smmfile_write(struct archive *a, void *client_data, const void *buff, 222238856Smm size_t length) 223228753Smm{ 224228753Smm struct write_file_data *mine; 225228753Smm ssize_t bytesWritten; 226228753Smm 227228753Smm mine = (struct write_file_data *)client_data; 228228753Smm for (;;) { 229228753Smm bytesWritten = write(mine->fd, buff, length); 230228753Smm if (bytesWritten <= 0) { 231228753Smm if (errno == EINTR) 232228753Smm continue; 233228753Smm archive_set_error(a, errno, "Write error"); 234228753Smm return (-1); 235228753Smm } 236228753Smm return (bytesWritten); 237228753Smm } 238228753Smm} 239228753Smm 240228753Smmstatic int 241228753Smmfile_close(struct archive *a, void *client_data) 242228753Smm{ 243228753Smm struct write_file_data *mine = (struct write_file_data *)client_data; 244228753Smm 245228753Smm (void)a; /* UNUSED */ 246228753Smm close(mine->fd); 247238856Smm archive_mstring_clean(&mine->filename); 248228753Smm free(mine); 249228753Smm return (ARCHIVE_OK); 250228753Smm} 251