1///////////////////////////////////////////////////////////////////////////////
2//
3/// \file       file_io.c
4/// \brief      File opening, unlinking, and closing
5//
6//  Author:     Lasse Collin
7//
8//  This file has been put into the public domain.
9//  You can do whatever you want with this file.
10//
11///////////////////////////////////////////////////////////////////////////////
12
13#include "private.h"
14
15#include <fcntl.h>
16
17#ifdef TUKLIB_DOSLIKE
18#	include <io.h>
19#else
20static bool warn_fchown;
21#endif
22
23#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMES)
24#	include <sys/time.h>
25#elif defined(HAVE_UTIME)
26#	include <utime.h>
27#endif
28
29#include "tuklib_open_stdxxx.h"
30
31#ifndef O_BINARY
32#	define O_BINARY 0
33#endif
34
35#ifndef O_NOCTTY
36#	define O_NOCTTY 0
37#endif
38
39
40/// If true, try to create sparse files when decompressing.
41static bool try_sparse = true;
42
43#ifndef TUKLIB_DOSLIKE
44/// File status flags of standard output. This is used by io_open_dest()
45/// and io_close_dest().
46static int stdout_flags = 0;
47#endif
48
49
50static bool io_write_buf(file_pair *pair, const uint8_t *buf, size_t size);
51
52
53extern void
54io_init(void)
55{
56	// Make sure that stdin, stdout, and stderr are connected to
57	// a valid file descriptor. Exit immediately with exit code ERROR
58	// if we cannot make the file descriptors valid. Maybe we should
59	// print an error message, but our stderr could be screwed anyway.
60	tuklib_open_stdxxx(E_ERROR);
61
62#ifndef TUKLIB_DOSLIKE
63	// If fchown() fails setting the owner, we warn about it only if
64	// we are root.
65	warn_fchown = geteuid() == 0;
66#endif
67
68#ifdef __DJGPP__
69	// Avoid doing useless things when statting files.
70	// This isn't important but doesn't hurt.
71	_djstat_flags = _STAT_INODE | _STAT_EXEC_EXT
72			| _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
73#endif
74
75	return;
76}
77
78
79extern void
80io_no_sparse(void)
81{
82	try_sparse = false;
83	return;
84}
85
86
87/// \brief      Unlink a file
88///
89/// This tries to verify that the file being unlinked really is the file that
90/// we want to unlink by verifying device and inode numbers. There's still
91/// a small unavoidable race, but this is much better than nothing (the file
92/// could have been moved/replaced even hours earlier).
93static void
94io_unlink(const char *name, const struct stat *known_st)
95{
96#if defined(TUKLIB_DOSLIKE)
97	// On DOS-like systems, st_ino is meaningless, so don't bother
98	// testing it. Just silence a compiler warning.
99	(void)known_st;
100#else
101	struct stat new_st;
102
103	// If --force was used, use stat() instead of lstat(). This way
104	// (de)compressing symlinks works correctly. However, it also means
105	// that xz cannot detect if a regular file foo is renamed to bar
106	// and then a symlink foo -> bar is created. Because of stat()
107	// instead of lstat(), xz will think that foo hasn't been replaced
108	// with another file. Thus, xz will remove foo even though it no
109	// longer is the same file that xz used when it started compressing.
110	// Probably it's not too bad though, so this doesn't need a more
111	// complex fix.
112	const int stat_ret = opt_force
113			? stat(name, &new_st) : lstat(name, &new_st);
114
115	if (stat_ret
116#	ifdef __VMS
117			// st_ino is an array, and we don't want to
118			// compare st_dev at all.
119			|| memcmp(&new_st.st_ino, &known_st->st_ino,
120				sizeof(new_st.st_ino)) != 0
121#	else
122			// Typical POSIX-like system
123			|| new_st.st_dev != known_st->st_dev
124			|| new_st.st_ino != known_st->st_ino
125#	endif
126			)
127		// TRANSLATORS: When compression or decompression finishes,
128		// and xz is going to remove the source file, xz first checks
129		// if the source file still exists, and if it does, does its
130		// device and inode numbers match what xz saw when it opened
131		// the source file. If these checks fail, this message is
132		// shown, %s being the filename, and the file is not deleted.
133		// The check for device and inode numbers is there, because
134		// it is possible that the user has put a new file in place
135		// of the original file, and in that case it obviously
136		// shouldn't be removed.
137		message_error(_("%s: File seems to have been moved, "
138				"not removing"), name);
139	else
140#endif
141		// There's a race condition between lstat() and unlink()
142		// but at least we have tried to avoid removing wrong file.
143		if (unlink(name))
144			message_error(_("%s: Cannot remove: %s"),
145					name, strerror(errno));
146
147	return;
148}
149
150
151/// \brief      Copies owner/group and permissions
152///
153/// \todo       ACL and EA support
154///
155static void
156io_copy_attrs(const file_pair *pair)
157{
158	// Skip chown and chmod on Windows.
159#ifndef TUKLIB_DOSLIKE
160	// This function is more tricky than you may think at first.
161	// Blindly copying permissions may permit users to access the
162	// destination file who didn't have permission to access the
163	// source file.
164
165	// Try changing the owner of the file. If we aren't root or the owner
166	// isn't already us, fchown() probably doesn't succeed. We warn
167	// about failing fchown() only if we are root.
168	if (fchown(pair->dest_fd, pair->src_st.st_uid, -1) && warn_fchown)
169		message_warning(_("%s: Cannot set the file owner: %s"),
170				pair->dest_name, strerror(errno));
171
172	mode_t mode;
173
174	if (fchown(pair->dest_fd, -1, pair->src_st.st_gid)) {
175		message_warning(_("%s: Cannot set the file group: %s"),
176				pair->dest_name, strerror(errno));
177		// We can still safely copy some additional permissions:
178		// `group' must be at least as strict as `other' and
179		// also vice versa.
180		//
181		// NOTE: After this, the owner of the source file may
182		// get additional permissions. This shouldn't be too bad,
183		// because the owner would have had permission to chmod
184		// the original file anyway.
185		mode = ((pair->src_st.st_mode & 0070) >> 3)
186				& (pair->src_st.st_mode & 0007);
187		mode = (pair->src_st.st_mode & 0700) | (mode << 3) | mode;
188	} else {
189		// Drop the setuid, setgid, and sticky bits.
190		mode = pair->src_st.st_mode & 0777;
191	}
192
193	if (fchmod(pair->dest_fd, mode))
194		message_warning(_("%s: Cannot set the file permissions: %s"),
195				pair->dest_name, strerror(errno));
196#endif
197
198	// Copy the timestamps. We have several possible ways to do this, of
199	// which some are better in both security and precision.
200	//
201	// First, get the nanosecond part of the timestamps. As of writing,
202	// it's not standardized by POSIX, and there are several names for
203	// the same thing in struct stat.
204	long atime_nsec;
205	long mtime_nsec;
206
207#	if defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
208	// GNU and Solaris
209	atime_nsec = pair->src_st.st_atim.tv_nsec;
210	mtime_nsec = pair->src_st.st_mtim.tv_nsec;
211
212#	elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
213	// BSD
214	atime_nsec = pair->src_st.st_atimespec.tv_nsec;
215	mtime_nsec = pair->src_st.st_mtimespec.tv_nsec;
216
217#	elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
218	// GNU and BSD without extensions
219	atime_nsec = pair->src_st.st_atimensec;
220	mtime_nsec = pair->src_st.st_mtimensec;
221
222#	elif defined(HAVE_STRUCT_STAT_ST_UATIME)
223	// Tru64
224	atime_nsec = pair->src_st.st_uatime * 1000;
225	mtime_nsec = pair->src_st.st_umtime * 1000;
226
227#	elif defined(HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC)
228	// UnixWare
229	atime_nsec = pair->src_st.st_atim.st__tim.tv_nsec;
230	mtime_nsec = pair->src_st.st_mtim.st__tim.tv_nsec;
231
232#	else
233	// Safe fallback
234	atime_nsec = 0;
235	mtime_nsec = 0;
236#	endif
237
238	// Construct a structure to hold the timestamps and call appropriate
239	// function to set the timestamps.
240#if defined(HAVE_FUTIMENS)
241	// Use nanosecond precision.
242	struct timespec tv[2];
243	tv[0].tv_sec = pair->src_st.st_atime;
244	tv[0].tv_nsec = atime_nsec;
245	tv[1].tv_sec = pair->src_st.st_mtime;
246	tv[1].tv_nsec = mtime_nsec;
247
248	(void)futimens(pair->dest_fd, tv);
249
250#elif defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMES)
251	// Use microsecond precision.
252	struct timeval tv[2];
253	tv[0].tv_sec = pair->src_st.st_atime;
254	tv[0].tv_usec = atime_nsec / 1000;
255	tv[1].tv_sec = pair->src_st.st_mtime;
256	tv[1].tv_usec = mtime_nsec / 1000;
257
258#	if defined(HAVE_FUTIMES)
259	(void)futimes(pair->dest_fd, tv);
260#	elif defined(HAVE_FUTIMESAT)
261	(void)futimesat(pair->dest_fd, NULL, tv);
262#	else
263	// Argh, no function to use a file descriptor to set the timestamp.
264	(void)utimes(pair->dest_name, tv);
265#	endif
266
267#elif defined(HAVE_UTIME)
268	// Use one-second precision. utime() doesn't support using file
269	// descriptor either. Some systems have broken utime() prototype
270	// so don't make this const.
271	struct utimbuf buf = {
272		.actime = pair->src_st.st_atime,
273		.modtime = pair->src_st.st_mtime,
274	};
275
276	// Avoid warnings.
277	(void)atime_nsec;
278	(void)mtime_nsec;
279
280	(void)utime(pair->dest_name, &buf);
281#endif
282
283	return;
284}
285
286
287/// Opens the source file. Returns false on success, true on error.
288static bool
289io_open_src_real(file_pair *pair)
290{
291	// There's nothing to open when reading from stdin.
292	if (pair->src_name == stdin_filename) {
293		pair->src_fd = STDIN_FILENO;
294#ifdef TUKLIB_DOSLIKE
295		setmode(STDIN_FILENO, O_BINARY);
296#endif
297		return false;
298	}
299
300	// Symlinks are not followed unless writing to stdout or --force
301	// was used.
302	const bool follow_symlinks = opt_stdout || opt_force;
303
304	// We accept only regular files if we are writing the output
305	// to disk too. bzip2 allows overriding this with --force but
306	// gzip and xz don't.
307	const bool reg_files_only = !opt_stdout;
308
309	// Flags for open()
310	int flags = O_RDONLY | O_BINARY | O_NOCTTY;
311
312#ifndef TUKLIB_DOSLIKE
313	// If we accept only regular files, we need to be careful to avoid
314	// problems with special files like devices and FIFOs. O_NONBLOCK
315	// prevents blocking when opening such files. When we want to accept
316	// special files, we must not use O_NONBLOCK, or otherwise we won't
317	// block waiting e.g. FIFOs to become readable.
318	if (reg_files_only)
319		flags |= O_NONBLOCK;
320#endif
321
322#if defined(O_NOFOLLOW)
323	if (!follow_symlinks)
324		flags |= O_NOFOLLOW;
325#elif !defined(TUKLIB_DOSLIKE)
326	// Some POSIX-like systems lack O_NOFOLLOW (it's not required
327	// by POSIX). Check for symlinks with a separate lstat() on
328	// these systems.
329	if (!follow_symlinks) {
330		struct stat st;
331		if (lstat(pair->src_name, &st)) {
332			message_error("%s: %s", pair->src_name,
333					strerror(errno));
334			return true;
335
336		} else if (S_ISLNK(st.st_mode)) {
337			message_warning(_("%s: Is a symbolic link, "
338					"skipping"), pair->src_name);
339			return true;
340		}
341	}
342#else
343	// Avoid warnings.
344	(void)follow_symlinks;
345#endif
346
347	// Try to open the file. If we are accepting non-regular files,
348	// unblock the caught signals so that open() can be interrupted
349	// if it blocks e.g. due to a FIFO file.
350	if (!reg_files_only)
351		signals_unblock();
352
353	// Maybe this wouldn't need a loop, since all the signal handlers for
354	// which we don't use SA_RESTART set user_abort to true. But it
355	// doesn't hurt to have it just in case.
356	do {
357		pair->src_fd = open(pair->src_name, flags);
358	} while (pair->src_fd == -1 && errno == EINTR && !user_abort);
359
360	if (!reg_files_only)
361		signals_block();
362
363	if (pair->src_fd == -1) {
364		// If we were interrupted, don't display any error message.
365		if (errno == EINTR) {
366			// All the signals that don't have SA_RESTART
367			// set user_abort.
368			assert(user_abort);
369			return true;
370		}
371
372#ifdef O_NOFOLLOW
373		// Give an understandable error message if the reason
374		// for failing was that the file was a symbolic link.
375		//
376		// Note that at least Linux, OpenBSD, Solaris, and Darwin
377		// use ELOOP to indicate that O_NOFOLLOW was the reason
378		// that open() failed. Because there may be
379		// directories in the pathname, ELOOP may occur also
380		// because of a symlink loop in the directory part.
381		// So ELOOP doesn't tell us what actually went wrong,
382		// and this stupidity went into POSIX-1.2008 too.
383		//
384		// FreeBSD associates EMLINK with O_NOFOLLOW and
385		// Tru64 uses ENOTSUP. We use these directly here
386		// and skip the lstat() call and the associated race.
387		// I want to hear if there are other kernels that
388		// fail with something else than ELOOP with O_NOFOLLOW.
389		bool was_symlink = false;
390
391#	if defined(__FreeBSD__) || defined(__DragonFly__)
392		if (errno == EMLINK)
393			was_symlink = true;
394
395#	elif defined(__digital__) && defined(__unix__)
396		if (errno == ENOTSUP)
397			was_symlink = true;
398
399#	elif defined(__NetBSD__)
400		// As of 2010-09-05, NetBSD doesn't document what errno is
401		// used with O_NOFOLLOW. It is EFTYPE though, and I
402		// understood that is very unlikely to change even though
403		// it is undocumented.
404		if (errno == EFTYPE)
405			was_symlink = true;
406
407#	else
408		if (errno == ELOOP && !follow_symlinks) {
409			const int saved_errno = errno;
410			struct stat st;
411			if (lstat(pair->src_name, &st) == 0
412					&& S_ISLNK(st.st_mode))
413				was_symlink = true;
414
415			errno = saved_errno;
416		}
417#	endif
418
419		if (was_symlink)
420			message_warning(_("%s: Is a symbolic link, "
421					"skipping"), pair->src_name);
422		else
423#endif
424			// Something else than O_NOFOLLOW failing
425			// (assuming that the race conditions didn't
426			// confuse us).
427			message_error("%s: %s", pair->src_name,
428					strerror(errno));
429
430		return true;
431	}
432
433#ifndef TUKLIB_DOSLIKE
434	// Drop O_NONBLOCK, which is used only when we are accepting only
435	// regular files. After the open() call, we want things to block
436	// instead of giving EAGAIN.
437	if (reg_files_only) {
438		flags = fcntl(pair->src_fd, F_GETFL);
439		if (flags == -1)
440			goto error_msg;
441
442		flags &= ~O_NONBLOCK;
443
444		if (fcntl(pair->src_fd, F_SETFL, flags))
445			goto error_msg;
446	}
447#endif
448
449	// Stat the source file. We need the result also when we copy
450	// the permissions, and when unlinking.
451	if (fstat(pair->src_fd, &pair->src_st))
452		goto error_msg;
453
454	if (S_ISDIR(pair->src_st.st_mode)) {
455		message_warning(_("%s: Is a directory, skipping"),
456				pair->src_name);
457		goto error;
458	}
459
460	if (reg_files_only && !S_ISREG(pair->src_st.st_mode)) {
461		message_warning(_("%s: Not a regular file, skipping"),
462				pair->src_name);
463		goto error;
464	}
465
466#ifndef TUKLIB_DOSLIKE
467	if (reg_files_only && !opt_force) {
468		if (pair->src_st.st_mode & (S_ISUID | S_ISGID)) {
469			// gzip rejects setuid and setgid files even
470			// when --force was used. bzip2 doesn't check
471			// for them, but calls fchown() after fchmod(),
472			// and many systems automatically drop setuid
473			// and setgid bits there.
474			//
475			// We accept setuid and setgid files if
476			// --force was used. We drop these bits
477			// explicitly in io_copy_attr().
478			message_warning(_("%s: File has setuid or "
479					"setgid bit set, skipping"),
480					pair->src_name);
481			goto error;
482		}
483
484		if (pair->src_st.st_mode & S_ISVTX) {
485			message_warning(_("%s: File has sticky bit "
486					"set, skipping"),
487					pair->src_name);
488			goto error;
489		}
490
491		if (pair->src_st.st_nlink > 1) {
492			message_warning(_("%s: Input file has more "
493					"than one hard link, "
494					"skipping"), pair->src_name);
495			goto error;
496		}
497	}
498#endif
499
500	return false;
501
502error_msg:
503	message_error("%s: %s", pair->src_name, strerror(errno));
504error:
505	(void)close(pair->src_fd);
506	return true;
507}
508
509
510extern file_pair *
511io_open_src(const char *src_name)
512{
513	if (is_empty_filename(src_name))
514		return NULL;
515
516	// Since we have only one file open at a time, we can use
517	// a statically allocated structure.
518	static file_pair pair;
519
520	pair = (file_pair){
521		.src_name = src_name,
522		.dest_name = NULL,
523		.src_fd = -1,
524		.dest_fd = -1,
525		.src_eof = false,
526		.dest_try_sparse = false,
527		.dest_pending_sparse = 0,
528	};
529
530	// Block the signals, for which we have a custom signal handler, so
531	// that we don't need to worry about EINTR.
532	signals_block();
533	const bool error = io_open_src_real(&pair);
534	signals_unblock();
535
536	return error ? NULL : &pair;
537}
538
539
540/// \brief      Closes source file of the file_pair structure
541///
542/// \param      pair    File whose src_fd should be closed
543/// \param      success If true, the file will be removed from the disk if
544///                     closing succeeds and --keep hasn't been used.
545static void
546io_close_src(file_pair *pair, bool success)
547{
548	if (pair->src_fd != STDIN_FILENO && pair->src_fd != -1) {
549#ifdef TUKLIB_DOSLIKE
550		(void)close(pair->src_fd);
551#endif
552
553		// If we are going to unlink(), do it before closing the file.
554		// This way there's no risk that someone replaces the file and
555		// happens to get same inode number, which would make us
556		// unlink() wrong file.
557		//
558		// NOTE: DOS-like systems are an exception to this, because
559		// they don't allow unlinking files that are open. *sigh*
560		if (success && !opt_keep_original)
561			io_unlink(pair->src_name, &pair->src_st);
562
563#ifndef TUKLIB_DOSLIKE
564		(void)close(pair->src_fd);
565#endif
566	}
567
568	return;
569}
570
571
572static bool
573io_open_dest_real(file_pair *pair)
574{
575	if (opt_stdout || pair->src_fd == STDIN_FILENO) {
576		// We don't modify or free() this.
577		pair->dest_name = (char *)"(stdout)";
578		pair->dest_fd = STDOUT_FILENO;
579#ifdef TUKLIB_DOSLIKE
580		setmode(STDOUT_FILENO, O_BINARY);
581#endif
582	} else {
583		pair->dest_name = suffix_get_dest_name(pair->src_name);
584		if (pair->dest_name == NULL)
585			return true;
586
587		// If --force was used, unlink the target file first.
588		if (opt_force && unlink(pair->dest_name) && errno != ENOENT) {
589			message_error(_("%s: Cannot remove: %s"),
590					pair->dest_name, strerror(errno));
591			free(pair->dest_name);
592			return true;
593		}
594
595		// Open the file.
596		const int flags = O_WRONLY | O_BINARY | O_NOCTTY
597				| O_CREAT | O_EXCL;
598		const mode_t mode = S_IRUSR | S_IWUSR;
599		pair->dest_fd = open(pair->dest_name, flags, mode);
600
601		if (pair->dest_fd == -1) {
602			message_error("%s: %s", pair->dest_name,
603					strerror(errno));
604			free(pair->dest_name);
605			return true;
606		}
607	}
608
609	// If this really fails... well, we have a safe fallback.
610	if (fstat(pair->dest_fd, &pair->dest_st)) {
611#if defined(__VMS)
612		pair->dest_st.st_ino[0] = 0;
613		pair->dest_st.st_ino[1] = 0;
614		pair->dest_st.st_ino[2] = 0;
615#elif !defined(TUKLIB_DOSLIKE)
616		pair->dest_st.st_dev = 0;
617		pair->dest_st.st_ino = 0;
618#endif
619#ifndef TUKLIB_DOSLIKE
620	} else if (try_sparse && opt_mode == MODE_DECOMPRESS) {
621		// When writing to standard output, we need to be extra
622		// careful:
623		//  - It may be connected to something else than
624		//    a regular file.
625		//  - We aren't necessarily writing to a new empty file
626		//    or to the end of an existing file.
627		//  - O_APPEND may be active.
628		//
629		// TODO: I'm keeping this disabled for DOS-like systems
630		// for now. FAT doesn't support sparse files, but NTFS
631		// does, so maybe this should be enabled on Windows after
632		// some testing.
633		if (pair->dest_fd == STDOUT_FILENO) {
634			if (!S_ISREG(pair->dest_st.st_mode))
635				return false;
636
637			const int flags = fcntl(STDOUT_FILENO, F_GETFL);
638			if (flags == -1)
639				return false;
640
641			if (flags & O_APPEND) {
642				// Creating a sparse file is not possible
643				// when O_APPEND is active (it's used by
644				// shell's >> redirection). As I understand
645				// it, it is safe to temporarily disable
646				// O_APPEND in xz, because if someone
647				// happened to write to the same file at the
648				// same time, results would be bad anyway
649				// (users shouldn't assume that xz uses any
650				// specific block size when writing data).
651				//
652				// The write position may be something else
653				// than the end of the file, so we must fix
654				// it to start writing at the end of the file
655				// to imitate O_APPEND.
656				if (lseek(STDOUT_FILENO, 0, SEEK_END) == -1)
657					return false;
658
659				if (fcntl(STDOUT_FILENO, F_SETFL,
660						stdout_flags & ~O_APPEND))
661					return false;
662
663				// Remember the flags so that io_close_dest()
664				// can restore them.
665				stdout_flags = flags;
666
667			} else if (lseek(STDOUT_FILENO, 0, SEEK_CUR)
668					!= pair->dest_st.st_size) {
669				// Writing won't start exactly at the end
670				// of the file. We cannot use sparse output,
671				// because it would probably corrupt the file.
672				return false;
673			}
674		}
675
676		pair->dest_try_sparse = true;
677#endif
678	}
679
680	return false;
681}
682
683
684extern bool
685io_open_dest(file_pair *pair)
686{
687	signals_block();
688	const bool ret = io_open_dest_real(pair);
689	signals_unblock();
690	return ret;
691}
692
693
694/// \brief      Closes destination file of the file_pair structure
695///
696/// \param      pair    File whose dest_fd should be closed
697/// \param      success If false, the file will be removed from the disk.
698///
699/// \return     Zero if closing succeeds. On error, -1 is returned and
700///             error message printed.
701static bool
702io_close_dest(file_pair *pair, bool success)
703{
704#ifndef TUKLIB_DOSLIKE
705	// If io_open_dest() has disabled O_APPEND, restore it here.
706	if (stdout_flags != 0) {
707		assert(pair->dest_fd == STDOUT_FILENO);
708
709		const int fail = fcntl(STDOUT_FILENO, F_SETFL, stdout_flags);
710		stdout_flags = 0;
711
712		if (fail) {
713			message_error(_("Error restoring the O_APPEND flag "
714					"to standard output: %s"),
715					strerror(errno));
716			return true;
717		}
718	}
719#endif
720
721	if (pair->dest_fd == -1 || pair->dest_fd == STDOUT_FILENO)
722		return false;
723
724	if (close(pair->dest_fd)) {
725		message_error(_("%s: Closing the file failed: %s"),
726				pair->dest_name, strerror(errno));
727
728		// Closing destination file failed, so we cannot trust its
729		// contents. Get rid of junk:
730		io_unlink(pair->dest_name, &pair->dest_st);
731		free(pair->dest_name);
732		return true;
733	}
734
735	// If the operation using this file wasn't successful, we git rid
736	// of the junk file.
737	if (!success)
738		io_unlink(pair->dest_name, &pair->dest_st);
739
740	free(pair->dest_name);
741
742	return false;
743}
744
745
746extern void
747io_close(file_pair *pair, bool success)
748{
749	// Take care of sparseness at the end of the output file.
750	if (success && pair->dest_try_sparse
751			&& pair->dest_pending_sparse > 0) {
752		// Seek forward one byte less than the size of the pending
753		// hole, then write one zero-byte. This way the file grows
754		// to its correct size. An alternative would be to use
755		// ftruncate() but that isn't portable enough (e.g. it
756		// doesn't work with FAT on Linux; FAT isn't that important
757		// since it doesn't support sparse files anyway, but we don't
758		// want to create corrupt files on it).
759		if (lseek(pair->dest_fd, pair->dest_pending_sparse - 1,
760				SEEK_CUR) == -1) {
761			message_error(_("%s: Seeking failed when trying "
762					"to create a sparse file: %s"),
763					pair->dest_name, strerror(errno));
764			success = false;
765		} else {
766			const uint8_t zero[1] = { '\0' };
767			if (io_write_buf(pair, zero, 1))
768				success = false;
769		}
770	}
771
772	signals_block();
773
774	// Copy the file attributes. We need to skip this if destination
775	// file isn't open or it is standard output.
776	if (success && pair->dest_fd != -1 && pair->dest_fd != STDOUT_FILENO)
777		io_copy_attrs(pair);
778
779	// Close the destination first. If it fails, we must not remove
780	// the source file!
781	if (io_close_dest(pair, success))
782		success = false;
783
784	// Close the source file, and unlink it if the operation using this
785	// file pair was successful and we haven't requested to keep the
786	// source file.
787	io_close_src(pair, success);
788
789	signals_unblock();
790
791	return;
792}
793
794
795extern size_t
796io_read(file_pair *pair, io_buf *buf_union, size_t size)
797{
798	// We use small buffers here.
799	assert(size < SSIZE_MAX);
800
801	uint8_t *buf = buf_union->u8;
802	size_t left = size;
803
804	while (left > 0) {
805		const ssize_t amount = read(pair->src_fd, buf, left);
806
807		if (amount == 0) {
808			pair->src_eof = true;
809			break;
810		}
811
812		if (amount == -1) {
813			if (errno == EINTR) {
814				if (user_abort)
815					return SIZE_MAX;
816
817				continue;
818			}
819
820			message_error(_("%s: Read error: %s"),
821					pair->src_name, strerror(errno));
822
823			// FIXME Is this needed?
824			pair->src_eof = true;
825
826			return SIZE_MAX;
827		}
828
829		buf += (size_t)(amount);
830		left -= (size_t)(amount);
831	}
832
833	return size - left;
834}
835
836
837extern bool
838io_pread(file_pair *pair, io_buf *buf, size_t size, off_t pos)
839{
840	// Using lseek() and read() is more portable than pread() and
841	// for us it is as good as real pread().
842	if (lseek(pair->src_fd, pos, SEEK_SET) != pos) {
843		message_error(_("%s: Error seeking the file: %s"),
844				pair->src_name, strerror(errno));
845		return true;
846	}
847
848	const size_t amount = io_read(pair, buf, size);
849	if (amount == SIZE_MAX)
850		return true;
851
852	if (amount != size) {
853		message_error(_("%s: Unexpected end of file"),
854				pair->src_name);
855		return true;
856	}
857
858	return false;
859}
860
861
862static bool
863is_sparse(const io_buf *buf)
864{
865	assert(IO_BUFFER_SIZE % sizeof(uint64_t) == 0);
866
867	for (size_t i = 0; i < ARRAY_SIZE(buf->u64); ++i)
868		if (buf->u64[i] != 0)
869			return false;
870
871	return true;
872}
873
874
875static bool
876io_write_buf(file_pair *pair, const uint8_t *buf, size_t size)
877{
878	assert(size < SSIZE_MAX);
879
880	while (size > 0) {
881		const ssize_t amount = write(pair->dest_fd, buf, size);
882		if (amount == -1) {
883			if (errno == EINTR) {
884				if (user_abort)
885					return -1;
886
887				continue;
888			}
889
890			// Handle broken pipe specially. gzip and bzip2
891			// don't print anything on SIGPIPE. In addition,
892			// gzip --quiet uses exit status 2 (warning) on
893			// broken pipe instead of whatever raise(SIGPIPE)
894			// would make it return. It is there to hide "Broken
895			// pipe" message on some old shells (probably old
896			// GNU bash).
897			//
898			// We don't do anything special with --quiet, which
899			// is what bzip2 does too. If we get SIGPIPE, we
900			// will handle it like other signals by setting
901			// user_abort, and get EPIPE here.
902			if (errno != EPIPE)
903				message_error(_("%s: Write error: %s"),
904					pair->dest_name, strerror(errno));
905
906			return true;
907		}
908
909		buf += (size_t)(amount);
910		size -= (size_t)(amount);
911	}
912
913	return false;
914}
915
916
917extern bool
918io_write(file_pair *pair, const io_buf *buf, size_t size)
919{
920	assert(size <= IO_BUFFER_SIZE);
921
922	if (pair->dest_try_sparse) {
923		// Check if the block is sparse (contains only zeros). If it
924		// sparse, we just store the amount and return. We will take
925		// care of actually skipping over the hole when we hit the
926		// next data block or close the file.
927		//
928		// Since io_close() requires that dest_pending_sparse > 0
929		// if the file ends with sparse block, we must also return
930		// if size == 0 to avoid doing the lseek().
931		if (size == IO_BUFFER_SIZE) {
932			if (is_sparse(buf)) {
933				pair->dest_pending_sparse += size;
934				return false;
935			}
936		} else if (size == 0) {
937			return false;
938		}
939
940		// This is not a sparse block. If we have a pending hole,
941		// skip it now.
942		if (pair->dest_pending_sparse > 0) {
943			if (lseek(pair->dest_fd, pair->dest_pending_sparse,
944					SEEK_CUR) == -1) {
945				message_error(_("%s: Seeking failed when "
946						"trying to create a sparse "
947						"file: %s"), pair->dest_name,
948						strerror(errno));
949				return true;
950			}
951
952			pair->dest_pending_sparse = 0;
953		}
954	}
955
956	return io_write_buf(pair, buf->u8, size);
957}
958