- if (close (fd) < 0)
- FATAL_ERROR ((0, errno, _("Cannot close file #%d"), fd));
-}
-
-/*-----------------------------------------------------------------------.
-| Duplicate file descriptor FROM into becoming INTO, or else, issue |
-| MESSAGE. INTO is closed first and has to be the next available slot. |
-`-----------------------------------------------------------------------*/
-
-static void
-xdup2 (int from, int into, const char *message)
-{
- if (from != into)
- {
- int status = close (into);
-
- if (status < 0 && errno != EBADF)
- FATAL_ERROR ((0, errno, _("Cannot close descriptor %d"), into));
- status = dup (from);
- if (status != into)
- FATAL_ERROR ((0, errno, _("Cannot properly duplicate %s"), message));
- xclose (from);
- }
-}
-
-#if MSDOS
-
-/*-------------------------------------------------------.
-| Set ARCHIVE for writing, then compressing an archive. |
-`-------------------------------------------------------*/
-
-static void
-child_open_for_compress (void)
-{
- FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
-}
-
-/*---------------------------------------------------------.
-| Set ARCHIVE for uncompressing, then reading an archive. |
-`---------------------------------------------------------*/
-
-static void
-child_open_for_uncompress (void)
-{
- FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
-}
-
-#else /* not MSDOS */
-
-/*---------------------------------------------------------------------.
-| Return nonzero if NAME is the name of a regular file, or if the file |
-| does not exist (so it would be created as a regular file). |
-`---------------------------------------------------------------------*/
-
-static int
-is_regular_file (const char *name)
-{
- struct stat stbuf;
-
- if (stat (name, &stbuf) == 0)
- return S_ISREG (stbuf.st_mode);
- else
- return errno == ENOENT;
-}
-
-static ssize_t
-write_archive_buffer (void)
-{
- ssize_t status;
- ssize_t written = 0;
-
- while (0 <= (status = rmtwrite (archive, record_start->buffer + written,
- record_size - written)))
- {
- written += status;
- if (written == record_size
- || _isrmt (archive) || ! S_ISFIFO (archive_stat.st_mode))
- break;
- }
-
- return written ? written : status;
-}
-
-/*-------------------------------------------------------.
-| Set ARCHIVE for writing, then compressing an archive. |
-`-------------------------------------------------------*/
-
-static void
-child_open_for_compress (void)
-{
- int parent_pipe[2];
- int child_pipe[2];
- pid_t grandchild_pid;
-
- if (pipe (parent_pipe) < 0)
- FATAL_ERROR ((0, errno, _("Cannot open pipe")));
-
- child_pid = fork ();
- if (child_pid < 0)
- FATAL_ERROR ((0, errno, _("Cannot fork")));
-
- if (child_pid > 0)
- {
- /* The parent tar is still here! Just clean up. */
-
- archive = parent_pipe[PWRITE];
- xclose (parent_pipe[PREAD]);
- return;
- }
-
- /* The new born child tar is here! */
-
- program_name = _("tar (child)");
-
- xclose (parent_pipe[PWRITE]);
- xdup2 (parent_pipe[PREAD], STDIN_FILENO, _("(child) Pipe to stdin"));
-
- /* Check if we need a grandchild tar. This happens only if either:
- a) we are writing stdout: to force reblocking;
- b) the file is to be accessed by rmt: compressor doesn't know how;
- c) the file is not a plain file. */
-
- if (strcmp (archive_name_array[0], "-") != 0
- && !_remdev (archive_name_array[0])
- && is_regular_file (archive_name_array[0]))
- {
- if (backup_option)
- maybe_backup_file (archive_name_array[0], 1);
-
- /* We don't need a grandchild tar. Open the archive and launch the
- compressor. */
-
- archive = creat (archive_name_array[0], MODE_RW);
- if (archive < 0)
- {
- int saved_errno = errno;
-
- if (backup_option)
- undo_last_backup ();
- FATAL_ERROR ((0, saved_errno, _("Cannot open archive %s"),
- archive_name_array[0]));
- }
- xdup2 (archive, STDOUT_FILENO, _("Archive to stdout"));
- execlp (use_compress_program_option, use_compress_program_option,
- (char *) 0);
- FATAL_ERROR ((0, errno, _("Cannot exec %s"),
- use_compress_program_option));
- }
-
- /* We do need a grandchild tar. */
-
- if (pipe (child_pipe) < 0)
- FATAL_ERROR ((0, errno, _("Cannot open pipe")));
-
- grandchild_pid = fork ();
- if (grandchild_pid < 0)
- FATAL_ERROR ((0, errno, _("Child cannot fork")));
-
- if (grandchild_pid > 0)
- {
- /* The child tar is still here! Launch the compressor. */
-
- xdup2 (child_pipe[PWRITE], STDOUT_FILENO,
- _("((child)) Pipe to stdout"));
- xclose (child_pipe[PREAD]);
- execlp (use_compress_program_option, use_compress_program_option,
- (char *) 0);
- FATAL_ERROR ((0, errno, _("Cannot exec %s"),
- use_compress_program_option));
- }
-
- /* The new born grandchild tar is here! */
-
- program_name = _("tar (grandchild)");
-
- /* Prepare for reblocking the data from the compressor into the archive. */
-
- xdup2 (child_pipe[PREAD], STDIN_FILENO, _("(grandchild) Pipe to stdin"));
- xclose (child_pipe[PWRITE]);
-
- if (strcmp (archive_name_array[0], "-") == 0)
- archive = STDOUT_FILENO;
- else
- archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option);
- if (archive < 0)
- FATAL_ERROR ((0, errno, _("Cannot open archive %s"),
- archive_name_array[0]));
-
- /* Let's read out of the stdin pipe and write an archive. */
-
- while (1)
- {
- ssize_t status = 0;
- char *cursor;
- size_t length;
-
- /* Assemble a record. */
-
- for (length = 0, cursor = record_start->buffer;
- length < record_size;
- length += status, cursor += status)
- {
- size_t size = record_size - length;
-
- if (size < BLOCKSIZE)
- size = BLOCKSIZE;
- status = safe_read (STDIN_FILENO, cursor, size);
- if (status <= 0)
- break;
- }
-
- if (status < 0)
- FATAL_ERROR ((0, errno, _("Cannot read from compression program")));
-
- /* Copy the record. */
-
- if (status == 0)
- {
- /* We hit the end of the file. Write last record at
- full length, as the only role of the grandchild is
- doing proper reblocking. */
-
- if (length > 0)
- {
- memset (record_start->buffer + length, 0, record_size - length);
- status = write_archive_buffer ();
- if (status != record_size)
- write_error (status);
- }
-
- /* There is nothing else to read, break out. */
- break;
- }
-
- status = write_archive_buffer ();
- if (status != record_size)
- write_error (status);
- }
-
-#if 0
- close_archive ();
-#endif
- exit (exit_status);