1207753Smm///////////////////////////////////////////////////////////////////////////////
2207753Smm//
3207753Smm/// \file       file_io.c
4207753Smm/// \brief      File opening, unlinking, and closing
5207753Smm//
6207753Smm//  Author:     Lasse Collin
7207753Smm//
8207753Smm//  This file has been put into the public domain.
9207753Smm//  You can do whatever you want with this file.
10207753Smm//
11207753Smm///////////////////////////////////////////////////////////////////////////////
12207753Smm
13207753Smm#include "private.h"
14207753Smm
15207753Smm#include <fcntl.h>
16207753Smm
17207753Smm#ifdef TUKLIB_DOSLIKE
18207753Smm#	include <io.h>
19207753Smm#else
20292588Sdelphij#	include <poll.h>
21207753Smmstatic bool warn_fchown;
22207753Smm#endif
23207753Smm
24207753Smm#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMES)
25207753Smm#	include <sys/time.h>
26312518Sdelphij#elif defined(HAVE__FUTIME)
27312518Sdelphij#	include <sys/utime.h>
28207753Smm#elif defined(HAVE_UTIME)
29207753Smm#	include <utime.h>
30207753Smm#endif
31207753Smm
32312518Sdelphij#ifdef HAVE_CAPSICUM
33312518Sdelphij#	ifdef HAVE_SYS_CAPSICUM_H
34312518Sdelphij#		include <sys/capsicum.h>
35312518Sdelphij#	else
36312518Sdelphij#		include <sys/capability.h>
37312518Sdelphij#	endif
38312518Sdelphij#endif
39312518Sdelphij
40207753Smm#include "tuklib_open_stdxxx.h"
41207753Smm
42207753Smm#ifndef O_BINARY
43207753Smm#	define O_BINARY 0
44207753Smm#endif
45207753Smm
46207753Smm#ifndef O_NOCTTY
47207753Smm#	define O_NOCTTY 0
48207753Smm#endif
49207753Smm
50312518Sdelphij// Using this macro to silence a warning from gcc -Wlogical-op.
51312518Sdelphij#if EAGAIN == EWOULDBLOCK
52312518Sdelphij#	define IS_EAGAIN_OR_EWOULDBLOCK(e) ((e) == EAGAIN)
53312518Sdelphij#else
54312518Sdelphij#	define IS_EAGAIN_OR_EWOULDBLOCK(e) \
55312518Sdelphij		((e) == EAGAIN || (e) == EWOULDBLOCK)
56312518Sdelphij#endif
57207753Smm
58312518Sdelphij
59292588Sdelphijtypedef enum {
60292588Sdelphij	IO_WAIT_MORE,    // Reading or writing is possible.
61292588Sdelphij	IO_WAIT_ERROR,   // Error or user_abort
62292588Sdelphij	IO_WAIT_TIMEOUT, // poll() timed out
63292588Sdelphij} io_wait_ret;
64292588Sdelphij
65292588Sdelphij
66207753Smm/// If true, try to create sparse files when decompressing.
67207753Smmstatic bool try_sparse = true;
68207753Smm
69312518Sdelphij#ifdef ENABLE_SANDBOX
70312518Sdelphij/// True if the conditions for sandboxing (described in main()) have been met.
71312518Sdelphijstatic bool sandbox_allowed = false;
72312518Sdelphij#endif
73312518Sdelphij
74207753Smm#ifndef TUKLIB_DOSLIKE
75292588Sdelphij/// File status flags of standard input. This is used by io_open_src()
76292588Sdelphij/// and io_close_src().
77292588Sdelphijstatic int stdin_flags;
78292588Sdelphijstatic bool restore_stdin_flags = false;
79292588Sdelphij
80263285Sdelphij/// Original file status flags of standard output. This is used by
81263285Sdelphij/// io_open_dest() and io_close_dest() to save and restore the flags.
82263285Sdelphijstatic int stdout_flags;
83263285Sdelphijstatic bool restore_stdout_flags = false;
84292588Sdelphij
85292588Sdelphij/// Self-pipe used together with the user_abort variable to avoid
86292588Sdelphij/// race conditions with signal handling.
87292588Sdelphijstatic int user_abort_pipe[2];
88207753Smm#endif
89207753Smm
90207753Smm
91207753Smmstatic bool io_write_buf(file_pair *pair, const uint8_t *buf, size_t size);
92207753Smm
93207753Smm
94207753Smmextern void
95207753Smmio_init(void)
96207753Smm{
97223935Smm	// Make sure that stdin, stdout, and stderr are connected to
98207753Smm	// a valid file descriptor. Exit immediately with exit code ERROR
99207753Smm	// if we cannot make the file descriptors valid. Maybe we should
100207753Smm	// print an error message, but our stderr could be screwed anyway.
101207753Smm	tuklib_open_stdxxx(E_ERROR);
102207753Smm
103207753Smm#ifndef TUKLIB_DOSLIKE
104207753Smm	// If fchown() fails setting the owner, we warn about it only if
105207753Smm	// we are root.
106207753Smm	warn_fchown = geteuid() == 0;
107292588Sdelphij
108292588Sdelphij	// Create a pipe for the self-pipe trick.
109292588Sdelphij	if (pipe(user_abort_pipe))
110292588Sdelphij		message_fatal(_("Error creating a pipe: %s"),
111292588Sdelphij				strerror(errno));
112292588Sdelphij
113292588Sdelphij	// Make both ends of the pipe non-blocking.
114292588Sdelphij	for (unsigned i = 0; i < 2; ++i) {
115292588Sdelphij		int flags = fcntl(user_abort_pipe[i], F_GETFL);
116292588Sdelphij		if (flags == -1 || fcntl(user_abort_pipe[i], F_SETFL,
117292588Sdelphij				flags | O_NONBLOCK) == -1)
118292588Sdelphij			message_fatal(_("Error creating a pipe: %s"),
119292588Sdelphij					strerror(errno));
120292588Sdelphij	}
121207753Smm#endif
122207753Smm
123207753Smm#ifdef __DJGPP__
124207753Smm	// Avoid doing useless things when statting files.
125207753Smm	// This isn't important but doesn't hurt.
126292588Sdelphij	_djstat_flags = _STAT_EXEC_EXT | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
127207753Smm#endif
128207753Smm
129207753Smm	return;
130207753Smm}
131207753Smm
132207753Smm
133292588Sdelphij#ifndef TUKLIB_DOSLIKE
134207753Smmextern void
135292588Sdelphijio_write_to_user_abort_pipe(void)
136292588Sdelphij{
137292588Sdelphij	// If the write() fails, it's probably due to the pipe being full.
138292588Sdelphij	// Failing in that case is fine. If the reason is something else,
139292588Sdelphij	// there's not much we can do since this is called in a signal
140292588Sdelphij	// handler. So ignore the errors and try to avoid warnings with
141292588Sdelphij	// GCC and glibc when _FORTIFY_SOURCE=2 is used.
142292588Sdelphij	uint8_t b = '\0';
143292588Sdelphij	const int ret = write(user_abort_pipe[1], &b, 1);
144292588Sdelphij	(void)ret;
145292588Sdelphij	return;
146292588Sdelphij}
147292588Sdelphij#endif
148292588Sdelphij
149292588Sdelphij
150292588Sdelphijextern void
151207753Smmio_no_sparse(void)
152207753Smm{
153207753Smm	try_sparse = false;
154207753Smm	return;
155207753Smm}
156207753Smm
157207753Smm
158312518Sdelphij#ifdef ENABLE_SANDBOX
159312518Sdelphijextern void
160312518Sdelphijio_allow_sandbox(void)
161312518Sdelphij{
162312518Sdelphij	sandbox_allowed = true;
163312518Sdelphij	return;
164312518Sdelphij}
165312518Sdelphij
166312518Sdelphij
167312518Sdelphij/// Enables operating-system-specific sandbox if it is possible.
168312518Sdelphij/// src_fd is the file descriptor of the input file.
169312518Sdelphijstatic void
170312518Sdelphijio_sandbox_enter(int src_fd)
171312518Sdelphij{
172312518Sdelphij	if (!sandbox_allowed) {
173312518Sdelphij		message(V_DEBUG, _("Sandbox is disabled due "
174312518Sdelphij				"to incompatible command line arguments"));
175312518Sdelphij		return;
176312518Sdelphij	}
177312518Sdelphij
178312518Sdelphij	const char dummy_str[] = "x";
179312518Sdelphij
180312518Sdelphij	// Try to ensure that both libc and xz locale files have been
181312518Sdelphij	// loaded when NLS is enabled.
182312518Sdelphij	snprintf(NULL, 0, "%s%s", _(dummy_str), strerror(EINVAL));
183312518Sdelphij
184312518Sdelphij	// Try to ensure that iconv data files needed for handling multibyte
185312518Sdelphij	// characters have been loaded. This is needed at least with glibc.
186312518Sdelphij	tuklib_mbstr_width(dummy_str, NULL);
187312518Sdelphij
188312518Sdelphij#ifdef HAVE_CAPSICUM
189312518Sdelphij	// Capsicum needs FreeBSD 10.0 or later.
190312518Sdelphij	cap_rights_t rights;
191312518Sdelphij
192312518Sdelphij	if (cap_rights_limit(src_fd, cap_rights_init(&rights,
193312518Sdelphij			CAP_EVENT, CAP_FCNTL, CAP_LOOKUP, CAP_READ, CAP_SEEK)))
194312518Sdelphij		goto error;
195312518Sdelphij
196312518Sdelphij	if (cap_rights_limit(STDOUT_FILENO, cap_rights_init(&rights,
197312518Sdelphij			CAP_EVENT, CAP_FCNTL, CAP_FSTAT, CAP_LOOKUP,
198312518Sdelphij			CAP_WRITE, CAP_SEEK)))
199312518Sdelphij		goto error;
200312518Sdelphij
201312518Sdelphij	if (cap_rights_limit(user_abort_pipe[0], cap_rights_init(&rights,
202312518Sdelphij			CAP_EVENT)))
203312518Sdelphij		goto error;
204312518Sdelphij
205312518Sdelphij	if (cap_rights_limit(user_abort_pipe[1], cap_rights_init(&rights,
206312518Sdelphij			CAP_WRITE)))
207312518Sdelphij		goto error;
208312518Sdelphij
209312518Sdelphij	if (cap_enter())
210312518Sdelphij		goto error;
211312518Sdelphij
212312518Sdelphij#else
213312518Sdelphij#	error ENABLE_SANDBOX is defined but no sandboxing method was found.
214312518Sdelphij#endif
215312518Sdelphij
216312518Sdelphij	message(V_DEBUG, _("Sandbox was successfully enabled"));
217312518Sdelphij	return;
218312518Sdelphij
219312518Sdelphijerror:
220312518Sdelphij	message(V_DEBUG, _("Failed to enable the sandbox"));
221312518Sdelphij}
222312518Sdelphij#endif // ENABLE_SANDBOX
223312518Sdelphij
224312518Sdelphij
225292588Sdelphij#ifndef TUKLIB_DOSLIKE
226292588Sdelphij/// \brief      Waits for input or output to become available or for a signal
227292588Sdelphij///
228292588Sdelphij/// This uses the self-pipe trick to avoid a race condition that can occur
229292588Sdelphij/// if a signal is caught after user_abort has been checked but before e.g.
230292588Sdelphij/// read() has been called. In that situation read() could block unless
231292588Sdelphij/// non-blocking I/O is used. With non-blocking I/O something like select()
232292588Sdelphij/// or poll() is needed to avoid a busy-wait loop, and the same race condition
233292588Sdelphij/// pops up again. There are pselect() (POSIX-1.2001) and ppoll() (not in
234292588Sdelphij/// POSIX) but neither is portable enough in 2013. The self-pipe trick is
235292588Sdelphij/// old and very portable.
236292588Sdelphijstatic io_wait_ret
237292588Sdelphijio_wait(file_pair *pair, int timeout, bool is_reading)
238292588Sdelphij{
239292588Sdelphij	struct pollfd pfd[2];
240292588Sdelphij
241292588Sdelphij	if (is_reading) {
242292588Sdelphij		pfd[0].fd = pair->src_fd;
243292588Sdelphij		pfd[0].events = POLLIN;
244292588Sdelphij	} else {
245292588Sdelphij		pfd[0].fd = pair->dest_fd;
246292588Sdelphij		pfd[0].events = POLLOUT;
247292588Sdelphij	}
248292588Sdelphij
249292588Sdelphij	pfd[1].fd = user_abort_pipe[0];
250292588Sdelphij	pfd[1].events = POLLIN;
251292588Sdelphij
252292588Sdelphij	while (true) {
253292588Sdelphij		const int ret = poll(pfd, 2, timeout);
254292588Sdelphij
255292588Sdelphij		if (user_abort)
256292588Sdelphij			return IO_WAIT_ERROR;
257292588Sdelphij
258292588Sdelphij		if (ret == -1) {
259292588Sdelphij			if (errno == EINTR || errno == EAGAIN)
260292588Sdelphij				continue;
261292588Sdelphij
262292588Sdelphij			message_error(_("%s: poll() failed: %s"),
263292588Sdelphij					is_reading ? pair->src_name
264292588Sdelphij						: pair->dest_name,
265292588Sdelphij					strerror(errno));
266292588Sdelphij			return IO_WAIT_ERROR;
267292588Sdelphij		}
268292588Sdelphij
269292588Sdelphij		if (ret == 0) {
270292588Sdelphij			assert(opt_flush_timeout != 0);
271292588Sdelphij			flush_needed = true;
272292588Sdelphij			return IO_WAIT_TIMEOUT;
273292588Sdelphij		}
274292588Sdelphij
275292588Sdelphij		if (pfd[0].revents != 0)
276292588Sdelphij			return IO_WAIT_MORE;
277292588Sdelphij	}
278292588Sdelphij}
279292588Sdelphij#endif
280292588Sdelphij
281292588Sdelphij
282207753Smm/// \brief      Unlink a file
283207753Smm///
284207753Smm/// This tries to verify that the file being unlinked really is the file that
285207753Smm/// we want to unlink by verifying device and inode numbers. There's still
286207753Smm/// a small unavoidable race, but this is much better than nothing (the file
287207753Smm/// could have been moved/replaced even hours earlier).
288207753Smmstatic void
289207753Smmio_unlink(const char *name, const struct stat *known_st)
290207753Smm{
291207753Smm#if defined(TUKLIB_DOSLIKE)
292207753Smm	// On DOS-like systems, st_ino is meaningless, so don't bother
293207753Smm	// testing it. Just silence a compiler warning.
294207753Smm	(void)known_st;
295207753Smm#else
296207753Smm	struct stat new_st;
297207753Smm
298207753Smm	// If --force was used, use stat() instead of lstat(). This way
299207753Smm	// (de)compressing symlinks works correctly. However, it also means
300207753Smm	// that xz cannot detect if a regular file foo is renamed to bar
301207753Smm	// and then a symlink foo -> bar is created. Because of stat()
302207753Smm	// instead of lstat(), xz will think that foo hasn't been replaced
303207753Smm	// with another file. Thus, xz will remove foo even though it no
304207753Smm	// longer is the same file that xz used when it started compressing.
305207753Smm	// Probably it's not too bad though, so this doesn't need a more
306207753Smm	// complex fix.
307207753Smm	const int stat_ret = opt_force
308207753Smm			? stat(name, &new_st) : lstat(name, &new_st);
309207753Smm
310207753Smm	if (stat_ret
311207753Smm#	ifdef __VMS
312207753Smm			// st_ino is an array, and we don't want to
313207753Smm			// compare st_dev at all.
314207753Smm			|| memcmp(&new_st.st_ino, &known_st->st_ino,
315207753Smm				sizeof(new_st.st_ino)) != 0
316207753Smm#	else
317207753Smm			// Typical POSIX-like system
318207753Smm			|| new_st.st_dev != known_st->st_dev
319207753Smm			|| new_st.st_ino != known_st->st_ino
320207753Smm#	endif
321207753Smm			)
322207753Smm		// TRANSLATORS: When compression or decompression finishes,
323207753Smm		// and xz is going to remove the source file, xz first checks
324207753Smm		// if the source file still exists, and if it does, does its
325207753Smm		// device and inode numbers match what xz saw when it opened
326207753Smm		// the source file. If these checks fail, this message is
327207753Smm		// shown, %s being the filename, and the file is not deleted.
328207753Smm		// The check for device and inode numbers is there, because
329207753Smm		// it is possible that the user has put a new file in place
330207753Smm		// of the original file, and in that case it obviously
331207753Smm		// shouldn't be removed.
332207753Smm		message_error(_("%s: File seems to have been moved, "
333207753Smm				"not removing"), name);
334207753Smm	else
335207753Smm#endif
336207753Smm		// There's a race condition between lstat() and unlink()
337207753Smm		// but at least we have tried to avoid removing wrong file.
338207753Smm		if (unlink(name))
339207753Smm			message_error(_("%s: Cannot remove: %s"),
340207753Smm					name, strerror(errno));
341207753Smm
342207753Smm	return;
343207753Smm}
344207753Smm
345207753Smm
346207753Smm/// \brief      Copies owner/group and permissions
347207753Smm///
348207753Smm/// \todo       ACL and EA support
349207753Smm///
350207753Smmstatic void
351207753Smmio_copy_attrs(const file_pair *pair)
352207753Smm{
353207753Smm	// Skip chown and chmod on Windows.
354207753Smm#ifndef TUKLIB_DOSLIKE
355207753Smm	// This function is more tricky than you may think at first.
356207753Smm	// Blindly copying permissions may permit users to access the
357207753Smm	// destination file who didn't have permission to access the
358207753Smm	// source file.
359207753Smm
360207753Smm	// Try changing the owner of the file. If we aren't root or the owner
361207753Smm	// isn't already us, fchown() probably doesn't succeed. We warn
362207753Smm	// about failing fchown() only if we are root.
363207753Smm	if (fchown(pair->dest_fd, pair->src_st.st_uid, -1) && warn_fchown)
364207753Smm		message_warning(_("%s: Cannot set the file owner: %s"),
365207753Smm				pair->dest_name, strerror(errno));
366207753Smm
367207753Smm	mode_t mode;
368207753Smm
369207753Smm	if (fchown(pair->dest_fd, -1, pair->src_st.st_gid)) {
370207753Smm		message_warning(_("%s: Cannot set the file group: %s"),
371207753Smm				pair->dest_name, strerror(errno));
372207753Smm		// We can still safely copy some additional permissions:
373207753Smm		// `group' must be at least as strict as `other' and
374207753Smm		// also vice versa.
375207753Smm		//
376207753Smm		// NOTE: After this, the owner of the source file may
377207753Smm		// get additional permissions. This shouldn't be too bad,
378207753Smm		// because the owner would have had permission to chmod
379207753Smm		// the original file anyway.
380207753Smm		mode = ((pair->src_st.st_mode & 0070) >> 3)
381207753Smm				& (pair->src_st.st_mode & 0007);
382207753Smm		mode = (pair->src_st.st_mode & 0700) | (mode << 3) | mode;
383207753Smm	} else {
384207753Smm		// Drop the setuid, setgid, and sticky bits.
385207753Smm		mode = pair->src_st.st_mode & 0777;
386207753Smm	}
387207753Smm
388207753Smm	if (fchmod(pair->dest_fd, mode))
389207753Smm		message_warning(_("%s: Cannot set the file permissions: %s"),
390207753Smm				pair->dest_name, strerror(errno));
391207753Smm#endif
392207753Smm
393207753Smm	// Copy the timestamps. We have several possible ways to do this, of
394207753Smm	// which some are better in both security and precision.
395207753Smm	//
396207753Smm	// First, get the nanosecond part of the timestamps. As of writing,
397207753Smm	// it's not standardized by POSIX, and there are several names for
398207753Smm	// the same thing in struct stat.
399207753Smm	long atime_nsec;
400207753Smm	long mtime_nsec;
401207753Smm
402207753Smm#	if defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
403207753Smm	// GNU and Solaris
404207753Smm	atime_nsec = pair->src_st.st_atim.tv_nsec;
405207753Smm	mtime_nsec = pair->src_st.st_mtim.tv_nsec;
406207753Smm
407207753Smm#	elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
408207753Smm	// BSD
409207753Smm	atime_nsec = pair->src_st.st_atimespec.tv_nsec;
410207753Smm	mtime_nsec = pair->src_st.st_mtimespec.tv_nsec;
411207753Smm
412207753Smm#	elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
413207753Smm	// GNU and BSD without extensions
414207753Smm	atime_nsec = pair->src_st.st_atimensec;
415207753Smm	mtime_nsec = pair->src_st.st_mtimensec;
416207753Smm
417207753Smm#	elif defined(HAVE_STRUCT_STAT_ST_UATIME)
418207753Smm	// Tru64
419207753Smm	atime_nsec = pair->src_st.st_uatime * 1000;
420207753Smm	mtime_nsec = pair->src_st.st_umtime * 1000;
421207753Smm
422207753Smm#	elif defined(HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC)
423207753Smm	// UnixWare
424207753Smm	atime_nsec = pair->src_st.st_atim.st__tim.tv_nsec;
425207753Smm	mtime_nsec = pair->src_st.st_mtim.st__tim.tv_nsec;
426207753Smm
427207753Smm#	else
428207753Smm	// Safe fallback
429207753Smm	atime_nsec = 0;
430207753Smm	mtime_nsec = 0;
431207753Smm#	endif
432207753Smm
433207753Smm	// Construct a structure to hold the timestamps and call appropriate
434207753Smm	// function to set the timestamps.
435207753Smm#if defined(HAVE_FUTIMENS)
436207753Smm	// Use nanosecond precision.
437207753Smm	struct timespec tv[2];
438207753Smm	tv[0].tv_sec = pair->src_st.st_atime;
439207753Smm	tv[0].tv_nsec = atime_nsec;
440207753Smm	tv[1].tv_sec = pair->src_st.st_mtime;
441207753Smm	tv[1].tv_nsec = mtime_nsec;
442207753Smm
443207753Smm	(void)futimens(pair->dest_fd, tv);
444207753Smm
445207753Smm#elif defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMES)
446207753Smm	// Use microsecond precision.
447207753Smm	struct timeval tv[2];
448207753Smm	tv[0].tv_sec = pair->src_st.st_atime;
449207753Smm	tv[0].tv_usec = atime_nsec / 1000;
450207753Smm	tv[1].tv_sec = pair->src_st.st_mtime;
451207753Smm	tv[1].tv_usec = mtime_nsec / 1000;
452207753Smm
453207753Smm#	if defined(HAVE_FUTIMES)
454207753Smm	(void)futimes(pair->dest_fd, tv);
455207753Smm#	elif defined(HAVE_FUTIMESAT)
456207753Smm	(void)futimesat(pair->dest_fd, NULL, tv);
457207753Smm#	else
458207753Smm	// Argh, no function to use a file descriptor to set the timestamp.
459207753Smm	(void)utimes(pair->dest_name, tv);
460207753Smm#	endif
461207753Smm
462312518Sdelphij#elif defined(HAVE__FUTIME)
463312518Sdelphij	// Use one-second precision with Windows-specific _futime().
464312518Sdelphij	// We could use utime() too except that for some reason the
465312518Sdelphij	// timestamp will get reset at close(). With _futime() it works.
466312518Sdelphij	// This struct cannot be const as _futime() takes a non-const pointer.
467312518Sdelphij	struct _utimbuf buf = {
468312518Sdelphij		.actime = pair->src_st.st_atime,
469312518Sdelphij		.modtime = pair->src_st.st_mtime,
470312518Sdelphij	};
471312518Sdelphij
472312518Sdelphij	// Avoid warnings.
473312518Sdelphij	(void)atime_nsec;
474312518Sdelphij	(void)mtime_nsec;
475312518Sdelphij
476312518Sdelphij	(void)_futime(pair->dest_fd, &buf);
477312518Sdelphij
478207753Smm#elif defined(HAVE_UTIME)
479207753Smm	// Use one-second precision. utime() doesn't support using file
480207753Smm	// descriptor either. Some systems have broken utime() prototype
481207753Smm	// so don't make this const.
482207753Smm	struct utimbuf buf = {
483207753Smm		.actime = pair->src_st.st_atime,
484207753Smm		.modtime = pair->src_st.st_mtime,
485207753Smm	};
486207753Smm
487207753Smm	// Avoid warnings.
488207753Smm	(void)atime_nsec;
489207753Smm	(void)mtime_nsec;
490207753Smm
491207753Smm	(void)utime(pair->dest_name, &buf);
492207753Smm#endif
493207753Smm
494207753Smm	return;
495207753Smm}
496207753Smm
497207753Smm
498207753Smm/// Opens the source file. Returns false on success, true on error.
499207753Smmstatic bool
500207753Smmio_open_src_real(file_pair *pair)
501207753Smm{
502207753Smm	// There's nothing to open when reading from stdin.
503207753Smm	if (pair->src_name == stdin_filename) {
504207753Smm		pair->src_fd = STDIN_FILENO;
505207753Smm#ifdef TUKLIB_DOSLIKE
506207753Smm		setmode(STDIN_FILENO, O_BINARY);
507292588Sdelphij#else
508292588Sdelphij		// Try to set stdin to non-blocking mode. It won't work
509292588Sdelphij		// e.g. on OpenBSD if stdout is e.g. /dev/null. In such
510292588Sdelphij		// case we proceed as if stdin were non-blocking anyway
511292588Sdelphij		// (in case of /dev/null it will be in practice). The
512292588Sdelphij		// same applies to stdout in io_open_dest_real().
513292588Sdelphij		stdin_flags = fcntl(STDIN_FILENO, F_GETFL);
514292588Sdelphij		if (stdin_flags == -1) {
515292588Sdelphij			message_error(_("Error getting the file status flags "
516292588Sdelphij					"from standard input: %s"),
517292588Sdelphij					strerror(errno));
518292588Sdelphij			return true;
519292588Sdelphij		}
520292588Sdelphij
521292588Sdelphij		if ((stdin_flags & O_NONBLOCK) == 0
522292588Sdelphij				&& fcntl(STDIN_FILENO, F_SETFL,
523292588Sdelphij					stdin_flags | O_NONBLOCK) != -1)
524292588Sdelphij			restore_stdin_flags = true;
525207753Smm#endif
526292588Sdelphij#ifdef HAVE_POSIX_FADVISE
527292588Sdelphij		// It will fail if stdin is a pipe and that's fine.
528292588Sdelphij		(void)posix_fadvise(STDIN_FILENO, 0, 0, POSIX_FADV_SEQUENTIAL);
529292588Sdelphij#endif
530207753Smm		return false;
531207753Smm	}
532207753Smm
533207753Smm	// Symlinks are not followed unless writing to stdout or --force
534207753Smm	// was used.
535207753Smm	const bool follow_symlinks = opt_stdout || opt_force;
536207753Smm
537207753Smm	// We accept only regular files if we are writing the output
538207753Smm	// to disk too. bzip2 allows overriding this with --force but
539207753Smm	// gzip and xz don't.
540207753Smm	const bool reg_files_only = !opt_stdout;
541207753Smm
542207753Smm	// Flags for open()
543207753Smm	int flags = O_RDONLY | O_BINARY | O_NOCTTY;
544207753Smm
545207753Smm#ifndef TUKLIB_DOSLIKE
546292588Sdelphij	// Use non-blocking I/O:
547292588Sdelphij	//   - It prevents blocking when opening FIFOs and some other
548292588Sdelphij	//     special files, which is good if we want to accept only
549292588Sdelphij	//     regular files.
550292588Sdelphij	//   - It can help avoiding some race conditions with signal handling.
551292588Sdelphij	flags |= O_NONBLOCK;
552207753Smm#endif
553207753Smm
554207753Smm#if defined(O_NOFOLLOW)
555207753Smm	if (!follow_symlinks)
556207753Smm		flags |= O_NOFOLLOW;
557207753Smm#elif !defined(TUKLIB_DOSLIKE)
558207753Smm	// Some POSIX-like systems lack O_NOFOLLOW (it's not required
559207753Smm	// by POSIX). Check for symlinks with a separate lstat() on
560207753Smm	// these systems.
561207753Smm	if (!follow_symlinks) {
562207753Smm		struct stat st;
563207753Smm		if (lstat(pair->src_name, &st)) {
564207753Smm			message_error("%s: %s", pair->src_name,
565207753Smm					strerror(errno));
566207753Smm			return true;
567207753Smm
568207753Smm		} else if (S_ISLNK(st.st_mode)) {
569207753Smm			message_warning(_("%s: Is a symbolic link, "
570207753Smm					"skipping"), pair->src_name);
571207753Smm			return true;
572207753Smm		}
573207753Smm	}
574207753Smm#else
575207753Smm	// Avoid warnings.
576207753Smm	(void)follow_symlinks;
577207753Smm#endif
578207753Smm
579292588Sdelphij	// Try to open the file. Signals have been blocked so EINTR shouldn't
580292588Sdelphij	// be possible.
581292588Sdelphij	pair->src_fd = open(pair->src_name, flags);
582207753Smm
583207753Smm	if (pair->src_fd == -1) {
584292588Sdelphij		// Signals (that have a signal handler) have been blocked.
585292588Sdelphij		assert(errno != EINTR);
586207753Smm
587207753Smm#ifdef O_NOFOLLOW
588213700Smm		// Give an understandable error message if the reason
589207753Smm		// for failing was that the file was a symbolic link.
590207753Smm		//
591207753Smm		// Note that at least Linux, OpenBSD, Solaris, and Darwin
592213700Smm		// use ELOOP to indicate that O_NOFOLLOW was the reason
593207753Smm		// that open() failed. Because there may be
594207753Smm		// directories in the pathname, ELOOP may occur also
595207753Smm		// because of a symlink loop in the directory part.
596213700Smm		// So ELOOP doesn't tell us what actually went wrong,
597213700Smm		// and this stupidity went into POSIX-1.2008 too.
598207753Smm		//
599207753Smm		// FreeBSD associates EMLINK with O_NOFOLLOW and
600207753Smm		// Tru64 uses ENOTSUP. We use these directly here
601207753Smm		// and skip the lstat() call and the associated race.
602207753Smm		// I want to hear if there are other kernels that
603207753Smm		// fail with something else than ELOOP with O_NOFOLLOW.
604207753Smm		bool was_symlink = false;
605207753Smm
606207753Smm#	if defined(__FreeBSD__) || defined(__DragonFly__)
607207753Smm		if (errno == EMLINK)
608207753Smm			was_symlink = true;
609207753Smm
610207753Smm#	elif defined(__digital__) && defined(__unix__)
611207753Smm		if (errno == ENOTSUP)
612207753Smm			was_symlink = true;
613207753Smm
614207753Smm#	elif defined(__NetBSD__)
615207753Smm		if (errno == EFTYPE)
616207753Smm			was_symlink = true;
617207753Smm
618207753Smm#	else
619207753Smm		if (errno == ELOOP && !follow_symlinks) {
620207753Smm			const int saved_errno = errno;
621207753Smm			struct stat st;
622207753Smm			if (lstat(pair->src_name, &st) == 0
623207753Smm					&& S_ISLNK(st.st_mode))
624207753Smm				was_symlink = true;
625207753Smm
626207753Smm			errno = saved_errno;
627207753Smm		}
628207753Smm#	endif
629207753Smm
630207753Smm		if (was_symlink)
631207753Smm			message_warning(_("%s: Is a symbolic link, "
632207753Smm					"skipping"), pair->src_name);
633207753Smm		else
634207753Smm#endif
635207753Smm			// Something else than O_NOFOLLOW failing
636207753Smm			// (assuming that the race conditions didn't
637207753Smm			// confuse us).
638207753Smm			message_error("%s: %s", pair->src_name,
639207753Smm					strerror(errno));
640207753Smm
641207753Smm		return true;
642207753Smm	}
643207753Smm
644207753Smm	// Stat the source file. We need the result also when we copy
645207753Smm	// the permissions, and when unlinking.
646292588Sdelphij	//
647292588Sdelphij	// NOTE: Use stat() instead of fstat() with DJGPP, because
648292588Sdelphij	// then we have a better chance to get st_ino value that can
649292588Sdelphij	// be used in io_open_dest_real() to prevent overwriting the
650292588Sdelphij	// source file.
651292588Sdelphij#ifdef __DJGPP__
652292588Sdelphij	if (stat(pair->src_name, &pair->src_st))
653292588Sdelphij		goto error_msg;
654292588Sdelphij#else
655207753Smm	if (fstat(pair->src_fd, &pair->src_st))
656207753Smm		goto error_msg;
657292588Sdelphij#endif
658207753Smm
659207753Smm	if (S_ISDIR(pair->src_st.st_mode)) {
660207753Smm		message_warning(_("%s: Is a directory, skipping"),
661207753Smm				pair->src_name);
662207753Smm		goto error;
663207753Smm	}
664207753Smm
665219001Smm	if (reg_files_only && !S_ISREG(pair->src_st.st_mode)) {
666219001Smm		message_warning(_("%s: Not a regular file, skipping"),
667219001Smm				pair->src_name);
668219001Smm		goto error;
669219001Smm	}
670207753Smm
671207753Smm#ifndef TUKLIB_DOSLIKE
672219001Smm	if (reg_files_only && !opt_force) {
673207753Smm		if (pair->src_st.st_mode & (S_ISUID | S_ISGID)) {
674207753Smm			// gzip rejects setuid and setgid files even
675207753Smm			// when --force was used. bzip2 doesn't check
676207753Smm			// for them, but calls fchown() after fchmod(),
677207753Smm			// and many systems automatically drop setuid
678207753Smm			// and setgid bits there.
679207753Smm			//
680207753Smm			// We accept setuid and setgid files if
681207753Smm			// --force was used. We drop these bits
682207753Smm			// explicitly in io_copy_attr().
683207753Smm			message_warning(_("%s: File has setuid or "
684207753Smm					"setgid bit set, skipping"),
685207753Smm					pair->src_name);
686207753Smm			goto error;
687207753Smm		}
688207753Smm
689207753Smm		if (pair->src_st.st_mode & S_ISVTX) {
690207753Smm			message_warning(_("%s: File has sticky bit "
691207753Smm					"set, skipping"),
692207753Smm					pair->src_name);
693207753Smm			goto error;
694207753Smm		}
695207753Smm
696207753Smm		if (pair->src_st.st_nlink > 1) {
697207753Smm			message_warning(_("%s: Input file has more "
698207753Smm					"than one hard link, "
699207753Smm					"skipping"), pair->src_name);
700207753Smm			goto error;
701207753Smm		}
702219001Smm	}
703292588Sdelphij
704292588Sdelphij	// If it is something else than a regular file, wait until
705292588Sdelphij	// there is input available. This way reading from FIFOs
706292588Sdelphij	// will work when open() is used with O_NONBLOCK.
707292588Sdelphij	if (!S_ISREG(pair->src_st.st_mode)) {
708292588Sdelphij		signals_unblock();
709292588Sdelphij		const io_wait_ret ret = io_wait(pair, -1, true);
710292588Sdelphij		signals_block();
711292588Sdelphij
712292588Sdelphij		if (ret != IO_WAIT_MORE)
713292588Sdelphij			goto error;
714292588Sdelphij	}
715207753Smm#endif
716207753Smm
717292588Sdelphij#ifdef HAVE_POSIX_FADVISE
718292588Sdelphij	// It will fail with some special files like FIFOs but that is fine.
719292588Sdelphij	(void)posix_fadvise(pair->src_fd, 0, 0, POSIX_FADV_SEQUENTIAL);
720292588Sdelphij#endif
721292588Sdelphij
722207753Smm	return false;
723207753Smm
724207753Smmerror_msg:
725207753Smm	message_error("%s: %s", pair->src_name, strerror(errno));
726207753Smmerror:
727207753Smm	(void)close(pair->src_fd);
728207753Smm	return true;
729207753Smm}
730207753Smm
731207753Smm
732207753Smmextern file_pair *
733207753Smmio_open_src(const char *src_name)
734207753Smm{
735207753Smm	if (is_empty_filename(src_name))
736207753Smm		return NULL;
737207753Smm
738207753Smm	// Since we have only one file open at a time, we can use
739207753Smm	// a statically allocated structure.
740207753Smm	static file_pair pair;
741207753Smm
742207753Smm	pair = (file_pair){
743207753Smm		.src_name = src_name,
744207753Smm		.dest_name = NULL,
745207753Smm		.src_fd = -1,
746207753Smm		.dest_fd = -1,
747207753Smm		.src_eof = false,
748207753Smm		.dest_try_sparse = false,
749207753Smm		.dest_pending_sparse = 0,
750207753Smm	};
751207753Smm
752207753Smm	// Block the signals, for which we have a custom signal handler, so
753207753Smm	// that we don't need to worry about EINTR.
754207753Smm	signals_block();
755207753Smm	const bool error = io_open_src_real(&pair);
756207753Smm	signals_unblock();
757207753Smm
758312518Sdelphij#ifdef ENABLE_SANDBOX
759312518Sdelphij	if (!error)
760312518Sdelphij		io_sandbox_enter(pair.src_fd);
761312518Sdelphij#endif
762312518Sdelphij
763207753Smm	return error ? NULL : &pair;
764207753Smm}
765207753Smm
766207753Smm
767207753Smm/// \brief      Closes source file of the file_pair structure
768207753Smm///
769207753Smm/// \param      pair    File whose src_fd should be closed
770207753Smm/// \param      success If true, the file will be removed from the disk if
771207753Smm///                     closing succeeds and --keep hasn't been used.
772207753Smmstatic void
773207753Smmio_close_src(file_pair *pair, bool success)
774207753Smm{
775292588Sdelphij#ifndef TUKLIB_DOSLIKE
776292588Sdelphij	if (restore_stdin_flags) {
777292588Sdelphij		assert(pair->src_fd == STDIN_FILENO);
778292588Sdelphij
779292588Sdelphij		restore_stdin_flags = false;
780292588Sdelphij
781292588Sdelphij		if (fcntl(STDIN_FILENO, F_SETFL, stdin_flags) == -1)
782292588Sdelphij			message_error(_("Error restoring the status flags "
783292588Sdelphij					"to standard input: %s"),
784292588Sdelphij					strerror(errno));
785292588Sdelphij	}
786292588Sdelphij#endif
787292588Sdelphij
788207753Smm	if (pair->src_fd != STDIN_FILENO && pair->src_fd != -1) {
789312518Sdelphij		// Close the file before possibly unlinking it. On DOS-like
790312518Sdelphij		// systems this is always required since unlinking will fail
791312518Sdelphij		// if the file is open. On POSIX systems it usually works
792312518Sdelphij		// to unlink open files, but in some cases it doesn't and
793312518Sdelphij		// one gets EBUSY in errno.
794312518Sdelphij		//
795312518Sdelphij		// xz 5.2.2 and older unlinked the file before closing it
796312518Sdelphij		// (except on DOS-like systems). The old code didn't handle
797312518Sdelphij		// EBUSY and could fail e.g. on some CIFS shares. The
798312518Sdelphij		// advantage of unlinking before closing is negligible
799312518Sdelphij		// (avoids a race between close() and stat()/lstat() and
800312518Sdelphij		// unlink()), so let's keep this simple.
801207753Smm		(void)close(pair->src_fd);
802207753Smm
803207753Smm		if (success && !opt_keep_original)
804207753Smm			io_unlink(pair->src_name, &pair->src_st);
805207753Smm	}
806207753Smm
807207753Smm	return;
808207753Smm}
809207753Smm
810207753Smm
811207753Smmstatic bool
812207753Smmio_open_dest_real(file_pair *pair)
813207753Smm{
814207753Smm	if (opt_stdout || pair->src_fd == STDIN_FILENO) {
815207753Smm		// We don't modify or free() this.
816207753Smm		pair->dest_name = (char *)"(stdout)";
817207753Smm		pair->dest_fd = STDOUT_FILENO;
818207753Smm#ifdef TUKLIB_DOSLIKE
819207753Smm		setmode(STDOUT_FILENO, O_BINARY);
820292588Sdelphij#else
821292588Sdelphij		// Try to set O_NONBLOCK if it isn't already set.
822292588Sdelphij		// If it fails, we assume that stdout is non-blocking
823292588Sdelphij		// in practice. See the comments in io_open_src_real()
824292588Sdelphij		// for similar situation with stdin.
825292588Sdelphij		//
826292588Sdelphij		// NOTE: O_APPEND may be unset later in this function
827292588Sdelphij		// and it relies on stdout_flags being set here.
828292588Sdelphij		stdout_flags = fcntl(STDOUT_FILENO, F_GETFL);
829292588Sdelphij		if (stdout_flags == -1) {
830292588Sdelphij			message_error(_("Error getting the file status flags "
831292588Sdelphij					"from standard output: %s"),
832292588Sdelphij					strerror(errno));
833292588Sdelphij			return true;
834292588Sdelphij		}
835292588Sdelphij
836292588Sdelphij		if ((stdout_flags & O_NONBLOCK) == 0
837292588Sdelphij				&& fcntl(STDOUT_FILENO, F_SETFL,
838292588Sdelphij					stdout_flags | O_NONBLOCK) != -1)
839292588Sdelphij				restore_stdout_flags = true;
840207753Smm#endif
841207753Smm	} else {
842207753Smm		pair->dest_name = suffix_get_dest_name(pair->src_name);
843207753Smm		if (pair->dest_name == NULL)
844207753Smm			return true;
845207753Smm
846292588Sdelphij#ifdef __DJGPP__
847292588Sdelphij		struct stat st;
848292588Sdelphij		if (stat(pair->dest_name, &st) == 0) {
849292588Sdelphij			// Check that it isn't a special file like "prn".
850292588Sdelphij			if (st.st_dev == -1) {
851292588Sdelphij				message_error("%s: Refusing to write to "
852292588Sdelphij						"a DOS special file",
853292588Sdelphij						pair->dest_name);
854292588Sdelphij				free(pair->dest_name);
855292588Sdelphij				return true;
856292588Sdelphij			}
857292588Sdelphij
858292588Sdelphij			// Check that we aren't overwriting the source file.
859292588Sdelphij			if (st.st_dev == pair->src_st.st_dev
860292588Sdelphij					&& st.st_ino == pair->src_st.st_ino) {
861292588Sdelphij				message_error("%s: Output file is the same "
862292588Sdelphij						"as the input file",
863292588Sdelphij						pair->dest_name);
864292588Sdelphij				free(pair->dest_name);
865292588Sdelphij				return true;
866292588Sdelphij			}
867292588Sdelphij		}
868292588Sdelphij#endif
869292588Sdelphij
870207753Smm		// If --force was used, unlink the target file first.
871207753Smm		if (opt_force && unlink(pair->dest_name) && errno != ENOENT) {
872207753Smm			message_error(_("%s: Cannot remove: %s"),
873207753Smm					pair->dest_name, strerror(errno));
874207753Smm			free(pair->dest_name);
875207753Smm			return true;
876207753Smm		}
877207753Smm
878207753Smm		// Open the file.
879292588Sdelphij		int flags = O_WRONLY | O_BINARY | O_NOCTTY
880207753Smm				| O_CREAT | O_EXCL;
881292588Sdelphij#ifndef TUKLIB_DOSLIKE
882292588Sdelphij		flags |= O_NONBLOCK;
883292588Sdelphij#endif
884207753Smm		const mode_t mode = S_IRUSR | S_IWUSR;
885207753Smm		pair->dest_fd = open(pair->dest_name, flags, mode);
886207753Smm
887207753Smm		if (pair->dest_fd == -1) {
888207753Smm			message_error("%s: %s", pair->dest_name,
889207753Smm					strerror(errno));
890207753Smm			free(pair->dest_name);
891207753Smm			return true;
892207753Smm		}
893207753Smm	}
894207753Smm
895292588Sdelphij#ifndef TUKLIB_DOSLIKE
896292588Sdelphij	// dest_st isn't used on DOS-like systems except as a dummy
897292588Sdelphij	// argument to io_unlink(), so don't fstat() on such systems.
898207753Smm	if (fstat(pair->dest_fd, &pair->dest_st)) {
899292588Sdelphij		// If fstat() really fails, we have a safe fallback here.
900292588Sdelphij#	if defined(__VMS)
901207753Smm		pair->dest_st.st_ino[0] = 0;
902207753Smm		pair->dest_st.st_ino[1] = 0;
903207753Smm		pair->dest_st.st_ino[2] = 0;
904292588Sdelphij#	else
905207753Smm		pair->dest_st.st_dev = 0;
906207753Smm		pair->dest_st.st_ino = 0;
907292588Sdelphij#	endif
908207753Smm	} else if (try_sparse && opt_mode == MODE_DECOMPRESS) {
909207753Smm		// When writing to standard output, we need to be extra
910207753Smm		// careful:
911207753Smm		//  - It may be connected to something else than
912207753Smm		//    a regular file.
913207753Smm		//  - We aren't necessarily writing to a new empty file
914207753Smm		//    or to the end of an existing file.
915207753Smm		//  - O_APPEND may be active.
916207753Smm		//
917207753Smm		// TODO: I'm keeping this disabled for DOS-like systems
918207753Smm		// for now. FAT doesn't support sparse files, but NTFS
919207753Smm		// does, so maybe this should be enabled on Windows after
920207753Smm		// some testing.
921207753Smm		if (pair->dest_fd == STDOUT_FILENO) {
922207753Smm			if (!S_ISREG(pair->dest_st.st_mode))
923207753Smm				return false;
924207753Smm
925263285Sdelphij			if (stdout_flags & O_APPEND) {
926207753Smm				// Creating a sparse file is not possible
927207753Smm				// when O_APPEND is active (it's used by
928207753Smm				// shell's >> redirection). As I understand
929207753Smm				// it, it is safe to temporarily disable
930207753Smm				// O_APPEND in xz, because if someone
931207753Smm				// happened to write to the same file at the
932207753Smm				// same time, results would be bad anyway
933207753Smm				// (users shouldn't assume that xz uses any
934207753Smm				// specific block size when writing data).
935207753Smm				//
936207753Smm				// The write position may be something else
937207753Smm				// than the end of the file, so we must fix
938207753Smm				// it to start writing at the end of the file
939207753Smm				// to imitate O_APPEND.
940207753Smm				if (lseek(STDOUT_FILENO, 0, SEEK_END) == -1)
941207753Smm					return false;
942207753Smm
943292588Sdelphij				// Construct the new file status flags.
944292588Sdelphij				// If O_NONBLOCK was set earlier in this
945292588Sdelphij				// function, it must be kept here too.
946292588Sdelphij				int flags = stdout_flags & ~O_APPEND;
947292588Sdelphij				if (restore_stdout_flags)
948292588Sdelphij					flags |= O_NONBLOCK;
949292588Sdelphij
950292588Sdelphij				// If this fcntl() fails, we continue but won't
951292588Sdelphij				// try to create sparse output. The original
952292588Sdelphij				// flags will still be restored if needed (to
953292588Sdelphij				// unset O_NONBLOCK) when the file is finished.
954292588Sdelphij				if (fcntl(STDOUT_FILENO, F_SETFL, flags) == -1)
955207753Smm					return false;
956207753Smm
957263285Sdelphij				// Disabling O_APPEND succeeded. Mark
958263285Sdelphij				// that the flags should be restored
959292588Sdelphij				// in io_close_dest(). (This may have already
960292588Sdelphij				// been set when enabling O_NONBLOCK.)
961263285Sdelphij				restore_stdout_flags = true;
962207753Smm
963207753Smm			} else if (lseek(STDOUT_FILENO, 0, SEEK_CUR)
964207753Smm					!= pair->dest_st.st_size) {
965207753Smm				// Writing won't start exactly at the end
966207753Smm				// of the file. We cannot use sparse output,
967207753Smm				// because it would probably corrupt the file.
968207753Smm				return false;
969207753Smm			}
970207753Smm		}
971207753Smm
972207753Smm		pair->dest_try_sparse = true;
973292588Sdelphij	}
974207753Smm#endif
975207753Smm
976207753Smm	return false;
977207753Smm}
978207753Smm
979207753Smm
980207753Smmextern bool
981207753Smmio_open_dest(file_pair *pair)
982207753Smm{
983207753Smm	signals_block();
984207753Smm	const bool ret = io_open_dest_real(pair);
985207753Smm	signals_unblock();
986207753Smm	return ret;
987207753Smm}
988207753Smm
989207753Smm
990207753Smm/// \brief      Closes destination file of the file_pair structure
991207753Smm///
992207753Smm/// \param      pair    File whose dest_fd should be closed
993207753Smm/// \param      success If false, the file will be removed from the disk.
994207753Smm///
995207753Smm/// \return     Zero if closing succeeds. On error, -1 is returned and
996207753Smm///             error message printed.
997207753Smmstatic bool
998207753Smmio_close_dest(file_pair *pair, bool success)
999207753Smm{
1000207753Smm#ifndef TUKLIB_DOSLIKE
1001207753Smm	// If io_open_dest() has disabled O_APPEND, restore it here.
1002263285Sdelphij	if (restore_stdout_flags) {
1003207753Smm		assert(pair->dest_fd == STDOUT_FILENO);
1004207753Smm
1005263285Sdelphij		restore_stdout_flags = false;
1006207753Smm
1007263285Sdelphij		if (fcntl(STDOUT_FILENO, F_SETFL, stdout_flags) == -1) {
1008207753Smm			message_error(_("Error restoring the O_APPEND flag "
1009207753Smm					"to standard output: %s"),
1010207753Smm					strerror(errno));
1011207753Smm			return true;
1012207753Smm		}
1013207753Smm	}
1014207753Smm#endif
1015207753Smm
1016207753Smm	if (pair->dest_fd == -1 || pair->dest_fd == STDOUT_FILENO)
1017207753Smm		return false;
1018207753Smm
1019207753Smm	if (close(pair->dest_fd)) {
1020207753Smm		message_error(_("%s: Closing the file failed: %s"),
1021207753Smm				pair->dest_name, strerror(errno));
1022207753Smm
1023207753Smm		// Closing destination file failed, so we cannot trust its
1024207753Smm		// contents. Get rid of junk:
1025207753Smm		io_unlink(pair->dest_name, &pair->dest_st);
1026207753Smm		free(pair->dest_name);
1027207753Smm		return true;
1028207753Smm	}
1029207753Smm
1030207753Smm	// If the operation using this file wasn't successful, we git rid
1031207753Smm	// of the junk file.
1032207753Smm	if (!success)
1033207753Smm		io_unlink(pair->dest_name, &pair->dest_st);
1034207753Smm
1035207753Smm	free(pair->dest_name);
1036207753Smm
1037207753Smm	return false;
1038207753Smm}
1039207753Smm
1040207753Smm
1041207753Smmextern void
1042207753Smmio_close(file_pair *pair, bool success)
1043207753Smm{
1044207753Smm	// Take care of sparseness at the end of the output file.
1045207753Smm	if (success && pair->dest_try_sparse
1046207753Smm			&& pair->dest_pending_sparse > 0) {
1047207753Smm		// Seek forward one byte less than the size of the pending
1048207753Smm		// hole, then write one zero-byte. This way the file grows
1049207753Smm		// to its correct size. An alternative would be to use
1050207753Smm		// ftruncate() but that isn't portable enough (e.g. it
1051207753Smm		// doesn't work with FAT on Linux; FAT isn't that important
1052207753Smm		// since it doesn't support sparse files anyway, but we don't
1053207753Smm		// want to create corrupt files on it).
1054207753Smm		if (lseek(pair->dest_fd, pair->dest_pending_sparse - 1,
1055207753Smm				SEEK_CUR) == -1) {
1056207753Smm			message_error(_("%s: Seeking failed when trying "
1057207753Smm					"to create a sparse file: %s"),
1058207753Smm					pair->dest_name, strerror(errno));
1059207753Smm			success = false;
1060207753Smm		} else {
1061207753Smm			const uint8_t zero[1] = { '\0' };
1062207753Smm			if (io_write_buf(pair, zero, 1))
1063207753Smm				success = false;
1064207753Smm		}
1065207753Smm	}
1066207753Smm
1067207753Smm	signals_block();
1068207753Smm
1069207753Smm	// Copy the file attributes. We need to skip this if destination
1070207753Smm	// file isn't open or it is standard output.
1071207753Smm	if (success && pair->dest_fd != -1 && pair->dest_fd != STDOUT_FILENO)
1072207753Smm		io_copy_attrs(pair);
1073207753Smm
1074207753Smm	// Close the destination first. If it fails, we must not remove
1075207753Smm	// the source file!
1076207753Smm	if (io_close_dest(pair, success))
1077207753Smm		success = false;
1078207753Smm
1079207753Smm	// Close the source file, and unlink it if the operation using this
1080207753Smm	// file pair was successful and we haven't requested to keep the
1081207753Smm	// source file.
1082207753Smm	io_close_src(pair, success);
1083207753Smm
1084207753Smm	signals_unblock();
1085207753Smm
1086207753Smm	return;
1087207753Smm}
1088207753Smm
1089207753Smm
1090292588Sdelphijextern void
1091292588Sdelphijio_fix_src_pos(file_pair *pair, size_t rewind_size)
1092292588Sdelphij{
1093292588Sdelphij	assert(rewind_size <= IO_BUFFER_SIZE);
1094292588Sdelphij
1095292588Sdelphij	if (rewind_size > 0) {
1096292588Sdelphij		// This doesn't need to work on unseekable file descriptors,
1097292588Sdelphij		// so just ignore possible errors.
1098292588Sdelphij		(void)lseek(pair->src_fd, -(off_t)(rewind_size), SEEK_CUR);
1099292588Sdelphij	}
1100292588Sdelphij
1101292588Sdelphij	return;
1102292588Sdelphij}
1103292588Sdelphij
1104292588Sdelphij
1105207753Smmextern size_t
1106207753Smmio_read(file_pair *pair, io_buf *buf_union, size_t size)
1107207753Smm{
1108207753Smm	// We use small buffers here.
1109207753Smm	assert(size < SSIZE_MAX);
1110207753Smm
1111207753Smm	uint8_t *buf = buf_union->u8;
1112207753Smm	size_t left = size;
1113207753Smm
1114207753Smm	while (left > 0) {
1115207753Smm		const ssize_t amount = read(pair->src_fd, buf, left);
1116207753Smm
1117207753Smm		if (amount == 0) {
1118207753Smm			pair->src_eof = true;
1119207753Smm			break;
1120207753Smm		}
1121207753Smm
1122207753Smm		if (amount == -1) {
1123207753Smm			if (errno == EINTR) {
1124207753Smm				if (user_abort)
1125207753Smm					return SIZE_MAX;
1126207753Smm
1127207753Smm				continue;
1128207753Smm			}
1129207753Smm
1130292588Sdelphij#ifndef TUKLIB_DOSLIKE
1131312518Sdelphij			if (IS_EAGAIN_OR_EWOULDBLOCK(errno)) {
1132292588Sdelphij				const io_wait_ret ret = io_wait(pair,
1133292588Sdelphij						mytime_get_flush_timeout(),
1134292588Sdelphij						true);
1135292588Sdelphij				switch (ret) {
1136292588Sdelphij				case IO_WAIT_MORE:
1137292588Sdelphij					continue;
1138292588Sdelphij
1139292588Sdelphij				case IO_WAIT_ERROR:
1140292588Sdelphij					return SIZE_MAX;
1141292588Sdelphij
1142292588Sdelphij				case IO_WAIT_TIMEOUT:
1143292588Sdelphij					return size - left;
1144292588Sdelphij
1145292588Sdelphij				default:
1146292588Sdelphij					message_bug();
1147292588Sdelphij				}
1148292588Sdelphij			}
1149292588Sdelphij#endif
1150292588Sdelphij
1151207753Smm			message_error(_("%s: Read error: %s"),
1152207753Smm					pair->src_name, strerror(errno));
1153207753Smm
1154207753Smm			return SIZE_MAX;
1155207753Smm		}
1156207753Smm
1157207753Smm		buf += (size_t)(amount);
1158207753Smm		left -= (size_t)(amount);
1159207753Smm	}
1160207753Smm
1161207753Smm	return size - left;
1162207753Smm}
1163207753Smm
1164207753Smm
1165207753Smmextern bool
1166207753Smmio_pread(file_pair *pair, io_buf *buf, size_t size, off_t pos)
1167207753Smm{
1168207753Smm	// Using lseek() and read() is more portable than pread() and
1169207753Smm	// for us it is as good as real pread().
1170207753Smm	if (lseek(pair->src_fd, pos, SEEK_SET) != pos) {
1171207753Smm		message_error(_("%s: Error seeking the file: %s"),
1172207753Smm				pair->src_name, strerror(errno));
1173207753Smm		return true;
1174207753Smm	}
1175207753Smm
1176207753Smm	const size_t amount = io_read(pair, buf, size);
1177207753Smm	if (amount == SIZE_MAX)
1178207753Smm		return true;
1179207753Smm
1180207753Smm	if (amount != size) {
1181207753Smm		message_error(_("%s: Unexpected end of file"),
1182207753Smm				pair->src_name);
1183207753Smm		return true;
1184207753Smm	}
1185207753Smm
1186207753Smm	return false;
1187207753Smm}
1188207753Smm
1189207753Smm
1190207753Smmstatic bool
1191207753Smmis_sparse(const io_buf *buf)
1192207753Smm{
1193207753Smm	assert(IO_BUFFER_SIZE % sizeof(uint64_t) == 0);
1194207753Smm
1195207753Smm	for (size_t i = 0; i < ARRAY_SIZE(buf->u64); ++i)
1196207753Smm		if (buf->u64[i] != 0)
1197207753Smm			return false;
1198207753Smm
1199207753Smm	return true;
1200207753Smm}
1201207753Smm
1202207753Smm
1203207753Smmstatic bool
1204207753Smmio_write_buf(file_pair *pair, const uint8_t *buf, size_t size)
1205207753Smm{
1206207753Smm	assert(size < SSIZE_MAX);
1207207753Smm
1208207753Smm	while (size > 0) {
1209207753Smm		const ssize_t amount = write(pair->dest_fd, buf, size);
1210207753Smm		if (amount == -1) {
1211207753Smm			if (errno == EINTR) {
1212207753Smm				if (user_abort)
1213263285Sdelphij					return true;
1214207753Smm
1215207753Smm				continue;
1216207753Smm			}
1217207753Smm
1218292588Sdelphij#ifndef TUKLIB_DOSLIKE
1219312518Sdelphij			if (IS_EAGAIN_OR_EWOULDBLOCK(errno)) {
1220292588Sdelphij				if (io_wait(pair, -1, false) == IO_WAIT_MORE)
1221292588Sdelphij					continue;
1222292588Sdelphij
1223292588Sdelphij				return true;
1224292588Sdelphij			}
1225292588Sdelphij#endif
1226292588Sdelphij
1227207753Smm			// Handle broken pipe specially. gzip and bzip2
1228207753Smm			// don't print anything on SIGPIPE. In addition,
1229207753Smm			// gzip --quiet uses exit status 2 (warning) on
1230207753Smm			// broken pipe instead of whatever raise(SIGPIPE)
1231207753Smm			// would make it return. It is there to hide "Broken
1232207753Smm			// pipe" message on some old shells (probably old
1233207753Smm			// GNU bash).
1234207753Smm			//
1235207753Smm			// We don't do anything special with --quiet, which
1236207753Smm			// is what bzip2 does too. If we get SIGPIPE, we
1237207753Smm			// will handle it like other signals by setting
1238207753Smm			// user_abort, and get EPIPE here.
1239207753Smm			if (errno != EPIPE)
1240207753Smm				message_error(_("%s: Write error: %s"),
1241207753Smm					pair->dest_name, strerror(errno));
1242207753Smm
1243207753Smm			return true;
1244207753Smm		}
1245207753Smm
1246207753Smm		buf += (size_t)(amount);
1247207753Smm		size -= (size_t)(amount);
1248207753Smm	}
1249207753Smm
1250207753Smm	return false;
1251207753Smm}
1252207753Smm
1253207753Smm
1254207753Smmextern bool
1255207753Smmio_write(file_pair *pair, const io_buf *buf, size_t size)
1256207753Smm{
1257207753Smm	assert(size <= IO_BUFFER_SIZE);
1258207753Smm
1259207753Smm	if (pair->dest_try_sparse) {
1260207753Smm		// Check if the block is sparse (contains only zeros). If it
1261207753Smm		// sparse, we just store the amount and return. We will take
1262207753Smm		// care of actually skipping over the hole when we hit the
1263207753Smm		// next data block or close the file.
1264207753Smm		//
1265207753Smm		// Since io_close() requires that dest_pending_sparse > 0
1266207753Smm		// if the file ends with sparse block, we must also return
1267207753Smm		// if size == 0 to avoid doing the lseek().
1268207753Smm		if (size == IO_BUFFER_SIZE) {
1269207753Smm			if (is_sparse(buf)) {
1270207753Smm				pair->dest_pending_sparse += size;
1271207753Smm				return false;
1272207753Smm			}
1273207753Smm		} else if (size == 0) {
1274207753Smm			return false;
1275207753Smm		}
1276207753Smm
1277207753Smm		// This is not a sparse block. If we have a pending hole,
1278207753Smm		// skip it now.
1279207753Smm		if (pair->dest_pending_sparse > 0) {
1280207753Smm			if (lseek(pair->dest_fd, pair->dest_pending_sparse,
1281207753Smm					SEEK_CUR) == -1) {
1282207753Smm				message_error(_("%s: Seeking failed when "
1283207753Smm						"trying to create a sparse "
1284207753Smm						"file: %s"), pair->dest_name,
1285207753Smm						strerror(errno));
1286207753Smm				return true;
1287207753Smm			}
1288207753Smm
1289207753Smm			pair->dest_pending_sparse = 0;
1290207753Smm		}
1291207753Smm	}
1292207753Smm
1293207753Smm	return io_write_buf(pair, buf->u8, size);
1294207753Smm}
1295