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> 26207753Smm#elif defined(HAVE_UTIME) 27207753Smm# include <utime.h> 28207753Smm#endif 29207753Smm 30207753Smm#include "tuklib_open_stdxxx.h" 31207753Smm 32207753Smm#ifndef O_BINARY 33207753Smm# define O_BINARY 0 34207753Smm#endif 35207753Smm 36207753Smm#ifndef O_NOCTTY 37207753Smm# define O_NOCTTY 0 38207753Smm#endif 39207753Smm 40207753Smm 41292588Sdelphijtypedef enum { 42292588Sdelphij IO_WAIT_MORE, // Reading or writing is possible. 43292588Sdelphij IO_WAIT_ERROR, // Error or user_abort 44292588Sdelphij IO_WAIT_TIMEOUT, // poll() timed out 45292588Sdelphij} io_wait_ret; 46292588Sdelphij 47292588Sdelphij 48207753Smm/// If true, try to create sparse files when decompressing. 49207753Smmstatic bool try_sparse = true; 50207753Smm 51207753Smm#ifndef TUKLIB_DOSLIKE 52292588Sdelphij/// File status flags of standard input. This is used by io_open_src() 53292588Sdelphij/// and io_close_src(). 54292588Sdelphijstatic int stdin_flags; 55292588Sdelphijstatic bool restore_stdin_flags = false; 56292588Sdelphij 57263285Sdelphij/// Original file status flags of standard output. This is used by 58263285Sdelphij/// io_open_dest() and io_close_dest() to save and restore the flags. 59263285Sdelphijstatic int stdout_flags; 60263285Sdelphijstatic bool restore_stdout_flags = false; 61292588Sdelphij 62292588Sdelphij/// Self-pipe used together with the user_abort variable to avoid 63292588Sdelphij/// race conditions with signal handling. 64292588Sdelphijstatic int user_abort_pipe[2]; 65207753Smm#endif 66207753Smm 67207753Smm 68207753Smmstatic bool io_write_buf(file_pair *pair, const uint8_t *buf, size_t size); 69207753Smm 70207753Smm 71207753Smmextern void 72207753Smmio_init(void) 73207753Smm{ 74223935Smm // Make sure that stdin, stdout, and stderr are connected to 75207753Smm // a valid file descriptor. Exit immediately with exit code ERROR 76207753Smm // if we cannot make the file descriptors valid. Maybe we should 77207753Smm // print an error message, but our stderr could be screwed anyway. 78207753Smm tuklib_open_stdxxx(E_ERROR); 79207753Smm 80207753Smm#ifndef TUKLIB_DOSLIKE 81207753Smm // If fchown() fails setting the owner, we warn about it only if 82207753Smm // we are root. 83207753Smm warn_fchown = geteuid() == 0; 84292588Sdelphij 85292588Sdelphij // Create a pipe for the self-pipe trick. 86292588Sdelphij if (pipe(user_abort_pipe)) 87292588Sdelphij message_fatal(_("Error creating a pipe: %s"), 88292588Sdelphij strerror(errno)); 89292588Sdelphij 90292588Sdelphij // Make both ends of the pipe non-blocking. 91292588Sdelphij for (unsigned i = 0; i < 2; ++i) { 92292588Sdelphij int flags = fcntl(user_abort_pipe[i], F_GETFL); 93292588Sdelphij if (flags == -1 || fcntl(user_abort_pipe[i], F_SETFL, 94292588Sdelphij flags | O_NONBLOCK) == -1) 95292588Sdelphij message_fatal(_("Error creating a pipe: %s"), 96292588Sdelphij strerror(errno)); 97292588Sdelphij } 98207753Smm#endif 99207753Smm 100207753Smm#ifdef __DJGPP__ 101207753Smm // Avoid doing useless things when statting files. 102207753Smm // This isn't important but doesn't hurt. 103292588Sdelphij _djstat_flags = _STAT_EXEC_EXT | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; 104207753Smm#endif 105207753Smm 106207753Smm return; 107207753Smm} 108207753Smm 109207753Smm 110292588Sdelphij#ifndef TUKLIB_DOSLIKE 111207753Smmextern void 112292588Sdelphijio_write_to_user_abort_pipe(void) 113292588Sdelphij{ 114292588Sdelphij // If the write() fails, it's probably due to the pipe being full. 115292588Sdelphij // Failing in that case is fine. If the reason is something else, 116292588Sdelphij // there's not much we can do since this is called in a signal 117292588Sdelphij // handler. So ignore the errors and try to avoid warnings with 118292588Sdelphij // GCC and glibc when _FORTIFY_SOURCE=2 is used. 119292588Sdelphij uint8_t b = '\0'; 120292588Sdelphij const int ret = write(user_abort_pipe[1], &b, 1); 121292588Sdelphij (void)ret; 122292588Sdelphij return; 123292588Sdelphij} 124292588Sdelphij#endif 125292588Sdelphij 126292588Sdelphij 127292588Sdelphijextern void 128207753Smmio_no_sparse(void) 129207753Smm{ 130207753Smm try_sparse = false; 131207753Smm return; 132207753Smm} 133207753Smm 134207753Smm 135292588Sdelphij#ifndef TUKLIB_DOSLIKE 136292588Sdelphij/// \brief Waits for input or output to become available or for a signal 137292588Sdelphij/// 138292588Sdelphij/// This uses the self-pipe trick to avoid a race condition that can occur 139292588Sdelphij/// if a signal is caught after user_abort has been checked but before e.g. 140292588Sdelphij/// read() has been called. In that situation read() could block unless 141292588Sdelphij/// non-blocking I/O is used. With non-blocking I/O something like select() 142292588Sdelphij/// or poll() is needed to avoid a busy-wait loop, and the same race condition 143292588Sdelphij/// pops up again. There are pselect() (POSIX-1.2001) and ppoll() (not in 144292588Sdelphij/// POSIX) but neither is portable enough in 2013. The self-pipe trick is 145292588Sdelphij/// old and very portable. 146292588Sdelphijstatic io_wait_ret 147292588Sdelphijio_wait(file_pair *pair, int timeout, bool is_reading) 148292588Sdelphij{ 149292588Sdelphij struct pollfd pfd[2]; 150292588Sdelphij 151292588Sdelphij if (is_reading) { 152292588Sdelphij pfd[0].fd = pair->src_fd; 153292588Sdelphij pfd[0].events = POLLIN; 154292588Sdelphij } else { 155292588Sdelphij pfd[0].fd = pair->dest_fd; 156292588Sdelphij pfd[0].events = POLLOUT; 157292588Sdelphij } 158292588Sdelphij 159292588Sdelphij pfd[1].fd = user_abort_pipe[0]; 160292588Sdelphij pfd[1].events = POLLIN; 161292588Sdelphij 162292588Sdelphij while (true) { 163292588Sdelphij const int ret = poll(pfd, 2, timeout); 164292588Sdelphij 165292588Sdelphij if (user_abort) 166292588Sdelphij return IO_WAIT_ERROR; 167292588Sdelphij 168292588Sdelphij if (ret == -1) { 169292588Sdelphij if (errno == EINTR || errno == EAGAIN) 170292588Sdelphij continue; 171292588Sdelphij 172292588Sdelphij message_error(_("%s: poll() failed: %s"), 173292588Sdelphij is_reading ? pair->src_name 174292588Sdelphij : pair->dest_name, 175292588Sdelphij strerror(errno)); 176292588Sdelphij return IO_WAIT_ERROR; 177292588Sdelphij } 178292588Sdelphij 179292588Sdelphij if (ret == 0) { 180292588Sdelphij assert(opt_flush_timeout != 0); 181292588Sdelphij flush_needed = true; 182292588Sdelphij return IO_WAIT_TIMEOUT; 183292588Sdelphij } 184292588Sdelphij 185292588Sdelphij if (pfd[0].revents != 0) 186292588Sdelphij return IO_WAIT_MORE; 187292588Sdelphij } 188292588Sdelphij} 189292588Sdelphij#endif 190292588Sdelphij 191292588Sdelphij 192207753Smm/// \brief Unlink a file 193207753Smm/// 194207753Smm/// This tries to verify that the file being unlinked really is the file that 195207753Smm/// we want to unlink by verifying device and inode numbers. There's still 196207753Smm/// a small unavoidable race, but this is much better than nothing (the file 197207753Smm/// could have been moved/replaced even hours earlier). 198207753Smmstatic void 199207753Smmio_unlink(const char *name, const struct stat *known_st) 200207753Smm{ 201207753Smm#if defined(TUKLIB_DOSLIKE) 202207753Smm // On DOS-like systems, st_ino is meaningless, so don't bother 203207753Smm // testing it. Just silence a compiler warning. 204207753Smm (void)known_st; 205207753Smm#else 206207753Smm struct stat new_st; 207207753Smm 208207753Smm // If --force was used, use stat() instead of lstat(). This way 209207753Smm // (de)compressing symlinks works correctly. However, it also means 210207753Smm // that xz cannot detect if a regular file foo is renamed to bar 211207753Smm // and then a symlink foo -> bar is created. Because of stat() 212207753Smm // instead of lstat(), xz will think that foo hasn't been replaced 213207753Smm // with another file. Thus, xz will remove foo even though it no 214207753Smm // longer is the same file that xz used when it started compressing. 215207753Smm // Probably it's not too bad though, so this doesn't need a more 216207753Smm // complex fix. 217207753Smm const int stat_ret = opt_force 218207753Smm ? stat(name, &new_st) : lstat(name, &new_st); 219207753Smm 220207753Smm if (stat_ret 221207753Smm# ifdef __VMS 222207753Smm // st_ino is an array, and we don't want to 223207753Smm // compare st_dev at all. 224207753Smm || memcmp(&new_st.st_ino, &known_st->st_ino, 225207753Smm sizeof(new_st.st_ino)) != 0 226207753Smm# else 227207753Smm // Typical POSIX-like system 228207753Smm || new_st.st_dev != known_st->st_dev 229207753Smm || new_st.st_ino != known_st->st_ino 230207753Smm# endif 231207753Smm ) 232207753Smm // TRANSLATORS: When compression or decompression finishes, 233207753Smm // and xz is going to remove the source file, xz first checks 234207753Smm // if the source file still exists, and if it does, does its 235207753Smm // device and inode numbers match what xz saw when it opened 236207753Smm // the source file. If these checks fail, this message is 237207753Smm // shown, %s being the filename, and the file is not deleted. 238207753Smm // The check for device and inode numbers is there, because 239207753Smm // it is possible that the user has put a new file in place 240207753Smm // of the original file, and in that case it obviously 241207753Smm // shouldn't be removed. 242207753Smm message_error(_("%s: File seems to have been moved, " 243207753Smm "not removing"), name); 244207753Smm else 245207753Smm#endif 246207753Smm // There's a race condition between lstat() and unlink() 247207753Smm // but at least we have tried to avoid removing wrong file. 248207753Smm if (unlink(name)) 249207753Smm message_error(_("%s: Cannot remove: %s"), 250207753Smm name, strerror(errno)); 251207753Smm 252207753Smm return; 253207753Smm} 254207753Smm 255207753Smm 256207753Smm/// \brief Copies owner/group and permissions 257207753Smm/// 258207753Smm/// \todo ACL and EA support 259207753Smm/// 260207753Smmstatic void 261207753Smmio_copy_attrs(const file_pair *pair) 262207753Smm{ 263207753Smm // Skip chown and chmod on Windows. 264207753Smm#ifndef TUKLIB_DOSLIKE 265207753Smm // This function is more tricky than you may think at first. 266207753Smm // Blindly copying permissions may permit users to access the 267207753Smm // destination file who didn't have permission to access the 268207753Smm // source file. 269207753Smm 270207753Smm // Try changing the owner of the file. If we aren't root or the owner 271207753Smm // isn't already us, fchown() probably doesn't succeed. We warn 272207753Smm // about failing fchown() only if we are root. 273207753Smm if (fchown(pair->dest_fd, pair->src_st.st_uid, -1) && warn_fchown) 274207753Smm message_warning(_("%s: Cannot set the file owner: %s"), 275207753Smm pair->dest_name, strerror(errno)); 276207753Smm 277207753Smm mode_t mode; 278207753Smm 279207753Smm if (fchown(pair->dest_fd, -1, pair->src_st.st_gid)) { 280207753Smm message_warning(_("%s: Cannot set the file group: %s"), 281207753Smm pair->dest_name, strerror(errno)); 282207753Smm // We can still safely copy some additional permissions: 283207753Smm // `group' must be at least as strict as `other' and 284207753Smm // also vice versa. 285207753Smm // 286207753Smm // NOTE: After this, the owner of the source file may 287207753Smm // get additional permissions. This shouldn't be too bad, 288207753Smm // because the owner would have had permission to chmod 289207753Smm // the original file anyway. 290207753Smm mode = ((pair->src_st.st_mode & 0070) >> 3) 291207753Smm & (pair->src_st.st_mode & 0007); 292207753Smm mode = (pair->src_st.st_mode & 0700) | (mode << 3) | mode; 293207753Smm } else { 294207753Smm // Drop the setuid, setgid, and sticky bits. 295207753Smm mode = pair->src_st.st_mode & 0777; 296207753Smm } 297207753Smm 298207753Smm if (fchmod(pair->dest_fd, mode)) 299207753Smm message_warning(_("%s: Cannot set the file permissions: %s"), 300207753Smm pair->dest_name, strerror(errno)); 301207753Smm#endif 302207753Smm 303207753Smm // Copy the timestamps. We have several possible ways to do this, of 304207753Smm // which some are better in both security and precision. 305207753Smm // 306207753Smm // First, get the nanosecond part of the timestamps. As of writing, 307207753Smm // it's not standardized by POSIX, and there are several names for 308207753Smm // the same thing in struct stat. 309207753Smm long atime_nsec; 310207753Smm long mtime_nsec; 311207753Smm 312207753Smm# if defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) 313207753Smm // GNU and Solaris 314207753Smm atime_nsec = pair->src_st.st_atim.tv_nsec; 315207753Smm mtime_nsec = pair->src_st.st_mtim.tv_nsec; 316207753Smm 317207753Smm# elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC) 318207753Smm // BSD 319207753Smm atime_nsec = pair->src_st.st_atimespec.tv_nsec; 320207753Smm mtime_nsec = pair->src_st.st_mtimespec.tv_nsec; 321207753Smm 322207753Smm# elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) 323207753Smm // GNU and BSD without extensions 324207753Smm atime_nsec = pair->src_st.st_atimensec; 325207753Smm mtime_nsec = pair->src_st.st_mtimensec; 326207753Smm 327207753Smm# elif defined(HAVE_STRUCT_STAT_ST_UATIME) 328207753Smm // Tru64 329207753Smm atime_nsec = pair->src_st.st_uatime * 1000; 330207753Smm mtime_nsec = pair->src_st.st_umtime * 1000; 331207753Smm 332207753Smm# elif defined(HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC) 333207753Smm // UnixWare 334207753Smm atime_nsec = pair->src_st.st_atim.st__tim.tv_nsec; 335207753Smm mtime_nsec = pair->src_st.st_mtim.st__tim.tv_nsec; 336207753Smm 337207753Smm# else 338207753Smm // Safe fallback 339207753Smm atime_nsec = 0; 340207753Smm mtime_nsec = 0; 341207753Smm# endif 342207753Smm 343207753Smm // Construct a structure to hold the timestamps and call appropriate 344207753Smm // function to set the timestamps. 345207753Smm#if defined(HAVE_FUTIMENS) 346207753Smm // Use nanosecond precision. 347207753Smm struct timespec tv[2]; 348207753Smm tv[0].tv_sec = pair->src_st.st_atime; 349207753Smm tv[0].tv_nsec = atime_nsec; 350207753Smm tv[1].tv_sec = pair->src_st.st_mtime; 351207753Smm tv[1].tv_nsec = mtime_nsec; 352207753Smm 353207753Smm (void)futimens(pair->dest_fd, tv); 354207753Smm 355207753Smm#elif defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMES) 356207753Smm // Use microsecond precision. 357207753Smm struct timeval tv[2]; 358207753Smm tv[0].tv_sec = pair->src_st.st_atime; 359207753Smm tv[0].tv_usec = atime_nsec / 1000; 360207753Smm tv[1].tv_sec = pair->src_st.st_mtime; 361207753Smm tv[1].tv_usec = mtime_nsec / 1000; 362207753Smm 363207753Smm# if defined(HAVE_FUTIMES) 364207753Smm (void)futimes(pair->dest_fd, tv); 365207753Smm# elif defined(HAVE_FUTIMESAT) 366207753Smm (void)futimesat(pair->dest_fd, NULL, tv); 367207753Smm# else 368207753Smm // Argh, no function to use a file descriptor to set the timestamp. 369207753Smm (void)utimes(pair->dest_name, tv); 370207753Smm# endif 371207753Smm 372207753Smm#elif defined(HAVE_UTIME) 373207753Smm // Use one-second precision. utime() doesn't support using file 374207753Smm // descriptor either. Some systems have broken utime() prototype 375207753Smm // so don't make this const. 376207753Smm struct utimbuf buf = { 377207753Smm .actime = pair->src_st.st_atime, 378207753Smm .modtime = pair->src_st.st_mtime, 379207753Smm }; 380207753Smm 381207753Smm // Avoid warnings. 382207753Smm (void)atime_nsec; 383207753Smm (void)mtime_nsec; 384207753Smm 385207753Smm (void)utime(pair->dest_name, &buf); 386207753Smm#endif 387207753Smm 388207753Smm return; 389207753Smm} 390207753Smm 391207753Smm 392207753Smm/// Opens the source file. Returns false on success, true on error. 393207753Smmstatic bool 394207753Smmio_open_src_real(file_pair *pair) 395207753Smm{ 396207753Smm // There's nothing to open when reading from stdin. 397207753Smm if (pair->src_name == stdin_filename) { 398207753Smm pair->src_fd = STDIN_FILENO; 399207753Smm#ifdef TUKLIB_DOSLIKE 400207753Smm setmode(STDIN_FILENO, O_BINARY); 401292588Sdelphij#else 402292588Sdelphij // Try to set stdin to non-blocking mode. It won't work 403292588Sdelphij // e.g. on OpenBSD if stdout is e.g. /dev/null. In such 404292588Sdelphij // case we proceed as if stdin were non-blocking anyway 405292588Sdelphij // (in case of /dev/null it will be in practice). The 406292588Sdelphij // same applies to stdout in io_open_dest_real(). 407292588Sdelphij stdin_flags = fcntl(STDIN_FILENO, F_GETFL); 408292588Sdelphij if (stdin_flags == -1) { 409292588Sdelphij message_error(_("Error getting the file status flags " 410292588Sdelphij "from standard input: %s"), 411292588Sdelphij strerror(errno)); 412292588Sdelphij return true; 413292588Sdelphij } 414292588Sdelphij 415292588Sdelphij if ((stdin_flags & O_NONBLOCK) == 0 416292588Sdelphij && fcntl(STDIN_FILENO, F_SETFL, 417292588Sdelphij stdin_flags | O_NONBLOCK) != -1) 418292588Sdelphij restore_stdin_flags = true; 419207753Smm#endif 420292588Sdelphij#ifdef HAVE_POSIX_FADVISE 421292588Sdelphij // It will fail if stdin is a pipe and that's fine. 422292588Sdelphij (void)posix_fadvise(STDIN_FILENO, 0, 0, POSIX_FADV_SEQUENTIAL); 423292588Sdelphij#endif 424207753Smm return false; 425207753Smm } 426207753Smm 427207753Smm // Symlinks are not followed unless writing to stdout or --force 428207753Smm // was used. 429207753Smm const bool follow_symlinks = opt_stdout || opt_force; 430207753Smm 431207753Smm // We accept only regular files if we are writing the output 432207753Smm // to disk too. bzip2 allows overriding this with --force but 433207753Smm // gzip and xz don't. 434207753Smm const bool reg_files_only = !opt_stdout; 435207753Smm 436207753Smm // Flags for open() 437207753Smm int flags = O_RDONLY | O_BINARY | O_NOCTTY; 438207753Smm 439207753Smm#ifndef TUKLIB_DOSLIKE 440292588Sdelphij // Use non-blocking I/O: 441292588Sdelphij // - It prevents blocking when opening FIFOs and some other 442292588Sdelphij // special files, which is good if we want to accept only 443292588Sdelphij // regular files. 444292588Sdelphij // - It can help avoiding some race conditions with signal handling. 445292588Sdelphij flags |= O_NONBLOCK; 446207753Smm#endif 447207753Smm 448207753Smm#if defined(O_NOFOLLOW) 449207753Smm if (!follow_symlinks) 450207753Smm flags |= O_NOFOLLOW; 451207753Smm#elif !defined(TUKLIB_DOSLIKE) 452207753Smm // Some POSIX-like systems lack O_NOFOLLOW (it's not required 453207753Smm // by POSIX). Check for symlinks with a separate lstat() on 454207753Smm // these systems. 455207753Smm if (!follow_symlinks) { 456207753Smm struct stat st; 457207753Smm if (lstat(pair->src_name, &st)) { 458207753Smm message_error("%s: %s", pair->src_name, 459207753Smm strerror(errno)); 460207753Smm return true; 461207753Smm 462207753Smm } else if (S_ISLNK(st.st_mode)) { 463207753Smm message_warning(_("%s: Is a symbolic link, " 464207753Smm "skipping"), pair->src_name); 465207753Smm return true; 466207753Smm } 467207753Smm } 468207753Smm#else 469207753Smm // Avoid warnings. 470207753Smm (void)follow_symlinks; 471207753Smm#endif 472207753Smm 473292588Sdelphij // Try to open the file. Signals have been blocked so EINTR shouldn't 474292588Sdelphij // be possible. 475292588Sdelphij pair->src_fd = open(pair->src_name, flags); 476207753Smm 477207753Smm if (pair->src_fd == -1) { 478292588Sdelphij // Signals (that have a signal handler) have been blocked. 479292588Sdelphij assert(errno != EINTR); 480207753Smm 481207753Smm#ifdef O_NOFOLLOW 482213700Smm // Give an understandable error message if the reason 483207753Smm // for failing was that the file was a symbolic link. 484207753Smm // 485207753Smm // Note that at least Linux, OpenBSD, Solaris, and Darwin 486213700Smm // use ELOOP to indicate that O_NOFOLLOW was the reason 487207753Smm // that open() failed. Because there may be 488207753Smm // directories in the pathname, ELOOP may occur also 489207753Smm // because of a symlink loop in the directory part. 490213700Smm // So ELOOP doesn't tell us what actually went wrong, 491213700Smm // and this stupidity went into POSIX-1.2008 too. 492207753Smm // 493207753Smm // FreeBSD associates EMLINK with O_NOFOLLOW and 494207753Smm // Tru64 uses ENOTSUP. We use these directly here 495207753Smm // and skip the lstat() call and the associated race. 496207753Smm // I want to hear if there are other kernels that 497207753Smm // fail with something else than ELOOP with O_NOFOLLOW. 498207753Smm bool was_symlink = false; 499207753Smm 500207753Smm# if defined(__FreeBSD__) || defined(__DragonFly__) 501207753Smm if (errno == EMLINK) 502207753Smm was_symlink = true; 503207753Smm 504207753Smm# elif defined(__digital__) && defined(__unix__) 505207753Smm if (errno == ENOTSUP) 506207753Smm was_symlink = true; 507207753Smm 508207753Smm# elif defined(__NetBSD__) 509207753Smm if (errno == EFTYPE) 510207753Smm was_symlink = true; 511207753Smm 512207753Smm# else 513207753Smm if (errno == ELOOP && !follow_symlinks) { 514207753Smm const int saved_errno = errno; 515207753Smm struct stat st; 516207753Smm if (lstat(pair->src_name, &st) == 0 517207753Smm && S_ISLNK(st.st_mode)) 518207753Smm was_symlink = true; 519207753Smm 520207753Smm errno = saved_errno; 521207753Smm } 522207753Smm# endif 523207753Smm 524207753Smm if (was_symlink) 525207753Smm message_warning(_("%s: Is a symbolic link, " 526207753Smm "skipping"), pair->src_name); 527207753Smm else 528207753Smm#endif 529207753Smm // Something else than O_NOFOLLOW failing 530207753Smm // (assuming that the race conditions didn't 531207753Smm // confuse us). 532207753Smm message_error("%s: %s", pair->src_name, 533207753Smm strerror(errno)); 534207753Smm 535207753Smm return true; 536207753Smm } 537207753Smm 538207753Smm // Stat the source file. We need the result also when we copy 539207753Smm // the permissions, and when unlinking. 540292588Sdelphij // 541292588Sdelphij // NOTE: Use stat() instead of fstat() with DJGPP, because 542292588Sdelphij // then we have a better chance to get st_ino value that can 543292588Sdelphij // be used in io_open_dest_real() to prevent overwriting the 544292588Sdelphij // source file. 545292588Sdelphij#ifdef __DJGPP__ 546292588Sdelphij if (stat(pair->src_name, &pair->src_st)) 547292588Sdelphij goto error_msg; 548292588Sdelphij#else 549207753Smm if (fstat(pair->src_fd, &pair->src_st)) 550207753Smm goto error_msg; 551292588Sdelphij#endif 552207753Smm 553207753Smm if (S_ISDIR(pair->src_st.st_mode)) { 554207753Smm message_warning(_("%s: Is a directory, skipping"), 555207753Smm pair->src_name); 556207753Smm goto error; 557207753Smm } 558207753Smm 559219001Smm if (reg_files_only && !S_ISREG(pair->src_st.st_mode)) { 560219001Smm message_warning(_("%s: Not a regular file, skipping"), 561219001Smm pair->src_name); 562219001Smm goto error; 563219001Smm } 564207753Smm 565207753Smm#ifndef TUKLIB_DOSLIKE 566219001Smm if (reg_files_only && !opt_force) { 567207753Smm if (pair->src_st.st_mode & (S_ISUID | S_ISGID)) { 568207753Smm // gzip rejects setuid and setgid files even 569207753Smm // when --force was used. bzip2 doesn't check 570207753Smm // for them, but calls fchown() after fchmod(), 571207753Smm // and many systems automatically drop setuid 572207753Smm // and setgid bits there. 573207753Smm // 574207753Smm // We accept setuid and setgid files if 575207753Smm // --force was used. We drop these bits 576207753Smm // explicitly in io_copy_attr(). 577207753Smm message_warning(_("%s: File has setuid or " 578207753Smm "setgid bit set, skipping"), 579207753Smm pair->src_name); 580207753Smm goto error; 581207753Smm } 582207753Smm 583207753Smm if (pair->src_st.st_mode & S_ISVTX) { 584207753Smm message_warning(_("%s: File has sticky bit " 585207753Smm "set, skipping"), 586207753Smm pair->src_name); 587207753Smm goto error; 588207753Smm } 589207753Smm 590207753Smm if (pair->src_st.st_nlink > 1) { 591207753Smm message_warning(_("%s: Input file has more " 592207753Smm "than one hard link, " 593207753Smm "skipping"), pair->src_name); 594207753Smm goto error; 595207753Smm } 596219001Smm } 597292588Sdelphij 598292588Sdelphij // If it is something else than a regular file, wait until 599292588Sdelphij // there is input available. This way reading from FIFOs 600292588Sdelphij // will work when open() is used with O_NONBLOCK. 601292588Sdelphij if (!S_ISREG(pair->src_st.st_mode)) { 602292588Sdelphij signals_unblock(); 603292588Sdelphij const io_wait_ret ret = io_wait(pair, -1, true); 604292588Sdelphij signals_block(); 605292588Sdelphij 606292588Sdelphij if (ret != IO_WAIT_MORE) 607292588Sdelphij goto error; 608292588Sdelphij } 609207753Smm#endif 610207753Smm 611292588Sdelphij#ifdef HAVE_POSIX_FADVISE 612292588Sdelphij // It will fail with some special files like FIFOs but that is fine. 613292588Sdelphij (void)posix_fadvise(pair->src_fd, 0, 0, POSIX_FADV_SEQUENTIAL); 614292588Sdelphij#endif 615292588Sdelphij 616207753Smm return false; 617207753Smm 618207753Smmerror_msg: 619207753Smm message_error("%s: %s", pair->src_name, strerror(errno)); 620207753Smmerror: 621207753Smm (void)close(pair->src_fd); 622207753Smm return true; 623207753Smm} 624207753Smm 625207753Smm 626207753Smmextern file_pair * 627207753Smmio_open_src(const char *src_name) 628207753Smm{ 629207753Smm if (is_empty_filename(src_name)) 630207753Smm return NULL; 631207753Smm 632207753Smm // Since we have only one file open at a time, we can use 633207753Smm // a statically allocated structure. 634207753Smm static file_pair pair; 635207753Smm 636207753Smm pair = (file_pair){ 637207753Smm .src_name = src_name, 638207753Smm .dest_name = NULL, 639207753Smm .src_fd = -1, 640207753Smm .dest_fd = -1, 641207753Smm .src_eof = false, 642207753Smm .dest_try_sparse = false, 643207753Smm .dest_pending_sparse = 0, 644207753Smm }; 645207753Smm 646207753Smm // Block the signals, for which we have a custom signal handler, so 647207753Smm // that we don't need to worry about EINTR. 648207753Smm signals_block(); 649207753Smm const bool error = io_open_src_real(&pair); 650207753Smm signals_unblock(); 651207753Smm 652207753Smm return error ? NULL : &pair; 653207753Smm} 654207753Smm 655207753Smm 656207753Smm/// \brief Closes source file of the file_pair structure 657207753Smm/// 658207753Smm/// \param pair File whose src_fd should be closed 659207753Smm/// \param success If true, the file will be removed from the disk if 660207753Smm/// closing succeeds and --keep hasn't been used. 661207753Smmstatic void 662207753Smmio_close_src(file_pair *pair, bool success) 663207753Smm{ 664292588Sdelphij#ifndef TUKLIB_DOSLIKE 665292588Sdelphij if (restore_stdin_flags) { 666292588Sdelphij assert(pair->src_fd == STDIN_FILENO); 667292588Sdelphij 668292588Sdelphij restore_stdin_flags = false; 669292588Sdelphij 670292588Sdelphij if (fcntl(STDIN_FILENO, F_SETFL, stdin_flags) == -1) 671292588Sdelphij message_error(_("Error restoring the status flags " 672292588Sdelphij "to standard input: %s"), 673292588Sdelphij strerror(errno)); 674292588Sdelphij } 675292588Sdelphij#endif 676292588Sdelphij 677207753Smm if (pair->src_fd != STDIN_FILENO && pair->src_fd != -1) { 678207753Smm#ifdef TUKLIB_DOSLIKE 679207753Smm (void)close(pair->src_fd); 680207753Smm#endif 681207753Smm 682207753Smm // If we are going to unlink(), do it before closing the file. 683207753Smm // This way there's no risk that someone replaces the file and 684207753Smm // happens to get same inode number, which would make us 685207753Smm // unlink() wrong file. 686207753Smm // 687207753Smm // NOTE: DOS-like systems are an exception to this, because 688207753Smm // they don't allow unlinking files that are open. *sigh* 689207753Smm if (success && !opt_keep_original) 690207753Smm io_unlink(pair->src_name, &pair->src_st); 691207753Smm 692207753Smm#ifndef TUKLIB_DOSLIKE 693207753Smm (void)close(pair->src_fd); 694207753Smm#endif 695207753Smm } 696207753Smm 697207753Smm return; 698207753Smm} 699207753Smm 700207753Smm 701207753Smmstatic bool 702207753Smmio_open_dest_real(file_pair *pair) 703207753Smm{ 704207753Smm if (opt_stdout || pair->src_fd == STDIN_FILENO) { 705207753Smm // We don't modify or free() this. 706207753Smm pair->dest_name = (char *)"(stdout)"; 707207753Smm pair->dest_fd = STDOUT_FILENO; 708207753Smm#ifdef TUKLIB_DOSLIKE 709207753Smm setmode(STDOUT_FILENO, O_BINARY); 710292588Sdelphij#else 711292588Sdelphij // Try to set O_NONBLOCK if it isn't already set. 712292588Sdelphij // If it fails, we assume that stdout is non-blocking 713292588Sdelphij // in practice. See the comments in io_open_src_real() 714292588Sdelphij // for similar situation with stdin. 715292588Sdelphij // 716292588Sdelphij // NOTE: O_APPEND may be unset later in this function 717292588Sdelphij // and it relies on stdout_flags being set here. 718292588Sdelphij stdout_flags = fcntl(STDOUT_FILENO, F_GETFL); 719292588Sdelphij if (stdout_flags == -1) { 720292588Sdelphij message_error(_("Error getting the file status flags " 721292588Sdelphij "from standard output: %s"), 722292588Sdelphij strerror(errno)); 723292588Sdelphij return true; 724292588Sdelphij } 725292588Sdelphij 726292588Sdelphij if ((stdout_flags & O_NONBLOCK) == 0 727292588Sdelphij && fcntl(STDOUT_FILENO, F_SETFL, 728292588Sdelphij stdout_flags | O_NONBLOCK) != -1) 729292588Sdelphij restore_stdout_flags = true; 730207753Smm#endif 731207753Smm } else { 732207753Smm pair->dest_name = suffix_get_dest_name(pair->src_name); 733207753Smm if (pair->dest_name == NULL) 734207753Smm return true; 735207753Smm 736292588Sdelphij#ifdef __DJGPP__ 737292588Sdelphij struct stat st; 738292588Sdelphij if (stat(pair->dest_name, &st) == 0) { 739292588Sdelphij // Check that it isn't a special file like "prn". 740292588Sdelphij if (st.st_dev == -1) { 741292588Sdelphij message_error("%s: Refusing to write to " 742292588Sdelphij "a DOS special file", 743292588Sdelphij pair->dest_name); 744292588Sdelphij free(pair->dest_name); 745292588Sdelphij return true; 746292588Sdelphij } 747292588Sdelphij 748292588Sdelphij // Check that we aren't overwriting the source file. 749292588Sdelphij if (st.st_dev == pair->src_st.st_dev 750292588Sdelphij && st.st_ino == pair->src_st.st_ino) { 751292588Sdelphij message_error("%s: Output file is the same " 752292588Sdelphij "as the input file", 753292588Sdelphij pair->dest_name); 754292588Sdelphij free(pair->dest_name); 755292588Sdelphij return true; 756292588Sdelphij } 757292588Sdelphij } 758292588Sdelphij#endif 759292588Sdelphij 760207753Smm // If --force was used, unlink the target file first. 761207753Smm if (opt_force && unlink(pair->dest_name) && errno != ENOENT) { 762207753Smm message_error(_("%s: Cannot remove: %s"), 763207753Smm pair->dest_name, strerror(errno)); 764207753Smm free(pair->dest_name); 765207753Smm return true; 766207753Smm } 767207753Smm 768207753Smm // Open the file. 769292588Sdelphij int flags = O_WRONLY | O_BINARY | O_NOCTTY 770207753Smm | O_CREAT | O_EXCL; 771292588Sdelphij#ifndef TUKLIB_DOSLIKE 772292588Sdelphij flags |= O_NONBLOCK; 773292588Sdelphij#endif 774207753Smm const mode_t mode = S_IRUSR | S_IWUSR; 775207753Smm pair->dest_fd = open(pair->dest_name, flags, mode); 776207753Smm 777207753Smm if (pair->dest_fd == -1) { 778207753Smm message_error("%s: %s", pair->dest_name, 779207753Smm strerror(errno)); 780207753Smm free(pair->dest_name); 781207753Smm return true; 782207753Smm } 783207753Smm } 784207753Smm 785292588Sdelphij#ifndef TUKLIB_DOSLIKE 786292588Sdelphij // dest_st isn't used on DOS-like systems except as a dummy 787292588Sdelphij // argument to io_unlink(), so don't fstat() on such systems. 788207753Smm if (fstat(pair->dest_fd, &pair->dest_st)) { 789292588Sdelphij // If fstat() really fails, we have a safe fallback here. 790292588Sdelphij# if defined(__VMS) 791207753Smm pair->dest_st.st_ino[0] = 0; 792207753Smm pair->dest_st.st_ino[1] = 0; 793207753Smm pair->dest_st.st_ino[2] = 0; 794292588Sdelphij# else 795207753Smm pair->dest_st.st_dev = 0; 796207753Smm pair->dest_st.st_ino = 0; 797292588Sdelphij# endif 798207753Smm } else if (try_sparse && opt_mode == MODE_DECOMPRESS) { 799207753Smm // When writing to standard output, we need to be extra 800207753Smm // careful: 801207753Smm // - It may be connected to something else than 802207753Smm // a regular file. 803207753Smm // - We aren't necessarily writing to a new empty file 804207753Smm // or to the end of an existing file. 805207753Smm // - O_APPEND may be active. 806207753Smm // 807207753Smm // TODO: I'm keeping this disabled for DOS-like systems 808207753Smm // for now. FAT doesn't support sparse files, but NTFS 809207753Smm // does, so maybe this should be enabled on Windows after 810207753Smm // some testing. 811207753Smm if (pair->dest_fd == STDOUT_FILENO) { 812207753Smm if (!S_ISREG(pair->dest_st.st_mode)) 813207753Smm return false; 814207753Smm 815263285Sdelphij if (stdout_flags & O_APPEND) { 816207753Smm // Creating a sparse file is not possible 817207753Smm // when O_APPEND is active (it's used by 818207753Smm // shell's >> redirection). As I understand 819207753Smm // it, it is safe to temporarily disable 820207753Smm // O_APPEND in xz, because if someone 821207753Smm // happened to write to the same file at the 822207753Smm // same time, results would be bad anyway 823207753Smm // (users shouldn't assume that xz uses any 824207753Smm // specific block size when writing data). 825207753Smm // 826207753Smm // The write position may be something else 827207753Smm // than the end of the file, so we must fix 828207753Smm // it to start writing at the end of the file 829207753Smm // to imitate O_APPEND. 830207753Smm if (lseek(STDOUT_FILENO, 0, SEEK_END) == -1) 831207753Smm return false; 832207753Smm 833292588Sdelphij // Construct the new file status flags. 834292588Sdelphij // If O_NONBLOCK was set earlier in this 835292588Sdelphij // function, it must be kept here too. 836292588Sdelphij int flags = stdout_flags & ~O_APPEND; 837292588Sdelphij if (restore_stdout_flags) 838292588Sdelphij flags |= O_NONBLOCK; 839292588Sdelphij 840292588Sdelphij // If this fcntl() fails, we continue but won't 841292588Sdelphij // try to create sparse output. The original 842292588Sdelphij // flags will still be restored if needed (to 843292588Sdelphij // unset O_NONBLOCK) when the file is finished. 844292588Sdelphij if (fcntl(STDOUT_FILENO, F_SETFL, flags) == -1) 845207753Smm return false; 846207753Smm 847263285Sdelphij // Disabling O_APPEND succeeded. Mark 848263285Sdelphij // that the flags should be restored 849292588Sdelphij // in io_close_dest(). (This may have already 850292588Sdelphij // been set when enabling O_NONBLOCK.) 851263285Sdelphij restore_stdout_flags = true; 852207753Smm 853207753Smm } else if (lseek(STDOUT_FILENO, 0, SEEK_CUR) 854207753Smm != pair->dest_st.st_size) { 855207753Smm // Writing won't start exactly at the end 856207753Smm // of the file. We cannot use sparse output, 857207753Smm // because it would probably corrupt the file. 858207753Smm return false; 859207753Smm } 860207753Smm } 861207753Smm 862207753Smm pair->dest_try_sparse = true; 863292588Sdelphij } 864207753Smm#endif 865207753Smm 866207753Smm return false; 867207753Smm} 868207753Smm 869207753Smm 870207753Smmextern bool 871207753Smmio_open_dest(file_pair *pair) 872207753Smm{ 873207753Smm signals_block(); 874207753Smm const bool ret = io_open_dest_real(pair); 875207753Smm signals_unblock(); 876207753Smm return ret; 877207753Smm} 878207753Smm 879207753Smm 880207753Smm/// \brief Closes destination file of the file_pair structure 881207753Smm/// 882207753Smm/// \param pair File whose dest_fd should be closed 883207753Smm/// \param success If false, the file will be removed from the disk. 884207753Smm/// 885207753Smm/// \return Zero if closing succeeds. On error, -1 is returned and 886207753Smm/// error message printed. 887207753Smmstatic bool 888207753Smmio_close_dest(file_pair *pair, bool success) 889207753Smm{ 890207753Smm#ifndef TUKLIB_DOSLIKE 891207753Smm // If io_open_dest() has disabled O_APPEND, restore it here. 892263285Sdelphij if (restore_stdout_flags) { 893207753Smm assert(pair->dest_fd == STDOUT_FILENO); 894207753Smm 895263285Sdelphij restore_stdout_flags = false; 896207753Smm 897263285Sdelphij if (fcntl(STDOUT_FILENO, F_SETFL, stdout_flags) == -1) { 898207753Smm message_error(_("Error restoring the O_APPEND flag " 899207753Smm "to standard output: %s"), 900207753Smm strerror(errno)); 901207753Smm return true; 902207753Smm } 903207753Smm } 904207753Smm#endif 905207753Smm 906207753Smm if (pair->dest_fd == -1 || pair->dest_fd == STDOUT_FILENO) 907207753Smm return false; 908207753Smm 909207753Smm if (close(pair->dest_fd)) { 910207753Smm message_error(_("%s: Closing the file failed: %s"), 911207753Smm pair->dest_name, strerror(errno)); 912207753Smm 913207753Smm // Closing destination file failed, so we cannot trust its 914207753Smm // contents. Get rid of junk: 915207753Smm io_unlink(pair->dest_name, &pair->dest_st); 916207753Smm free(pair->dest_name); 917207753Smm return true; 918207753Smm } 919207753Smm 920207753Smm // If the operation using this file wasn't successful, we git rid 921207753Smm // of the junk file. 922207753Smm if (!success) 923207753Smm io_unlink(pair->dest_name, &pair->dest_st); 924207753Smm 925207753Smm free(pair->dest_name); 926207753Smm 927207753Smm return false; 928207753Smm} 929207753Smm 930207753Smm 931207753Smmextern void 932207753Smmio_close(file_pair *pair, bool success) 933207753Smm{ 934207753Smm // Take care of sparseness at the end of the output file. 935207753Smm if (success && pair->dest_try_sparse 936207753Smm && pair->dest_pending_sparse > 0) { 937207753Smm // Seek forward one byte less than the size of the pending 938207753Smm // hole, then write one zero-byte. This way the file grows 939207753Smm // to its correct size. An alternative would be to use 940207753Smm // ftruncate() but that isn't portable enough (e.g. it 941207753Smm // doesn't work with FAT on Linux; FAT isn't that important 942207753Smm // since it doesn't support sparse files anyway, but we don't 943207753Smm // want to create corrupt files on it). 944207753Smm if (lseek(pair->dest_fd, pair->dest_pending_sparse - 1, 945207753Smm SEEK_CUR) == -1) { 946207753Smm message_error(_("%s: Seeking failed when trying " 947207753Smm "to create a sparse file: %s"), 948207753Smm pair->dest_name, strerror(errno)); 949207753Smm success = false; 950207753Smm } else { 951207753Smm const uint8_t zero[1] = { '\0' }; 952207753Smm if (io_write_buf(pair, zero, 1)) 953207753Smm success = false; 954207753Smm } 955207753Smm } 956207753Smm 957207753Smm signals_block(); 958207753Smm 959207753Smm // Copy the file attributes. We need to skip this if destination 960207753Smm // file isn't open or it is standard output. 961207753Smm if (success && pair->dest_fd != -1 && pair->dest_fd != STDOUT_FILENO) 962207753Smm io_copy_attrs(pair); 963207753Smm 964207753Smm // Close the destination first. If it fails, we must not remove 965207753Smm // the source file! 966207753Smm if (io_close_dest(pair, success)) 967207753Smm success = false; 968207753Smm 969207753Smm // Close the source file, and unlink it if the operation using this 970207753Smm // file pair was successful and we haven't requested to keep the 971207753Smm // source file. 972207753Smm io_close_src(pair, success); 973207753Smm 974207753Smm signals_unblock(); 975207753Smm 976207753Smm return; 977207753Smm} 978207753Smm 979207753Smm 980292588Sdelphijextern void 981292588Sdelphijio_fix_src_pos(file_pair *pair, size_t rewind_size) 982292588Sdelphij{ 983292588Sdelphij assert(rewind_size <= IO_BUFFER_SIZE); 984292588Sdelphij 985292588Sdelphij if (rewind_size > 0) { 986292588Sdelphij // This doesn't need to work on unseekable file descriptors, 987292588Sdelphij // so just ignore possible errors. 988292588Sdelphij (void)lseek(pair->src_fd, -(off_t)(rewind_size), SEEK_CUR); 989292588Sdelphij } 990292588Sdelphij 991292588Sdelphij return; 992292588Sdelphij} 993292588Sdelphij 994292588Sdelphij 995207753Smmextern size_t 996207753Smmio_read(file_pair *pair, io_buf *buf_union, size_t size) 997207753Smm{ 998207753Smm // We use small buffers here. 999207753Smm assert(size < SSIZE_MAX); 1000207753Smm 1001207753Smm uint8_t *buf = buf_union->u8; 1002207753Smm size_t left = size; 1003207753Smm 1004207753Smm while (left > 0) { 1005207753Smm const ssize_t amount = read(pair->src_fd, buf, left); 1006207753Smm 1007207753Smm if (amount == 0) { 1008207753Smm pair->src_eof = true; 1009207753Smm break; 1010207753Smm } 1011207753Smm 1012207753Smm if (amount == -1) { 1013207753Smm if (errno == EINTR) { 1014207753Smm if (user_abort) 1015207753Smm return SIZE_MAX; 1016207753Smm 1017207753Smm continue; 1018207753Smm } 1019207753Smm 1020292588Sdelphij#ifndef TUKLIB_DOSLIKE 1021292588Sdelphij if (errno == EAGAIN || errno == EWOULDBLOCK) { 1022292588Sdelphij const io_wait_ret ret = io_wait(pair, 1023292588Sdelphij mytime_get_flush_timeout(), 1024292588Sdelphij true); 1025292588Sdelphij switch (ret) { 1026292588Sdelphij case IO_WAIT_MORE: 1027292588Sdelphij continue; 1028292588Sdelphij 1029292588Sdelphij case IO_WAIT_ERROR: 1030292588Sdelphij return SIZE_MAX; 1031292588Sdelphij 1032292588Sdelphij case IO_WAIT_TIMEOUT: 1033292588Sdelphij return size - left; 1034292588Sdelphij 1035292588Sdelphij default: 1036292588Sdelphij message_bug(); 1037292588Sdelphij } 1038292588Sdelphij } 1039292588Sdelphij#endif 1040292588Sdelphij 1041207753Smm message_error(_("%s: Read error: %s"), 1042207753Smm pair->src_name, strerror(errno)); 1043207753Smm 1044207753Smm return SIZE_MAX; 1045207753Smm } 1046207753Smm 1047207753Smm buf += (size_t)(amount); 1048207753Smm left -= (size_t)(amount); 1049207753Smm } 1050207753Smm 1051207753Smm return size - left; 1052207753Smm} 1053207753Smm 1054207753Smm 1055207753Smmextern bool 1056207753Smmio_pread(file_pair *pair, io_buf *buf, size_t size, off_t pos) 1057207753Smm{ 1058207753Smm // Using lseek() and read() is more portable than pread() and 1059207753Smm // for us it is as good as real pread(). 1060207753Smm if (lseek(pair->src_fd, pos, SEEK_SET) != pos) { 1061207753Smm message_error(_("%s: Error seeking the file: %s"), 1062207753Smm pair->src_name, strerror(errno)); 1063207753Smm return true; 1064207753Smm } 1065207753Smm 1066207753Smm const size_t amount = io_read(pair, buf, size); 1067207753Smm if (amount == SIZE_MAX) 1068207753Smm return true; 1069207753Smm 1070207753Smm if (amount != size) { 1071207753Smm message_error(_("%s: Unexpected end of file"), 1072207753Smm pair->src_name); 1073207753Smm return true; 1074207753Smm } 1075207753Smm 1076207753Smm return false; 1077207753Smm} 1078207753Smm 1079207753Smm 1080207753Smmstatic bool 1081207753Smmis_sparse(const io_buf *buf) 1082207753Smm{ 1083207753Smm assert(IO_BUFFER_SIZE % sizeof(uint64_t) == 0); 1084207753Smm 1085207753Smm for (size_t i = 0; i < ARRAY_SIZE(buf->u64); ++i) 1086207753Smm if (buf->u64[i] != 0) 1087207753Smm return false; 1088207753Smm 1089207753Smm return true; 1090207753Smm} 1091207753Smm 1092207753Smm 1093207753Smmstatic bool 1094207753Smmio_write_buf(file_pair *pair, const uint8_t *buf, size_t size) 1095207753Smm{ 1096207753Smm assert(size < SSIZE_MAX); 1097207753Smm 1098207753Smm while (size > 0) { 1099207753Smm const ssize_t amount = write(pair->dest_fd, buf, size); 1100207753Smm if (amount == -1) { 1101207753Smm if (errno == EINTR) { 1102207753Smm if (user_abort) 1103263285Sdelphij return true; 1104207753Smm 1105207753Smm continue; 1106207753Smm } 1107207753Smm 1108292588Sdelphij#ifndef TUKLIB_DOSLIKE 1109292588Sdelphij if (errno == EAGAIN || errno == EWOULDBLOCK) { 1110292588Sdelphij if (io_wait(pair, -1, false) == IO_WAIT_MORE) 1111292588Sdelphij continue; 1112292588Sdelphij 1113292588Sdelphij return true; 1114292588Sdelphij } 1115292588Sdelphij#endif 1116292588Sdelphij 1117207753Smm // Handle broken pipe specially. gzip and bzip2 1118207753Smm // don't print anything on SIGPIPE. In addition, 1119207753Smm // gzip --quiet uses exit status 2 (warning) on 1120207753Smm // broken pipe instead of whatever raise(SIGPIPE) 1121207753Smm // would make it return. It is there to hide "Broken 1122207753Smm // pipe" message on some old shells (probably old 1123207753Smm // GNU bash). 1124207753Smm // 1125207753Smm // We don't do anything special with --quiet, which 1126207753Smm // is what bzip2 does too. If we get SIGPIPE, we 1127207753Smm // will handle it like other signals by setting 1128207753Smm // user_abort, and get EPIPE here. 1129207753Smm if (errno != EPIPE) 1130207753Smm message_error(_("%s: Write error: %s"), 1131207753Smm pair->dest_name, strerror(errno)); 1132207753Smm 1133207753Smm return true; 1134207753Smm } 1135207753Smm 1136207753Smm buf += (size_t)(amount); 1137207753Smm size -= (size_t)(amount); 1138207753Smm } 1139207753Smm 1140207753Smm return false; 1141207753Smm} 1142207753Smm 1143207753Smm 1144207753Smmextern bool 1145207753Smmio_write(file_pair *pair, const io_buf *buf, size_t size) 1146207753Smm{ 1147207753Smm assert(size <= IO_BUFFER_SIZE); 1148207753Smm 1149207753Smm if (pair->dest_try_sparse) { 1150207753Smm // Check if the block is sparse (contains only zeros). If it 1151207753Smm // sparse, we just store the amount and return. We will take 1152207753Smm // care of actually skipping over the hole when we hit the 1153207753Smm // next data block or close the file. 1154207753Smm // 1155207753Smm // Since io_close() requires that dest_pending_sparse > 0 1156207753Smm // if the file ends with sparse block, we must also return 1157207753Smm // if size == 0 to avoid doing the lseek(). 1158207753Smm if (size == IO_BUFFER_SIZE) { 1159207753Smm if (is_sparse(buf)) { 1160207753Smm pair->dest_pending_sparse += size; 1161207753Smm return false; 1162207753Smm } 1163207753Smm } else if (size == 0) { 1164207753Smm return false; 1165207753Smm } 1166207753Smm 1167207753Smm // This is not a sparse block. If we have a pending hole, 1168207753Smm // skip it now. 1169207753Smm if (pair->dest_pending_sparse > 0) { 1170207753Smm if (lseek(pair->dest_fd, pair->dest_pending_sparse, 1171207753Smm SEEK_CUR) == -1) { 1172207753Smm message_error(_("%s: Seeking failed when " 1173207753Smm "trying to create a sparse " 1174207753Smm "file: %s"), pair->dest_name, 1175207753Smm strerror(errno)); 1176207753Smm return true; 1177207753Smm } 1178207753Smm 1179207753Smm pair->dest_pending_sparse = 0; 1180207753Smm } 1181207753Smm } 1182207753Smm 1183207753Smm return io_write_buf(pair, buf->u8, size); 1184207753Smm} 1185