]> icculus.org git repositories - icculus/xz.git/blob - src/lzma/io.c
b972099f83a33cbe7966c78a71e5f69c0d0d59fb
[icculus/xz.git] / src / lzma / 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 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
23 #       include <sys/time.h>
24 #endif
25
26 #ifndef O_SEARCH
27 #       define O_SEARCH O_RDONLY
28 #endif
29
30
31 /// \brief      Number of open file_pairs
32 ///
33 /// Once the main() function has requested processing of all files,
34 /// we wait that open_pairs drops back to zero. Then it is safe to
35 /// exit from the program.
36 static size_t open_pairs = 0;
37
38
39 /// \brief      mutex for file system operations
40 ///
41 /// All file system operations are done via the functions in this file.
42 /// They use fchdir() to avoid some race conditions (more portable than
43 /// openat() & co.).
44 ///
45 /// Synchronizing all file system operations shouldn't affect speed notably,
46 /// since the actual reading from and writing to files is done in parallel.
47 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
48
49
50 /// This condition is invoked when a file is closed and the value of
51 /// the open_files variable has dropped to zero. The only listener for
52 /// this condition is io_finish() which is called from main().
53 static pthread_cond_t io_cond = PTHREAD_COND_INITIALIZER;
54
55
56 /// True when stdout is being used by some thread
57 static bool stdout_in_use = false;
58
59
60 /// This condition is signalled when a thread releases stdout (no longer
61 /// writes data to it).
62 static pthread_cond_t stdout_cond = PTHREAD_COND_INITIALIZER;
63
64
65 /// \brief      Directory where we were started
66 ///
67 /// This is needed when a new file, whose name was given on command line,
68 /// is opened.
69 static int start_dir;
70
71
72 static uid_t uid;
73 static gid_t gid;
74
75
76 extern void
77 io_init(void)
78 {
79         start_dir = open(".", O_SEARCH | O_NOCTTY);
80         if (start_dir == -1) {
81                 errmsg(V_ERROR, _("Cannot get file descriptor of the current "
82                                 "directory: %s"), strerror(errno));
83                 my_exit(ERROR);
84         }
85
86         uid = getuid();
87         gid = getgid();
88
89         return;
90 }
91
92
93 /// Waits until the number of open file_pairs has dropped to zero.
94 extern void
95 io_finish(void)
96 {
97         pthread_mutex_lock(&mutex);
98
99         while (open_pairs != 0)
100                 pthread_cond_wait(&io_cond, &mutex);
101
102         (void)close(start_dir);
103
104         pthread_mutex_unlock(&mutex);
105
106         return;
107 }
108
109
110 /// \brief      Unlinks a file
111 ///
112 /// \param      dir_fd  File descriptor of the directory containing the file
113 /// \param      name    Name of the file with or without path
114 ///
115 /// \return     Zero on success. On error, -1 is returned and errno set.
116 ///
117 static void
118 io_unlink(int dir_fd, const char *name, ino_t ino)
119 {
120         const char *base = str_filename(name);
121         if (base == NULL) {
122                 // This shouldn't happen.
123                 errmsg(V_ERROR, _("%s: Invalid filename"), name);
124                 return;
125         }
126
127         pthread_mutex_lock(&mutex);
128
129         if (fchdir(dir_fd)) {
130                 errmsg(V_ERROR, _("Cannot change directory: %s"),
131                                 strerror(errno));
132         } else {
133                 struct stat st;
134                 if (lstat(base, &st) || st.st_ino != ino)
135                         errmsg(V_ERROR, _("%s: File seems to be moved, "
136                                         "not removing"), name);
137
138                 // There's a race condition between lstat() and unlink()
139                 // but at least we have tried to avoid removing wrong file.
140                 else if (unlink(base))
141                         errmsg(V_ERROR, _("%s: Cannot remove: %s"),
142                                         name, strerror(errno));
143         }
144
145         pthread_mutex_unlock(&mutex);
146
147         return;
148 }
149
150
151 /// \brief      Copies owner/group and permissions
152 ///
153 /// \todo       ACL and EA support
154 ///
155 static void
156 io_copy_attrs(const file_pair *pair)
157 {
158         // This function is more tricky than you may think at first.
159         // Blindly copying permissions may permit users to access the
160         // destination file who didn't have permission to access the
161         // source file.
162
163         if (uid == 0 && fchown(pair->dest_fd, pair->src_st.st_uid, -1))
164                 errmsg(V_WARNING, _("%s: Cannot set the file owner: %s"),
165                                 pair->dest_name, strerror(errno));
166
167         mode_t mode;
168
169         if (fchown(pair->dest_fd, -1, pair->src_st.st_gid)) {
170                 errmsg(V_WARNING, _("%s: Cannot set the file group: %s"),
171                                 pair->dest_name, strerror(errno));
172                 // We can still safely copy some additional permissions:
173                 // `group' must be at least as strict as `other' and
174                 // also vice versa.
175                 //
176                 // NOTE: After this, the owner of the source file may
177                 // get additional permissions. This shouldn't be too bad,
178                 // because the owner would have had permission to chmod
179                 // the original file anyway.
180                 mode = ((pair->src_st.st_mode & 0070) >> 3)
181                                 & (pair->src_st.st_mode & 0007);
182                 mode = (pair->src_st.st_mode & 0700) | (mode << 3) | mode;
183         } else {
184                 // Drop the setuid, setgid, and sticky bits.
185                 mode = pair->src_st.st_mode & 0777;
186         }
187
188         if (fchmod(pair->dest_fd, mode))
189                 errmsg(V_WARNING, _("%s: Cannot set the file permissions: %s"),
190                                 pair->dest_name, strerror(errno));
191
192         // Copy the timestamps only if we have a secure function to do it.
193 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
194         struct timeval tv[2];
195         tv[0].tv_sec = pair->src_st.st_atime;
196         tv[1].tv_sec = pair->src_st.st_mtime;
197
198 #       if defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
199         tv[0].tv_usec = pair->src_st.st_atim.tv_nsec / 1000;
200 #       elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
201         tv[0].tv_usec = pair->src_st.st_atimespec.tv_nsec / 1000;
202 #       else
203         tv[0].tv_usec = 0;
204 #       endif
205
206 #       if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
207         tv[1].tv_usec = pair->src_st.st_mtim.tv_nsec / 1000;
208 #       elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
209         tv[1].tv_usec = pair->src_st.st_mtimespec.tv_nsec / 1000;
210 #       else
211         tv[1].tv_usec = 0;
212 #       endif
213
214 #       ifdef HAVE_FUTIMES
215         (void)futimes(pair->dest_fd, tv);
216 #       else
217         (void)futimesat(pair->dest_fd, NULL, tv);
218 #       endif
219 #endif
220
221         return;
222 }
223
224
225 /// Opens and changes into the directory containing the source file.
226 static int
227 io_open_dir(file_pair *pair)
228 {
229         if (pair->src_name == stdin_filename)
230                 return 0;
231
232         if (fchdir(start_dir)) {
233                 errmsg(V_ERROR, _("Cannot change directory: %s"),
234                                 strerror(errno));
235                 return -1;
236         }
237
238         const char *split = strrchr(pair->src_name, '/');
239         if (split == NULL) {
240                 pair->dir_fd = start_dir;
241         } else {
242                 // Copy also the slash. It's needed to support filenames
243                 // like "/foo" (dirname being "/"), and it never hurts anyway.
244                 const size_t dirname_len = split - pair->src_name + 1;
245                 char dirname[dirname_len + 1];
246                 memcpy(dirname, pair->src_name, dirname_len);
247                 dirname[dirname_len] = '\0';
248
249                 // Open the directory and change into it.
250                 pair->dir_fd = open(dirname, O_SEARCH | O_NOCTTY);
251                 if (pair->dir_fd == -1 || fchdir(pair->dir_fd)) {
252                         errmsg(V_ERROR, _("%s: Cannot open the directory "
253                                         "containing the file: %s"),
254                                         pair->src_name, strerror(errno));
255                         (void)close(pair->dir_fd);
256                         return -1;
257                 }
258         }
259
260         return 0;
261 }
262
263
264 static void
265 io_close_dir(file_pair *pair)
266 {
267         if (pair->dir_fd != start_dir)
268                 (void)close(pair->dir_fd);
269
270         return;
271 }
272
273
274 /// Opens the source file. The file is opened using the plain filename without
275 /// path, thus the file must be in the current working directory. This is
276 /// ensured because io_open_dir() is always called before this function.
277 static int
278 io_open_src(file_pair *pair)
279 {
280         if (pair->src_name == stdin_filename) {
281                 pair->src_fd = STDIN_FILENO;
282         } else {
283                 // Strip the pathname. Thanks to io_open_dir(), the file
284                 // is now in the current working directory.
285                 const char *filename = str_filename(pair->src_name);
286                 if (filename == NULL)
287                         return -1;
288
289                 // Symlinks are followed if --stdout or --force has been
290                 // specified.
291                 const bool follow_symlinks = opt_stdout || opt_force;
292                 pair->src_fd = open(filename, O_RDONLY | O_NOCTTY
293                                 | (follow_symlinks ? 0 : O_NOFOLLOW));
294                 if (pair->src_fd == -1) {
295                         // Give an understandable error message in if reason
296                         // for failing was that the file was a symbolic link.
297                         //  - Linux, OpenBSD, Solaris: ELOOP
298                         //  - FreeBSD: EMLINK
299                         //  - Tru64: ENOTSUP
300                         // It seems to be safe to check for all these, since
301                         // those errno values aren't used for other purporses
302                         // on any of the listed operating system *when* the
303                         // above flags are used with open().
304                         if (!follow_symlinks
305                                         && (errno == ELOOP
306 #ifdef EMLINK
307                                         || errno == EMLINK
308 #endif
309 #ifdef ENOTSUP
310                                         || errno == ENOTSUP
311 #endif
312                                         )) {
313                                 errmsg(V_WARNING, _("%s: Is a symbolic link, "
314                                                 "skipping"), pair->src_name);
315                         } else {
316                                 errmsg(V_ERROR, "%s: %s", pair->src_name,
317                                                 strerror(errno));
318                         }
319
320                         return -1;
321                 }
322
323                 if (fstat(pair->src_fd, &pair->src_st)) {
324                         errmsg(V_ERROR, "%s: %s", pair->src_name,
325                                         strerror(errno));
326                         goto error;
327                 }
328
329                 if (S_ISDIR(pair->src_st.st_mode)) {
330                         errmsg(V_WARNING, _("%s: Is a directory, skipping"),
331                                         pair->src_name);
332                         goto error;
333                 }
334
335                 if (!opt_stdout) {
336                         if (!opt_force && !S_ISREG(pair->src_st.st_mode)) {
337                                 errmsg(V_WARNING, _("%s: Not a regular file, "
338                                                 "skipping"), pair->src_name);
339                                 goto error;
340                         }
341
342                         if (pair->src_st.st_mode & (S_ISUID | S_ISGID)) {
343                                 // Setuid and setgid files are rejected even
344                                 // with --force. This is good for security
345                                 // (hopefully) but it's a bit weird to reject
346                                 // file when --force was given. At least this
347                                 // matches gzip's behavior.
348                                 errmsg(V_WARNING, _("%s: File has setuid or "
349                                                 "setgid bit set, skipping"),
350                                                 pair->src_name);
351                                 goto error;
352                         }
353
354                         if (!opt_force && (pair->src_st.st_mode & S_ISVTX)) {
355                                 errmsg(V_WARNING, _("%s: File has sticky bit "
356                                                 "set, skipping"),
357                                                 pair->src_name);
358                                 goto error;
359                         }
360
361                         if (pair->src_st.st_nlink > 1) {
362                                 errmsg(V_WARNING, _("%s: Input file has more "
363                                                 "than one hard link, "
364                                                 "skipping"), pair->src_name);
365                                 goto error;
366                         }
367                 }
368         }
369
370         return 0;
371
372 error:
373         (void)close(pair->src_fd);
374         return -1;
375 }
376
377
378 /// \brief      Closes source file of the file_pair structure
379 ///
380 /// \param      pair    File whose src_fd should be closed
381 /// \param      success If true, the file will be removed from the disk if
382 ///                     closing succeeds and --keep hasn't been used.
383 static void
384 io_close_src(file_pair *pair, bool success)
385 {
386         if (pair->src_fd == STDIN_FILENO || pair->src_fd == -1)
387                 return;
388
389         if (close(pair->src_fd)) {
390                 errmsg(V_ERROR, _("%s: Closing the file failed: %s"),
391                                 pair->src_name, strerror(errno));
392         } else if (success && !opt_keep_original) {
393                 io_unlink(pair->dir_fd, pair->src_name, pair->src_st.st_ino);
394         }
395
396         return;
397 }
398
399
400 static int
401 io_open_dest(file_pair *pair)
402 {
403         if (opt_stdout || pair->src_fd == STDIN_FILENO) {
404                 // We don't modify or free() this.
405                 pair->dest_name = (char *)"(stdout)";
406                 pair->dest_fd = STDOUT_FILENO;
407
408                 // Synchronize the order in which files get written to stdout.
409                 // Unlocking the mutex is safe, because opening the file_pair
410                 // can no longer fail.
411                 while (stdout_in_use)
412                         pthread_cond_wait(&stdout_cond, &mutex);
413
414                 stdout_in_use = true;
415
416         } else {
417                 pair->dest_name = get_dest_name(pair->src_name);
418                 if (pair->dest_name == NULL)
419                         return -1;
420
421                 // This cannot fail, because get_dest_name() doesn't return
422                 // invalid names.
423                 const char *filename = str_filename(pair->dest_name);
424                 assert(filename != NULL);
425
426                 pair->dest_fd = open(filename, O_WRONLY | O_NOCTTY | O_CREAT
427                                 | (opt_force ? O_TRUNC : O_EXCL),
428                                 S_IRUSR | S_IWUSR);
429                 if (pair->dest_fd == -1) {
430                         errmsg(V_ERROR, "%s: %s", pair->dest_name,
431                                         strerror(errno));
432                         free(pair->dest_name);
433                         return -1;
434                 }
435
436                 // If this really fails... well, we have a safe fallback.
437                 struct stat st;
438                 if (fstat(pair->dest_fd, &st))
439                         pair->dest_ino = 0;
440                 else
441                         pair->dest_ino = st.st_ino;
442         }
443
444         return 0;
445 }
446
447
448 /// \brief      Closes destination file of the file_pair structure
449 ///
450 /// \param      pair    File whose dest_fd should be closed
451 /// \param      success If false, the file will be removed from the disk.
452 ///
453 /// \return     Zero if closing succeeds. On error, -1 is returned and
454 ///             error message printed.
455 static int
456 io_close_dest(file_pair *pair, bool success)
457 {
458         if (pair->dest_fd == -1)
459                 return 0;
460
461         if (pair->dest_fd == STDOUT_FILENO) {
462                 stdout_in_use = false;
463                 pthread_cond_signal(&stdout_cond);
464                 return 0;
465         }
466
467         if (close(pair->dest_fd)) {
468                 errmsg(V_ERROR, _("%s: Closing the file failed: %s"),
469                                 pair->dest_name, strerror(errno));
470
471                 // Closing destination file failed, so we cannot trust its
472                 // contents. Get rid of junk:
473                 io_unlink(pair->dir_fd, pair->dest_name, pair->dest_ino);
474                 free(pair->dest_name);
475                 return -1;
476         }
477
478         // If the operation using this file wasn't successful, we git rid
479         // of the junk file.
480         if (!success)
481                 io_unlink(pair->dir_fd, pair->dest_name, pair->dest_ino);
482
483         free(pair->dest_name);
484
485         return 0;
486 }
487
488
489 extern file_pair *
490 io_open(const char *src_name)
491 {
492         if (is_empty_filename(src_name))
493                 return NULL;
494
495         file_pair *pair = malloc(sizeof(file_pair));
496         if (pair == NULL) {
497                 out_of_memory();
498                 return NULL;
499         }
500
501         *pair = (file_pair){
502                 .src_name = src_name,
503                 .dest_name = NULL,
504                 .dir_fd = -1,
505                 .src_fd = -1,
506                 .dest_fd = -1,
507                 .src_eof = false,
508         };
509
510         pthread_mutex_lock(&mutex);
511
512         ++open_pairs;
513
514         if (io_open_dir(pair))
515                 goto error_dir;
516
517         if (io_open_src(pair))
518                 goto error_src;
519
520         if (user_abort || io_open_dest(pair))
521                 goto error_dest;
522
523         pthread_mutex_unlock(&mutex);
524
525         return pair;
526
527 error_dest:
528         io_close_src(pair, false);
529 error_src:
530         io_close_dir(pair);
531 error_dir:
532         --open_pairs;
533         pthread_mutex_unlock(&mutex);
534         free(pair);
535         return NULL;
536 }
537
538
539 /// \brief      Closes the file descriptors and frees the structure
540 extern void
541 io_close(file_pair *pair, bool success)
542 {
543         if (success && pair->dest_fd != STDOUT_FILENO)
544                 io_copy_attrs(pair);
545
546         // Close the destination first. If it fails, we must not remove
547         // the source file!
548         if (!io_close_dest(pair, success)) {
549                 // Closing destination file succeeded. Remove the source file
550                 // if the operation using this file pair was successful
551                 // and we haven't been requested to keep the source file.
552                 io_close_src(pair, success);
553         } else {
554                 // We don't care if operation using this file pair was
555                 // successful or not, since closing the destination file
556                 // failed. Don't remove the original file.
557                 io_close_src(pair, false);
558         }
559
560         io_close_dir(pair);
561
562         free(pair);
563
564         pthread_mutex_lock(&mutex);
565
566         if (--open_pairs == 0)
567                 pthread_cond_signal(&io_cond);
568
569         pthread_mutex_unlock(&mutex);
570
571         return;
572 }
573
574
575 /// \brief      Reads from a file to a buffer
576 ///
577 /// \param      pair    File pair having the sourcefile open for reading
578 /// \param      buf     Destination buffer to hold the read data
579 /// \param      size    Size of the buffer; assumed be smaller than SSIZE_MAX
580 ///
581 /// \return     On success, number of bytes read is returned. On end of
582 ///             file zero is returned and pair->src_eof set to true.
583 ///             On error, SIZE_MAX is returned and error message printed.
584 ///
585 /// \note       This does no locking, thus two threads must not read from
586 ///             the same file. This no problem in this program.
587 extern size_t
588 io_read(file_pair *pair, uint8_t *buf, size_t size)
589 {
590         // We use small buffers here.
591         assert(size < SSIZE_MAX);
592
593         size_t left = size;
594
595         while (left > 0) {
596                 const ssize_t amount = read(pair->src_fd, buf, left);
597
598                 if (amount == 0) {
599                         pair->src_eof = true;
600                         break;
601                 }
602
603                 if (amount == -1) {
604                         if (errno == EINTR) {
605                                 if (user_abort)
606                                         return SIZE_MAX;
607
608                                 continue;
609                         }
610
611                         errmsg(V_ERROR, _("%s: Read error: %s"),
612                                         pair->src_name, strerror(errno));
613
614                         // FIXME Is this needed?
615                         pair->src_eof = true;
616
617                         return SIZE_MAX;
618                 }
619
620                 buf += (size_t)(amount);
621                 left -= (size_t)(amount);
622         }
623
624         return size - left;
625 }
626
627
628 /// \brief      Writes a buffer to a file
629 ///
630 /// \param      pair    File pair having the destination file open for writing
631 /// \param      buf     Buffer containing the data to be written
632 /// \param      size    Size of the buffer; assumed be smaller than SSIZE_MAX
633 ///
634 /// \return     On success, zero is returned. On error, -1 is returned
635 ///             and error message printed.
636 ///
637 /// \note       This does no locking, thus two threads must not write to
638 ///             the same file. This no problem in this program.
639 extern int
640 io_write(const file_pair *pair, const uint8_t *buf, size_t size)
641 {
642         assert(size < SSIZE_MAX);
643
644         while (size > 0) {
645                 const ssize_t amount = write(pair->dest_fd, buf, size);
646                 if (amount == -1) {
647                         if (errno == EINTR) {
648                                 if (user_abort)
649                                         return -1;
650
651                                 continue;
652                         }
653
654                         // Handle broken pipe specially. gzip and bzip2
655                         // don't print anything on SIGPIPE. In addition,
656                         // gzip --quiet uses exit status 2 (warning) on
657                         // broken pipe instead of whatever raise(SIGPIPE)
658                         // would make it return. It is there to hide "Broken
659                         // pipe" message on some old shells (probably old
660                         // GNU bash).
661                         //
662                         // We don't do anything special with --quiet, which
663                         // is what bzip2 does too. However, we print a
664                         // message if --verbose was used (or should that
665                         // only be with double --verbose i.e. debugging?).
666                         errmsg(errno == EPIPE ? V_VERBOSE : V_ERROR,
667                                         _("%s: Write error: %s"),
668                                         pair->dest_name, strerror(errno));
669                         return -1;
670                 }
671
672                 buf += (size_t)(amount);
673                 size -= (size_t)(amount);
674         }
675
676         return 0;
677 }