-/* Duplicate file descriptor FROM into becoming INTO.
- INTO is closed first and has to be the next available slot. */
-
-static void
-xdup2 (int from, int into)
-{
- if (from != into)
- {
- int status = close (into);
-
- if (status != 0 && errno != EBADF)
- {
- int e = errno;
- FATAL_ERROR ((0, e, _("Cannot close")));
- }
- status = dup (from);
- if (status != into)
- {
- if (status < 0)
- {
- int e = errno;
- FATAL_ERROR ((0, e, _("Cannot dup")));
- }
- abort ();
- }
- 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;
-
- xpipe (parent_pipe);
- child_pid = xfork ();
-
- 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)");
-
- xdup2 (parent_pipe[PREAD], STDIN_FILENO);
- xclose (parent_pipe[PWRITE]);
-
- /* 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 ();
- errno = saved_errno;
- open_fatal (archive_name_array[0]);
- }
- xdup2 (archive, STDOUT_FILENO);
- execlp (use_compress_program_option, use_compress_program_option,
- (char *) 0);
- exec_fatal (use_compress_program_option);
- }
-
- /* We do need a grandchild tar. */
-
- xpipe (child_pipe);
- grandchild_pid = xfork ();
-
- if (grandchild_pid > 0)
- {
- /* The child tar is still here! Launch the compressor. */
-
- xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
- xclose (child_pipe[PREAD]);
- execlp (use_compress_program_option, use_compress_program_option,
- (char *) 0);
- exec_fatal (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);
- 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)
- open_fatal (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)
- read_fatal (use_compress_program_option);
-
- /* 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)
- archive_write_error (status);
- }
-
- /* There is nothing else to read, break out. */
- break;
- }
-
- status = write_archive_buffer ();
- if (status != record_size)
- archive_write_error (status);
- }
-
-#if 0
- close_archive ();
-#endif
- exit (exit_status);
-}
-
-/*---------------------------------------------------------.
-| Set ARCHIVE for uncompressing, then reading an archive. |
-`---------------------------------------------------------*/
-
-static void
-child_open_for_uncompress (void)
-{
- int parent_pipe[2];
- int child_pipe[2];
- pid_t grandchild_pid;
-
- xpipe (parent_pipe);
- child_pid = xfork ();
-
- if (child_pid > 0)
- {
- /* The parent tar is still here! Just clean up. */
-
- read_full_records_option = 1;
- archive = parent_pipe[PREAD];
- xclose (parent_pipe[PWRITE]);
- return;
- }
-
- /* The new born child tar is here! */
-
- program_name = _("tar (child)");
-
- xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
- xclose (parent_pipe[PREAD]);
-
- /* Check if we need a grandchild tar. This happens only if either:
- a) we're reading stdin: to force unblocking;
- 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]))
- {
- /* We don't need a grandchild tar. Open the archive and lauch the
- uncompressor. */
-
- archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
- if (archive < 0)
- open_fatal (archive_name_array[0]);
- xdup2 (archive, STDIN_FILENO);
- execlp (use_compress_program_option, use_compress_program_option,
- "-d", (char *) 0);
- exec_fatal (use_compress_program_option);
- }
-
- /* We do need a grandchild tar. */
-
- xpipe (child_pipe);
- grandchild_pid = xfork ();
-
- if (grandchild_pid > 0)
- {
- /* The child tar is still here! Launch the uncompressor. */
-
- xdup2 (child_pipe[PREAD], STDIN_FILENO);
- xclose (child_pipe[PWRITE]);
- execlp (use_compress_program_option, use_compress_program_option,
- "-d", (char *) 0);
- exec_fatal (use_compress_program_option);
- }
-
- /* The new born grandchild tar is here! */
-
- program_name = _("tar (grandchild)");
-
- /* Prepare for unblocking the data from the archive into the uncompressor. */
-
- xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
- xclose (child_pipe[PREAD]);
-
- if (strcmp (archive_name_array[0], "-") == 0)
- archive = STDIN_FILENO;
- else
- archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
- MODE_RW, rsh_command_option);
- if (archive < 0)
- open_fatal (archive_name_array[0]);
-
- /* Let's read the archive and pipe it into stdout. */
-
- while (1)
- {
- char *cursor;
- size_t maximum;
- size_t count;
- ssize_t status;
-
- read_error_count = 0;
-
- error_loop:
- status = rmtread (archive, record_start->buffer, record_size);
- if (status < 0)
- {
- archive_read_error ();
- goto error_loop;
- }
- if (status == 0)
- break;
- cursor = record_start->buffer;
- maximum = status;
- while (maximum)
- {
- count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
- status = full_write (STDOUT_FILENO, cursor, count);
- if (status < 0)
- write_error (use_compress_program_option);
-
- if (status != count)
- {
- ERROR ((0, 0, _("Write to compression program short %lu bytes"),
- (unsigned long) (count - status)));
- count = status;
- }
-
- cursor += count;
- maximum -= count;
- }
- }
-
-#if 0
- close_archive ();
-#endif
- exit (exit_status);
-}
-
-#endif /* not MSDOS */
-
-/*--------------------------------------------------------------------------.
-| Check the LABEL block against the volume label, seen as a globbing |
-| pattern. Return true if the pattern matches. In case of failure, retry |
-| matching a volume sequence number before giving up in multi-volume mode. |
-`--------------------------------------------------------------------------*/
-