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