1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief File opening, unlinking, and closing
6 // Copyright (C) 2007 Lasse Collin
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.
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.
18 ///////////////////////////////////////////////////////////////////////////////
22 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
23 # include <sys/time.h>
27 # define O_SEARCH O_RDONLY
31 /// \brief Number of open file_pairs
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;
39 /// \brief mutex for file system operations
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
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;
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;
56 /// True when stdout is being used by some thread
57 static bool stdout_in_use = false;
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;
65 /// \brief Directory where we were started
67 /// This is needed when a new file, whose name was given on command line,
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));
93 /// Waits until the number of open file_pairs has dropped to zero.
97 pthread_mutex_lock(&mutex);
99 while (open_pairs != 0)
100 pthread_cond_wait(&io_cond, &mutex);
102 (void)close(start_dir);
104 pthread_mutex_unlock(&mutex);
110 /// \brief Unlinks a file
112 /// \param dir_fd File descriptor of the directory containing the file
113 /// \param name Name of the file with or without path
115 /// \return Zero on success. On error, -1 is returned and errno set.
118 io_unlink(int dir_fd, const char *name, ino_t ino)
120 const char *base = str_filename(name);
122 // This shouldn't happen.
123 errmsg(V_ERROR, _("%s: Invalid filename"), name);
127 pthread_mutex_lock(&mutex);
129 if (fchdir(dir_fd)) {
130 errmsg(V_ERROR, _("Cannot change directory: %s"),
134 if (lstat(base, &st) || st.st_ino != ino)
135 errmsg(V_ERROR, _("%s: File seems to be moved, "
136 "not removing"), name);
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));
145 pthread_mutex_unlock(&mutex);
151 /// \brief Copies owner/group and permissions
153 /// \todo ACL and EA support
156 io_copy_attrs(const file_pair *pair)
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
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));
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
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;
184 // Drop the setuid, setgid, and sticky bits.
185 mode = pair->src_st.st_mode & 0777;
188 if (fchmod(pair->dest_fd, mode))
189 errmsg(V_WARNING, _("%s: Cannot set the file permissions: %s"),
190 pair->dest_name, strerror(errno));
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;
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;
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;
215 (void)futimes(pair->dest_fd, tv);
217 (void)futimesat(pair->dest_fd, NULL, tv);
225 /// Opens and changes into the directory containing the source file.
227 io_open_dir(file_pair *pair)
229 if (pair->src_name == stdin_filename)
232 if (fchdir(start_dir)) {
233 errmsg(V_ERROR, _("Cannot change directory: %s"),
238 const char *split = strrchr(pair->src_name, '/');
240 pair->dir_fd = start_dir;
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';
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);
265 io_close_dir(file_pair *pair)
267 if (pair->dir_fd != start_dir)
268 (void)close(pair->dir_fd);
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.
278 io_open_src(file_pair *pair)
280 if (pair->src_name == stdin_filename) {
281 pair->src_fd = STDIN_FILENO;
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)
289 // Symlinks are followed if --stdout or --force has been
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
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().
313 errmsg(V_WARNING, _("%s: Is a symbolic link, "
314 "skipping"), pair->src_name);
316 errmsg(V_ERROR, "%s: %s", pair->src_name,
323 if (fstat(pair->src_fd, &pair->src_st)) {
324 errmsg(V_ERROR, "%s: %s", pair->src_name,
329 if (S_ISDIR(pair->src_st.st_mode)) {
330 errmsg(V_WARNING, _("%s: Is a directory, skipping"),
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);
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"),
354 if (!opt_force && (pair->src_st.st_mode & S_ISVTX)) {
355 errmsg(V_WARNING, _("%s: File has sticky bit "
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);
373 (void)close(pair->src_fd);
378 /// \brief Closes source file of the file_pair structure
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.
384 io_close_src(file_pair *pair, bool success)
386 if (pair->src_fd == STDIN_FILENO || pair->src_fd == -1)
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);
401 io_open_dest(file_pair *pair)
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;
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);
414 stdout_in_use = true;
417 pair->dest_name = get_dest_name(pair->src_name);
418 if (pair->dest_name == NULL)
421 // This cannot fail, because get_dest_name() doesn't return
423 const char *filename = str_filename(pair->dest_name);
424 assert(filename != NULL);
426 pair->dest_fd = open(filename, O_WRONLY | O_NOCTTY | O_CREAT
427 | (opt_force ? O_TRUNC : O_EXCL),
429 if (pair->dest_fd == -1) {
430 errmsg(V_ERROR, "%s: %s", pair->dest_name,
432 free(pair->dest_name);
436 // If this really fails... well, we have a safe fallback.
438 if (fstat(pair->dest_fd, &st))
441 pair->dest_ino = st.st_ino;
448 /// \brief Closes destination file of the file_pair structure
450 /// \param pair File whose dest_fd should be closed
451 /// \param success If false, the file will be removed from the disk.
453 /// \return Zero if closing succeeds. On error, -1 is returned and
454 /// error message printed.
456 io_close_dest(file_pair *pair, bool success)
458 if (pair->dest_fd == -1)
461 if (pair->dest_fd == STDOUT_FILENO) {
462 stdout_in_use = false;
463 pthread_cond_signal(&stdout_cond);
467 if (close(pair->dest_fd)) {
468 errmsg(V_ERROR, _("%s: Closing the file failed: %s"),
469 pair->dest_name, strerror(errno));
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);
478 // If the operation using this file wasn't successful, we git rid
481 io_unlink(pair->dir_fd, pair->dest_name, pair->dest_ino);
483 free(pair->dest_name);
490 io_open(const char *src_name)
492 if (is_empty_filename(src_name))
495 file_pair *pair = malloc(sizeof(file_pair));
502 .src_name = src_name,
510 pthread_mutex_lock(&mutex);
514 if (io_open_dir(pair))
517 if (io_open_src(pair))
520 if (user_abort || io_open_dest(pair))
523 pthread_mutex_unlock(&mutex);
528 io_close_src(pair, false);
533 pthread_mutex_unlock(&mutex);
539 /// \brief Closes the file descriptors and frees the structure
541 io_close(file_pair *pair, bool success)
543 if (success && pair->dest_fd != STDOUT_FILENO)
546 // Close the destination first. If it fails, we must not remove
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);
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);
564 pthread_mutex_lock(&mutex);
566 if (--open_pairs == 0)
567 pthread_cond_signal(&io_cond);
569 pthread_mutex_unlock(&mutex);
575 /// \brief Reads from a file to a buffer
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
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.
585 /// \note This does no locking, thus two threads must not read from
586 /// the same file. This no problem in this program.
588 io_read(file_pair *pair, uint8_t *buf, size_t size)
590 // We use small buffers here.
591 assert(size < SSIZE_MAX);
596 const ssize_t amount = read(pair->src_fd, buf, left);
599 pair->src_eof = true;
604 if (errno == EINTR) {
611 errmsg(V_ERROR, _("%s: Read error: %s"),
612 pair->src_name, strerror(errno));
614 // FIXME Is this needed?
615 pair->src_eof = true;
620 buf += (size_t)(amount);
621 left -= (size_t)(amount);
628 /// \brief Writes a buffer to a file
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
634 /// \return On success, zero is returned. On error, -1 is returned
635 /// and error message printed.
637 /// \note This does no locking, thus two threads must not write to
638 /// the same file. This no problem in this program.
640 io_write(const file_pair *pair, const uint8_t *buf, size_t size)
642 assert(size < SSIZE_MAX);
645 const ssize_t amount = write(pair->dest_fd, buf, size);
647 if (errno == EINTR) {
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
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));
672 buf += (size_t)(amount);
673 size -= (size_t)(amount);