]> icculus.org git repositories - icculus/xz.git/blob - src/xz/io.c
5ee84a957092e8eb3173b5858d3c26fffd54d5a3
[icculus/xz.git] / src / xz / io.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       io.c
4 /// \brief      File opening, unlinking, and closing
5 //
6 //  Copyright (C) 2007 Lasse Collin
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "private.h"
21
22 #include <fcntl.h>
23
24 #ifdef DOSLIKE
25 #       include <io.h>
26 #endif
27
28 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMES)
29 #       include <sys/time.h>
30 #elif defined(HAVE_UTIME)
31 #       include <utime.h>
32 #endif
33
34 #ifndef O_BINARY
35 #       define O_BINARY 0
36 #endif
37
38 #ifndef O_NOCTTY
39 #       define O_NOCTTY 0
40 #endif
41
42 #ifndef DOSLIKE
43 #       include "open_stdxxx.h"
44 static bool warn_fchown;
45 #endif
46
47
48 extern void
49 io_init(void)
50 {
51 #ifndef DOSLIKE
52         // Make sure that stdin, stdout, and and stderr are connected to
53         // a valid file descriptor. Exit immediatelly with exit code ERROR
54         // if we cannot make the file descriptors valid. Maybe we should
55         // print an error message, but our stderr could be screwed anyway.
56         open_stdxxx(E_ERROR);
57
58         // If fchown() fails setting the owner, we warn about it only if
59         // we are root.
60         warn_fchown = geteuid() == 0;
61 #endif
62
63 #ifdef __DJGPP__
64         // Avoid doing useless things when statting files.
65         // This isn't important but doesn't hurt.
66         _djstat_flags = _STAT_INODE | _STAT_EXEC_EXT
67                         | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
68 #endif
69
70         return;
71 }
72
73
74 /// \brief      Unlinks a file
75 ///
76 /// This tries to verify that the file being unlinked really is the file that
77 /// we want to unlink by verifying device and inode numbers. There's still
78 /// a small unavoidable race, but this is much better than nothing (the file
79 /// could have been moved/replaced even hours earlier).
80 static void
81 io_unlink(const char *name, const struct stat *known_st)
82 {
83         // On Windows, st_ino is meaningless, so don't bother testing it.
84 #ifndef DOSLIKE
85         struct stat new_st;
86
87         if (lstat(name, &new_st)
88                         || new_st.st_dev != known_st->st_dev
89                         || new_st.st_ino != known_st->st_ino)
90                 message_error(_("%s: File seems to be moved, not removing"),
91                                 name);
92         else
93 #endif
94                 // There's a race condition between lstat() and unlink()
95                 // but at least we have tried to avoid removing wrong file.
96                 if (unlink(name))
97                         message_error(_("%s: Cannot remove: %s"),
98                                         name, strerror(errno));
99
100         return;
101 }
102
103
104 /// \brief      Copies owner/group and permissions
105 ///
106 /// \todo       ACL and EA support
107 ///
108 static void
109 io_copy_attrs(const file_pair *pair)
110 {
111         // Skip chown and chmod on Windows.
112 #ifndef DOSLIKE
113         // This function is more tricky than you may think at first.
114         // Blindly copying permissions may permit users to access the
115         // destination file who didn't have permission to access the
116         // source file.
117
118         // Try changing the owner of the file. If we aren't root or the owner
119         // isn't already us, fchown() probably doesn't succeed. We warn
120         // about failing fchown() only if we are root.
121         if (fchown(pair->dest_fd, pair->src_st.st_uid, -1) && warn_fchown)
122                 message_warning(_("%s: Cannot set the file owner: %s"),
123                                 pair->dest_name, strerror(errno));
124
125         mode_t mode;
126
127         if (fchown(pair->dest_fd, -1, pair->src_st.st_gid)) {
128                 message_warning(_("%s: Cannot set the file group: %s"),
129                                 pair->dest_name, strerror(errno));
130                 // We can still safely copy some additional permissions:
131                 // `group' must be at least as strict as `other' and
132                 // also vice versa.
133                 //
134                 // NOTE: After this, the owner of the source file may
135                 // get additional permissions. This shouldn't be too bad,
136                 // because the owner would have had permission to chmod
137                 // the original file anyway.
138                 mode = ((pair->src_st.st_mode & 0070) >> 3)
139                                 & (pair->src_st.st_mode & 0007);
140                 mode = (pair->src_st.st_mode & 0700) | (mode << 3) | mode;
141         } else {
142                 // Drop the setuid, setgid, and sticky bits.
143                 mode = pair->src_st.st_mode & 0777;
144         }
145
146         if (fchmod(pair->dest_fd, mode))
147                 message_warning(_("%s: Cannot set the file permissions: %s"),
148                                 pair->dest_name, strerror(errno));
149 #endif
150
151         // Copy the timestamps. We have several possible ways to do this, of
152         // which some are better in both security and precision.
153         //
154         // First, get the nanosecond part of the timestamps. As of writing,
155         // it's not standardized by POSIX, and there are several names for
156         // the same thing in struct stat.
157         long atime_nsec;
158         long mtime_nsec;
159
160 #       if defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
161         // GNU and Solaris
162         atime_nsec = pair->src_st.st_atim.tv_nsec;
163         mtime_nsec = pair->src_st.st_mtim.tv_nsec;
164
165 #       elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
166         // BSD
167         atime_nsec = pair->src_st.st_atimespec.tv_nsec;
168         mtime_nsec = pair->src_st.st_mtimespec.tv_nsec;
169
170 #       elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
171         // GNU and BSD without extensions
172         atime_nsec = pair->src_st.st_atimensec;
173         mtime_nsec = pair->src_st.st_mtimensec;
174
175 #       elif defined(HAVE_STRUCT_STAT_ST_UATIME)
176         // Tru64
177         atime_nsec = pair->src_st.st_uatime * 1000;
178         mtime_nsec = pair->src_st.st_umtime * 1000;
179
180 #       elif defined(HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC)
181         // UnixWare
182         atime_nsec = pair->src_st.st_atim.st__tim.tv_nsec;
183         mtime_nsec = pair->src_st.st_mtim.st__tim.tv_nsec;
184
185 #       else
186         // Safe fallback
187         atime_nsec = 0;
188         mtime_nsec = 0;
189 #       endif
190
191         // Construct a structure to hold the timestamps and call appropriate
192         // function to set the timestamps.
193 #if defined(HAVE_FUTIMENS)
194         // Use nanosecond precision.
195         struct timespec tv[2];
196         tv[0].tv_sec = pair->src_st.st_atime;
197         tv[0].tv_nsec = atime_nsec;
198         tv[1].tv_sec = pair->src_st.st_mtime;
199         tv[1].tv_nsec = mtime_nsec;
200
201         (void)futimens(pair->dest_fd, tv);
202
203 #elif defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMES)
204         // Use microsecond precision.
205         struct timeval tv[2];
206         tv[0].tv_sec = pair->src_st.st_atime;
207         tv[0].tv_usec = atime_nsec / 1000;
208         tv[1].tv_sec = pair->src_st.st_mtime;
209         tv[1].tv_usec = mtime_nsec / 1000;
210
211 #       if defined(HAVE_FUTIMES)
212         (void)futimes(pair->dest_fd, tv);
213 #       elif defined(HAVE_FUTIMESAT)
214         (void)futimesat(pair->dest_fd, NULL, tv);
215 #       else
216         // Argh, no function to use a file descriptor to set the timestamp.
217         (void)utimes(pair->dest_name, tv);
218 #       endif
219
220 #elif defined(HAVE_UTIME)
221         // Use one-second precision. utime() doesn't support using file
222         // descriptor either. Some systems have broken utime() prototype
223         // so don't make this const.
224         struct utimbuf buf = {
225                 .actime = pair->src_st.st_atime,
226                 .modtime = pair->src_st.st_mtime,
227         };
228
229         // Avoid warnings.
230         (void)atime_nsec;
231         (void)mtime_nsec;
232
233         (void)utime(pair->dest_name, &buf);
234 #endif
235
236         return;
237 }
238
239
240 /// Opens the source file. Returns false on success, true on error.
241 static bool
242 io_open_src(file_pair *pair)
243 {
244         // There's nothing to open when reading from stdin.
245         if (pair->src_name == stdin_filename) {
246                 pair->src_fd = STDIN_FILENO;
247 #ifdef DOSLIKE
248                 setmode(STDIN_FILENO, O_BINARY);
249 #endif
250                 return false;
251         }
252
253         // We accept only regular files if we are writing the output
254         // to disk too, and if --force was not given.
255         const bool reg_files_only = !opt_stdout && !opt_force;
256
257         // Flags for open()
258         int flags = O_RDONLY | O_BINARY | O_NOCTTY;
259
260 #ifndef DOSLIKE
261         // If we accept only regular files, we need to be careful to avoid
262         // problems with special files like devices and FIFOs. O_NONBLOCK
263         // prevents blocking when opening such files. When we want to accept
264         // special files, we must not use O_NONBLOCK, or otherwise we won't
265         // block waiting e.g. FIFOs to become readable.
266         if (reg_files_only)
267                 flags |= O_NONBLOCK;
268 #endif
269
270 #if defined(O_NOFOLLOW)
271         if (reg_files_only)
272                 flags |= O_NOFOLLOW;
273 #elif !defined(DOSLIKE)
274         // Some POSIX-like systems lack O_NOFOLLOW (it's not required
275         // by POSIX). Check for symlinks with a separate lstat() on
276         // these systems.
277         if (reg_files_only) {
278                 struct stat st;
279                 if (lstat(pair->src_name, &st)) {
280                         message_error("%s: %s", pair->src_name,
281                                         strerror(errno));
282                         return true;
283
284                 } else if (S_ISLNK(st.st_mode)) {
285                         message_warning(_("%s: Is a symbolic link, "
286                                         "skipping"), pair->src_name);
287                         return true;
288                 }
289         }
290 #endif
291
292         // Try to open the file. If we are accepting non-regular files,
293         // unblock the caught signals so that open() can be interrupted
294         // if it blocks e.g. due to a FIFO file.
295         if (!reg_files_only)
296                 signals_unblock();
297
298         // Maybe this wouldn't need a loop, since all the signal handlers for
299         // which we don't use SA_RESTART set user_abort to true. But it
300         // doesn't hurt to have it just in case.
301         do {
302                 pair->src_fd = open(pair->src_name, flags);
303         } while (pair->src_fd == -1 && errno == EINTR && !user_abort);
304
305         if (!reg_files_only)
306                 signals_block();
307
308         if (pair->src_fd == -1) {
309                 // If we were interrupted, don't display any error message.
310                 if (errno == EINTR) {
311                         // All the signals that don't have SA_RESTART
312                         // set user_abort.
313                         assert(user_abort);
314                         return true;
315                 }
316
317 #ifdef O_NOFOLLOW
318                 // Give an understandable error message in if reason
319                 // for failing was that the file was a symbolic link.
320                 //
321                 // Note that at least Linux, OpenBSD, Solaris, and Darwin
322                 // use ELOOP to indicate if O_NOFOLLOW was the reason
323                 // that open() failed. Because there may be
324                 // directories in the pathname, ELOOP may occur also
325                 // because of a symlink loop in the directory part.
326                 // So ELOOP doesn't tell us what actually went wrong.
327                 //
328                 // FreeBSD associates EMLINK with O_NOFOLLOW and
329                 // Tru64 uses ENOTSUP. We use these directly here
330                 // and skip the lstat() call and the associated race.
331                 // I want to hear if there are other kernels that
332                 // fail with something else than ELOOP with O_NOFOLLOW.
333                 bool was_symlink = false;
334
335 #       if defined(__FreeBSD__) || defined(__DragonFly__)
336                 if (errno == EMLINK)
337                         was_symlink = true;
338
339 #       elif defined(__digital__) && defined(__unix__)
340                 if (errno == ENOTSUP)
341                         was_symlink = true;
342
343 #       elif defined(__NetBSD__)
344                 // FIXME? As of 2008-11-20, NetBSD doesn't document what
345                 // errno is used with O_NOFOLLOW. It seems to be EFTYPE,
346                 // but since it isn't documented, it may be wrong to rely
347                 // on it here.
348                 if (errno == EFTYPE)
349                         was_symlink = true;
350
351 #       else
352                 if (errno == ELOOP && reg_files_only) {
353                         const int saved_errno = errno;
354                         struct stat st;
355                         if (lstat(pair->src_name, &st) == 0
356                                         && S_ISLNK(st.st_mode))
357                                 was_symlink = true;
358
359                         errno = saved_errno;
360                 }
361 #       endif
362
363                 if (was_symlink)
364                         message_warning(_("%s: Is a symbolic link, "
365                                         "skipping"), pair->src_name);
366                 else
367 #endif
368                         // Something else than O_NOFOLLOW failing
369                         // (assuming that the race conditions didn't
370                         // confuse us).
371                         message_error("%s: %s", pair->src_name,
372                                         strerror(errno));
373
374                 return true;
375         }
376
377 #ifndef DOSLIKE
378         // Drop O_NONBLOCK, which is used only when we are accepting only
379         // regular files. After the open() call, we want things to block
380         // instead of giving EAGAIN.
381         if (reg_files_only) {
382                 flags = fcntl(pair->src_fd, F_GETFL);
383                 if (flags == -1)
384                         goto error_msg;
385
386                 flags &= ~O_NONBLOCK;
387
388                 if (fcntl(pair->src_fd, F_SETFL, flags))
389                         goto error_msg;
390         }
391 #endif
392
393         // Stat the source file. We need the result also when we copy
394         // the permissions, and when unlinking.
395         if (fstat(pair->src_fd, &pair->src_st))
396                 goto error_msg;
397
398         if (S_ISDIR(pair->src_st.st_mode)) {
399                 message_warning(_("%s: Is a directory, skipping"),
400                                 pair->src_name);
401                 goto error;
402         }
403
404         if (reg_files_only) {
405                 if (!S_ISREG(pair->src_st.st_mode)) {
406                         message_warning(_("%s: Not a regular file, "
407                                         "skipping"), pair->src_name);
408                         goto error;
409                 }
410
411                 // These are meaningless on Windows.
412 #ifndef DOSLIKE
413                 if (pair->src_st.st_mode & (S_ISUID | S_ISGID)) {
414                         // gzip rejects setuid and setgid files even
415                         // when --force was used. bzip2 doesn't check
416                         // for them, but calls fchown() after fchmod(),
417                         // and many systems automatically drop setuid
418                         // and setgid bits there.
419                         //
420                         // We accept setuid and setgid files if
421                         // --force was used. We drop these bits
422                         // explicitly in io_copy_attr().
423                         message_warning(_("%s: File has setuid or "
424                                         "setgid bit set, skipping"),
425                                         pair->src_name);
426                         goto error;
427                 }
428
429                 if (pair->src_st.st_mode & S_ISVTX) {
430                         message_warning(_("%s: File has sticky bit "
431                                         "set, skipping"),
432                                         pair->src_name);
433                         goto error;
434                 }
435
436                 if (pair->src_st.st_nlink > 1) {
437                         message_warning(_("%s: Input file has more "
438                                         "than one hard link, "
439                                         "skipping"), pair->src_name);
440                         goto error;
441                 }
442 #endif
443         }
444
445         return false;
446
447 error_msg:
448         message_error("%s: %s", pair->src_name, strerror(errno));
449 error:
450         (void)close(pair->src_fd);
451         return true;
452 }
453
454
455 /// \brief      Closes source file of the file_pair structure
456 ///
457 /// \param      pair    File whose src_fd should be closed
458 /// \param      success If true, the file will be removed from the disk if
459 ///                     closing succeeds and --keep hasn't been used.
460 static void
461 io_close_src(file_pair *pair, bool success)
462 {
463         if (pair->src_fd != STDIN_FILENO && pair->src_fd != -1) {
464 #ifdef DOSLIKE
465                 (void)close(pair->src_fd);
466 #endif
467
468                 // If we are going to unlink(), do it before closing the file.
469                 // This way there's no risk that someone replaces the file and
470                 // happens to get same inode number, which would make us
471                 // unlink() wrong file.
472                 //
473                 // NOTE: DOS-like systems are an exception to this, because
474                 // they don't allow unlinking files that are open. *sigh*
475                 if (success && !opt_keep_original)
476                         io_unlink(pair->src_name, &pair->src_st);
477
478 #ifndef DOSLIKE
479                 (void)close(pair->src_fd);
480 #endif
481         }
482
483         return;
484 }
485
486
487 static bool
488 io_open_dest(file_pair *pair)
489 {
490         if (opt_stdout || pair->src_fd == STDIN_FILENO) {
491                 // We don't modify or free() this.
492                 pair->dest_name = (char *)"(stdout)";
493                 pair->dest_fd = STDOUT_FILENO;
494 #ifdef DOSLIKE
495                 setmode(STDOUT_FILENO, O_BINARY);
496 #endif
497                 return false;
498         }
499
500         pair->dest_name = suffix_get_dest_name(pair->src_name);
501         if (pair->dest_name == NULL)
502                 return true;
503
504         // If --force was used, unlink the target file first.
505         if (opt_force && unlink(pair->dest_name) && errno != ENOENT) {
506                 message_error("%s: Cannot unlink: %s",
507                                 pair->dest_name, strerror(errno));
508                 free(pair->dest_name);
509                 return true;
510         }
511
512         if (opt_force && unlink(pair->dest_name) && errno != ENOENT) {
513                 message_error("%s: Cannot unlink: %s", pair->dest_name,
514                                 strerror(errno));
515                 free(pair->dest_name);
516                 return true;
517         }
518
519         // Open the file.
520         const int flags = O_WRONLY | O_BINARY | O_NOCTTY | O_CREAT | O_EXCL;
521         const mode_t mode = S_IRUSR | S_IWUSR;
522         pair->dest_fd = open(pair->dest_name, flags, mode);
523
524         if (pair->dest_fd == -1) {
525                 // Don't bother with error message if user requested
526                 // us to exit anyway.
527                 if (!user_abort)
528                         message_error("%s: %s", pair->dest_name,
529                                         strerror(errno));
530
531                 free(pair->dest_name);
532                 return true;
533         }
534
535         // If this really fails... well, we have a safe fallback.
536         if (fstat(pair->dest_fd, &pair->dest_st)) {
537                 pair->dest_st.st_dev = 0;
538                 pair->dest_st.st_ino = 0;
539         }
540
541         return false;
542 }
543
544
545 /// \brief      Closes destination file of the file_pair structure
546 ///
547 /// \param      pair    File whose dest_fd should be closed
548 /// \param      success If false, the file will be removed from the disk.
549 ///
550 /// \return     Zero if closing succeeds. On error, -1 is returned and
551 ///             error message printed.
552 static int
553 io_close_dest(file_pair *pair, bool success)
554 {
555         if (pair->dest_fd == -1 || pair->dest_fd == STDOUT_FILENO)
556                 return 0;
557
558         if (close(pair->dest_fd)) {
559                 message_error(_("%s: Closing the file failed: %s"),
560                                 pair->dest_name, strerror(errno));
561
562                 // Closing destination file failed, so we cannot trust its
563                 // contents. Get rid of junk:
564                 io_unlink(pair->dest_name, &pair->dest_st);
565                 free(pair->dest_name);
566                 return -1;
567         }
568
569         // If the operation using this file wasn't successful, we git rid
570         // of the junk file.
571         if (!success)
572                 io_unlink(pair->dest_name, &pair->dest_st);
573
574         free(pair->dest_name);
575
576         return 0;
577 }
578
579
580 extern file_pair *
581 io_open(const char *src_name)
582 {
583         if (is_empty_filename(src_name))
584                 return NULL;
585
586         // Since we have only one file open at a time, we can use
587         // a statically allocated structure.
588         static file_pair pair;
589
590         pair = (file_pair){
591                 .src_name = src_name,
592                 .dest_name = NULL,
593                 .src_fd = -1,
594                 .dest_fd = -1,
595                 .src_eof = false,
596         };
597
598         // Block the signals, for which we have a custom signal handler, so
599         // that we don't need to worry about EINTR.
600         signals_block();
601
602         file_pair *ret = NULL;
603         if (!io_open_src(&pair)) {
604                 // io_open_src() may have unblocked the signals temporarily,
605                 // and thus user_abort may have got set even if open()
606                 // succeeded.
607                 if (user_abort || io_open_dest(&pair))
608                         io_close_src(&pair, false);
609                 else
610                         ret = &pair;
611         }
612
613         signals_unblock();
614
615         return ret;
616 }
617
618
619 extern void
620 io_close(file_pair *pair, bool success)
621 {
622         signals_block();
623
624         if (success && pair->dest_fd != STDOUT_FILENO)
625                 io_copy_attrs(pair);
626
627         // Close the destination first. If it fails, we must not remove
628         // the source file!
629         if (io_close_dest(pair, success))
630                 success = false;
631
632         // Close the source file, and unlink it if the operation using this
633         // file pair was successful and we haven't requested to keep the
634         // source file.
635         io_close_src(pair, success);
636
637         signals_unblock();
638
639         return;
640 }
641
642
643 extern size_t
644 io_read(file_pair *pair, uint8_t *buf, size_t size)
645 {
646         // We use small buffers here.
647         assert(size < SSIZE_MAX);
648
649         size_t left = size;
650
651         while (left > 0) {
652                 const ssize_t amount = read(pair->src_fd, buf, left);
653
654                 if (amount == 0) {
655                         pair->src_eof = true;
656                         break;
657                 }
658
659                 if (amount == -1) {
660                         if (errno == EINTR) {
661                                 if (user_abort)
662                                         return SIZE_MAX;
663
664                                 continue;
665                         }
666
667                         message_error(_("%s: Read error: %s"),
668                                         pair->src_name, strerror(errno));
669
670                         // FIXME Is this needed?
671                         pair->src_eof = true;
672
673                         return SIZE_MAX;
674                 }
675
676                 buf += (size_t)(amount);
677                 left -= (size_t)(amount);
678         }
679
680         return size - left;
681 }
682
683
684 extern bool
685 io_write(const file_pair *pair, const uint8_t *buf, size_t size)
686 {
687         assert(size < SSIZE_MAX);
688
689         while (size > 0) {
690                 const ssize_t amount = write(pair->dest_fd, buf, size);
691                 if (amount == -1) {
692                         if (errno == EINTR) {
693                                 if (user_abort)
694                                         return -1;
695
696                                 continue;
697                         }
698
699                         // Handle broken pipe specially. gzip and bzip2
700                         // don't print anything on SIGPIPE. In addition,
701                         // gzip --quiet uses exit status 2 (warning) on
702                         // broken pipe instead of whatever raise(SIGPIPE)
703                         // would make it return. It is there to hide "Broken
704                         // pipe" message on some old shells (probably old
705                         // GNU bash).
706                         //
707                         // We don't do anything special with --quiet, which
708                         // is what bzip2 does too. If we get SIGPIPE, we
709                         // will handle it like other signals by setting
710                         // user_abort, and get EPIPE here.
711                         if (errno != EPIPE)
712                                 message_error(_("%s: Write error: %s"),
713                                         pair->dest_name, strerror(errno));
714
715                         return true;
716                 }
717
718                 buf += (size_t)(amount);
719                 size -= (size_t)(amount);
720         }
721
722         return false;
723 }