1caf54c4fSMartin Matuska /*-
2caf54c4fSMartin Matuska * Copyright (c) 2003-2007 Tim Kientzle
3caf54c4fSMartin Matuska * All rights reserved.
4caf54c4fSMartin Matuska *
5caf54c4fSMartin Matuska * Redistribution and use in source and binary forms, with or without
6caf54c4fSMartin Matuska * modification, are permitted provided that the following conditions
7caf54c4fSMartin Matuska * are met:
8caf54c4fSMartin Matuska * 1. Redistributions of source code must retain the above copyright
9caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer.
10caf54c4fSMartin Matuska * 2. Redistributions in binary form must reproduce the above copyright
11caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer in the
12caf54c4fSMartin Matuska * documentation and/or other materials provided with the distribution.
13caf54c4fSMartin Matuska *
14caf54c4fSMartin Matuska * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15caf54c4fSMartin Matuska * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16caf54c4fSMartin Matuska * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17caf54c4fSMartin Matuska * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18caf54c4fSMartin Matuska * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19caf54c4fSMartin Matuska * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20caf54c4fSMartin Matuska * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21caf54c4fSMartin Matuska * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22caf54c4fSMartin Matuska * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23caf54c4fSMartin Matuska * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24caf54c4fSMartin Matuska */
25caf54c4fSMartin Matuska
26caf54c4fSMartin Matuska #include "archive_platform.h"
27caf54c4fSMartin Matuska
28caf54c4fSMartin Matuska #ifdef HAVE_SYS_STAT_H
29caf54c4fSMartin Matuska #include <sys/stat.h>
30caf54c4fSMartin Matuska #endif
31caf54c4fSMartin Matuska #ifdef HAVE_ERRNO_H
32caf54c4fSMartin Matuska #include <errno.h>
33caf54c4fSMartin Matuska #endif
34caf54c4fSMartin Matuska #ifdef HAVE_FCNTL_H
35caf54c4fSMartin Matuska #include <fcntl.h>
36caf54c4fSMartin Matuska #endif
37caf54c4fSMartin Matuska #ifdef HAVE_STDLIB_H
38caf54c4fSMartin Matuska #include <stdlib.h>
39caf54c4fSMartin Matuska #endif
40caf54c4fSMartin Matuska #ifdef HAVE_STRING_H
41caf54c4fSMartin Matuska #include <string.h>
42caf54c4fSMartin Matuska #endif
43caf54c4fSMartin Matuska #ifdef HAVE_UNISTD_H
44caf54c4fSMartin Matuska #include <unistd.h>
45caf54c4fSMartin Matuska #endif
46caf54c4fSMartin Matuska
47caf54c4fSMartin Matuska #include "archive.h"
48acc60b03SMartin Matuska #include "archive_private.h"
496c95142eSMartin Matuska #include "archive_string.h"
50caf54c4fSMartin Matuska
51caf54c4fSMartin Matuska #ifndef O_BINARY
52caf54c4fSMartin Matuska #define O_BINARY 0
53caf54c4fSMartin Matuska #endif
54acc60b03SMartin Matuska #ifndef O_CLOEXEC
55acc60b03SMartin Matuska #define O_CLOEXEC 0
56acc60b03SMartin Matuska #endif
57caf54c4fSMartin Matuska
58caf54c4fSMartin Matuska struct write_file_data {
59caf54c4fSMartin Matuska int fd;
60fd082e96SMartin Matuska struct archive_mstring filename;
61caf54c4fSMartin Matuska };
62caf54c4fSMartin Matuska
63caf54c4fSMartin Matuska static int file_close(struct archive *, void *);
64c3afd20fSMartin Matuska static int file_free(struct archive *, void *);
65caf54c4fSMartin Matuska static int file_open(struct archive *, void *);
66caf54c4fSMartin Matuska static ssize_t file_write(struct archive *, void *, const void *buff, size_t);
67fd082e96SMartin Matuska static int open_filename(struct archive *, int, const void *);
68caf54c4fSMartin Matuska
69caf54c4fSMartin Matuska int
archive_write_open_file(struct archive * a,const char * filename)70caf54c4fSMartin Matuska archive_write_open_file(struct archive *a, const char *filename)
71caf54c4fSMartin Matuska {
72caf54c4fSMartin Matuska return (archive_write_open_filename(a, filename));
73caf54c4fSMartin Matuska }
74caf54c4fSMartin Matuska
75caf54c4fSMartin Matuska int
archive_write_open_filename(struct archive * a,const char * filename)76caf54c4fSMartin Matuska archive_write_open_filename(struct archive *a, const char *filename)
77caf54c4fSMartin Matuska {
78caf54c4fSMartin Matuska
79caf54c4fSMartin Matuska if (filename == NULL || filename[0] == '\0')
80caf54c4fSMartin Matuska return (archive_write_open_fd(a, 1));
81caf54c4fSMartin Matuska
82fd082e96SMartin Matuska return (open_filename(a, 1, filename));
83caf54c4fSMartin Matuska }
84caf54c4fSMartin Matuska
856c95142eSMartin Matuska int
archive_write_open_filename_w(struct archive * a,const wchar_t * filename)866c95142eSMartin Matuska archive_write_open_filename_w(struct archive *a, const wchar_t *filename)
876c95142eSMartin Matuska {
886c95142eSMartin Matuska
896c95142eSMartin Matuska if (filename == NULL || filename[0] == L'\0')
906c95142eSMartin Matuska return (archive_write_open_fd(a, 1));
916c95142eSMartin Matuska
92fd082e96SMartin Matuska return (open_filename(a, 0, filename));
93fd082e96SMartin Matuska }
94fd082e96SMartin Matuska
95fd082e96SMartin Matuska static int
open_filename(struct archive * a,int mbs_fn,const void * filename)96fd082e96SMartin Matuska open_filename(struct archive *a, int mbs_fn, const void *filename)
97fd082e96SMartin Matuska {
98fd082e96SMartin Matuska struct write_file_data *mine;
99fd082e96SMartin Matuska int r;
100fd082e96SMartin Matuska
101fd082e96SMartin Matuska mine = (struct write_file_data *)calloc(1, sizeof(*mine));
1026c95142eSMartin Matuska if (mine == NULL) {
1036c95142eSMartin Matuska archive_set_error(a, ENOMEM, "No memory");
1046c95142eSMartin Matuska return (ARCHIVE_FATAL);
1056c95142eSMartin Matuska }
106fd082e96SMartin Matuska if (mbs_fn)
107fd082e96SMartin Matuska r = archive_mstring_copy_mbs(&mine->filename, filename);
108fd082e96SMartin Matuska else
109fd082e96SMartin Matuska r = archive_mstring_copy_wcs(&mine->filename, filename);
110fd082e96SMartin Matuska if (r < 0) {
111fd082e96SMartin Matuska if (errno == ENOMEM) {
112fd082e96SMartin Matuska archive_set_error(a, ENOMEM, "No memory");
113fd082e96SMartin Matuska return (ARCHIVE_FATAL);
114fd082e96SMartin Matuska }
115fd082e96SMartin Matuska if (mbs_fn)
116fd082e96SMartin Matuska archive_set_error(a, ARCHIVE_ERRNO_MISC,
117fd082e96SMartin Matuska "Can't convert '%s' to WCS",
118fd082e96SMartin Matuska (const char *)filename);
119fd082e96SMartin Matuska else
120fd082e96SMartin Matuska archive_set_error(a, ARCHIVE_ERRNO_MISC,
121fd082e96SMartin Matuska "Can't convert '%S' to MBS",
122fd082e96SMartin Matuska (const wchar_t *)filename);
123fd082e96SMartin Matuska return (ARCHIVE_FAILED);
124fd082e96SMartin Matuska }
1256c95142eSMartin Matuska mine->fd = -1;
126c3afd20fSMartin Matuska return (archive_write_open2(a, mine,
127c3afd20fSMartin Matuska file_open, file_write, file_close, file_free));
1286c95142eSMartin Matuska }
1296c95142eSMartin Matuska
130caf54c4fSMartin Matuska static int
file_open(struct archive * a,void * client_data)131caf54c4fSMartin Matuska file_open(struct archive *a, void *client_data)
132caf54c4fSMartin Matuska {
133caf54c4fSMartin Matuska int flags;
134caf54c4fSMartin Matuska struct write_file_data *mine;
135caf54c4fSMartin Matuska struct stat st;
136fd082e96SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
137fd082e96SMartin Matuska wchar_t *fullpath;
138fd082e96SMartin Matuska #endif
139fd082e96SMartin Matuska const wchar_t *wcs;
140fd082e96SMartin Matuska const char *mbs;
141caf54c4fSMartin Matuska
142caf54c4fSMartin Matuska mine = (struct write_file_data *)client_data;
143acc60b03SMartin Matuska flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC;
144caf54c4fSMartin Matuska
145caf54c4fSMartin Matuska /*
146caf54c4fSMartin Matuska * Open the file.
147caf54c4fSMartin Matuska */
148fd082e96SMartin Matuska mbs = NULL; wcs = NULL;
1496c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
150fd082e96SMartin Matuska if (archive_mstring_get_wcs(a, &mine->filename, &wcs) != 0) {
151fd082e96SMartin Matuska if (errno == ENOMEM)
152fd082e96SMartin Matuska archive_set_error(a, errno, "No memory");
153fd082e96SMartin Matuska else {
154fd082e96SMartin Matuska archive_mstring_get_mbs(a, &mine->filename, &mbs);
155fd082e96SMartin Matuska archive_set_error(a, errno,
156fd082e96SMartin Matuska "Can't convert '%s' to WCS", mbs);
157fd082e96SMartin Matuska }
158fd082e96SMartin Matuska return (ARCHIVE_FATAL);
159fd082e96SMartin Matuska }
160fd082e96SMartin Matuska fullpath = __la_win_permissive_name_w(wcs);
1616c95142eSMartin Matuska if (fullpath != NULL) {
1626c95142eSMartin Matuska mine->fd = _wopen(fullpath, flags, 0666);
1636c95142eSMartin Matuska free(fullpath);
164fd082e96SMartin Matuska } else
165fd082e96SMartin Matuska mine->fd = _wopen(wcs, flags, 0666);
166fd082e96SMartin Matuska #else
167fd082e96SMartin Matuska if (archive_mstring_get_mbs(a, &mine->filename, &mbs) != 0) {
168fd082e96SMartin Matuska if (errno == ENOMEM)
169fd082e96SMartin Matuska archive_set_error(a, errno, "No memory");
170fd082e96SMartin Matuska else {
171fd082e96SMartin Matuska archive_mstring_get_wcs(a, &mine->filename, &wcs);
172fd082e96SMartin Matuska archive_set_error(a, errno,
173fd082e96SMartin Matuska "Can't convert '%S' to MBS", wcs);
1746c95142eSMartin Matuska }
175fd082e96SMartin Matuska return (ARCHIVE_FATAL);
1766c95142eSMartin Matuska }
177fd082e96SMartin Matuska mine->fd = open(mbs, flags, 0666);
178acc60b03SMartin Matuska __archive_ensure_cloexec_flag(mine->fd);
179fd082e96SMartin Matuska #endif
1806c95142eSMartin Matuska if (mine->fd < 0) {
181fd082e96SMartin Matuska if (mbs != NULL)
182fd082e96SMartin Matuska archive_set_error(a, errno, "Failed to open '%s'", mbs);
183fd082e96SMartin Matuska else
184fd082e96SMartin Matuska archive_set_error(a, errno, "Failed to open '%S'", wcs);
1856c95142eSMartin Matuska return (ARCHIVE_FATAL);
1866c95142eSMartin Matuska }
1876c95142eSMartin Matuska
1886c95142eSMartin Matuska if (fstat(mine->fd, &st) != 0) {
189fd082e96SMartin Matuska if (mbs != NULL)
190fd082e96SMartin Matuska archive_set_error(a, errno, "Couldn't stat '%s'", mbs);
191fd082e96SMartin Matuska else
192fd082e96SMartin Matuska archive_set_error(a, errno, "Couldn't stat '%S'", wcs);
1936c95142eSMartin Matuska return (ARCHIVE_FATAL);
1946c95142eSMartin Matuska }
195caf54c4fSMartin Matuska
196caf54c4fSMartin Matuska /*
197caf54c4fSMartin Matuska * Set up default last block handling.
198caf54c4fSMartin Matuska */
199caf54c4fSMartin Matuska if (archive_write_get_bytes_in_last_block(a) < 0) {
200caf54c4fSMartin Matuska if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) ||
201caf54c4fSMartin Matuska S_ISFIFO(st.st_mode))
202caf54c4fSMartin Matuska /* Pad last block when writing to device or FIFO. */
203caf54c4fSMartin Matuska archive_write_set_bytes_in_last_block(a, 0);
204caf54c4fSMartin Matuska else
205caf54c4fSMartin Matuska /* Don't pad last block otherwise. */
206caf54c4fSMartin Matuska archive_write_set_bytes_in_last_block(a, 1);
207caf54c4fSMartin Matuska }
208caf54c4fSMartin Matuska
209caf54c4fSMartin Matuska /*
210caf54c4fSMartin Matuska * If the output file is a regular file, don't add it to
211caf54c4fSMartin Matuska * itself. If it's a device file, it's okay to add the device
212caf54c4fSMartin Matuska * entry to the output archive.
213caf54c4fSMartin Matuska */
214caf54c4fSMartin Matuska if (S_ISREG(st.st_mode))
215caf54c4fSMartin Matuska archive_write_set_skip_file(a, st.st_dev, st.st_ino);
216caf54c4fSMartin Matuska
217caf54c4fSMartin Matuska return (ARCHIVE_OK);
218caf54c4fSMartin Matuska }
219caf54c4fSMartin Matuska
220caf54c4fSMartin Matuska static ssize_t
file_write(struct archive * a,void * client_data,const void * buff,size_t length)221fd082e96SMartin Matuska file_write(struct archive *a, void *client_data, const void *buff,
222fd082e96SMartin Matuska size_t length)
223caf54c4fSMartin Matuska {
224caf54c4fSMartin Matuska struct write_file_data *mine;
225caf54c4fSMartin Matuska ssize_t bytesWritten;
226caf54c4fSMartin Matuska
227caf54c4fSMartin Matuska mine = (struct write_file_data *)client_data;
228caf54c4fSMartin Matuska for (;;) {
229caf54c4fSMartin Matuska bytesWritten = write(mine->fd, buff, length);
230caf54c4fSMartin Matuska if (bytesWritten <= 0) {
231caf54c4fSMartin Matuska if (errno == EINTR)
232caf54c4fSMartin Matuska continue;
233caf54c4fSMartin Matuska archive_set_error(a, errno, "Write error");
234caf54c4fSMartin Matuska return (-1);
235caf54c4fSMartin Matuska }
236caf54c4fSMartin Matuska return (bytesWritten);
237caf54c4fSMartin Matuska }
238caf54c4fSMartin Matuska }
239caf54c4fSMartin Matuska
240caf54c4fSMartin Matuska static int
file_close(struct archive * a,void * client_data)241caf54c4fSMartin Matuska file_close(struct archive *a, void *client_data)
242caf54c4fSMartin Matuska {
243caf54c4fSMartin Matuska struct write_file_data *mine = (struct write_file_data *)client_data;
244caf54c4fSMartin Matuska
245caf54c4fSMartin Matuska (void)a; /* UNUSED */
246cdf63a70SMartin Matuska
247c3afd20fSMartin Matuska if (mine == NULL)
248c3afd20fSMartin Matuska return (ARCHIVE_FATAL);
249c3afd20fSMartin Matuska
250cdf63a70SMartin Matuska if (mine->fd >= 0)
251caf54c4fSMartin Matuska close(mine->fd);
252cdf63a70SMartin Matuska
253c3afd20fSMartin Matuska return (ARCHIVE_OK);
254c3afd20fSMartin Matuska }
255c3afd20fSMartin Matuska
256c3afd20fSMartin Matuska static int
file_free(struct archive * a,void * client_data)257c3afd20fSMartin Matuska file_free(struct archive *a, void *client_data)
258c3afd20fSMartin Matuska {
259c3afd20fSMartin Matuska struct write_file_data *mine = (struct write_file_data *)client_data;
260c3afd20fSMartin Matuska
261c3afd20fSMartin Matuska (void)a; /* UNUSED */
262c3afd20fSMartin Matuska
263c3afd20fSMartin Matuska if (mine == NULL)
264c3afd20fSMartin Matuska return (ARCHIVE_OK);
265c3afd20fSMartin Matuska
266fd082e96SMartin Matuska archive_mstring_clean(&mine->filename);
267caf54c4fSMartin Matuska free(mine);
268caf54c4fSMartin Matuska return (ARCHIVE_OK);
269caf54c4fSMartin Matuska }
270