summaryrefslogtreecommitdiffstats
path: root/contrib/tar/src
diff options
context:
space:
mode:
authorru <ru@FreeBSD.org>2006-09-15 08:04:23 +0000
committerru <ru@FreeBSD.org>2006-09-15 08:04:23 +0000
commit6b78b3a81dfd58cd5838b6fae2c4f76e95a5f930 (patch)
tree6f83030fb91083cd8f95441274f042914ff7d0c4 /contrib/tar/src
parent35f71d316ffcfbb768fb65dafa20f846cff14ba6 (diff)
downloadFreeBSD-src-6b78b3a81dfd58cd5838b6fae2c4f76e95a5f930.zip
FreeBSD-src-6b78b3a81dfd58cd5838b6fae2c4f76e95a5f930.tar.gz
Remove vestiges of GNU tar.
Diffstat (limited to 'contrib/tar/src')
-rw-r--r--contrib/tar/src/arith.h27
-rw-r--r--contrib/tar/src/buffer.c1619
-rw-r--r--contrib/tar/src/common.h586
-rw-r--r--contrib/tar/src/compare.c823
-rw-r--r--contrib/tar/src/create.c1552
-rw-r--r--contrib/tar/src/delete.c364
-rw-r--r--contrib/tar/src/extract.c1333
-rw-r--r--contrib/tar/src/incremen.c584
-rw-r--r--contrib/tar/src/list.c1211
-rw-r--r--contrib/tar/src/mangle.c121
-rw-r--r--contrib/tar/src/misc.c854
-rw-r--r--contrib/tar/src/names.c976
-rw-r--r--contrib/tar/src/rmt.c576
-rw-r--r--contrib/tar/src/rmt.h93
-rw-r--r--contrib/tar/src/rtapelib.c723
-rw-r--r--contrib/tar/src/system.h587
-rw-r--r--contrib/tar/src/tar.c1366
-rw-r--r--contrib/tar/src/tar.h235
-rw-r--r--contrib/tar/src/update.c195
19 files changed, 0 insertions, 13825 deletions
diff --git a/contrib/tar/src/arith.h b/contrib/tar/src/arith.h
deleted file mode 100644
index a1e532f..0000000
--- a/contrib/tar/src/arith.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Long integers, for GNU tar.
- Copyright 1999 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* Handle large integers for calculating big tape lengths and the
- like. In practice, double precision does for now. On the vast
- majority of machines, it counts up to 2**52 bytes without any loss
- of information, and counts up to 2**62 bytes if data are always
- blocked in 1 kB boundaries. We'll need arbitrary precision
- arithmetic anyway once we get into the 2**64 range, so there's no
- point doing anything fancy before then. */
-
-#define TARLONG_FORMAT "%.0f"
-typedef double tarlong;
diff --git a/contrib/tar/src/buffer.c b/contrib/tar/src/buffer.c
deleted file mode 100644
index ae6eb5d..0000000
--- a/contrib/tar/src/buffer.c
+++ /dev/null
@@ -1,1619 +0,0 @@
-/* Buffer management for tar.
-
- Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
- Software Foundation, Inc.
-
- Written by John Gilmore, on 1985-08-25.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* $FreeBSD$ */
-
-#include "system.h"
-
-#include <signal.h>
-
-#if __FreeBSD__
-# include <paths.h>
-#else
-# define _PATH_BSHELL "/bin/sh"
-#endif
-
-#if MSDOS
-# include <process.h>
-#endif
-
-#if XENIX
-# include <sys/inode.h>
-#endif
-
-#include <fnmatch.h>
-#include <human.h>
-#include <quotearg.h>
-
-#include "common.h"
-#include "rmt.h"
-
-#define PREAD 0 /* read file descriptor from pipe() */
-#define PWRITE 1 /* write file descriptor from pipe() */
-
-/* Number of retries before giving up on read. */
-#define READ_ERROR_MAX 10
-
-/* Globbing pattern to append to volume label if initial match failed. */
-#define VOLUME_LABEL_APPEND " Volume [1-9]*"
-
-/* Variables. */
-
-static tarlong prev_written; /* bytes written on previous volumes */
-static tarlong bytes_written; /* bytes written on this volume */
-
-/* FIXME: The following variables should ideally be static to this
- module. However, this cannot be done yet. The cleanup continues! */
-
-union block *record_start; /* start of record of archive */
-union block *record_end; /* last+1 block of archive record */
-union block *current_block; /* current block of archive */
-enum access_mode access_mode; /* how do we handle the archive */
-off_t records_read; /* number of records read from this archive */
-off_t records_written; /* likewise, for records written */
-
-static struct stat archive_stat; /* stat block for archive file */
-
-static off_t record_start_block; /* block ordinal at record_start */
-
-/* Where we write list messages (not errors, not interactions) to. Stdout
- unless we're writing a pipe, in which case stderr. */
-FILE *stdlis;
-
-static void backspace_output PARAMS ((void));
-static int new_volume PARAMS ((enum access_mode));
-static void archive_write_error PARAMS ((ssize_t)) __attribute__ ((noreturn));
-static void archive_read_error PARAMS ((void));
-
-#if !MSDOS
-/* Obnoxious test to see if dimwit is trying to dump the archive. */
-dev_t ar_dev;
-ino_t ar_ino;
-#endif
-
-/* PID of child program, if compress_option or remote archive access. */
-static pid_t child_pid;
-
-/* Error recovery stuff */
-static int read_error_count;
-
-/* Have we hit EOF yet? */
-static int hit_eof;
-
-/* Checkpointing counter */
-static int checkpoint;
-
-/* We're reading, but we just read the last block and its time to update. */
-/* As least EXTERN like this one as possible. FIXME! */
-extern int time_to_start_writing;
-
-int file_to_switch_to = -1; /* if remote update, close archive, and use
- this descriptor to write to */
-
-static int volno = 1; /* which volume of a multi-volume tape we're
- on */
-static int global_volno = 1; /* volume number to print in external
- messages */
-static pid_t grandchild_pid;
-
-/* The pointer save_name, which is set in function dump_file() of module
- create.c, points to the original long filename instead of the new,
- shorter mangled name that is set in start_header() of module create.c.
- The pointer save_name is only used in multi-volume mode when the file
- being processed is non-sparse; if a file is split between volumes, the
- save_name is used in generating the LF_MULTIVOL record on the second
- volume. (From Pierce Cantrell, 1991-08-13.) */
-
-char *save_name; /* name of the file we are currently writing */
-off_t save_totsize; /* total size of file we are writing, only
- valid if save_name is nonzero */
-off_t save_sizeleft; /* where we are in the file we are writing,
- only valid if save_name is nonzero */
-
-bool write_archive_to_stdout;
-
-/* Used by flush_read and flush_write to store the real info about saved
- names. */
-static char *real_s_name;
-static off_t real_s_totsize;
-static off_t real_s_sizeleft;
-
-/* Functions. */
-
-void
-print_total_written (void)
-{
- tarlong written = prev_written + bytes_written;
- char bytes[sizeof (tarlong) * CHAR_BIT];
- char abbr[LONGEST_HUMAN_READABLE + 1];
- char rate[LONGEST_HUMAN_READABLE + 1];
- double seconds;
-
-#if HAVE_CLOCK_GETTIME
- struct timespec now;
- if (clock_gettime (CLOCK_REALTIME, &now) == 0)
- seconds = ((now.tv_sec - start_timespec.tv_sec)
- + (now.tv_nsec - start_timespec.tv_nsec) / 1e9);
- else
-#endif
- seconds = time (0) - start_time;
-
- sprintf (bytes, TARLONG_FORMAT, written);
-
- /* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*". */
- fprintf (stderr, _("Total bytes written: %s (%sB, %sB/s)\n"), bytes,
- human_readable ((uintmax_t) written, abbr, 1, -1024),
- (0 < seconds && written / seconds < (uintmax_t) -1
- ? human_readable ((uintmax_t) (written / seconds), rate, 1, -1024)
- : "?"));
-}
-
-/* Compute and return the block ordinal at current_block. */
-off_t
-current_block_ordinal (void)
-{
- return record_start_block + (current_block - record_start);
-}
-
-/* If the EOF flag is set, reset it, as well as current_block, etc. */
-void
-reset_eof (void)
-{
- if (hit_eof)
- {
- hit_eof = 0;
- current_block = record_start;
- record_end = record_start + blocking_factor;
- access_mode = ACCESS_WRITE;
- }
-}
-
-/* Return the location of the next available input or output block.
- Return zero for EOF. Once we have returned zero, we just keep returning
- it, to avoid accidentally going on to the next file on the tape. */
-union block *
-find_next_block (void)
-{
- if (current_block == record_end)
- {
- if (hit_eof)
- return 0;
- flush_archive ();
- if (current_block == record_end)
- {
- hit_eof = 1;
- return 0;
- }
- }
- return current_block;
-}
-
-/* Indicate that we have used all blocks up thru BLOCK.
- FIXME: should the arg have an off-by-1? */
-void
-set_next_block_after (union block *block)
-{
- while (block >= current_block)
- current_block++;
-
- /* Do *not* flush the archive here. If we do, the same argument to
- set_next_block_after could mean the next block (if the input record
- is exactly one block long), which is not what is intended. */
-
- if (current_block > record_end)
- abort ();
-}
-
-/* Return the number of bytes comprising the space between POINTER
- through the end of the current buffer of blocks. This space is
- available for filling with data, or taking data from. POINTER is
- usually (but not always) the result previous find_next_block call. */
-size_t
-available_space_after (union block *pointer)
-{
- return record_end->buffer - pointer->buffer;
-}
-
-/* Close file having descriptor FD, and abort if close unsuccessful. */
-static void
-xclose (int fd)
-{
- if (close (fd) != 0)
- close_error (_("(pipe)"));
-}
-
-/* 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)
- || S_ISSOCK (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];
- int wait_status;
-
- 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 newborn grandchild tar is here! Launch the compressor. */
-
- program_name = _("tar (grandchild)");
-
- 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 child tar is still here! */
-
- /* 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
-
- /* Propagate any failure of the grandchild back to the parent. */
-
- while (waitpid (grandchild_pid, &wait_status, 0) == -1)
- if (errno != EINTR)
- {
- waitpid_error (use_compress_program_option);
- break;
- }
-
- if (WIFSIGNALED (wait_status))
- {
- kill (child_pid, WTERMSIG (wait_status));
- exit_status = TAREXIT_FAILURE;
- }
- else if (WEXITSTATUS (wait_status) != 0)
- exit_status = WEXITSTATUS (wait_status);
-
- exit (exit_status);
-}
-
-static void
-sig_propagate(int sig)
-{
- kill (grandchild_pid, sig);
- exit (TAREXIT_FAILURE);
-}
-
-/* Set ARCHIVE for uncompressing, then reading an archive. */
-static void
-child_open_for_uncompress (void)
-{
- int parent_pipe[2];
- int child_pipe[2];
- int wait_status;
-
- 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 newborn 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 newborn grandchild tar is here! Launch the uncompressor. */
-
- program_name = _("tar (grandchild)");
-
- 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 child tar is still here! */
- signal (SIGTERM, sig_propagate);
-
- /* 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;
- if (full_write (STDOUT_FILENO, cursor, count) != count)
- write_error (use_compress_program_option);
- cursor += count;
- maximum -= count;
- }
- }
-
- xclose (STDOUT_FILENO);
-#if 0
- close_archive ();
-#endif
-
- /* Propagate any failure of the grandchild back to the parent. */
-
- while (waitpid (grandchild_pid, &wait_status, 0) == -1)
- if (errno != EINTR)
- {
- waitpid_error (use_compress_program_option);
- break;
- }
-
- if (WIFSIGNALED (wait_status))
- {
- kill (child_pid, WTERMSIG (wait_status));
- exit_status = TAREXIT_FAILURE;
- }
- else if (WEXITSTATUS (wait_status) != 0)
- exit_status = WEXITSTATUS (wait_status);
-
- 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. */
-static int
-check_label_pattern (union block *label)
-{
- char *string;
- int result;
-
- if (! memchr (label->header.name, '\0', sizeof label->header.name))
- return 0;
-
- if (fnmatch (volume_label_option, label->header.name, 0) == 0)
- return 1;
-
- if (!multi_volume_option)
- return 0;
-
- string = xmalloc (strlen (volume_label_option)
- + sizeof VOLUME_LABEL_APPEND + 1);
- strcpy (string, volume_label_option);
- strcat (string, VOLUME_LABEL_APPEND);
- result = fnmatch (string, label->header.name, 0) == 0;
- free (string);
- return result;
-}
-
-/* Open an archive file. The argument specifies whether we are
- reading or writing, or both. */
-void
-open_archive (enum access_mode wanted_access)
-{
- int backed_up_flag = 0;
-
- stdlis = to_stdout_option ? stderr : stdout;
-
- if (record_size == 0)
- FATAL_ERROR ((0, 0, _("Invalid value for record_size")));
-
- if (archive_names == 0)
- FATAL_ERROR ((0, 0, _("No archive name given")));
-
- current_file_name = 0;
- current_link_name = 0;
- save_name = 0;
- real_s_name = 0;
-
- if (multi_volume_option)
- {
- if (verify_option)
- FATAL_ERROR ((0, 0, _("Cannot verify multi-volume archives")));
- record_start = valloc (record_size + (2 * BLOCKSIZE));
- if (record_start)
- record_start += 2;
- }
- else
- record_start = valloc (record_size);
- if (!record_start)
- FATAL_ERROR ((0, 0, _("Cannot allocate memory for blocking factor %d"),
- blocking_factor));
-
- current_block = record_start;
- record_end = record_start + blocking_factor;
- /* When updating the archive, we start with reading. */
- access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
-
- if (use_compress_program_option)
- {
- if (multi_volume_option)
- FATAL_ERROR ((0, 0, _("Cannot use multi-volume compressed archives")));
- if (verify_option)
- FATAL_ERROR ((0, 0, _("Cannot verify compressed archives")));
-
- switch (wanted_access)
- {
- case ACCESS_READ:
- child_open_for_uncompress ();
- break;
-
- case ACCESS_WRITE:
- child_open_for_compress ();
- break;
-
- case ACCESS_UPDATE:
- FATAL_ERROR ((0, 0, _("Cannot update compressed archives")));
- break;
- }
-
- if (wanted_access == ACCESS_WRITE
- && strcmp (archive_name_array[0], "-") == 0)
- stdlis = stderr;
- }
- else if (strcmp (archive_name_array[0], "-") == 0)
- {
- read_full_records_option = 1; /* could be a pipe, be safe */
- if (verify_option)
- FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
-
- switch (wanted_access)
- {
- case ACCESS_READ:
- archive = STDIN_FILENO;
- break;
-
- case ACCESS_WRITE:
- archive = STDOUT_FILENO;
- stdlis = stderr;
- break;
-
- case ACCESS_UPDATE:
- archive = STDIN_FILENO;
- stdlis = stderr;
- write_archive_to_stdout = 1;
- break;
- }
- }
- else if (verify_option)
- archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
- MODE_RW, rsh_command_option);
- else
- switch (wanted_access)
- {
- case ACCESS_READ:
- archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
- MODE_RW, rsh_command_option);
- break;
-
- case ACCESS_WRITE:
- if (backup_option)
- {
- maybe_backup_file (archive_name_array[0], 1);
- backed_up_flag = 1;
- }
- archive = rmtcreat (archive_name_array[0], MODE_RW,
- rsh_command_option);
- break;
-
- case ACCESS_UPDATE:
- archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
- MODE_RW, rsh_command_option);
- break;
- }
-
- if (archive < 0
- || (! _isrmt (archive) && fstat (archive, &archive_stat) < 0))
- {
- int saved_errno = errno;
-
- if (backed_up_flag)
- undo_last_backup ();
- errno = saved_errno;
- open_fatal (archive_name_array[0]);
- }
-
-#if !MSDOS
-
- /* Detect if outputting to "/dev/null". */
- {
- static char const dev_null[] = "/dev/null";
- struct stat dev_null_stat;
-
- dev_null_output =
- (strcmp (archive_name_array[0], dev_null) == 0
- || (! _isrmt (archive)
- && S_ISCHR (archive_stat.st_mode)
- && stat (dev_null, &dev_null_stat) == 0
- && archive_stat.st_dev == dev_null_stat.st_dev
- && archive_stat.st_ino == dev_null_stat.st_ino));
- }
-
- if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
- {
- ar_dev = archive_stat.st_dev;
- ar_ino = archive_stat.st_ino;
- }
- else
- ar_dev = 0;
-
-#endif /* not MSDOS */
-
-#if MSDOS
- setmode (archive, O_BINARY);
-#endif
-
- switch (wanted_access)
- {
- case ACCESS_UPDATE:
- records_written = 0;
- case ACCESS_READ:
- records_read = 0;
- record_end = record_start; /* set up for 1st record = # 0 */
- find_next_block (); /* read it in, check for EOF */
-
- if (volume_label_option)
- {
- union block *label = find_next_block ();
-
- if (!label)
- FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),
- quote (volume_label_option)));
- if (!check_label_pattern (label))
- FATAL_ERROR ((0, 0, _("Volume %s does not match %s"),
- quote_n (0, label->header.name),
- quote_n (1, volume_label_option)));
- }
- break;
-
- case ACCESS_WRITE:
- records_written = 0;
- if (volume_label_option)
- {
- memset (record_start, 0, BLOCKSIZE);
- if (multi_volume_option)
- sprintf (record_start->header.name, "%s Volume 1",
- volume_label_option);
- else
- strcpy (record_start->header.name, volume_label_option);
-
- assign_string (&current_file_name, record_start->header.name);
-
- record_start->header.typeflag = GNUTYPE_VOLHDR;
- TIME_TO_CHARS (start_time, record_start->header.mtime);
- finish_header (record_start);
-#if 0
- current_block++;
-#endif
- }
- break;
- }
-}
-
-/* Perform a write to flush the buffer. */
-void
-flush_write (void)
-{
- int copy_back;
- ssize_t status;
-
- if (checkpoint_option && !(++checkpoint % 10))
- WARN ((0, 0, _("Write checkpoint %d"), checkpoint));
-
- if (tape_length_option && tape_length_option <= bytes_written)
- {
- errno = ENOSPC;
- status = 0;
- }
- else if (dev_null_output)
- status = record_size;
- else
- status = write_archive_buffer ();
- if (status != record_size && !multi_volume_option)
- archive_write_error (status);
-
- if (status > 0)
- {
- records_written++;
- bytes_written += status;
- }
-
- if (status == record_size)
- {
- if (multi_volume_option)
- {
- char *cursor;
-
- if (!save_name)
- {
- assign_string (&real_s_name, 0);
- real_s_totsize = 0;
- real_s_sizeleft = 0;
- return;
- }
-
- cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
- while (ISSLASH (*cursor))
- cursor++;
-
- assign_string (&real_s_name, cursor);
- real_s_totsize = save_totsize;
- real_s_sizeleft = save_sizeleft;
- }
- return;
- }
-
- /* We're multivol. Panic if we didn't get the right kind of response. */
-
- /* ENXIO is for the UNIX PC. */
- if (status < 0 && errno != ENOSPC && errno != EIO && errno != ENXIO)
- archive_write_error (status);
-
- /* If error indicates a short write, we just move to the next tape. */
-
- if (!new_volume (ACCESS_WRITE))
- return;
-
- if (totals_option)
- prev_written += bytes_written;
- bytes_written = 0;
-
- if (volume_label_option && real_s_name)
- {
- copy_back = 2;
- record_start -= 2;
- }
- else if (volume_label_option || real_s_name)
- {
- copy_back = 1;
- record_start--;
- }
- else
- copy_back = 0;
-
- if (volume_label_option)
- {
- memset (record_start, 0, BLOCKSIZE);
- sprintf (record_start->header.name, "%s Volume %d",
- volume_label_option, volno);
- TIME_TO_CHARS (start_time, record_start->header.mtime);
- record_start->header.typeflag = GNUTYPE_VOLHDR;
- finish_header (record_start);
- }
-
- if (real_s_name)
- {
- int tmp;
-
- if (volume_label_option)
- record_start++;
-
- memset (record_start, 0, BLOCKSIZE);
-
- /* FIXME: Michael P Urban writes: [a long name file] is being written
- when a new volume rolls around [...] Looks like the wrong value is
- being preserved in real_s_name, though. */
-
- strcpy (record_start->header.name, real_s_name);
- record_start->header.typeflag = GNUTYPE_MULTIVOL;
- OFF_TO_CHARS (real_s_sizeleft, record_start->header.size);
- OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
- record_start->oldgnu_header.offset);
- tmp = verbose_option;
- verbose_option = 0;
- finish_header (record_start);
- verbose_option = tmp;
-
- if (volume_label_option)
- record_start--;
- }
-
- status = write_archive_buffer ();
- if (status != record_size)
- archive_write_error (status);
-
- bytes_written += status;
-
- if (copy_back)
- {
- record_start += copy_back;
- memcpy (current_block,
- record_start + blocking_factor - copy_back,
- copy_back * BLOCKSIZE);
- current_block += copy_back;
-
- if (real_s_sizeleft >= copy_back * BLOCKSIZE)
- real_s_sizeleft -= copy_back * BLOCKSIZE;
- else if ((real_s_sizeleft + BLOCKSIZE - 1) / BLOCKSIZE <= copy_back)
- assign_string (&real_s_name, 0);
- else
- {
- char *cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
-
- while (ISSLASH (*cursor))
- cursor++;
-
- assign_string (&real_s_name, cursor);
- real_s_sizeleft = save_sizeleft;
- real_s_totsize = save_totsize;
- }
- copy_back = 0;
- }
-}
-
-/* Handle write errors on the archive. Write errors are always fatal.
- Hitting the end of a volume does not cause a write error unless the
- write was the first record of the volume. */
-static void
-archive_write_error (ssize_t status)
-{
- /* It might be useful to know how much was written before the error
- occurred. */
- if (totals_option)
- {
- int e = errno;
- print_total_written ();
- errno = e;
- }
-
- write_fatal_details (*archive_name_cursor, status, record_size);
-}
-
-/* Handle read errors on the archive. If the read should be retried,
- return to the caller. */
-static void
-archive_read_error (void)
-{
- read_error (*archive_name_cursor);
-
- if (record_start_block == 0)
- FATAL_ERROR ((0, 0, _("At beginning of tape, quitting now")));
-
- /* Read error in mid archive. We retry up to READ_ERROR_MAX times and
- then give up on reading the archive. */
-
- if (read_error_count++ > READ_ERROR_MAX)
- FATAL_ERROR ((0, 0, _("Too many errors, quitting")));
- return;
-}
-
-/* Perform a read to flush the buffer. */
-void
-flush_read (void)
-{
- ssize_t status; /* result from system call */
- size_t left; /* bytes left */
- char *more; /* pointer to next byte to read */
-
- if (checkpoint_option && !(++checkpoint % 10))
- WARN ((0, 0, _("Read checkpoint %d"), checkpoint));
-
- /* Clear the count of errors. This only applies to a single call to
- flush_read. */
-
- read_error_count = 0; /* clear error count */
-
- if (write_archive_to_stdout && record_start_block != 0)
- {
- archive = STDOUT_FILENO;
- status = write_archive_buffer ();
- archive = STDIN_FILENO;
- if (status != record_size)
- archive_write_error (status);
- }
- if (multi_volume_option)
- {
- if (save_name)
- {
- char *cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
-
- while (ISSLASH (*cursor))
- cursor++;
-
- assign_string (&real_s_name, cursor);
- real_s_sizeleft = save_sizeleft;
- real_s_totsize = save_totsize;
- }
- else
- {
- assign_string (&real_s_name, 0);
- real_s_totsize = 0;
- real_s_sizeleft = 0;
- }
- }
-
- error_loop:
- status = rmtread (archive, record_start->buffer, record_size);
- if (status == record_size)
- {
- records_read++;
- return;
- }
-
- if ((status == 0
- || (status < 0 && errno == ENOSPC)
- || (status > 0 && !read_full_records_option))
- && multi_volume_option)
- {
- union block *cursor;
-
- try_volume:
- switch (subcommand_option)
- {
- case APPEND_SUBCOMMAND:
- case CAT_SUBCOMMAND:
- case UPDATE_SUBCOMMAND:
- if (!new_volume (ACCESS_UPDATE))
- return;
- break;
-
- default:
- if (!new_volume (ACCESS_READ))
- return;
- break;
- }
-
- vol_error:
- status = rmtread (archive, record_start->buffer, record_size);
- if (status < 0)
- {
- archive_read_error ();
- goto vol_error;
- }
- if (status != record_size)
- goto short_read;
-
- cursor = record_start;
-
- if (cursor->header.typeflag == GNUTYPE_VOLHDR)
- {
- if (volume_label_option)
- {
- if (!check_label_pattern (cursor))
- {
- WARN ((0, 0, _("Volume %s does not match %s"),
- quote_n (0, cursor->header.name),
- quote_n (1, volume_label_option)));
- volno--;
- global_volno--;
- goto try_volume;
- }
- }
- if (verbose_option)
- fprintf (stdlis, _("Reading %s\n"), quote (cursor->header.name));
- cursor++;
- }
- else if (volume_label_option)
- WARN ((0, 0, _("WARNING: No volume header")));
-
- if (real_s_name)
- {
- uintmax_t s1, s2;
- if (cursor->header.typeflag != GNUTYPE_MULTIVOL
- || strcmp (cursor->header.name, real_s_name))
- {
- WARN ((0, 0, _("%s is not continued on this volume"),
- quote (real_s_name)));
- volno--;
- global_volno--;
- goto try_volume;
- }
- s1 = UINTMAX_FROM_HEADER (cursor->header.size);
- s2 = UINTMAX_FROM_HEADER (cursor->oldgnu_header.offset);
- if (real_s_totsize != s1 + s2 || s1 + s2 < s2)
- {
- char totsizebuf[UINTMAX_STRSIZE_BOUND];
- char s1buf[UINTMAX_STRSIZE_BOUND];
- char s2buf[UINTMAX_STRSIZE_BOUND];
-
- WARN ((0, 0, _("%s is the wrong size (%s != %s + %s)"),
- quote (cursor->header.name),
- STRINGIFY_BIGINT (save_totsize, totsizebuf),
- STRINGIFY_BIGINT (s1, s1buf),
- STRINGIFY_BIGINT (s2, s2buf)));
- volno--;
- global_volno--;
- goto try_volume;
- }
- if (real_s_totsize - real_s_sizeleft
- != OFF_FROM_HEADER (cursor->oldgnu_header.offset))
- {
- WARN ((0, 0, _("This volume is out of sequence")));
- volno--;
- global_volno--;
- goto try_volume;
- }
- cursor++;
- }
- current_block = cursor;
- records_read++;
- return;
- }
- else if (status < 0)
- {
- archive_read_error ();
- goto error_loop; /* try again */
- }
-
- short_read:
- more = record_start->buffer + status;
- left = record_size - status;
-
- while (left % BLOCKSIZE != 0
- || (left && status && read_full_records_option))
- {
- if (status)
- while ((status = rmtread (archive, more, left)) < 0)
- archive_read_error ();
-
- if (status == 0)
- break;
-
- if (! read_full_records_option)
- FATAL_ERROR ((0, 0, _("Unaligned block (%lu bytes) in archive"),
- (unsigned long) (record_size - left)));
-
- /* User warned us about this. Fix up. */
-
- left -= status;
- more += status;
- }
-
- /* FIXME: for size=0, multi-volume support. On the first record, warn
- about the problem. */
-
- if (!read_full_records_option && verbose_option
- && record_start_block == 0 && status > 0)
- WARN ((0, 0, _("Record size = %lu blocks"),
- (unsigned long) ((record_size - left) / BLOCKSIZE)));
-
- record_end = record_start + (record_size - left) / BLOCKSIZE;
- records_read++;
-}
-
-/* Flush the current buffer to/from the archive. */
-void
-flush_archive (void)
-{
- record_start_block += record_end - record_start;
- current_block = record_start;
- record_end = record_start + blocking_factor;
-
- if (access_mode == ACCESS_READ && time_to_start_writing)
- {
- access_mode = ACCESS_WRITE;
- time_to_start_writing = 0;
-
- if (file_to_switch_to >= 0)
- {
- if (rmtclose (archive) != 0)
- close_warn (*archive_name_cursor);
-
- archive = file_to_switch_to;
- }
- else
- backspace_output ();
- }
-
- switch (access_mode)
- {
- case ACCESS_READ:
- flush_read ();
- break;
-
- case ACCESS_WRITE:
- flush_write ();
- break;
-
- case ACCESS_UPDATE:
- abort ();
- }
-}
-
-/* Backspace the archive descriptor by one record worth. If it's a
- tape, MTIOCTOP will work. If it's something else, try to seek on
- it. If we can't seek, we lose! */
-static void
-backspace_output (void)
-{
-#ifdef MTIOCTOP
- {
- struct mtop operation;
-
- operation.mt_op = MTBSR;
- operation.mt_count = 1;
- if (rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
- return;
- if (errno == EIO && rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
- return;
- }
-#endif
-
- {
- off_t position = rmtlseek (archive, (off_t) 0, SEEK_CUR);
-
- /* Seek back to the beginning of this record and start writing there. */
-
- position -= record_size;
- if (position < 0)
- position = 0;
- if (rmtlseek (archive, position, SEEK_SET) != position)
- {
- /* Lseek failed. Try a different method. */
-
- WARN ((0, 0,
- _("Cannot backspace archive file; it may be unreadable without -i")));
-
- /* Replace the first part of the record with NULs. */
-
- if (record_start->buffer != output_start)
- memset (record_start->buffer, 0,
- output_start - record_start->buffer);
- }
- }
-}
-
-/* Close the archive file. */
-void
-close_archive (void)
-{
- if (time_to_start_writing || access_mode == ACCESS_WRITE)
- flush_archive ();
-
-#if !MSDOS
-
- /* Manage to fully drain a pipe we might be reading, so to not break it on
- the producer after the EOF block. FIXME: one of these days, GNU tar
- might become clever enough to just stop working, once there is no more
- work to do, we might have to revise this area in such time. */
-
- if (fast_read_option && namelist_freed && child_pid > 0)
- kill(child_pid, SIGTERM);
-
- if (access_mode == ACCESS_READ
- && ! _isrmt (archive)
- && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
- while (rmtread (archive, record_start->buffer, record_size) > 0)
- continue;
-#endif
-
- if (verify_option)
- verify_volume ();
-
- if (rmtclose (archive) != 0)
- close_warn (*archive_name_cursor);
-
-#if !MSDOS
-
- if (child_pid)
- {
- int wait_status;
-
- while (waitpid (child_pid, &wait_status, 0) == -1)
- if (errno != EINTR)
- {
- waitpid_error (use_compress_program_option);
- break;
- }
-
- if (!fast_read_option || !namelist_freed)
- if (WIFSIGNALED (wait_status))
- ERROR ((0, 0, _("Child died with signal %d"),
- WTERMSIG (wait_status)));
- else if (WEXITSTATUS (wait_status) != 0)
- ERROR ((0, 0, _("Child returned status %d"),
- WEXITSTATUS (wait_status)));
- }
-#endif /* !MSDOS */
-
- if (current_file_name)
- free (current_file_name);
- if (current_link_name)
- free (current_link_name);
- if (save_name)
- free (save_name);
- if (real_s_name)
- free (real_s_name);
- free (multi_volume_option ? record_start - 2 : record_start);
-}
-
-/* Called to initialize the global volume number. */
-void
-init_volume_number (void)
-{
- FILE *file = fopen (volno_file_option, "r");
-
- if (file)
- {
- if (fscanf (file, "%d", &global_volno) != 1
- || global_volno < 0)
- FATAL_ERROR ((0, 0, _("%s: contains invalid volume number"),
- quotearg_colon (volno_file_option)));
- if (ferror (file))
- read_error (volno_file_option);
- if (fclose (file) != 0)
- close_error (volno_file_option);
- }
- else if (errno != ENOENT)
- open_error (volno_file_option);
-}
-
-/* Called to write out the closing global volume number. */
-void
-closeout_volume_number (void)
-{
- FILE *file = fopen (volno_file_option, "w");
-
- if (file)
- {
- fprintf (file, "%d\n", global_volno);
- if (ferror (file))
- write_error (volno_file_option);
- if (fclose (file) != 0)
- close_error (volno_file_option);
- }
- else
- open_error (volno_file_option);
-}
-
-/* We've hit the end of the old volume. Close it and open the next one.
- Return nonzero on success. */
-static int
-new_volume (enum access_mode access)
-{
- static FILE *read_file;
- static int looped;
-
- if (!read_file && !info_script_option)
- /* FIXME: if fopen is used, it will never be closed. */
- read_file = archive == STDIN_FILENO ? fopen (TTY_NAME, "r") : stdin;
-
- if (now_verifying)
- return 0;
- if (verify_option)
- verify_volume ();
-
- if (rmtclose (archive) != 0)
- close_warn (*archive_name_cursor);
-
- global_volno++;
- if (global_volno < 0)
- FATAL_ERROR ((0, 0, _("Volume number overflow")));
- volno++;
- archive_name_cursor++;
- if (archive_name_cursor == archive_name_array + archive_names)
- {
- archive_name_cursor = archive_name_array;
- looped = 1;
- }
-
- tryagain:
- if (looped)
- {
- /* We have to prompt from now on. */
-
- if (info_script_option)
- {
- if (volno_file_option)
- closeout_volume_number ();
- if (system (info_script_option) != 0)
- FATAL_ERROR ((0, 0, _("`%s' command failed"), info_script_option));
- }
- else
- while (1)
- {
- char input_buffer[80];
-
- fputc ('\007', stderr);
- fprintf (stderr,
- _("Prepare volume #%d for %s and hit return: "),
- global_volno, quote (*archive_name_cursor));
- fflush (stderr);
-
- if (fgets (input_buffer, sizeof input_buffer, read_file) == 0)
- {
- WARN ((0, 0, _("EOF where user reply was expected")));
-
- if (subcommand_option != EXTRACT_SUBCOMMAND
- && subcommand_option != LIST_SUBCOMMAND
- && subcommand_option != DIFF_SUBCOMMAND)
- WARN ((0, 0, _("WARNING: Archive is incomplete")));
-
- fatal_exit ();
- }
- if (input_buffer[0] == '\n'
- || input_buffer[0] == 'y'
- || input_buffer[0] == 'Y')
- break;
-
- switch (input_buffer[0])
- {
- case '?':
- {
- fprintf (stderr, _("\
- n [name] Give a new file name for the next (and subsequent) volume(s)\n\
- q Abort tar\n\
- ! Spawn a subshell\n\
- ? Print this list\n"));
- }
- break;
-
- case 'q':
- /* Quit. */
-
- WARN ((0, 0, _("No new volume; exiting.\n")));
-
- if (subcommand_option != EXTRACT_SUBCOMMAND
- && subcommand_option != LIST_SUBCOMMAND
- && subcommand_option != DIFF_SUBCOMMAND)
- WARN ((0, 0, _("WARNING: Archive is incomplete")));
-
- fatal_exit ();
-
- case 'n':
- /* Get new file name. */
-
- {
- char *name = &input_buffer[1];
- char *cursor;
-
- while (*name == ' ' || *name == '\t')
- name++;
- cursor = name;
- while (*cursor && *cursor != '\n')
- cursor++;
- *cursor = '\0';
-
- /* FIXME: the following allocation is never reclaimed. */
- *archive_name_cursor = xstrdup (name);
- }
- break;
-
- case '!':
-#if MSDOS
- spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
-#else /* not MSDOS */
- {
- pid_t child;
- const char *shell = getenv ("SHELL");
- if (! shell)
- shell = _PATH_BSHELL;
- child = xfork ();
- if (child == 0)
- {
- execlp (shell, "-sh", "-i", (char *) 0);
- exec_fatal (shell);
- }
- else
- {
- int wait_status;
- while (waitpid (child, &wait_status, 0) == -1)
- if (errno != EINTR)
- {
- waitpid_error (shell);
- break;
- }
- }
- }
-#endif /* not MSDOS */
- break;
- }
- }
- }
-
- if (verify_option)
- archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,
- rsh_command_option);
- else
- switch (access)
- {
- case ACCESS_READ:
- archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
- rsh_command_option);
- break;
-
- case ACCESS_WRITE:
- if (backup_option)
- maybe_backup_file (*archive_name_cursor, 1);
- archive = rmtcreat (*archive_name_cursor, MODE_RW,
- rsh_command_option);
- break;
-
- case ACCESS_UPDATE:
- archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,
- rsh_command_option);
- break;
- }
-
- if (archive < 0)
- {
- open_warn (*archive_name_cursor);
- if (!verify_option && access == ACCESS_WRITE && backup_option)
- undo_last_backup ();
- goto tryagain;
- }
-
-#if MSDOS
- setmode (archive, O_BINARY);
-#endif
-
- return 1;
-}
diff --git a/contrib/tar/src/common.h b/contrib/tar/src/common.h
deleted file mode 100644
index 40e0ab6..0000000
--- a/contrib/tar/src/common.h
+++ /dev/null
@@ -1,586 +0,0 @@
-/* Common declarations for the tar program.
-
- Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
- Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* $FreeBSD$ */
-
-/* Declare the GNU tar archive format. */
-#include "tar.h"
-
-/* The checksum field is filled with this while the checksum is computed. */
-#define CHKBLANKS " " /* 8 blanks, no null */
-
-/* Some constants from POSIX are given names. */
-#define NAME_FIELD_SIZE 100
-#define PREFIX_FIELD_SIZE 155
-#define UNAME_FIELD_SIZE 32
-#define GNAME_FIELD_SIZE 32
-
-/* Some various global definitions. */
-
-/* Name of file to use for interacting with user. */
-#if MSDOS
-# define TTY_NAME "con"
-#else
-# define TTY_NAME "/dev/tty"
-#endif
-
-/* GLOBAL is defined to empty in tar.c only, and left alone in other *.c
- modules. Here, we merely set it to "extern" if it is not already set.
- GNU tar does depend on the system loader to preset all GLOBAL variables to
- neutral (or zero) values, explicit initialization is usually not done. */
-#ifndef GLOBAL
-# define GLOBAL extern
-#endif
-
-/* Exit status for GNU tar. Let's try to keep this list as simple as
- possible. -d option strongly invites a status different for unequal
- comparison and other errors. */
-GLOBAL int exit_status;
-
-#define TAREXIT_SUCCESS 0
-#define TAREXIT_DIFFERS 1
-#define TAREXIT_FAILURE 2
-
-/* Both WARN and ERROR write a message on stderr and continue processing,
- however ERROR manages so tar will exit unsuccessfully. FATAL_ERROR
- writes a message on stderr and aborts immediately, with another message
- line telling so. USAGE_ERROR works like FATAL_ERROR except that the
- other message line suggests trying --help. All four macros accept a
- single argument of the form ((0, errno, _("FORMAT"), Args...)). errno
- is zero when the error is not being detected by the system. */
-
-#define WARN(Args) \
- error Args
-#define ERROR(Args) \
- (error Args, exit_status = TAREXIT_FAILURE)
-#define FATAL_ERROR(Args) \
- (error Args, fatal_exit ())
-#define USAGE_ERROR(Args) \
- (error Args, usage (TAREXIT_FAILURE))
-
-/* Information gleaned from the command line. */
-
-#include "arith.h"
-#include <backupfile.h>
-#include <exclude.h>
-#include <modechange.h>
-#include <safe-read.h>
-#include <full-write.h>
-
-/* Log base 2 of common values. */
-#define LG_8 3
-#define LG_64 6
-#define LG_256 8
-
-/* Name of this program. */
-GLOBAL const char *program_name;
-
-/* Main command option. */
-
-enum subcommand
-{
- UNKNOWN_SUBCOMMAND, /* none of the following */
- APPEND_SUBCOMMAND, /* -r */
- CAT_SUBCOMMAND, /* -A */
- CREATE_SUBCOMMAND, /* -c */
- DELETE_SUBCOMMAND, /* -D */
- DIFF_SUBCOMMAND, /* -d */
- EXTRACT_SUBCOMMAND, /* -x */
- LIST_SUBCOMMAND, /* -t */
- UPDATE_SUBCOMMAND /* -u */
-};
-
-GLOBAL enum subcommand subcommand_option;
-
-/* Selected format for output archive. */
-GLOBAL enum archive_format archive_format;
-
-/* Either NL or NUL, as decided by the --null option. */
-GLOBAL char filename_terminator;
-
-/* Size of each record, once in blocks, once in bytes. Those two variables
- are always related, the second being BLOCKSIZE times the first. They do
- not have _option in their name, even if their values is derived from
- option decoding, as these are especially important in tar. */
-GLOBAL int blocking_factor;
-GLOBAL size_t record_size;
-
-/* Boolean value. */
-GLOBAL int absolute_names_option;
-
-/* This variable tells how to interpret newer_mtime_option, below. If zero,
- files get archived if their mtime is not less than newer_mtime_option.
- If nonzero, files get archived if *either* their ctime or mtime is not less
- than newer_mtime_option. */
-GLOBAL int after_date_option;
-
-/* Boolean value. */
-GLOBAL int atime_preserve_option;
-
-/* Boolean value. */
-GLOBAL int backup_option;
-
-/* Type of backups being made. */
-GLOBAL enum backup_type backup_type;
-
-/* Boolean value. */
-GLOBAL int block_number_option;
-
-/* Boolean value. */
-GLOBAL int checkpoint_option;
-
-/* Specified name of compression program, or "gzip" as implied by -z. */
-GLOBAL const char *use_compress_program_option;
-
-/* Boolean value. */
-GLOBAL int dereference_option;
-
-/* Patterns that match file names to be excluded. */
-GLOBAL struct exclude *excluded;
-
-/* Boolean value. */
-GLOBAL int fast_read_option;
-
-/* Specified file containing names to work on. */
-GLOBAL const char *files_from_option;
-
-/* Boolean value. */
-GLOBAL int force_local_option;
-
-/* Specified value to be put into tar file in place of stat () results, or
- just -1 if such an override should not take place. */
-GLOBAL gid_t group_option;
-
-/* Boolean value. */
-GLOBAL int ignore_failed_read_option;
-
-/* Boolean value. */
-GLOBAL int ignore_zeros_option;
-
-/* Boolean value. */
-GLOBAL int incremental_option;
-
-/* Specified name of script to run at end of each tape change. */
-GLOBAL const char *info_script_option;
-
-/* Boolean value. */
-GLOBAL int interactive_option;
-
-enum old_files
-{
- DEFAULT_OLD_FILES, /* default */
- UNLINK_FIRST_OLD_FILES, /* --unlink-first */
- KEEP_OLD_FILES, /* --keep-old-files */
- OVERWRITE_OLD_DIRS, /* --overwrite-dir */
- OVERWRITE_OLD_FILES /* --overwrite */
-};
-GLOBAL enum old_files old_files_option;
-
-/* Specified file name for incremental list. */
-GLOBAL const char *listed_incremental_option;
-
-/* Specified mode change string. */
-GLOBAL struct mode_change *mode_option;
-
-/* Boolean value. */
-GLOBAL int multi_volume_option;
-
-/* Boolean value. */
-GLOBAL int namelist_freed;
-
-/* The same variable hold the time, whether mtime or ctime. Just fake a
- non-existing option, for making the code clearer, elsewhere. */
-#define newer_ctime_option newer_mtime_option
-
-/* Specified threshold date and time. Files having an older time stamp
- do not get archived (also see after_date_option above). */
-GLOBAL time_t newer_mtime_option;
-
-/* Zero if there is no recursion, otherwise FNM_LEADING_DIR. */
-GLOBAL int recursion_option;
-
-/* Boolean value. */
-GLOBAL int numeric_owner_option;
-
-/* Boolean value. */
-GLOBAL int one_file_system_option;
-
-/* Specified value to be put into tar file in place of stat () results, or
- just -1 if such an override should not take place. */
-GLOBAL uid_t owner_option;
-
-/* Boolean value. */
-GLOBAL int recursive_unlink_option;
-
-/* Boolean value. */
-GLOBAL int read_full_records_option;
-
-/* Boolean value. */
-GLOBAL int remove_files_option;
-
-/* Specified remote shell command. */
-GLOBAL const char *rsh_command_option;
-
-/* Boolean value. */
-GLOBAL int same_order_option;
-
-/* If positive, preserve ownership when extracting. */
-GLOBAL int same_owner_option;
-
-/* If positive, preserve permissions when extracting. */
-GLOBAL int same_permissions_option;
-
-/* Boolean value. */
-GLOBAL int show_omitted_dirs_option;
-
-/* Boolean value. */
-GLOBAL int sparse_option;
-
-/* Boolean value. */
-GLOBAL int starting_file_option;
-
-/* Specified maximum byte length of each tape volume (multiple of 1024). */
-GLOBAL tarlong tape_length_option;
-
-/* Boolean value. */
-GLOBAL int to_stdout_option;
-
-/* Boolean value. */
-GLOBAL int totals_option;
-
-/* Boolean value. */
-GLOBAL int touch_option;
-
-/* Count how many times the option has been set, multiple setting yields
- more verbose behavior. Value 0 means no verbosity, 1 means file name
- only, 2 means file name and all attributes. More than 2 is just like 2. */
-GLOBAL int verbose_option;
-
-/* Boolean value. */
-GLOBAL int verify_option;
-
-/* Specified name of file containing the volume number. */
-GLOBAL const char *volno_file_option;
-
-/* Specified value or pattern. */
-GLOBAL const char *volume_label_option;
-
-/* Other global variables. */
-
-/* File descriptor for archive file. */
-GLOBAL int archive;
-
-/* Nonzero when outputting to /dev/null. */
-GLOBAL int dev_null_output;
-
-/* Timestamp for when we started execution. */
-#if HAVE_CLOCK_GETTIME
- GLOBAL struct timespec start_timespec;
-# define start_time (start_timespec.tv_sec)
-#else
- GLOBAL time_t start_time;
-#endif
-
-/* Name of file for the current archive entry. */
-GLOBAL char *current_file_name;
-
-/* Name of link for the current archive entry. */
-GLOBAL char *current_link_name;
-
-/* List of tape drive names, number of such tape drives, allocated number,
- and current cursor in list. */
-GLOBAL const char **archive_name_array;
-GLOBAL int archive_names;
-GLOBAL int allocated_archive_names;
-GLOBAL const char **archive_name_cursor;
-
-/* Structure for keeping track of filenames and lists thereof. */
-struct name
- {
- struct name *next;
- size_t length; /* cached strlen(name) */
- char found; /* a matching file has been found */
- char firstch; /* first char is literally matched */
- char regexp; /* this name is a regexp, not literal */
- int change_dir; /* set with the -C option */
- char const *dir_contents; /* for incremental_option */
- char fake; /* dummy entry */
- char name[1];
- };
-
-/* Information about a sparse file. */
-struct sp_array
- {
- off_t offset;
- size_t numbytes;
- };
-GLOBAL struct sp_array *sparsearray;
-
-/* Number of elements in sparsearray. */
-GLOBAL int sp_array_size;
-
-/* Declarations for each module. */
-
-/* FIXME: compare.c should not directly handle the following variable,
- instead, this should be done in buffer.c only. */
-
-enum access_mode
-{
- ACCESS_READ,
- ACCESS_WRITE,
- ACCESS_UPDATE
-};
-extern enum access_mode access_mode;
-
-/* Module buffer.c. */
-
-extern FILE *stdlis;
-extern char *save_name;
-extern off_t save_sizeleft;
-extern off_t save_totsize;
-extern bool write_archive_to_stdout;
-
-size_t available_space_after PARAMS ((union block *));
-off_t current_block_ordinal PARAMS ((void));
-void close_archive PARAMS ((void));
-void closeout_volume_number PARAMS ((void));
-union block *find_next_block PARAMS ((void));
-void flush_read PARAMS ((void));
-void flush_write PARAMS ((void));
-void flush_archive PARAMS ((void));
-void init_volume_number PARAMS ((void));
-void open_archive PARAMS ((enum access_mode));
-void print_total_written PARAMS ((void));
-void reset_eof PARAMS ((void));
-void set_next_block_after PARAMS ((union block *));
-
-/* Module create.c. */
-
-void create_archive PARAMS ((void));
-void dump_file PARAMS ((char *, int, dev_t));
-void finish_header PARAMS ((union block *));
-void write_eot PARAMS ((void));
-
-#define GID_TO_CHARS(val, where) gid_to_chars (val, where, sizeof (where))
-#define MAJOR_TO_CHARS(val, where) major_to_chars (val, where, sizeof (where))
-#define MINOR_TO_CHARS(val, where) minor_to_chars (val, where, sizeof (where))
-#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where))
-#define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where))
-#define SIZE_TO_CHARS(val, where) size_to_chars (val, where, sizeof (where))
-#define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where))
-#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where))
-#define UINTMAX_TO_CHARS(val, where) uintmax_to_chars (val, where, sizeof (where))
-
-void gid_to_chars PARAMS ((gid_t, char *, size_t));
-void major_to_chars PARAMS ((major_t, char *, size_t));
-void minor_to_chars PARAMS ((minor_t, char *, size_t));
-void mode_to_chars PARAMS ((mode_t, char *, size_t));
-void off_to_chars PARAMS ((off_t, char *, size_t));
-void size_to_chars PARAMS ((size_t, char *, size_t));
-void time_to_chars PARAMS ((time_t, char *, size_t));
-void uid_to_chars PARAMS ((uid_t, char *, size_t));
-void uintmax_to_chars PARAMS ((uintmax_t, char *, size_t));
-
-/* Module diffarch.c. */
-
-extern int now_verifying;
-
-void diff_archive PARAMS ((void));
-void diff_init PARAMS ((void));
-void verify_volume PARAMS ((void));
-
-/* Module extract.c. */
-
-extern int we_are_root;
-void extr_init PARAMS ((void));
-void extract_archive PARAMS ((void));
-void extract_finish PARAMS ((void));
-void fatal_exit PARAMS ((void)) __attribute__ ((noreturn));
-
-/* Module delete.c. */
-
-void delete_archive_members PARAMS ((void));
-
-/* Module incremen.c. */
-
-char *get_directory_contents PARAMS ((char *, dev_t));
-void read_directory_file PARAMS ((void));
-void write_directory_file PARAMS ((void));
-void gnu_restore PARAMS ((size_t));
-
-/* Module list.c. */
-
-enum read_header
-{
- HEADER_STILL_UNREAD, /* for when read_header has not been called */
- HEADER_SUCCESS, /* header successfully read and checksummed */
- HEADER_SUCCESS_EXTENDED, /* likewise, but we got an extended header */
- HEADER_ZERO_BLOCK, /* zero block where header expected */
- HEADER_END_OF_FILE, /* true end of file while header expected */
- HEADER_FAILURE /* ill-formed header, or bad checksum */
-};
-
-extern union block *current_header;
-extern struct stat current_stat;
-extern enum archive_format current_format;
-
-void decode_header PARAMS ((union block *, struct stat *,
- enum archive_format *, int));
-#define STRINGIFY_BIGINT(i, b) \
- stringify_uintmax_t_backwards ((uintmax_t) (i), (b) + UINTMAX_STRSIZE_BOUND)
-char *stringify_uintmax_t_backwards PARAMS ((uintmax_t, char *));
-char const *tartime PARAMS ((time_t));
-
-#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
-#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
-#define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where))
-#define MODE_FROM_HEADER(where) mode_from_header (where, sizeof (where))
-#define OFF_FROM_HEADER(where) off_from_header (where, sizeof (where))
-#define SIZE_FROM_HEADER(where) size_from_header (where, sizeof (where))
-#define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where))
-#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
-#define UINTMAX_FROM_HEADER(where) uintmax_from_header (where, sizeof (where))
-
-gid_t gid_from_header PARAMS ((const char *, size_t));
-major_t major_from_header PARAMS ((const char *, size_t));
-minor_t minor_from_header PARAMS ((const char *, size_t));
-mode_t mode_from_header PARAMS ((const char *, size_t));
-off_t off_from_header PARAMS ((const char *, size_t));
-size_t size_from_header PARAMS ((const char *, size_t));
-time_t time_from_header PARAMS ((const char *, size_t));
-uid_t uid_from_header PARAMS ((const char *, size_t));
-uintmax_t uintmax_from_header PARAMS ((const char *, size_t));
-
-void list_archive PARAMS ((void));
-void print_for_mkdir PARAMS ((char *, int, mode_t));
-void print_header PARAMS ((void));
-void read_and PARAMS ((void (*do_) ()));
-enum read_header read_header PARAMS ((bool));
-void skip_file PARAMS ((off_t));
-void skip_member PARAMS ((void));
-
-/* Module mangle.c. */
-
-void extract_mangle PARAMS ((void));
-
-/* Module misc.c. */
-
-void assign_string PARAMS ((char **, const char *));
-char *quote_copy_string PARAMS ((const char *));
-int unquote_string PARAMS ((char *));
-
-int contains_dot_dot PARAMS ((char const *));
-
-int remove_any_file PARAMS ((const char *, int));
-int maybe_backup_file PARAMS ((const char *, int));
-void undo_last_backup PARAMS ((void));
-
-int deref_stat PARAMS ((int, char const *, struct stat *));
-
-int chdir_arg PARAMS ((char const *));
-void chdir_do PARAMS ((int));
-
-void decode_mode PARAMS ((mode_t, char *));
-
-void chdir_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
-void chmod_error_details PARAMS ((char const *, mode_t));
-void chown_error_details PARAMS ((char const *, uid_t, gid_t));
-void close_error PARAMS ((char const *));
-void close_warn PARAMS ((char const *));
-void exec_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
-void link_error PARAMS ((char const *, char const *));
-void mkdir_error PARAMS ((char const *));
-void mkfifo_error PARAMS ((char const *));
-void mknod_error PARAMS ((char const *));
-void open_error PARAMS ((char const *));
-void open_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
-void open_warn PARAMS ((char const *));
-void read_error PARAMS ((char const *));
-void read_error_details PARAMS ((char const *, off_t, size_t));
-void read_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
-void read_fatal_details PARAMS ((char const *, off_t, size_t));
-void read_warn_details PARAMS ((char const *, off_t, size_t));
-void readlink_error PARAMS ((char const *));
-void readlink_warn PARAMS ((char const *));
-void savedir_error PARAMS ((char const *));
-void savedir_warn PARAMS ((char const *));
-void seek_error PARAMS ((char const *));
-void seek_error_details PARAMS ((char const *, off_t));
-void seek_warn PARAMS ((char const *));
-void seek_warn_details PARAMS ((char const *, off_t));
-void stat_error PARAMS ((char const *));
-void stat_warn PARAMS ((char const *));
-void symlink_error PARAMS ((char const *, char const *));
-void truncate_error PARAMS ((char const *));
-void truncate_warn PARAMS ((char const *));
-void unlink_error PARAMS ((char const *));
-void utime_error PARAMS ((char const *));
-void waitpid_error PARAMS ((char const *));
-void write_error PARAMS ((char const *));
-void write_error_details PARAMS ((char const *, ssize_t, size_t));
-void write_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
-void write_fatal_details PARAMS ((char const *, ssize_t, size_t))
- __attribute__ ((noreturn));
-
-pid_t xfork PARAMS ((void));
-void xpipe PARAMS ((int[2]));
-
-char const *quote PARAMS ((char const *));
-char const *quote_n PARAMS ((int, char const *));
-
-/* Module names.c. */
-
-extern struct name *gnu_list_name;
-
-void gid_to_gname PARAMS ((gid_t, char gname[GNAME_FIELD_SIZE]));
-int gname_to_gid PARAMS ((char gname[GNAME_FIELD_SIZE], gid_t *));
-void uid_to_uname PARAMS ((uid_t, char uname[UNAME_FIELD_SIZE]));
-int uname_to_uid PARAMS ((char uname[UNAME_FIELD_SIZE], uid_t *));
-
-void init_names PARAMS ((void));
-void name_add PARAMS ((const char *));
-void name_init PARAMS ((int, char *const *));
-void name_term PARAMS ((void));
-char *name_next PARAMS ((int));
-void name_close PARAMS ((void));
-void name_gather PARAMS ((void));
-struct name *addname PARAMS ((char const *, int));
-int name_match PARAMS ((const char *));
-void names_notfound PARAMS ((void));
-void collect_and_sort_names PARAMS ((void));
-struct name *name_scan PARAMS ((const char *));
-char *name_from_list PARAMS ((void));
-void blank_name_list PARAMS ((void));
-char *new_name PARAMS ((const char *, const char *));
-
-bool excluded_name PARAMS ((char const *));
-
-void add_avoided_name PARAMS ((char const *));
-int is_avoided_name PARAMS ((char const *));
-
-/* Module tar.c. */
-
-int confirm PARAMS ((const char *, const char *));
-void request_stdin PARAMS ((const char *));
-
-/* Module update.c. */
-
-extern char *output_start;
-
-void update_archive PARAMS ((void));
diff --git a/contrib/tar/src/compare.c b/contrib/tar/src/compare.c
deleted file mode 100644
index da9dc33..0000000
--- a/contrib/tar/src/compare.c
+++ /dev/null
@@ -1,823 +0,0 @@
-/* Diff files from a tar archive.
-
- Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
- Software Foundation, Inc.
-
- Written by John Gilmore, on 1987-04-30.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* $FreeBSD$ */
-
-#include "system.h"
-
-#if HAVE_UTIME_H
-# include <utime.h>
-#else
-struct utimbuf
- {
- long actime;
- long modtime;
- };
-#endif
-
-#if HAVE_LINUX_FD_H
-# include <linux/fd.h>
-#endif
-
-#include <quotearg.h>
-
-#include "common.h"
-#include "rmt.h"
-
-/* Spare space for messages, hopefully safe even after gettext. */
-#define MESSAGE_BUFFER_SIZE 100
-
-/* Nonzero if we are verifying at the moment. */
-int now_verifying;
-
-/* File descriptor for the file we are diffing. */
-static int diff_handle;
-
-/* Area for reading file contents into. */
-static char *diff_buffer;
-
-/* Initialize for a diff operation. */
-void
-diff_init (void)
-{
- diff_buffer = valloc (record_size);
- if (!diff_buffer)
- xalloc_die ();
-}
-
-/* Sigh about something that differs by writing a MESSAGE to stdlis,
- given MESSAGE is nonzero. Also set the exit status if not already. */
-static void
-report_difference (const char *message)
-{
- if (message)
- fprintf (stdlis, "%s: %s\n", quotearg_colon (current_file_name), message);
-
- if (exit_status == TAREXIT_SUCCESS)
- exit_status = TAREXIT_DIFFERS;
-}
-
-/* Take a buffer returned by read_and_process and do nothing with it. */
-static int
-process_noop (size_t size, char *data)
-{
- /* Yes, I know. SIZE and DATA are unused in this function. Some
- compilers may even report it. That's OK, just relax! */
- return 1;
-}
-
-static int
-process_rawdata (size_t bytes, char *buffer)
-{
- ssize_t status = safe_read (diff_handle, diff_buffer, bytes);
- char message[MESSAGE_BUFFER_SIZE];
-
- if (status != bytes)
- {
- if (status < 0)
- {
- read_error (current_file_name);
- report_difference (0);
- }
- else
- {
- sprintf (message, _("Could only read %lu of %lu bytes"),
- (unsigned long) status, (unsigned long) bytes);
- report_difference (message);
- }
- return 0;
- }
-
- if (memcmp (buffer, diff_buffer, bytes))
- {
- report_difference (_("Contents differ"));
- return 0;
- }
-
- return 1;
-}
-
-/* Directory contents, only for GNUTYPE_DUMPDIR. */
-
-static char *dumpdir_cursor;
-
-static int
-process_dumpdir (size_t bytes, char *buffer)
-{
- if (memcmp (buffer, dumpdir_cursor, bytes))
- {
- report_difference (_("Contents differ"));
- return 0;
- }
-
- dumpdir_cursor += bytes;
- return 1;
-}
-
-/* Some other routine wants SIZE bytes in the archive. For each chunk
- of the archive, call PROCESSOR with the size of the chunk, and the
- address of the chunk it can work with. The PROCESSOR should return
- nonzero for success. It it return error once, continue skipping
- without calling PROCESSOR anymore. */
-static void
-read_and_process (off_t size, int (*processor) (size_t, char *))
-{
- union block *data_block;
- size_t data_size;
-
- if (multi_volume_option)
- save_sizeleft = size;
- while (size)
- {
- data_block = find_next_block ();
- if (! data_block)
- {
- ERROR ((0, 0, _("Unexpected EOF in archive")));
- return;
- }
-
- data_size = available_space_after (data_block);
- if (data_size > size)
- data_size = size;
- if (!(*processor) (data_size, data_block->buffer))
- processor = process_noop;
- set_next_block_after ((union block *)
- (data_block->buffer + data_size - 1));
- size -= data_size;
- if (multi_volume_option)
- save_sizeleft -= data_size;
- }
-}
-
-/* JK This routine should be used more often than it is ... look into
- that. Anyhow, what it does is translate the sparse information on the
- header, and in any subsequent extended headers, into an array of
- structures with true numbers, as opposed to character strings. It
- simply makes our life much easier, doing so many comparisons and such.
- */
-static void
-fill_in_sparse_array (void)
-{
- int counter;
-
- /* Allocate space for our scratch space; it's initially 10 elements
- long, but can change in this routine if necessary. */
-
- sp_array_size = 10;
- sparsearray = xmalloc (sp_array_size * sizeof (struct sp_array));
-
- /* There are at most five of these structures in the header itself;
- read these in first. */
-
- for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
- {
- /* Compare to 0, or use !(int)..., for Pyramid's dumb compiler. */
- if (current_header->oldgnu_header.sp[counter].numbytes == 0)
- break;
-
- sparsearray[counter].offset =
- OFF_FROM_HEADER (current_header->oldgnu_header.sp[counter].offset);
- sparsearray[counter].numbytes =
- SIZE_FROM_HEADER (current_header->oldgnu_header.sp[counter].numbytes);
- }
-
- /* If the header's extended, we gotta read in exhdr's till we're done. */
-
- if (current_header->oldgnu_header.isextended)
- {
- /* How far into the sparsearray we are `so far'. */
- static int so_far_ind = SPARSES_IN_OLDGNU_HEADER;
- union block *exhdr;
-
- while (1)
- {
- exhdr = find_next_block ();
- if (!exhdr)
- FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
-
- for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
- {
- if (counter + so_far_ind > sp_array_size - 1)
- {
- /* We just ran out of room in our scratch area -
- realloc it. */
-
- sp_array_size *= 2;
- sparsearray =
- xrealloc (sparsearray,
- sp_array_size * sizeof (struct sp_array));
- }
-
- /* Convert the character strings into offsets and sizes. */
-
- sparsearray[counter + so_far_ind].offset =
- OFF_FROM_HEADER (exhdr->sparse_header.sp[counter].offset);
- sparsearray[counter + so_far_ind].numbytes =
- SIZE_FROM_HEADER (exhdr->sparse_header.sp[counter].numbytes);
- }
-
- /* If this is the last extended header for this file, we can
- stop. */
-
- if (!exhdr->sparse_header.isextended)
- break;
-
- so_far_ind += SPARSES_IN_SPARSE_HEADER;
- set_next_block_after (exhdr);
- }
-
- /* Be sure to skip past the last one. */
-
- set_next_block_after (exhdr);
- }
-}
-
-/* JK Diff'ing a sparse file with its counterpart on the tar file is a
- bit of a different story than a normal file. First, we must know what
- areas of the file to skip through, i.e., we need to construct a
- sparsearray, which will hold all the information we need. We must
- compare small amounts of data at a time as we find it. */
-
-/* FIXME: This does not look very solid to me, at first glance. Zero areas
- are not checked, spurious sparse entries seemingly goes undetected, and
- I'm not sure overall identical sparsity is verified. */
-
-static void
-diff_sparse_files (off_t size_of_file)
-{
- off_t remaining_size = size_of_file;
- char *buffer = xmalloc (BLOCKSIZE * sizeof (char));
- size_t buffer_size = BLOCKSIZE;
- union block *data_block = 0;
- int counter = 0;
- int different = 0;
-
- fill_in_sparse_array ();
-
- while (remaining_size > 0)
- {
- ssize_t status;
- size_t chunk_size;
- off_t offset;
-
-#if 0
- off_t amount_read = 0;
-#endif
-
- data_block = find_next_block ();
- if (!data_block)
- FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
- chunk_size = sparsearray[counter].numbytes;
- if (!chunk_size)
- break;
-
- offset = sparsearray[counter].offset;
- if (lseek (diff_handle, offset, SEEK_SET) < 0)
- {
- seek_error_details (current_file_name, offset);
- report_difference (0);
- }
-
- /* Take care to not run out of room in our buffer. */
-
- while (buffer_size < chunk_size)
- {
- if (buffer_size * 2 < buffer_size)
- xalloc_die ();
- buffer_size *= 2;
- buffer = xrealloc (buffer, buffer_size * sizeof (char));
- }
-
- while (chunk_size > BLOCKSIZE)
- {
- if (status = safe_read (diff_handle, buffer, BLOCKSIZE),
- status != BLOCKSIZE)
- {
- if (status < 0)
- {
- read_error (current_file_name);
- report_difference (0);
- }
- else
- {
- char message[MESSAGE_BUFFER_SIZE];
-
- sprintf (message, _("Could only read %lu of %lu bytes"),
- (unsigned long) status, (unsigned long) chunk_size);
- report_difference (message);
- }
- break;
- }
-
- if (memcmp (buffer, data_block->buffer, BLOCKSIZE))
- {
- different = 1;
- break;
- }
-
- chunk_size -= status;
- remaining_size -= status;
- set_next_block_after (data_block);
- data_block = find_next_block ();
- if (!data_block)
- FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
- }
- if (status = safe_read (diff_handle, buffer, chunk_size),
- status != chunk_size)
- {
- if (status < 0)
- {
- read_error (current_file_name);
- report_difference (0);
- }
- else
- {
- char message[MESSAGE_BUFFER_SIZE];
-
- sprintf (message, _("Could only read %lu of %lu bytes"),
- (unsigned long) status, (unsigned long) chunk_size);
- report_difference (message);
- }
- break;
- }
-
- if (memcmp (buffer, data_block->buffer, chunk_size))
- {
- different = 1;
- break;
- }
-#if 0
- amount_read += chunk_size;
- if (amount_read >= BLOCKSIZE)
- {
- amount_read = 0;
- set_next_block_after (data_block);
- data_block = find_next_block ();
- if (!data_block)
- FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
- }
-#endif
- set_next_block_after (data_block);
- counter++;
- remaining_size -= chunk_size;
- }
-
-#if 0
- /* If the number of bytes read isn't the number of bytes supposedly in
- the file, they're different. */
-
- if (amount_read != size_of_file)
- different = 1;
-#endif
-
- set_next_block_after (data_block);
- free (sparsearray);
-
- if (different)
- report_difference (_("Contents differ"));
-}
-
-/* Call either stat or lstat over STAT_DATA, depending on
- --dereference (-h), for a file which should exist. Diagnose any
- problem. Return nonzero for success, zero otherwise. */
-static int
-get_stat_data (char const *file_name, struct stat *stat_data)
-{
- int status = deref_stat (dereference_option, file_name, stat_data);
-
- if (status != 0)
- {
- if (errno == ENOENT)
- {
- report_difference (_("does not exist"));
- }
- else
- {
- stat_error (file_name);
- report_difference (0);
- }
- return 0;
- }
-
- return 1;
-}
-
-/* Diff a file against the archive. */
-void
-diff_archive (void)
-{
- struct stat stat_data;
- size_t name_length;
- int status;
- struct utimbuf restore_times;
-
- set_next_block_after (current_header);
- decode_header (current_header, &current_stat, &current_format, 1);
-
- /* Print the block from current_header and current_stat. */
-
- if (verbose_option)
- {
- if (now_verifying)
- fprintf (stdlis, _("Verify "));
- print_header ();
- }
-
- switch (current_header->header.typeflag)
- {
- default:
- ERROR ((0, 0, _("%s: Unknown file type '%c', diffed as normal file"),
- quotearg_colon (current_file_name),
- current_header->header.typeflag));
- /* Fall through. */
-
- case AREGTYPE:
- case REGTYPE:
- case GNUTYPE_SPARSE:
- case CONTTYPE:
-
- /* Appears to be a file. See if it's really a directory. */
-
- name_length = strlen (current_file_name) - 1;
- if (ISSLASH (current_file_name[name_length]))
- goto really_dir;
-
- if (!get_stat_data (current_file_name, &stat_data))
- {
- skip_member ();
- goto quit;
- }
-
- if (!S_ISREG (stat_data.st_mode))
- {
- report_difference (_("File type differs"));
- skip_member ();
- goto quit;
- }
-
- if ((current_stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
- report_difference (_("Mode differs"));
-
-#if !MSDOS
- /* stat() in djgpp's C library gives a constant number of 42 as the
- uid and gid of a file. So, comparing an FTP'ed archive just after
- unpack would fail on MSDOS. */
- if (stat_data.st_uid != current_stat.st_uid)
- report_difference (_("Uid differs"));
- if (stat_data.st_gid != current_stat.st_gid)
- report_difference (_("Gid differs"));
-#endif
-
- if (stat_data.st_mtime != current_stat.st_mtime)
- report_difference (_("Mod time differs"));
- if (current_header->header.typeflag != GNUTYPE_SPARSE &&
- stat_data.st_size != current_stat.st_size)
- {
- report_difference (_("Size differs"));
- skip_member ();
- goto quit;
- }
-
- diff_handle = open (current_file_name, O_RDONLY | O_BINARY);
-
- if (diff_handle < 0)
- {
- open_error (current_file_name);
- skip_member ();
- report_difference (0);
- goto quit;
- }
-
- restore_times.actime = stat_data.st_atime;
- restore_times.modtime = stat_data.st_mtime;
-
- /* Need to treat sparse files completely differently here. */
-
- if (current_header->header.typeflag == GNUTYPE_SPARSE)
- diff_sparse_files (current_stat.st_size);
- else
- {
- if (multi_volume_option)
- {
- assign_string (&save_name, current_file_name);
- save_totsize = current_stat.st_size;
- /* save_sizeleft is set in read_and_process. */
- }
-
- read_and_process (current_stat.st_size, process_rawdata);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
- }
-
- status = close (diff_handle);
- if (status != 0)
- close_error (current_file_name);
-
- if (atime_preserve_option)
- utime (current_file_name, &restore_times);
-
- quit:
- break;
-
-#if !MSDOS
- case LNKTYPE:
- {
- struct stat link_data;
-
- if (!get_stat_data (current_file_name, &stat_data))
- break;
- if (!get_stat_data (current_link_name, &link_data))
- break;
-
- if (stat_data.st_dev != link_data.st_dev
- || stat_data.st_ino != link_data.st_ino)
- {
- char *message =
- xmalloc (MESSAGE_BUFFER_SIZE + 4 * strlen (current_link_name));
-
- sprintf (message, _("Not linked to %s"),
- quote (current_link_name));
- report_difference (message);
- free (message);
- break;
- }
-
- break;
- }
-#endif /* not MSDOS */
-
-#ifdef HAVE_READLINK
- case SYMTYPE:
- {
- size_t len = strlen (current_link_name);
- char *linkbuf = alloca (len + 1);
-
- status = readlink (current_file_name, linkbuf, len);
-
- if (status < 0)
- {
- if (errno == ENOENT)
- readlink_warn (current_file_name);
- else
- readlink_error (current_file_name);
- report_difference (0);
- }
- else if (status != len
- || strncmp (current_link_name, linkbuf, len) != 0)
- report_difference (_("Symlink differs"));
-
- break;
- }
-#endif
-
- case CHRTYPE:
- case BLKTYPE:
- case FIFOTYPE:
-
- /* FIXME: deal with umask. */
-
- if (!get_stat_data (current_file_name, &stat_data))
- break;
-
- if (current_header->header.typeflag == CHRTYPE
- ? !S_ISCHR (stat_data.st_mode)
- : current_header->header.typeflag == BLKTYPE
- ? !S_ISBLK (stat_data.st_mode)
- : /* current_header->header.typeflag == FIFOTYPE */
- !S_ISFIFO (stat_data.st_mode))
- {
- report_difference (_("File type differs"));
- break;
- }
-
- if ((current_header->header.typeflag == CHRTYPE
- || current_header->header.typeflag == BLKTYPE)
- && current_stat.st_rdev != stat_data.st_rdev)
- {
- report_difference (_("Device number differs"));
- break;
- }
-
- if ((current_stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
- {
- report_difference (_("Mode differs"));
- break;
- }
-
- break;
-
- case GNUTYPE_DUMPDIR:
- {
- char *dumpdir_buffer = get_directory_contents (current_file_name, 0);
-
- if (multi_volume_option)
- {
- assign_string (&save_name, current_file_name);
- save_totsize = current_stat.st_size;
- /* save_sizeleft is set in read_and_process. */
- }
-
- if (dumpdir_buffer)
- {
- dumpdir_cursor = dumpdir_buffer;
- read_and_process (current_stat.st_size, process_dumpdir);
- free (dumpdir_buffer);
- }
- else
- read_and_process (current_stat.st_size, process_noop);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
- /* Fall through. */
- }
-
- case DIRTYPE:
- /* Check for trailing /. */
-
- name_length = strlen (current_file_name) - 1;
-
- really_dir:
- while (name_length && ISSLASH (current_file_name[name_length]))
- current_file_name[name_length--] = '\0'; /* zap / */
-
- if (!get_stat_data (current_file_name, &stat_data))
- break;
-
- if (!S_ISDIR (stat_data.st_mode))
- {
- report_difference (_("File type differs"));
- break;
- }
-
- if ((current_stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
- {
- report_difference (_("Mode differs"));
- break;
- }
-
- break;
-
- case GNUTYPE_VOLHDR:
- break;
-
- case GNUTYPE_MULTIVOL:
- {
- off_t offset;
-
- name_length = strlen (current_file_name) - 1;
- if (ISSLASH (current_file_name[name_length]))
- goto really_dir;
-
- if (!get_stat_data (current_file_name, &stat_data))
- break;
-
- if (!S_ISREG (stat_data.st_mode))
- {
- report_difference (_("File type differs"));
- skip_member ();
- break;
- }
-
- offset = OFF_FROM_HEADER (current_header->oldgnu_header.offset);
- if (stat_data.st_size != current_stat.st_size + offset)
- {
- report_difference (_("Size differs"));
- skip_member ();
- break;
- }
-
- diff_handle = open (current_file_name, O_RDONLY | O_BINARY);
-
- if (diff_handle < 0)
- {
- open_error (current_file_name);
- report_difference (0);
- skip_member ();
- break;
- }
-
- if (lseek (diff_handle, offset, SEEK_SET) < 0)
- {
- seek_error_details (current_file_name, offset);
- report_difference (0);
- break;
- }
-
- if (multi_volume_option)
- {
- assign_string (&save_name, current_file_name);
- save_totsize = stat_data.st_size;
- /* save_sizeleft is set in read_and_process. */
- }
-
- read_and_process (current_stat.st_size, process_rawdata);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
-
- status = close (diff_handle);
- if (status != 0)
- close_error (current_file_name);
-
- break;
- }
- }
-}
-
-void
-verify_volume (void)
-{
- if (!diff_buffer)
- diff_init ();
-
- /* Verifying an archive is meant to check if the physical media got it
- correctly, so try to defeat clever in-memory buffering pertaining to
- this particular media. On Linux, for example, the floppy drive would
- not even be accessed for the whole verification.
-
- The code was using fsync only when the ioctl is unavailable, but
- Marty Leisner says that the ioctl does not work when not preceded by
- fsync. So, until we know better, or maybe to please Marty, let's do it
- the unbelievable way :-). */
-
-#if HAVE_FSYNC
- fsync (archive);
-#endif
-#ifdef FDFLUSH
- ioctl (archive, FDFLUSH);
-#endif
-
-#ifdef MTIOCTOP
- {
- struct mtop operation;
- int status;
-
- operation.mt_op = MTBSF;
- operation.mt_count = 1;
- if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation), status < 0)
- {
- if (errno != EIO
- || (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
- status < 0))
- {
-#endif
- if (rmtlseek (archive, (off_t) 0, SEEK_SET) != 0)
- {
- /* Lseek failed. Try a different method. */
- seek_warn (archive_name_array[0]);
- return;
- }
-#ifdef MTIOCTOP
- }
- }
- }
-#endif
-
- access_mode = ACCESS_READ;
- now_verifying = 1;
-
- flush_read ();
- while (1)
- {
- enum read_header status = read_header (0);
-
- if (status == HEADER_FAILURE)
- {
- int counter = 0;
-
- while (status == HEADER_FAILURE);
- {
- counter++;
- status = read_header (0);
- }
- ERROR ((0, 0,
- _("VERIFY FAILURE: %d invalid header(s) detected"), counter));
- }
- if (status == HEADER_ZERO_BLOCK || status == HEADER_END_OF_FILE)
- break;
-
- diff_archive ();
- }
-
- access_mode = ACCESS_WRITE;
- now_verifying = 0;
-}
diff --git a/contrib/tar/src/create.c b/contrib/tar/src/create.c
deleted file mode 100644
index e1f2dda..0000000
--- a/contrib/tar/src/create.c
+++ /dev/null
@@ -1,1552 +0,0 @@
-/* Create a tar archive.
- Copyright 1985,92,93,94,96,97,99,2000, 2001 Free Software Foundation, Inc.
- Written by John Gilmore, on 1985-08-25.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* $FreeBSD$ */
-
-#include "system.h"
-
-#if !MSDOS
-# include <pwd.h>
-# include <grp.h>
-#endif
-
-#if HAVE_UTIME_H
-# include <utime.h>
-#else
-struct utimbuf
- {
- long actime;
- long modtime;
- };
-#endif
-
-#include <quotearg.h>
-
-#include "common.h"
-#include <hash.h>
-
-#ifndef MSDOS
-extern dev_t ar_dev;
-extern ino_t ar_ino;
-#endif
-
-struct link
- {
- dev_t dev;
- ino_t ino;
- char name[1];
- };
-
-/* The maximum uintmax_t value that can be represented with DIGITS digits,
- assuming that each digit is BITS_PER_DIGIT wide. */
-#define MAX_VAL_WITH_DIGITS(digits, bits_per_digit) \
- ((digits) * (bits_per_digit) < sizeof (uintmax_t) * CHAR_BIT \
- ? ((uintmax_t) 1 << ((digits) * (bits_per_digit))) - 1 \
- : (uintmax_t) -1)
-
-/* Convert VALUE to an octal representation suitable for tar headers.
- Output to buffer WHERE with size SIZE.
- The result is undefined if SIZE is 0 or if VALUE is too large to fit. */
-
-static void
-to_octal (uintmax_t value, char *where, size_t size)
-{
- uintmax_t v = value;
- size_t i = size;
-
- do
- {
- where[--i] = '0' + (v & ((1 << LG_8) - 1));
- v >>= LG_8;
- }
- while (i);
-}
-
-/* Convert NEGATIVE VALUE to a base-256 representation suitable for
- tar headers. NEGATIVE is 1 if VALUE was negative before being cast
- to uintmax_t, 0 otherwise. Output to buffer WHERE with size SIZE.
- The result is undefined if SIZE is 0 or if VALUE is too large to
- fit. */
-
-static void
-to_base256 (int negative, uintmax_t value, char *where, size_t size)
-{
- uintmax_t v = value;
- uintmax_t propagated_sign_bits =
- ((uintmax_t) - negative << (CHAR_BIT * sizeof v - LG_256));
- size_t i = size;
-
- do
- {
- where[--i] = v & ((1 << LG_256) - 1);
- v = propagated_sign_bits | (v >> LG_256);
- }
- while (i);
-}
-
-/* Convert NEGATIVE VALUE (which was originally of size VALSIZE) to
- external form, using SUBSTITUTE (...) if VALUE won't fit. Output
- to buffer WHERE with size SIZE. NEGATIVE is 1 iff VALUE was
- negative before being cast to uintmax_t; its original bitpattern
- can be deduced from VALSIZE, its original size before casting.
- TYPE is the kind of value being output (useful for diagnostics).
- Prefer the POSIX format of SIZE - 1 octal digits (with leading zero
- digits), followed by '\0'. If this won't work, and if GNU or
- OLDGNU format is allowed, use '\200' followed by base-256, or (if
- NEGATIVE is nonzero) '\377' followed by two's complement base-256.
- If neither format works, use SUBSTITUTE (...) instead. Pass to
- SUBSTITUTE the address of an 0-or-1 flag recording whether the
- substitute value is negative. */
-
-static void
-to_chars (int negative, uintmax_t value, size_t valsize,
- uintmax_t (*substitute) PARAMS ((int *)),
- char *where, size_t size, const char *type)
-{
- int base256_allowed = (archive_format == GNU_FORMAT
- || archive_format == OLDGNU_FORMAT);
-
- /* Generate the POSIX octal representation if the number fits. */
- if (! negative && value <= MAX_VAL_WITH_DIGITS (size - 1, LG_8))
- {
- where[size - 1] = '\0';
- to_octal (value, where, size - 1);
- }
-
- /* Otherwise, generate the base-256 representation if we are
- generating an old or new GNU format and if the number fits. */
- else if (((negative ? -1 - value : value)
- <= MAX_VAL_WITH_DIGITS (size - 1, LG_256))
- && base256_allowed)
- {
- where[0] = negative ? -1 : 1 << (LG_256 - 1);
- to_base256 (negative, value, where + 1, size - 1);
- }
-
- /* Otherwise, if the number is negative, and if it would not cause
- ambiguity on this host by confusing positive with negative
- values, then generate the POSIX octal representation of the value
- modulo 2**(field bits). The resulting tar file is
- machine-dependent, since it depends on the host word size. Yuck!
- But this is the traditional behavior. */
- else if (negative && valsize * CHAR_BIT <= (size - 1) * LG_8)
- {
- static int warned_once;
- if (! warned_once)
- {
- warned_once = 1;
- WARN ((0, 0, _("Generating negative octal headers")));
- }
- where[size - 1] = '\0';
- to_octal (value & MAX_VAL_WITH_DIGITS (valsize * CHAR_BIT, 1),
- where, size - 1);
- }
-
- /* Otherwise, output a substitute value if possible (with a
- warning), and an error message if not. */
- else
- {
- uintmax_t maxval = (base256_allowed
- ? MAX_VAL_WITH_DIGITS (size - 1, LG_256)
- : MAX_VAL_WITH_DIGITS (size - 1, LG_8));
- char valbuf[UINTMAX_STRSIZE_BOUND + 1];
- char maxbuf[UINTMAX_STRSIZE_BOUND];
- char minbuf[UINTMAX_STRSIZE_BOUND + 1];
- char const *minval_string;
- char const *maxval_string = STRINGIFY_BIGINT (maxval, maxbuf);
- char const *value_string;
-
- if (base256_allowed)
- {
- uintmax_t m = maxval + 1 ? maxval + 1 : maxval / 2 + 1;
- char *p = STRINGIFY_BIGINT (m, minbuf + 1);
- *--p = '-';
- minval_string = p;
- }
- else
- minval_string = "0";
-
- if (negative)
- {
- char *p = STRINGIFY_BIGINT (- value, valbuf + 1);
- *--p = '-';
- value_string = p;
- }
- else
- value_string = STRINGIFY_BIGINT (value, valbuf);
-
- if (substitute)
- {
- int negsub;
- uintmax_t sub = substitute (&negsub) & maxval;
- uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? - sub : sub;
- char subbuf[UINTMAX_STRSIZE_BOUND + 1];
- char *sub_string = STRINGIFY_BIGINT (s, subbuf + 1);
- if (negsub)
- *--sub_string = '-';
- WARN ((0, 0, _("value %s out of %s range %s..%s; substituting %s"),
- value_string, type, minval_string, maxval_string,
- sub_string));
- to_chars (negsub, s, valsize, 0, where, size, type);
- }
- else
- ERROR ((0, 0, _("value %s out of %s range %s..%s"),
- value_string, type, minval_string, maxval_string));
- }
-}
-
-static uintmax_t
-gid_substitute (int *negative)
-{
- gid_t r;
-#ifdef GID_NOBODY
- r = GID_NOBODY;
-#else
- static gid_t gid_nobody;
- if (!gid_nobody && !gname_to_gid ("nobody", &gid_nobody))
- gid_nobody = -2;
- r = gid_nobody;
-#endif
- *negative = r < 0;
- return r;
-}
-
-void
-gid_to_chars (gid_t v, char *p, size_t s)
-{
- to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t");
-}
-
-void
-major_to_chars (major_t v, char *p, size_t s)
-{
- to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "major_t");
-}
-
-void
-minor_to_chars (minor_t v, char *p, size_t s)
-{
- to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "minor_t");
-}
-
-void
-mode_to_chars (mode_t v, char *p, size_t s)
-{
- /* In the common case where the internal and external mode bits are the same,
- and we are not using POSIX or GNU format,
- propagate all unknown bits to the external mode.
- This matches historical practice.
- Otherwise, just copy the bits we know about. */
- int negative;
- uintmax_t u;
- if (S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX
- && S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC
- && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC
- && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
- && archive_format != POSIX_FORMAT
- && archive_format != GNU_FORMAT)
- {
- negative = v < 0;
- u = v;
- }
- else
- {
- negative = 0;
- u = ((v & S_ISUID ? TSUID : 0)
- | (v & S_ISGID ? TSGID : 0)
- | (v & S_ISVTX ? TSVTX : 0)
- | (v & S_IRUSR ? TUREAD : 0)
- | (v & S_IWUSR ? TUWRITE : 0)
- | (v & S_IXUSR ? TUEXEC : 0)
- | (v & S_IRGRP ? TGREAD : 0)
- | (v & S_IWGRP ? TGWRITE : 0)
- | (v & S_IXGRP ? TGEXEC : 0)
- | (v & S_IROTH ? TOREAD : 0)
- | (v & S_IWOTH ? TOWRITE : 0)
- | (v & S_IXOTH ? TOEXEC : 0));
- }
- to_chars (negative, u, sizeof v, 0, p, s, "mode_t");
-}
-
-void
-off_to_chars (off_t v, char *p, size_t s)
-{
- to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "off_t");
-}
-
-void
-size_to_chars (size_t v, char *p, size_t s)
-{
- to_chars (0, (uintmax_t) v, sizeof v, 0, p, s, "size_t");
-}
-
-void
-time_to_chars (time_t v, char *p, size_t s)
-{
- to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "time_t");
-}
-
-static uintmax_t
-uid_substitute (int *negative)
-{
- uid_t r;
-#ifdef UID_NOBODY
- r = UID_NOBODY;
-#else
- static uid_t uid_nobody;
- if (!uid_nobody && !uname_to_uid ("nobody", &uid_nobody))
- uid_nobody = -2;
- r = uid_nobody;
-#endif
- *negative = r < 0;
- return r;
-}
-
-void
-uid_to_chars (uid_t v, char *p, size_t s)
-{
- to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
-}
-
-void
-uintmax_to_chars (uintmax_t v, char *p, size_t s)
-{
- to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
-}
-
-/* Writing routines. */
-
-/* Zero out the buffer so we don't confuse ourselves with leftover
- data. */
-static void
-clear_buffer (char *buffer)
-{
- memset (buffer, 0, BLOCKSIZE);
-}
-
-/* Write the EOT block(s). Zero at least two blocks, through the end
- of the record. Old tar, as previous versions of GNU tar, writes
- garbage after two zeroed blocks. */
-void
-write_eot (void)
-{
- union block *pointer = find_next_block ();
- memset (pointer->buffer, 0, BLOCKSIZE);
- set_next_block_after (pointer);
- pointer = find_next_block ();
- memset (pointer->buffer, 0, available_space_after (pointer));
- set_next_block_after (pointer);
-}
-
-/* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */
-
-/* FIXME: Cross recursion between start_header and write_long! */
-
-static union block *start_header PARAMS ((const char *, struct stat *));
-
-static void
-write_long (const char *p, char type)
-{
- size_t size = strlen (p) + 1;
- size_t bufsize;
- union block *header;
- struct stat foo;
-
- memset (&foo, 0, sizeof foo);
- foo.st_size = size;
-
- header = start_header ("././@LongLink", &foo);
- header->header.typeflag = type;
- finish_header (header);
-
- header = find_next_block ();
-
- bufsize = available_space_after (header);
-
- while (bufsize < size)
- {
- memcpy (header->buffer, p, bufsize);
- p += bufsize;
- size -= bufsize;
- set_next_block_after (header + (bufsize - 1) / BLOCKSIZE);
- header = find_next_block ();
- bufsize = available_space_after (header);
- }
- memcpy (header->buffer, p, size);
- memset (header->buffer + size, 0, bufsize - size);
- set_next_block_after (header + (size - 1) / BLOCKSIZE);
-}
-
-/* Return a suffix of the file NAME that is a relative file name.
- Warn about `..' in file names. But return NAME if the user wants
- absolute file names. */
-static char const *
-relativize (char const *name)
-{
- if (! absolute_names_option)
- {
- {
- static int warned_once;
- if (! warned_once && contains_dot_dot (name))
- {
- warned_once = 1;
- WARN ((0, 0, _("Member names contain `..'")));
- }
- }
-
- {
- size_t prefix_len = FILESYSTEM_PREFIX_LEN (name);
-
- while (ISSLASH (name[prefix_len]))
- prefix_len++;
-
- if (prefix_len)
- {
- static int warned_once;
- if (!warned_once)
- {
- warned_once = 1;
- WARN ((0, 0, _("Removing leading `%.*s' from member names"),
- (int) prefix_len, name));
- }
- name += prefix_len;
- }
- }
- }
-
- return name;
-}
-
-/* Header handling. */
-
-/* Make a header block for the file whose stat info is st,
- and return its address. */
-
-static union block *
-start_header (const char *name, struct stat *st)
-{
- union block *header;
-
- name = relativize (name);
-
- if (sizeof header->header.name <= strlen (name))
- write_long (name, GNUTYPE_LONGNAME);
- header = find_next_block ();
- memset (header->buffer, 0, sizeof (union block));
-
- assign_string (&current_file_name, name);
-
- strncpy (header->header.name, name, NAME_FIELD_SIZE);
- header->header.name[NAME_FIELD_SIZE - 1] = '\0';
-
- /* Override some stat fields, if requested to do so. */
-
- if (owner_option != (uid_t) -1)
- st->st_uid = owner_option;
- if (group_option != (gid_t) -1)
- st->st_gid = group_option;
- if (mode_option)
- st->st_mode = ((st->st_mode & ~MODE_ALL)
- | mode_adjust (st->st_mode, mode_option));
-
- /* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a)
- for a few tars and came up with the following interoperability
- matrix:
-
- WRITER
- 1 2 3 4 5 6 7 8 9 READER
- . . . . . . . . . 1 = SunOS 4.2 tar
- # . . # # . . # # 2 = NEC SVR4.0.2 tar
- . . . # # . . # . 3 = Solaris 2.1 tar
- . . . . . . . . . 4 = GNU tar 1.11.1
- . . . . . . . . . 5 = HP-UX 8.07 tar
- . . . . . . . . . 6 = Ultrix 4.1
- . . . . . . . . . 7 = AIX 3.2
- . . . . . . . . . 8 = Hitachi HI-UX 1.03
- . . . . . . . . . 9 = Omron UNIOS-B 4.3BSD 1.60Beta
-
- . = works
- # = ``impossible file type''
-
- The following mask for old archive removes the `#'s in column 4
- above, thus making GNU tar both a universal donor and a universal
- acceptor for Paul's test. */
-
- if (archive_format == V7_FORMAT)
- MODE_TO_CHARS (st->st_mode & MODE_ALL, header->header.mode);
- else
- MODE_TO_CHARS (st->st_mode, header->header.mode);
-
- UID_TO_CHARS (st->st_uid, header->header.uid);
- GID_TO_CHARS (st->st_gid, header->header.gid);
- OFF_TO_CHARS (st->st_size, header->header.size);
- TIME_TO_CHARS (st->st_mtime, header->header.mtime);
-
- if (incremental_option)
- if (archive_format == OLDGNU_FORMAT)
- {
- TIME_TO_CHARS (st->st_atime, header->oldgnu_header.atime);
- TIME_TO_CHARS (st->st_ctime, header->oldgnu_header.ctime);
- }
-
- header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
-
- switch (archive_format)
- {
- case V7_FORMAT:
- break;
-
- case OLDGNU_FORMAT:
- /* Overwrite header->header.magic and header.version in one blow. */
- strcpy (header->header.magic, OLDGNU_MAGIC);
- break;
-
- case POSIX_FORMAT:
- case GNU_FORMAT:
- strncpy (header->header.magic, TMAGIC, TMAGLEN);
- strncpy (header->header.version, TVERSION, TVERSLEN);
- break;
-
- default:
- abort ();
- }
-
- if (archive_format == V7_FORMAT || numeric_owner_option)
- {
- /* header->header.[ug]name are left as the empty string. */
- }
- else
- {
- uid_to_uname (st->st_uid, header->header.uname);
- gid_to_gname (st->st_gid, header->header.gname);
- }
-
- return header;
-}
-
-/* Finish off a filled-in header block and write it out. We also
- print the file name and/or full info if verbose is on. */
-void
-finish_header (union block *header)
-{
- size_t i;
- int sum;
- char *p;
-
- memcpy (header->header.chksum, CHKBLANKS, sizeof header->header.chksum);
-
- sum = 0;
- p = header->buffer;
- for (i = sizeof *header; i-- != 0; )
- /* We can't use unsigned char here because of old compilers, e.g. V7. */
- sum += 0xFF & *p++;
-
- /* Fill in the checksum field. It's formatted differently from the
- other fields: it has [6] digits, a null, then a space -- rather than
- digits, then a null. We use to_chars.
- The final space is already there, from
- checksumming, and to_chars doesn't modify it.
-
- This is a fast way to do:
-
- sprintf(header->header.chksum, "%6o", sum); */
-
- uintmax_to_chars ((uintmax_t) sum, header->header.chksum, 7);
-
- if (verbose_option
- && header->header.typeflag != GNUTYPE_LONGLINK
- && header->header.typeflag != GNUTYPE_LONGNAME)
- {
- /* These globals are parameters to print_header, sigh. */
-
- current_header = header;
- /* current_stat is already set up. */
- current_format = archive_format;
- print_header ();
- }
-
- set_next_block_after (header);
-}
-
-/* Sparse file processing. */
-
-/* Takes a blockful of data and basically cruises through it to see if
- it's made *entirely* of zeros, returning a 0 the instant it finds
- something that is a nonzero, i.e., useful data. */
-static int
-zero_block_p (char *buffer)
-{
- int counter;
-
- for (counter = 0; counter < BLOCKSIZE; counter++)
- if (buffer[counter] != '\0')
- return 0;
- return 1;
-}
-
-static void
-init_sparsearray (void)
-{
- sp_array_size = 10;
-
- /* Make room for our scratch space -- initially is 10 elts long. */
-
- sparsearray = xmalloc (sp_array_size * sizeof (struct sp_array));
-}
-
-static off_t
-find_new_file_size (int sparses)
-{
- int i;
- off_t s = 0;
- for (i = 0; i < sparses; i++)
- s += sparsearray[i].numbytes;
- return s;
-}
-
-/* Make one pass over the file NAME, studying where any non-zero data
- is, that is, how far into the file each instance of data is, and
- how many bytes are there. Save this information in the
- sparsearray, which will later be translated into header
- information. */
-
-/* There is little point in trimming small amounts of null data at the head
- and tail of blocks, only avoid dumping full null blocks. */
-
-/* FIXME: this routine might accept bits of algorithmic cleanup, it is
- too kludgey for my taste... */
-
-static int
-deal_with_sparse (char *name, union block *header)
-{
- size_t numbytes = 0;
- off_t offset = 0;
- int file;
- int sparses = 0;
- ssize_t count;
- char buffer[BLOCKSIZE];
-
- if (archive_format == OLDGNU_FORMAT)
- header->oldgnu_header.isextended = 0;
-
- if (file = open (name, O_RDONLY), file < 0)
- /* This problem will be caught later on, so just return. */
- return 0;
-
- init_sparsearray ();
- clear_buffer (buffer);
-
- for (;;)
- {
- /* Realloc the scratch area as necessary. FIXME: should reallocate
- only at beginning of a new instance of non-zero data. */
-
- if (sp_array_size <= sparses)
- {
- sparsearray =
- xrealloc (sparsearray,
- 2 * sp_array_size * sizeof (struct sp_array));
- sp_array_size *= 2;
- }
-
- count = safe_read (file, buffer, sizeof buffer);
- if (count <= 0)
- break;
-
- /* Process one block. */
-
- if (count == sizeof buffer)
-
- if (zero_block_p (buffer))
- {
- if (numbytes)
- {
- sparsearray[sparses++].numbytes = numbytes;
- numbytes = 0;
- }
- }
- else
- {
- if (!numbytes)
- sparsearray[sparses].offset = offset;
- numbytes += count;
- }
-
- else
-
- /* Since count < sizeof buffer, we have the last bit of the file. */
-
- if (!zero_block_p (buffer))
- {
- if (!numbytes)
- sparsearray[sparses].offset = offset;
- numbytes += count;
- }
- else
- /* The next two lines are suggested by Andreas Degert, who says
- they are required for trailing full blocks to be written to the
- archive, when all zeroed. Yet, it seems to me that the case
- does not apply. Further, at restore time, the file is not as
- sparse as it should. So, some serious cleanup is *also* needed
- in this area. Just one more... :-(. FIXME. */
- if (numbytes)
- numbytes += count;
-
- /* Prepare for next block. */
-
- offset += count;
- /* FIXME: do not clear unless necessary. */
- clear_buffer (buffer);
- }
-
- if (numbytes)
- sparsearray[sparses++].numbytes = numbytes;
- else
- {
- sparsearray[sparses].offset = offset - 1;
- sparsearray[sparses++].numbytes = 1;
- }
-
- return close (file) == 0 && 0 <= count ? sparses : 0;
-}
-
-static int
-finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
-{
- union block *start;
- size_t bufsize;
- int sparses = 0;
- ssize_t count;
-
- while (*sizeleft > 0)
- {
- start = find_next_block ();
- memset (start->buffer, 0, BLOCKSIZE);
- bufsize = sparsearray[sparses].numbytes;
- if (! bufsize)
- abort ();
-
- if (lseek (file, sparsearray[sparses++].offset, SEEK_SET) < 0)
- {
- (ignore_failed_read_option ? seek_warn_details : seek_error_details)
- (name, sparsearray[sparses - 1].offset);
- break;
- }
-
- /* If the number of bytes to be written here exceeds the size of
- the temporary buffer, do it in steps. */
-
- while (bufsize > BLOCKSIZE)
- {
- count = safe_read (file, start->buffer, BLOCKSIZE);
- if (count < 0)
- {
- (ignore_failed_read_option
- ? read_warn_details
- : read_error_details)
- (name, fullsize - *sizeleft, bufsize);
- return 1;
- }
- bufsize -= count;
- *sizeleft -= count;
- set_next_block_after (start);
- start = find_next_block ();
- memset (start->buffer, 0, BLOCKSIZE);
- }
-
- {
- char buffer[BLOCKSIZE];
-
- clear_buffer (buffer);
- count = safe_read (file, buffer, bufsize);
- memcpy (start->buffer, buffer, BLOCKSIZE);
- }
-
- if (count < 0)
- {
- (ignore_failed_read_option
- ? read_warn_details
- : read_error_details)
- (name, fullsize - *sizeleft, bufsize);
- return 1;
- }
-
- *sizeleft -= count;
- set_next_block_after (start);
- }
- free (sparsearray);
-#if 0
- set_next_block_after (start + (count - 1) / BLOCKSIZE);
-#endif
- return 0;
-}
-
-/* Main functions of this module. */
-
-void
-create_archive (void)
-{
- char *p;
-
- open_archive (ACCESS_WRITE);
-
- if (incremental_option)
- {
- size_t buffer_size = 1000;
- char *buffer = xmalloc (buffer_size);
- const char *q;
-
- collect_and_sort_names ();
-
- while (p = name_from_list (), p)
- if (!excluded_name (p))
- dump_file (p, -1, (dev_t) 0);
-
- blank_name_list ();
- while (p = name_from_list (), p)
- if (!excluded_name (p))
- {
- size_t plen = strlen (p);
- if (buffer_size <= plen)
- {
- while ((buffer_size *= 2) <= plen)
- continue;
- buffer = xrealloc (buffer, buffer_size);
- }
- memcpy (buffer, p, plen);
- if (! ISSLASH (buffer[plen - 1]))
- buffer[plen++] = '/';
- q = gnu_list_name->dir_contents;
- if (q)
- while (*q)
- {
- size_t qlen = strlen (q);
- if (*q == 'Y')
- {
- if (buffer_size < plen + qlen)
- {
- while ((buffer_size *=2 ) < plen + qlen)
- continue;
- buffer = xrealloc (buffer, buffer_size);
- }
- strcpy (buffer + plen, q + 1);
- dump_file (buffer, -1, (dev_t) 0);
- }
- q += qlen + 1;
- }
- }
- free (buffer);
- }
- else
- {
- while (p = name_next (1), p)
- if (!excluded_name (p))
- dump_file (p, 1, (dev_t) 0);
- }
-
- write_eot ();
- close_archive ();
-
- if (listed_incremental_option)
- write_directory_file ();
-}
-
-
-/* Calculate the hash of a link. */
-static unsigned
-hash_link (void const *entry, unsigned n_buckets)
-{
- struct link const *link = entry;
- return (uintmax_t) (link->dev ^ link->ino) % n_buckets;
-}
-
-/* Compare two links for equality. */
-static bool
-compare_links (void const *entry1, void const *entry2)
-{
- struct link const *link1 = entry1;
- struct link const *link2 = entry2;
- return ((link1->dev ^ link2->dev) | (link1->ino ^ link2->ino)) == 0;
-}
-
-/* Dump a single file, recursing on directories. P is the file name
- to dump. TOP_LEVEL tells whether this is a top-level call; zero
- means no, positive means yes, and negative means an incremental
- dump. PARENT_DEVICE is the device of P's
- parent directory; it is examined only if TOP_LEVEL is zero.
-
- Set global CURRENT_STAT to stat output for this file. */
-
-/* FIXME: One should make sure that for *every* path leading to setting
- exit_status to failure, a clear diagnostic has been issued. */
-
-void
-dump_file (char *p, int top_level, dev_t parent_device)
-{
- union block *header;
- char type;
- union block *exhdr;
- char save_typeflag;
- time_t original_ctime;
- struct utimbuf restore_times;
-
- /* FIXME: `header' might be used uninitialized in this
- function. Reported by Bruno Haible. */
-
- if (interactive_option && !confirm ("add", p))
- return;
-
- if (deref_stat (dereference_option, p, &current_stat) != 0)
- {
- if (ignore_failed_read_option)
- stat_warn (p);
- else
- stat_error (p);
- return;
- }
-
- original_ctime = current_stat.st_ctime;
- restore_times.actime = current_stat.st_atime;
- restore_times.modtime = current_stat.st_mtime;
-
-#ifdef S_ISHIDDEN
- if (S_ISHIDDEN (current_stat.st_mode))
- {
- char *new = (char *) alloca (strlen (p) + 2);
- if (new)
- {
- strcpy (new, p);
- strcat (new, "@");
- p = new;
- }
- }
-#endif
-
- /* See if we want only new files, and check if this one is too old to
- put in the archive. */
-
- if ((0 < top_level || !incremental_option)
- && !S_ISDIR (current_stat.st_mode)
- && current_stat.st_mtime < newer_mtime_option
- && (!after_date_option || current_stat.st_ctime < newer_ctime_option))
- {
- if (0 < top_level)
- WARN ((0, 0, _("%s: file is unchanged; not dumped"),
- quotearg_colon (p)));
- /* FIXME: recheck this return. */
- return;
- }
-
-#if !MSDOS
- /* See if we are trying to dump the archive. */
-
- if (ar_dev && current_stat.st_dev == ar_dev && current_stat.st_ino == ar_ino)
- {
- WARN ((0, 0, _("%s: file is the archive; not dumped"),
- quotearg_colon (p)));
- return;
- }
-#endif
-
- if (S_ISDIR (current_stat.st_mode))
- {
- char *directory;
- char const *entry;
- size_t entrylen;
- char *namebuf;
- size_t buflen;
- size_t len;
- dev_t our_device = current_stat.st_dev;
-
- errno = 0;
-
- directory = savedir (p);
- if (! directory)
- {
- if (ignore_failed_read_option)
- savedir_warn (p);
- else
- savedir_error (p);
- return;
- }
-
- /* Build new prototype name. Ensure exactly one trailing slash. */
-
- len = strlen (p);
- buflen = len + NAME_FIELD_SIZE;
- namebuf = xmalloc (buflen + 1);
- memcpy (namebuf, p, len);
- while (len >= 1 && ISSLASH (namebuf[len - 1]))
- len--;
- namebuf[len++] = '/';
- namebuf[len] = '\0';
-
- if (! is_avoided_name (namebuf))
- {
- /* The condition above used to be "archive_format != V7_FORMAT".
- GNU tar was not writing directory blocks at all. Daniel Trinkle
- writes: ``All old versions of tar I have ever seen have
- correctly archived an empty directory. The really old ones I
- checked included HP-UX 7 and Mt. Xinu More/BSD. There may be
- some subtle reason for the exclusion that I don't know, but the
- current behavior is broken.'' I do not know those subtle
- reasons either, so until these are reported (anew?), just allow
- directory blocks to be written even with old archives. */
-
- current_stat.st_size = 0; /* force 0 size on dir */
-
- /* FIXME: If people could really read standard archives, this
- should be:
-
- header
- = start_header (standard_option ? p : namebuf, &current_stat);
-
- but since they'd interpret DIRTYPE blocks as regular
- files, we'd better put the / on the name. */
-
- header = start_header (namebuf, &current_stat);
-
- if (incremental_option)
- header->header.typeflag = GNUTYPE_DUMPDIR;
- else /* if (standard_option) */
- header->header.typeflag = DIRTYPE;
-
- /* If we're gnudumping, we aren't done yet so don't close it. */
-
- if (!incremental_option)
- finish_header (header); /* done with directory header */
- }
-
- if (incremental_option && gnu_list_name->dir_contents)
- {
- off_t sizeleft;
- off_t totsize;
- size_t bufsize;
- union block *start;
- ssize_t count;
- const char *buffer, *p_buffer;
-
- buffer = gnu_list_name->dir_contents; /* FOO */
- totsize = 0;
- for (p_buffer = buffer; p_buffer && *p_buffer;)
- {
- size_t tmp;
-
- tmp = strlen (p_buffer) + 1;
- totsize += tmp;
- p_buffer += tmp;
- }
- totsize++;
- OFF_TO_CHARS (totsize, header->header.size);
- finish_header (header);
- p_buffer = buffer;
- sizeleft = totsize;
- while (sizeleft > 0)
- {
- if (multi_volume_option)
- {
- assign_string (&save_name, p);
- save_sizeleft = sizeleft;
- save_totsize = totsize;
- }
- start = find_next_block ();
- bufsize = available_space_after (start);
- if (sizeleft < bufsize)
- {
- bufsize = sizeleft;
- count = bufsize % BLOCKSIZE;
- if (count)
- memset (start->buffer + sizeleft, 0, BLOCKSIZE - count);
- }
- memcpy (start->buffer, p_buffer, bufsize);
- sizeleft -= bufsize;
- p_buffer += bufsize;
- set_next_block_after (start + (bufsize - 1) / BLOCKSIZE);
- }
- if (multi_volume_option)
- assign_string (&save_name, 0);
- goto finish_dir;
- }
-
- /* See if we are about to recurse into a directory, and avoid doing
- so if the user wants that we do not descend into directories. */
-
- if (! recursion_option)
- goto finish_dir;
-
- /* See if we are crossing from one file system to another, and
- avoid doing so if the user only wants to dump one file system. */
-
- if (one_file_system_option && !top_level
- && parent_device != current_stat.st_dev)
- {
- if (verbose_option)
- WARN ((0, 0,
- _("%s: file is on a different filesystem; not dumped"),
- quotearg_colon (p)));
- goto finish_dir;
- }
-
- /* Now output all the files in the directory. */
-
- /* FIXME: Should speed this up by cd-ing into the dir. */
-
- for (entry = directory;
- (entrylen = strlen (entry)) != 0;
- entry += entrylen + 1)
- {
- if (buflen <= len + entrylen)
- {
- buflen = len + entrylen;
- namebuf = xrealloc (namebuf, buflen + 1);
- }
- strcpy (namebuf + len, entry);
- if (!excluded_name (namebuf))
- dump_file (namebuf, 0, our_device);
- }
-
- finish_dir:
-
- free (directory);
- free (namebuf);
- if (atime_preserve_option)
- utime (p, &restore_times);
- return;
- }
- else if (is_avoided_name (p))
- return;
- else
- {
- /* Check for multiple links.
-
- We maintain a table of all such files that we've written so
- far. Any time we see another, we check the table and avoid
- dumping the data again if we've done it once already. */
-
- if (1 < current_stat.st_nlink)
- {
- static Hash_table *link_table;
- struct link *lp = xmalloc (offsetof (struct link, name)
- + strlen (p) + 1);
- struct link *dup;
- lp->ino = current_stat.st_ino;
- lp->dev = current_stat.st_dev;
- strcpy (lp->name, p);
-
- if (! ((link_table
- || (link_table = hash_initialize (0, 0, hash_link,
- compare_links, 0)))
- && (dup = hash_insert (link_table, lp))))
- xalloc_die ();
-
- if (dup != lp)
- {
- /* We found a link. */
- char const *link_name = relativize (dup->name);
-
- free (lp);
-
- if (NAME_FIELD_SIZE <= strlen (link_name))
- write_long (link_name, GNUTYPE_LONGLINK);
- assign_string (&current_link_name, link_name);
-
- current_stat.st_size = 0;
- header = start_header (p, &current_stat);
- strncpy (header->header.linkname, link_name, NAME_FIELD_SIZE);
-
- /* Force null termination. */
- header->header.linkname[NAME_FIELD_SIZE - 1] = 0;
-
- header->header.typeflag = LNKTYPE;
- finish_header (header);
-
- /* FIXME: Maybe remove from table after all links found? */
-
- if (remove_files_option && unlink (p) != 0)
- unlink_error (p);
-
- /* We dumped it. */
- return;
- }
- }
-
- /* This is not a link to a previously dumped file, so dump it. */
-
- if (S_ISREG (current_stat.st_mode)
- || S_ISCTG (current_stat.st_mode))
- {
- int f; /* file descriptor */
- size_t bufsize;
- ssize_t count;
- off_t sizeleft;
- union block *start;
- int header_moved;
- char isextended = 0;
- int sparses = 0;
-
- header_moved = 0;
-
- if (sparse_option)
- {
- /* Check the size of the file against the number of blocks
- allocated for it, counting both data and indirect blocks.
- If there is a smaller number of blocks that would be
- necessary to accommodate a file of this size, this is safe
- to say that we have a sparse file: at least one of those
- blocks in the file is just a useless hole. For sparse
- files not having more hole blocks than indirect blocks, the
- sparseness will go undetected. */
-
- /* Bruno Haible sent me these statistics for Linux. It seems
- that some filesystems count indirect blocks in st_blocks,
- while others do not seem to:
-
- minix-fs tar: size=7205, st_blocks=18 and ST_NBLOCKS=18
- extfs tar: size=7205, st_blocks=18 and ST_NBLOCKS=18
- ext2fs tar: size=7205, st_blocks=16 and ST_NBLOCKS=16
- msdos-fs tar: size=7205, st_blocks=16 and ST_NBLOCKS=16
-
- Dick Streefland reports the previous numbers as misleading,
- because ext2fs use 12 direct blocks, while minix-fs uses only
- 6 direct blocks. Dick gets:
-
- ext2 size=20480 ls listed blocks=21
- minix size=20480 ls listed blocks=21
- msdos size=20480 ls listed blocks=20
-
- It seems that indirect blocks *are* included in st_blocks.
- The minix filesystem does not account for phantom blocks in
- st_blocks, so `du' and `ls -s' give wrong results. So, the
- --sparse option would not work on a minix filesystem. */
-
- if (ST_NBLOCKS (current_stat)
- < (current_stat.st_size / ST_NBLOCKSIZE
- + (current_stat.st_size % ST_NBLOCKSIZE != 0)))
- {
- int counter;
-
- header = start_header (p, &current_stat);
- header->header.typeflag = GNUTYPE_SPARSE;
- header_moved = 1;
-
- /* Call the routine that figures out the layout of the
- sparse file in question. SPARSES is the index of the
- first unused element of the "sparsearray," i.e.,
- the number of elements it needed to describe the file. */
-
- sparses = deal_with_sparse (p, header);
-
- /* See if we'll need an extended header later. */
-
- if (SPARSES_IN_OLDGNU_HEADER < sparses)
- header->oldgnu_header.isextended = 1;
-
- /* We store the "real" file size so we can show that in
- case someone wants to list the archive, i.e., tar tvf
- <file>. It might be kind of disconcerting if the
- shrunken file size was the one that showed up. */
-
- OFF_TO_CHARS (current_stat.st_size,
- header->oldgnu_header.realsize);
-
- /* This will be the new "size" of the file, i.e., the size
- of the file minus the blocks of holes that we're
- skipping over. */
-
- current_stat.st_size = find_new_file_size (sparses);
- OFF_TO_CHARS (current_stat.st_size, header->header.size);
-
- for (counter = 0;
- counter < sparses && counter < SPARSES_IN_OLDGNU_HEADER;
- counter++)
- {
- OFF_TO_CHARS (sparsearray[counter].offset,
- header->oldgnu_header.sp[counter].offset);
- SIZE_TO_CHARS (sparsearray[counter].numbytes,
- header->oldgnu_header.sp[counter].numbytes);
- }
- }
- }
-
- sizeleft = current_stat.st_size;
-
- /* Don't bother opening empty, world readable files. Also do not open
- files when archive is meant for /dev/null. */
-
- if (dev_null_output
- || (sizeleft == 0
- && MODE_R == (MODE_R & current_stat.st_mode)))
- f = -1;
- else
- {
- f = open (p, O_RDONLY | O_BINARY);
- if (f < 0)
- {
- if (! top_level && errno == ENOENT)
- WARN ((0, 0, _("%s: File removed before we read it"),
- quotearg_colon (p)));
- else
- (ignore_failed_read_option ? open_warn : open_error) (p);
- return;
- }
- }
-
- /* If the file is sparse, we've already taken care of this. */
-
- if (!header_moved)
- header = start_header (p, &current_stat);
-
- /* Mark contiguous files, if we support them. */
-
- if (archive_format != V7_FORMAT && S_ISCTG (current_stat.st_mode))
- header->header.typeflag = CONTTYPE;
-
- isextended = header->oldgnu_header.isextended;
- save_typeflag = header->header.typeflag;
- finish_header (header);
- if (isextended)
- {
- int sparses_emitted = SPARSES_IN_OLDGNU_HEADER;
-
- for (;;)
- {
- int i;
- exhdr = find_next_block ();
- memset (exhdr->buffer, 0, BLOCKSIZE);
- for (i = 0;
- (i < SPARSES_IN_SPARSE_HEADER
- && sparses_emitted + i < sparses);
- i++)
- {
- SIZE_TO_CHARS (sparsearray[sparses_emitted + i].numbytes,
- exhdr->sparse_header.sp[i].numbytes);
- OFF_TO_CHARS (sparsearray[sparses_emitted + i].offset,
- exhdr->sparse_header.sp[i].offset);
- }
- set_next_block_after (exhdr);
- sparses_emitted += i;
- if (sparses == sparses_emitted)
- break;
- exhdr->sparse_header.isextended = 1;
- }
- }
- if (save_typeflag == GNUTYPE_SPARSE)
- {
- if (f < 0
- || finish_sparse_file (f, &sizeleft,
- current_stat.st_size, p))
- goto padit;
- }
- else
- while (sizeleft > 0)
- {
- if (multi_volume_option)
- {
- assign_string (&save_name, p);
- save_sizeleft = sizeleft;
- save_totsize = current_stat.st_size;
- }
- start = find_next_block ();
-
- bufsize = available_space_after (start);
-
- if (sizeleft < bufsize)
- {
- /* Last read -- zero out area beyond. */
-
- bufsize = sizeleft;
- count = bufsize % BLOCKSIZE;
- if (count)
- memset (start->buffer + sizeleft, 0, BLOCKSIZE - count);
- }
- if (f < 0)
- count = bufsize;
- else
- count = safe_read (f, start->buffer, bufsize);
- if (count < 0)
- {
- (ignore_failed_read_option
- ? read_warn_details
- : read_error_details)
- (p, current_stat.st_size - sizeleft, bufsize);
- goto padit;
- }
- sizeleft -= bufsize;
-
- /* This is nonportable (the type of set_next_block_after's arg). */
-
- set_next_block_after (start + (bufsize - 1) / BLOCKSIZE);
-
-
- if (count != bufsize)
- {
- char buf[UINTMAX_STRSIZE_BOUND];
- memset (start->buffer + count, 0, bufsize - count);
- WARN ((0, 0,
- _("%s: File shrank by %s bytes; padding with zeros"),
- quotearg_colon (p),
- STRINGIFY_BIGINT (sizeleft, buf)));
- if (! ignore_failed_read_option)
- exit_status = TAREXIT_FAILURE;
- goto padit; /* short read */
- }
- }
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
-
- if (f >= 0)
- {
- struct stat final_stat;
- if (fstat (f, &final_stat) != 0)
- {
- if (ignore_failed_read_option)
- stat_warn (p);
- else
- stat_error (p);
- }
- else if (final_stat.st_ctime != original_ctime)
- {
- char const *qp = quotearg_colon (p);
- WARN ((0, 0, _("%s: file changed as we read it"), qp));
- if (! ignore_failed_read_option)
- exit_status = TAREXIT_FAILURE;
- }
- if (close (f) != 0)
- {
- if (ignore_failed_read_option)
- close_warn (p);
- else
- close_error (p);
- }
- if (atime_preserve_option)
- utime (p, &restore_times);
- }
- if (remove_files_option)
- {
- if (unlink (p) == -1)
- unlink_error (p);
- }
- return;
-
- /* File shrunk or gave error, pad out tape to match the size we
- specified in the header. */
-
- padit:
- while (sizeleft > 0)
- {
- save_sizeleft = sizeleft;
- start = find_next_block ();
- memset (start->buffer, 0, BLOCKSIZE);
- set_next_block_after (start);
- sizeleft -= BLOCKSIZE;
- }
- if (multi_volume_option)
- assign_string (&save_name, 0);
- if (f >= 0)
- {
- close (f);
- if (atime_preserve_option)
- utime (p, &restore_times);
- }
- return;
- }
-#ifdef HAVE_READLINK
- else if (S_ISLNK (current_stat.st_mode))
- {
- char *buffer;
- int size;
- size_t linklen = current_stat.st_size;
- if (linklen != current_stat.st_size || linklen + 1 == 0)
- xalloc_die ();
- buffer = (char *) alloca (linklen + 1);
- size = readlink (p, buffer, linklen);
- if (size < 0)
- {
- if (ignore_failed_read_option)
- readlink_warn (p);
- else
- readlink_error (p);
- return;
- }
- buffer[size] = '\0';
- if (size >= NAME_FIELD_SIZE)
- write_long (buffer, GNUTYPE_LONGLINK);
- assign_string (&current_link_name, buffer);
-
- current_stat.st_size = 0; /* force 0 size on symlink */
- header = start_header (p, &current_stat);
- strncpy (header->header.linkname, buffer, NAME_FIELD_SIZE);
- header->header.linkname[NAME_FIELD_SIZE - 1] = '\0';
- header->header.typeflag = SYMTYPE;
- finish_header (header); /* nothing more to do to it */
- if (remove_files_option)
- {
- if (unlink (p) == -1)
- unlink_error (p);
- }
- return;
- }
-#endif
- else if (S_ISCHR (current_stat.st_mode))
- type = CHRTYPE;
- else if (S_ISBLK (current_stat.st_mode))
- type = BLKTYPE;
- else if (S_ISFIFO (current_stat.st_mode))
- type = FIFOTYPE;
- else if (S_ISSOCK (current_stat.st_mode))
- {
- WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
- return;
- }
- else if (S_ISDOOR (current_stat.st_mode))
- {
- WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
- return;
- }
- else
- goto unknown;
- }
-
- if (archive_format == V7_FORMAT)
- goto unknown;
-
- current_stat.st_size = 0; /* force 0 size */
- header = start_header (p, &current_stat);
- header->header.typeflag = type;
-
- if (type != FIFOTYPE)
- {
- MAJOR_TO_CHARS (major (current_stat.st_rdev), header->header.devmajor);
- MINOR_TO_CHARS (minor (current_stat.st_rdev), header->header.devminor);
- }
-
- finish_header (header);
- if (remove_files_option)
- {
- if (unlink (p) == -1)
- unlink_error (p);
- }
- return;
-
-unknown:
- WARN ((0, 0, _("%s: Unknown file type; file ignored"),
- quotearg_colon (p)));
- if (! ignore_failed_read_option)
- exit_status = TAREXIT_FAILURE;
-}
diff --git a/contrib/tar/src/delete.c b/contrib/tar/src/delete.c
deleted file mode 100644
index ad7b590..0000000
--- a/contrib/tar/src/delete.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/* Delete entries from a tar archive.
-
- Copyright (C) 1988, 1992, 1994, 1996, 1997, 2000, 2001 Free
- Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "system.h"
-
-#include "common.h"
-#include "rmt.h"
-
-static union block *new_record;
-static int new_blocks;
-static bool acting_as_filter;
-
-/* FIXME: This module should not directly handle the following
- variables, instead, the interface should be cleaned up. */
-extern union block *record_start;
-extern union block *record_end;
-extern union block *current_block;
-extern union block *recent_long_name;
-extern union block *recent_long_link;
-extern size_t recent_long_name_blocks;
-extern size_t recent_long_link_blocks;
-extern off_t records_read;
-extern off_t records_written;
-
-/* The number of records skipped at the start of the archive, when
- passing over members that are not deleted. */
-static off_t records_skipped;
-
-/* Move archive descriptor by COUNT records worth. If COUNT is
- positive we move forward, else we move negative. If it's a tape,
- MTIOCTOP had better work. If it's something else, we try to seek
- on it. If we can't seek, we lose! */
-static void
-move_archive (off_t count)
-{
- if (count == 0)
- return;
-
-#ifdef MTIOCTOP
- {
- struct mtop operation;
-
- if (count < 0
- ? (operation.mt_op = MTBSR,
- operation.mt_count = -count,
- operation.mt_count == -count)
- : (operation.mt_op = MTFSR,
- operation.mt_count = count,
- operation.mt_count == count))
- {
- if (0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
- return;
-
- if (errno == EIO
- && 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
- return;
- }
- }
-#endif /* MTIOCTOP */
-
- {
- off_t position0 = rmtlseek (archive, (off_t) 0, SEEK_CUR);
- off_t increment = record_size * (off_t) count;
- off_t position = position0 + increment;
-
- if (increment / count != record_size
- || (position < position0) != (increment < 0)
- || (position = position < 0 ? 0 : position,
- rmtlseek (archive, position, SEEK_SET) != position))
- seek_error_details (archive_name_array[0], position);
-
- return;
- }
-}
-
-/* Write out the record which has been filled. If MOVE_BACK_FLAG,
- backspace to where we started. */
-static void
-write_record (int move_back_flag)
-{
- union block *save_record = record_start;
- record_start = new_record;
-
- if (acting_as_filter)
- {
- archive = STDOUT_FILENO;
- flush_write ();
- archive = STDIN_FILENO;
- }
- else
- {
- move_archive ((records_written + records_skipped) - records_read);
- flush_write ();
- }
-
- record_start = save_record;
-
- if (move_back_flag)
- {
- /* Move the tape head back to where we were. */
-
- if (! acting_as_filter)
- move_archive (records_read - (records_written + records_skipped));
- }
-
- new_blocks = 0;
-}
-
-static void
-write_recent_blocks (union block *h, size_t blocks)
-{
- size_t i;
- for (i = 0; i < blocks; i++)
- {
- new_record[new_blocks++] = h[i];
- if (new_blocks == blocking_factor)
- write_record (1);
- }
-}
-
-void
-delete_archive_members (void)
-{
- enum read_header logical_status = HEADER_STILL_UNREAD;
- enum read_header previous_status = HEADER_STILL_UNREAD;
-
- /* FIXME: Should clean the routine before cleaning these variables :-( */
- struct name *name;
- off_t blocks_to_skip = 0;
- off_t blocks_to_keep = 0;
- int kept_blocks_in_record;
-
- name_gather ();
- open_archive (ACCESS_UPDATE);
- acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
-
- do
- {
- enum read_header status = read_header (1);
-
- switch (status)
- {
- case HEADER_STILL_UNREAD:
- abort ();
-
- case HEADER_SUCCESS:
- if (name = name_scan (current_file_name), !name)
- {
- skip_member ();
- break;
- }
- name->found = 1;
- /* Fall through. */
- case HEADER_SUCCESS_EXTENDED:
- logical_status = status;
- break;
-
- case HEADER_ZERO_BLOCK:
- if (ignore_zeros_option)
- {
- set_next_block_after (current_header);
- break;
- }
- /* Fall through. */
- case HEADER_END_OF_FILE:
- logical_status = HEADER_END_OF_FILE;
- break;
-
- case HEADER_FAILURE:
- set_next_block_after (current_header);
- switch (previous_status)
- {
- case HEADER_STILL_UNREAD:
- WARN ((0, 0, _("This does not look like a tar archive")));
- /* Fall through. */
-
- case HEADER_SUCCESS:
- case HEADER_ZERO_BLOCK:
- ERROR ((0, 0, _("Skipping to next header")));
- /* Fall through. */
-
- case HEADER_FAILURE:
- break;
-
- case HEADER_END_OF_FILE:
- abort ();
- }
- break;
- }
-
- previous_status = status;
- }
- while (logical_status == HEADER_STILL_UNREAD);
-
- records_skipped = records_read - 1;
- new_record = xmalloc (record_size);
-
- if (logical_status == HEADER_SUCCESS
- || logical_status == HEADER_SUCCESS_EXTENDED)
- {
- write_archive_to_stdout = 0;
-
- /* Save away blocks before this one in this record. */
-
- new_blocks = current_block - record_start;
- if (new_blocks)
- memcpy (new_record, record_start, new_blocks * BLOCKSIZE);
-
- if (logical_status == HEADER_SUCCESS)
- {
- /* FIXME: Pheew! This is crufty code! */
- logical_status = HEADER_STILL_UNREAD;
- goto flush_file;
- }
-
- /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
- "delete.c", line 223: warning: loop not entered at top
- Reported by Bruno Haible. */
- while (1)
- {
- enum read_header status;
-
- /* Fill in a record. */
-
- if (current_block == record_end)
- flush_archive ();
- status = read_header (0);
-
- if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
- {
- set_next_block_after (current_header);
- continue;
- }
- if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
- {
- logical_status = HEADER_END_OF_FILE;
- break;
- }
-
- if (status == HEADER_FAILURE)
- {
- ERROR ((0, 0, _("Deleting non-header from archive")));
- set_next_block_after (current_header);
- continue;
- }
-
- /* Found another header. */
-
- if (name = name_scan (current_file_name), name)
- {
- name->found = 1;
- flush_file:
- set_next_block_after (current_header);
- blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
-
- while (record_end - current_block <= blocks_to_skip)
- {
- blocks_to_skip -= (record_end - current_block);
- flush_archive ();
- }
- current_block += blocks_to_skip;
- blocks_to_skip = 0;
- continue;
- }
-
- /* Copy header. */
-
- write_recent_blocks (recent_long_name, recent_long_name_blocks);
- write_recent_blocks (recent_long_link, recent_long_link_blocks);
- new_record[new_blocks] = *current_header;
- new_blocks++;
- blocks_to_keep
- = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
- set_next_block_after (current_header);
- if (new_blocks == blocking_factor)
- write_record (1);
-
- /* Copy data. */
-
- kept_blocks_in_record = record_end - current_block;
- if (kept_blocks_in_record > blocks_to_keep)
- kept_blocks_in_record = blocks_to_keep;
-
- while (blocks_to_keep)
- {
- int count;
-
- if (current_block == record_end)
- {
- flush_read ();
- current_block = record_start;
- kept_blocks_in_record = blocking_factor;
- if (kept_blocks_in_record > blocks_to_keep)
- kept_blocks_in_record = blocks_to_keep;
- }
- count = kept_blocks_in_record;
- if (blocking_factor - new_blocks < count)
- count = blocking_factor - new_blocks;
-
- if (! count)
- abort ();
-
- memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
- new_blocks += count;
- current_block += count;
- blocks_to_keep -= count;
- kept_blocks_in_record -= count;
-
- if (new_blocks == blocking_factor)
- write_record (1);
- }
- }
- }
-
- if (logical_status == HEADER_END_OF_FILE)
- {
- /* Write the end of tape. FIXME: we can't use write_eot here,
- as it gets confused when the input is at end of file. */
-
- int total_zero_blocks = 0;
-
- do
- {
- int zero_blocks = blocking_factor - new_blocks;
- memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
- total_zero_blocks += zero_blocks;
- write_record (total_zero_blocks < 2);
- }
- while (total_zero_blocks < 2);
- }
-
- free (new_record);
-
- if (! acting_as_filter && ! _isrmt (archive))
- {
-#if MSDOS
- int status = write (archive, "", 0);
-#else
- off_t pos = lseek (archive, (off_t) 0, SEEK_CUR);
- int status = pos < 0 ? -1 : ftruncate (archive, pos);
-#endif
- if (status != 0)
- truncate_warn (archive_name_array[0]);
- }
-
- close_archive ();
- names_notfound ();
-}
diff --git a/contrib/tar/src/extract.c b/contrib/tar/src/extract.c
deleted file mode 100644
index 3032da0..0000000
--- a/contrib/tar/src/extract.c
+++ /dev/null
@@ -1,1333 +0,0 @@
-/* Extract files from a tar archive.
-
- Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
- 2001 Free Software Foundation, Inc.
-
- Written by John Gilmore, on 1985-11-19.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* $FreeBSD$ */
-
-#include "system.h"
-#include <quotearg.h>
-
-#if HAVE_UTIME_H
-# include <utime.h>
-#else
-struct utimbuf
- {
- long actime;
- long modtime;
- };
-#endif
-
-#include "common.h"
-
-int we_are_root; /* true if our effective uid == 0 */
-static mode_t newdir_umask; /* umask when creating new directories */
-static mode_t current_umask; /* current umask (which is set to 0 if -p) */
-
-/* Status of the permissions of a file that we are extracting. */
-enum permstatus
-{
- /* This file may have existed already; its permissions are unknown. */
- UNKNOWN_PERMSTATUS,
-
- /* This file was created using the permissions from the archive. */
- ARCHIVED_PERMSTATUS,
-
- /* This is an intermediate directory; the archive did not specify
- its permissions. */
- INTERDIR_PERMSTATUS
-};
-
-/* List of directories whose statuses we need to extract after we've
- finished extracting their subsidiary files. If you consider each
- contiguous subsequence of elements of the form [D]?[^D]*, where [D]
- represents an element where AFTER_SYMLINKS is nonzero and [^D]
- represents an element where AFTER_SYMLINKS is zero, then the head
- of the subsequence has the longest name, and each non-head element
- in the prefix is an ancestor (in the directory hierarchy) of the
- preceding element. */
-
-struct delayed_set_stat
- {
- struct delayed_set_stat *next;
- struct stat stat_info;
- size_t file_name_len;
- mode_t invert_permissions;
- enum permstatus permstatus;
- bool after_symlinks;
- char file_name[1];
- };
-
-static struct delayed_set_stat *delayed_set_stat_head;
-
-/* List of symbolic links whose creation we have delayed. */
-struct delayed_symlink
- {
- /* The next delayed symbolic link in the list. */
- struct delayed_symlink *next;
-
- /* The device, inode number and last-modified time of the placeholder. */
- dev_t dev;
- ino_t ino;
- time_t mtime;
-
- /* The desired owner and group of the symbolic link. */
- uid_t uid;
- gid_t gid;
-
- /* A list of sources for this symlink. The sources are all to be
- hard-linked together. */
- struct string_list *sources;
-
- /* The desired target of the desired link. */
- char target[1];
- };
-
-static struct delayed_symlink *delayed_symlink_head;
-
-struct string_list
- {
- struct string_list *next;
- char string[1];
- };
-
-/* Set up to extract files. */
-void
-extr_init (void)
-{
- we_are_root = geteuid () == 0;
-#ifndef __FreeBSD__
- same_permissions_option += we_are_root;
-#endif
- same_owner_option += we_are_root;
- xalloc_fail_func = extract_finish;
-
- /* Option -p clears the kernel umask, so it does not affect proper
- restoration of file permissions. New intermediate directories will
- comply with umask at start of program. */
-
- newdir_umask = umask (0);
- if (0 < same_permissions_option)
- current_umask = 0;
- else
- {
- umask (newdir_umask); /* restore the kernel umask */
- current_umask = newdir_umask;
-#ifdef __FreeBSD__
- same_permissions_option++;
-#endif
- }
-}
-
-/* If restoring permissions, restore the mode for FILE_NAME from
- information given in *STAT_INFO (where *CURRENT_STAT_INFO gives
- the current status if CURRENT_STAT_INFO is nonzero); otherwise invert the
- INVERT_PERMISSIONS bits from the file's current permissions.
- PERMSTATUS specifies the status of the file's permissions.
- TYPEFLAG specifies the type of the file. */
-static void
-set_mode (char const *file_name, struct stat const *stat_info,
- struct stat const *current_stat_info,
- mode_t invert_permissions, enum permstatus permstatus,
- char typeflag)
-{
- mode_t mode;
-
- if (0 < same_permissions_option
- && permstatus != INTERDIR_PERMSTATUS)
- {
- mode = stat_info->st_mode;
-
- /* If we created the file and it has a usual mode, then its mode
- is normally set correctly already. But on many hosts, some
- directories inherit the setgid bits from their parents, so we
- we must set directories' modes explicitly. */
- if (permstatus == ARCHIVED_PERMSTATUS
- && ! (mode & ~ MODE_RWX)
- && typeflag != DIRTYPE
- && typeflag != GNUTYPE_DUMPDIR)
- return;
- }
- else if (! invert_permissions)
- return;
- else
- {
- /* We must inspect a directory's current permissions, since the
- directory may have inherited its setgid bit from its parent.
-
- INVERT_PERMISSIONS happens to be nonzero only for directories
- that we created, so there's no point optimizing this code for
- other cases. */
- struct stat st;
- if (! current_stat_info)
- {
- if (stat (file_name, &st) != 0)
- {
- stat_error (file_name);
- return;
- }
- current_stat_info = &st;
- }
- mode = current_stat_info->st_mode ^ invert_permissions;
- }
-
- if (chmod (file_name, mode & ~ current_umask) != 0)
- chmod_error_details (file_name, mode);
-}
-
-/* Check time after successfully setting FILE_NAME's time stamp to T. */
-static void
-check_time (char const *file_name, time_t t)
-{
- time_t now;
- if (start_time < t && (now = time (0)) < t)
- WARN ((0, 0, _("%s: time stamp %s is %lu s in the future"),
- file_name, tartime (t), (unsigned long) (t - now)));
-}
-
-/* Restore stat attributes (owner, group, mode and times) for
- FILE_NAME, using information given in *STAT_INFO.
- If CURRENT_STAT_INFO is nonzero, *CURRENT_STAT_INFO is the
- file's currernt status.
- If not restoring permissions, invert the
- INVERT_PERMISSIONS bits from the file's current permissions.
- PERMSTATUS specifies the status of the file's permissions.
- TYPEFLAG specifies the type of the file. */
-
-/* FIXME: About proper restoration of symbolic link attributes, we still do
- not have it right. Pretesters' reports tell us we need further study and
- probably more configuration. For now, just use lchown if it exists, and
- punt for the rest. Sigh! */
-
-static void
-set_stat (char const *file_name, struct stat const *stat_info,
- struct stat const *current_stat_info,
- mode_t invert_permissions, enum permstatus permstatus,
- char typeflag)
-{
- struct utimbuf utimbuf;
-
- if (typeflag != SYMTYPE)
- {
- /* We do the utime before the chmod because some versions of utime are
- broken and trash the modes of the file. */
-
- if (! touch_option && permstatus != INTERDIR_PERMSTATUS)
- {
- /* We set the accessed time to `now', which is really the time we
- started extracting files, unless incremental_option is used, in
- which case .st_atime is used. */
-
- /* FIXME: incremental_option should set ctime too, but how? */
-
- if (incremental_option)
- utimbuf.actime = stat_info->st_atime;
- else
- utimbuf.actime = start_time;
-
- utimbuf.modtime = stat_info->st_mtime;
-
- if (utime (file_name, &utimbuf) < 0)
- utime_error (file_name);
- else
- {
- check_time (file_name, stat_info->st_atime);
- check_time (file_name, stat_info->st_mtime);
- }
- }
-
- /* Some systems allow non-root users to give files away. Once this
- done, it is not possible anymore to change file permissions, so we
- have to set permissions prior to possibly giving files away. */
-
- set_mode (file_name, stat_info, current_stat_info,
- invert_permissions, permstatus, typeflag);
- }
-
- if (0 < same_owner_option && permstatus != INTERDIR_PERMSTATUS)
- {
- /* When lchown exists, it should be used to change the attributes of
- the symbolic link itself. In this case, a mere chown would change
- the attributes of the file the symbolic link is pointing to, and
- should be avoided. */
-
- if (typeflag == SYMTYPE)
- {
-#if HAVE_LCHOWN
- if (lchown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
- chown_error_details (file_name,
- stat_info->st_uid, stat_info->st_gid);
-#endif
- }
- else
- {
- if (chown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
- chown_error_details (file_name,
- stat_info->st_uid, stat_info->st_gid);
-
- /* On a few systems, and in particular, those allowing to give files
- away, changing the owner or group destroys the suid or sgid bits.
- So let's attempt setting these bits once more. */
- if (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX))
- set_mode (file_name, stat_info, 0,
- invert_permissions, permstatus, typeflag);
- }
- }
-}
-
-/* Remember to restore stat attributes (owner, group, mode and times)
- for the directory FILE_NAME, using information given in *STAT_INFO,
- once we stop extracting files into that directory.
- If not restoring permissions, remember to invert the
- INVERT_PERMISSIONS bits from the file's current permissions.
- PERMSTATUS specifies the status of the file's permissions. */
-static void
-delay_set_stat (char const *file_name, struct stat const *stat_info,
- mode_t invert_permissions, enum permstatus permstatus)
-{
- size_t file_name_len = strlen (file_name);
- struct delayed_set_stat *data =
- xmalloc (offsetof (struct delayed_set_stat, file_name)
- + file_name_len + 1);
- data->file_name_len = file_name_len;
- strcpy (data->file_name, file_name);
- data->invert_permissions = invert_permissions;
- data->permstatus = permstatus;
- data->after_symlinks = 0;
- data->stat_info = *stat_info;
- data->next = delayed_set_stat_head;
- delayed_set_stat_head = data;
-}
-
-/* Update the delayed_set_stat info for an intermediate directory
- created on the path to DIR_NAME. The intermediate directory turned
- out to be the same as this directory, e.g. due to ".." or symbolic
- links. *DIR_STAT_INFO is the status of the directory. */
-static void
-repair_delayed_set_stat (char const *dir_name,
- struct stat const *dir_stat_info)
-{
- struct delayed_set_stat *data;
- for (data = delayed_set_stat_head; data; data = data->next)
- {
- struct stat st;
- if (stat (data->file_name, &st) != 0)
- {
- stat_error (data->file_name);
- return;
- }
-
- if (st.st_dev == dir_stat_info->st_dev
- && st.st_ino == dir_stat_info->st_ino)
- {
- data->stat_info = current_stat;
- data->invert_permissions = (MODE_RWX
- & (current_stat.st_mode ^ st.st_mode));
- data->permstatus = ARCHIVED_PERMSTATUS;
- return;
- }
- }
-
- ERROR ((0, 0, _("%s: Unexpected inconsistency when making directory"),
- quotearg_colon (dir_name)));
-}
-
-/* After a file/link/symlink/directory creation has failed, see if
- it's because some required directory was not present, and if so,
- create all required directories. Return non-zero if a directory
- was created. */
-static int
-make_directories (char *file_name)
-{
- char *cursor0 = file_name + FILESYSTEM_PREFIX_LEN (file_name);
- char *cursor; /* points into path */
- int did_something = 0; /* did we do anything yet? */
- int mode;
- int invert_permissions;
- int status;
-
-
- for (cursor = cursor0; *cursor; cursor++)
- {
- if (! ISSLASH (*cursor))
- continue;
-
- /* Avoid mkdir of empty string, if leading or double '/'. */
-
- if (cursor == cursor0 || ISSLASH (cursor[-1]))
- continue;
-
- /* Avoid mkdir where last part of path is "." or "..". */
-
- if (cursor[-1] == '.'
- && (cursor == cursor0 + 1 || ISSLASH (cursor[-2])
- || (cursor[-2] == '.'
- && (cursor == cursor0 + 2 || ISSLASH (cursor[-3])))))
- continue;
-
- *cursor = '\0'; /* truncate the path there */
- mode = MODE_RWX & ~ newdir_umask;
- invert_permissions = we_are_root ? 0 : MODE_WXUSR & ~ mode;
- status = mkdir (file_name, mode ^ invert_permissions);
-
- if (status == 0)
- {
- /* Create a struct delayed_set_stat even if
- invert_permissions is zero, because
- repair_delayed_set_stat may need to update the struct. */
- delay_set_stat (file_name,
- &current_stat /* ignored */,
- invert_permissions, INTERDIR_PERMSTATUS);
-
- print_for_mkdir (file_name, cursor - file_name, mode);
- did_something = 1;
-
- *cursor = '/';
- continue;
- }
-
- *cursor = '/';
-
- if (errno == EEXIST
-#if MSDOS
- /* Turbo C mkdir gives a funny errno. */
- || errno == EACCES
-#endif
- )
- /* Directory already exists. */
- continue;
-
- /* Some other error in the mkdir. We return to the caller. */
- break;
- }
-
- return did_something; /* tell them to retry if we made one */
-}
-
-/* Prepare to extract a file.
- Return zero if extraction should not proceed. */
-
-static int
-prepare_to_extract (char const *file_name)
-{
- if (to_stdout_option)
- return 0;
-
- if (old_files_option == UNLINK_FIRST_OLD_FILES
- && !remove_any_file (file_name, recursive_unlink_option)
- && errno && errno != ENOENT)
- {
- unlink_error (file_name);
- return 0;
- }
-
- return 1;
-}
-
-/* Attempt repairing what went wrong with the extraction. Delete an
- already existing file or create missing intermediate directories.
- Return nonzero if we somewhat increased our chances at a successful
- extraction. errno is properly restored on zero return. */
-static int
-maybe_recoverable (char *file_name, int *interdir_made)
-{
- if (*interdir_made)
- return 0;
-
- switch (errno)
- {
- case EEXIST:
- /* Remove an old file, if the options allow this. */
-
- switch (old_files_option)
- {
- default:
- return 0;
-
- case DEFAULT_OLD_FILES:
- case OVERWRITE_OLD_DIRS:
- case OVERWRITE_OLD_FILES:
- {
- int r = remove_any_file (file_name, 0);
- errno = EEXIST;
- return r;
- }
- }
-
- case ENOENT:
- /* Attempt creating missing intermediate directories. */
- if (! make_directories (file_name))
- {
- errno = ENOENT;
- return 0;
- }
- *interdir_made = 1;
- return 1;
-
- default:
- /* Just say we can't do anything about it... */
-
- return 0;
- }
-}
-
-static void
-extract_sparse_file (int fd, off_t *sizeleft, off_t totalsize, char *name)
-{
- int sparse_ind = 0;
-
- /* assuming sizeleft is initially totalsize */
-
- while (*sizeleft > 0)
- {
- size_t written;
- size_t count;
- union block *data_block = find_next_block ();
- if (! data_block)
- {
- ERROR ((0, 0, _("Unexpected EOF in archive")));
- return;
- }
- if (lseek (fd, sparsearray[sparse_ind].offset, SEEK_SET) < 0)
- {
- seek_error_details (name, sparsearray[sparse_ind].offset);
- return;
- }
- written = sparsearray[sparse_ind++].numbytes;
- while (written > BLOCKSIZE)
- {
- count = full_write (fd, data_block->buffer, BLOCKSIZE);
- written -= count;
- *sizeleft -= count;
- if (count != BLOCKSIZE)
- {
- write_error_details (name, count, BLOCKSIZE);
- return;
- }
- set_next_block_after (data_block);
- data_block = find_next_block ();
- if (! data_block)
- {
- ERROR ((0, 0, _("Unexpected EOF in archive")));
- return;
- }
- }
-
- count = full_write (fd, data_block->buffer, written);
- *sizeleft -= count;
-
- if (count != written)
- {
- write_error_details (name, count, written);
- return;
- }
-
- set_next_block_after (data_block);
- }
-}
-
-/* Fix the statuses of all directories whose statuses need fixing, and
- which are not ancestors of FILE_NAME. If AFTER_SYMLINKS is
- nonzero, do this for all such directories; otherwise, stop at the
- first directory that is marked to be fixed up only after delayed
- symlinks are applied. */
-static void
-apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
-{
- size_t file_name_len = strlen (file_name);
- bool check_for_renamed_directories = 0;
-
- while (delayed_set_stat_head)
- {
- struct delayed_set_stat *data = delayed_set_stat_head;
- bool skip_this_one = 0;
- struct stat st;
- struct stat const *current_stat_info = 0;
-
- check_for_renamed_directories |= data->after_symlinks;
-
- if (after_symlinks < data->after_symlinks
- || (data->file_name_len < file_name_len
- && file_name[data->file_name_len]
- && (ISSLASH (file_name[data->file_name_len])
- || ISSLASH (file_name[data->file_name_len - 1]))
- && memcmp (file_name, data->file_name, data->file_name_len) == 0))
- break;
-
- if (check_for_renamed_directories)
- {
- current_stat_info = &st;
- if (stat (data->file_name, &st) != 0)
- {
- stat_error (data->file_name);
- skip_this_one = 1;
- }
- else if (! (st.st_dev == data->stat_info.st_dev
- && (st.st_ino == data->stat_info.st_ino)))
- {
- ERROR ((0, 0,
- _("%s: Directory renamed before its status could be extracted"),
- quotearg_colon (data->file_name)));
- skip_this_one = 1;
- }
- }
-
- if (! skip_this_one)
- set_stat (data->file_name, &data->stat_info, current_stat_info,
- data->invert_permissions, data->permstatus, DIRTYPE);
-
- delayed_set_stat_head = data->next;
- free (data);
- }
-}
-
-/* Extract a file from the archive. */
-void
-extract_archive (void)
-{
- union block *data_block;
- int fd;
- int status;
- size_t count;
- size_t name_length;
- size_t written;
- int openflag;
- mode_t mode;
- off_t size;
- size_t skipcrud;
- int counter;
- int interdir_made = 0;
- char typeflag;
- union block *exhdr;
-
-#define CURRENT_FILE_NAME (skipcrud + current_file_name)
-
- set_next_block_after (current_header);
- decode_header (current_header, &current_stat, &current_format, 1);
-
- if (interactive_option && !confirm ("extract", current_file_name))
- {
- skip_member ();
- return;
- }
-
- /* Print the block from current_header and current_stat. */
-
- if (verbose_option)
- print_header ();
-
- /* Check for fully specified file names and other atrocities. */
-
- skipcrud = 0;
- if (! absolute_names_option)
- {
- if (contains_dot_dot (CURRENT_FILE_NAME))
- {
- ERROR ((0, 0, _("%s: Member name contains `..'"),
- quotearg_colon (CURRENT_FILE_NAME)));
- skip_member ();
- return;
- }
-
- skipcrud = FILESYSTEM_PREFIX_LEN (current_file_name);
- while (ISSLASH (CURRENT_FILE_NAME[0]))
- skipcrud++;
-
- if (skipcrud)
- {
- static int warned_once;
-
- if (!warned_once)
- {
- warned_once = 1;
- WARN ((0, 0, _("Removing leading `%.*s' from member names"),
- (int) skipcrud, current_file_name));
- }
- }
- }
-
- apply_nonancestor_delayed_set_stat (CURRENT_FILE_NAME, 0);
-
- /* Take a safety backup of a previously existing file. */
-
- if (backup_option && !to_stdout_option)
- if (!maybe_backup_file (CURRENT_FILE_NAME, 0))
- {
- int e = errno;
- ERROR ((0, e, _("%s: Was unable to backup this file"),
- quotearg_colon (CURRENT_FILE_NAME)));
- skip_member ();
- return;
- }
-
- /* Extract the archive entry according to its type. */
-
- typeflag = current_header->header.typeflag;
- switch (typeflag)
- {
- /* JK - What we want to do if the file is sparse is loop through
- the array of sparse structures in the header and read in and
- translate the character strings representing 1) the offset at
- which to write and 2) how many bytes to write into numbers,
- which we store into the scratch array, "sparsearray". This
- array makes our life easier the same way it did in creating the
- tar file that had to deal with a sparse file.
-
- After we read in the first five (at most) sparse structures, we
- check to see if the file has an extended header, i.e., if more
- sparse structures are needed to describe the contents of the new
- file. If so, we read in the extended headers and continue to
- store their contents into the sparsearray. */
-
- case GNUTYPE_SPARSE:
- sp_array_size = 10;
- sparsearray =
- xmalloc (sp_array_size * sizeof (struct sp_array));
-
- for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
- {
- struct sparse const *s = &current_header->oldgnu_header.sp[counter];
- sparsearray[counter].offset = OFF_FROM_HEADER (s->offset);
- sparsearray[counter].numbytes = SIZE_FROM_HEADER (s->numbytes);
- if (!sparsearray[counter].numbytes)
- break;
- }
-
- if (current_header->oldgnu_header.isextended)
- {
- /* Read in the list of extended headers and translate them
- into the sparsearray as before. Note that this
- invalidates current_header. */
-
- /* static */ int ind = SPARSES_IN_OLDGNU_HEADER;
-
- while (1)
- {
- exhdr = find_next_block ();
- if (! exhdr)
- {
- ERROR ((0, 0, _("Unexpected EOF in archive")));
- return;
- }
- for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
- {
- struct sparse const *s = &exhdr->sparse_header.sp[counter];
- if (counter + ind > sp_array_size - 1)
- {
- /* Realloc the scratch area since we've run out of
- room. */
-
- sp_array_size *= 2;
- sparsearray =
- xrealloc (sparsearray,
- sp_array_size * sizeof (struct sp_array));
- }
- if (s->numbytes[0] == 0)
- break;
- sparsearray[counter + ind].offset =
- OFF_FROM_HEADER (s->offset);
- sparsearray[counter + ind].numbytes =
- SIZE_FROM_HEADER (s->numbytes);
- }
- if (!exhdr->sparse_header.isextended)
- break;
- else
- {
- ind += SPARSES_IN_SPARSE_HEADER;
- set_next_block_after (exhdr);
- }
- }
- set_next_block_after (exhdr);
- }
- /* Fall through. */
-
- case AREGTYPE:
- case REGTYPE:
- case CONTTYPE:
-
- /* Appears to be a file. But BSD tar uses the convention that a slash
- suffix means a directory. */
-
- name_length = strlen (CURRENT_FILE_NAME);
- if (FILESYSTEM_PREFIX_LEN (CURRENT_FILE_NAME) < name_length
- && CURRENT_FILE_NAME[name_length - 1] == '/')
- goto really_dir;
-
- /* FIXME: deal with protection issues. */
-
- again_file:
- openflag = (O_WRONLY | O_BINARY | O_CREAT
- | (old_files_option == OVERWRITE_OLD_FILES
- ? O_TRUNC
- : O_EXCL));
- mode = current_stat.st_mode & MODE_RWX & ~ current_umask;
-
- if (to_stdout_option)
- {
- fd = STDOUT_FILENO;
- goto extract_file;
- }
-
- if (! prepare_to_extract (CURRENT_FILE_NAME))
- {
- skip_member ();
- if (backup_option)
- undo_last_backup ();
- break;
- }
-
-#if O_CTG
- /* Contiguous files (on the Masscomp) have to specify the size in
- the open call that creates them. */
-
- if (typeflag == CONTTYPE)
- fd = open (CURRENT_FILE_NAME, openflag | O_CTG,
- mode, current_stat.st_size);
- else
- fd = open (CURRENT_FILE_NAME, openflag, mode);
-
-#else /* not O_CTG */
- if (typeflag == CONTTYPE)
- {
- static int conttype_diagnosed;
-
- if (!conttype_diagnosed)
- {
- conttype_diagnosed = 1;
- WARN ((0, 0, _("Extracting contiguous files as regular files")));
- }
- }
- fd = open (CURRENT_FILE_NAME, openflag, mode);
-
-#endif /* not O_CTG */
-
- if (fd < 0)
- {
- if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
- goto again_file;
-
- open_error (CURRENT_FILE_NAME);
- skip_member ();
- if (backup_option)
- undo_last_backup ();
- break;
- }
-
- extract_file:
- if (typeflag == GNUTYPE_SPARSE)
- {
- char *name;
- size_t name_length_bis;
-
- /* Kludge alert. NAME is assigned to header.name because
- during the extraction, the space that contains the header
- will get scribbled on, and the name will get munged, so any
- error messages that happen to contain the filename will look
- REAL interesting unless we do this. */
-
- name_length_bis = strlen (CURRENT_FILE_NAME) + 1;
- name = xmalloc (name_length_bis);
- memcpy (name, CURRENT_FILE_NAME, name_length_bis);
- size = current_stat.st_size;
- extract_sparse_file (fd, &size, current_stat.st_size, name);
- free (sparsearray);
- }
- else
- for (size = current_stat.st_size; size > 0; )
- {
- if (multi_volume_option)
- {
- assign_string (&save_name, current_file_name);
- save_totsize = current_stat.st_size;
- save_sizeleft = size;
- }
-
- /* Locate data, determine max length writeable, write it,
- block that we have used the data, then check if the write
- worked. */
-
- data_block = find_next_block ();
- if (! data_block)
- {
- ERROR ((0, 0, _("Unexpected EOF in archive")));
- break; /* FIXME: What happens, then? */
- }
-
- written = available_space_after (data_block);
-
- if (written > size)
- written = size;
- errno = 0;
- count = full_write (fd, data_block->buffer, written);
- size -= count;
-
- set_next_block_after ((union block *)
- (data_block->buffer + written - 1));
- if (count != written)
- {
- write_error_details (CURRENT_FILE_NAME, count, written);
- break;
- }
- }
-
- skip_file (size);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
-
- /* If writing to stdout, don't try to do anything to the filename;
- it doesn't exist, or we don't want to touch it anyway. */
-
- if (to_stdout_option)
- break;
-
- status = close (fd);
- if (status < 0)
- {
- close_error (CURRENT_FILE_NAME);
- if (backup_option)
- undo_last_backup ();
- }
-
- set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0,
- (old_files_option == OVERWRITE_OLD_FILES
- ? UNKNOWN_PERMSTATUS
- : ARCHIVED_PERMSTATUS),
- typeflag);
- break;
-
- case SYMTYPE:
-#ifdef HAVE_SYMLINK
- if (! prepare_to_extract (CURRENT_FILE_NAME))
- break;
-
- if (absolute_names_option
- || ! (ISSLASH (current_link_name
- [FILESYSTEM_PREFIX_LEN (current_link_name)])
- || contains_dot_dot (current_link_name)))
- {
- while (status = symlink (current_link_name, CURRENT_FILE_NAME),
- status != 0)
- if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
- break;
-
- if (status == 0)
- set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0, 0, SYMTYPE);
- else
- symlink_error (current_link_name, CURRENT_FILE_NAME);
- }
- else
- {
- /* This symbolic link is potentially dangerous. Don't
- create it now; instead, create a placeholder file, which
- will be replaced after other extraction is done. */
- struct stat st;
-
- while (fd = open (CURRENT_FILE_NAME, O_WRONLY | O_CREAT | O_EXCL, 0),
- fd < 0)
- if (! maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
- break;
-
- status = -1;
- if (fd < 0)
- open_error (CURRENT_FILE_NAME);
- else if (fstat (fd, &st) != 0)
- {
- stat_error (CURRENT_FILE_NAME);
- close (fd);
- }
- else if (close (fd) != 0)
- close_error (CURRENT_FILE_NAME);
- else
- {
- struct delayed_set_stat *h;
- struct delayed_symlink *p =
- xmalloc (offsetof (struct delayed_symlink, target)
- + strlen (current_link_name) + 1);
- p->next = delayed_symlink_head;
- delayed_symlink_head = p;
- p->dev = st.st_dev;
- p->ino = st.st_ino;
- p->mtime = st.st_mtime;
- p->uid = current_stat.st_uid;
- p->gid = current_stat.st_gid;
- p->sources = xmalloc (offsetof (struct string_list, string)
- + strlen (CURRENT_FILE_NAME) + 1);
- p->sources->next = 0;
- strcpy (p->sources->string, CURRENT_FILE_NAME);
- strcpy (p->target, current_link_name);
-
- h = delayed_set_stat_head;
- if (h && ! h->after_symlinks
- && strncmp (CURRENT_FILE_NAME, h->file_name, h->file_name_len) == 0
- && ISSLASH (CURRENT_FILE_NAME[h->file_name_len])
- && (base_name (CURRENT_FILE_NAME)
- == CURRENT_FILE_NAME + h->file_name_len + 1))
- {
- do
- {
- h->after_symlinks = 1;
-
- if (stat (h->file_name, &st) != 0)
- stat_error (h->file_name);
- else
- {
- h->stat_info.st_dev = st.st_dev;
- h->stat_info.st_ino = st.st_ino;
- }
- }
- while ((h = h->next) && ! h->after_symlinks);
- }
-
- status = 0;
- }
- }
-
- if (status != 0 && backup_option)
- undo_last_backup ();
- break;
-
-#else
- {
- static int warned_once;
-
- if (!warned_once)
- {
- warned_once = 1;
- WARN ((0, 0,
- _("Attempting extraction of symbolic links as hard links")));
- }
- }
- typeflag = LNKTYPE;
- /* Fall through. */
-#endif
-
- case LNKTYPE:
- if (! prepare_to_extract (CURRENT_FILE_NAME))
- break;
-
- again_link:
- {
- struct stat st1, st2;
- int e;
- size_t skiplinkcrud;
-
- if (absolute_names_option)
- skiplinkcrud = 0;
- else {
- skiplinkcrud = FILESYSTEM_PREFIX_LEN (current_link_name);
- while (ISSLASH (current_link_name[skiplinkcrud]))
- skiplinkcrud++;
- }
-
- /* MSDOS does not implement links. However, djgpp's link() actually
- copies the file. */
- status = link (current_link_name + skiplinkcrud, CURRENT_FILE_NAME);
-
- if (status == 0)
- {
- struct delayed_symlink *ds = delayed_symlink_head;
- if (ds && stat (current_link_name, &st1) == 0)
- for (; ds; ds = ds->next)
- if (ds->dev == st1.st_dev
- && ds->ino == st1.st_ino
- && ds->mtime == st1.st_mtime)
- {
- struct string_list *p =
- xmalloc (offsetof (struct string_list, string)
- + strlen (CURRENT_FILE_NAME) + 1);
- strcpy (p->string, CURRENT_FILE_NAME);
- p->next = ds->sources;
- ds->sources = p;
- break;
- }
- break;
- }
- if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
- goto again_link;
-
- if (incremental_option && errno == EEXIST)
- break;
- e = errno;
- if (stat (current_link_name, &st1) == 0
- && stat (CURRENT_FILE_NAME, &st2) == 0
- && st1.st_dev == st2.st_dev
- && st1.st_ino == st2.st_ino)
- break;
-
- link_error (current_link_name, CURRENT_FILE_NAME);
- if (backup_option)
- undo_last_backup ();
- }
- break;
-
-#if S_IFCHR
- case CHRTYPE:
- current_stat.st_mode |= S_IFCHR;
- goto make_node;
-#endif
-
-#if S_IFBLK
- case BLKTYPE:
- current_stat.st_mode |= S_IFBLK;
-#endif
-
-#if S_IFCHR || S_IFBLK
- make_node:
- if (! prepare_to_extract (CURRENT_FILE_NAME))
- break;
-
- status = mknod (CURRENT_FILE_NAME, current_stat.st_mode,
- current_stat.st_rdev);
- if (status != 0)
- {
- if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
- goto make_node;
- mknod_error (CURRENT_FILE_NAME);
- if (backup_option)
- undo_last_backup ();
- break;
- };
- set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0,
- ARCHIVED_PERMSTATUS, typeflag);
- break;
-#endif
-
-#if HAVE_MKFIFO || defined mkfifo
- case FIFOTYPE:
- if (! prepare_to_extract (CURRENT_FILE_NAME))
- break;
-
- while (status = mkfifo (CURRENT_FILE_NAME, current_stat.st_mode),
- status != 0)
- if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
- break;
-
- if (status == 0)
- set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0,
- ARCHIVED_PERMSTATUS, typeflag);
- else
- {
- mkfifo_error (CURRENT_FILE_NAME);
- if (backup_option)
- undo_last_backup ();
- }
- break;
-#endif
-
- case DIRTYPE:
- case GNUTYPE_DUMPDIR:
- name_length = strlen (CURRENT_FILE_NAME);
-
- really_dir:
- /* Remove any redundant trailing "/"s. */
- while (FILESYSTEM_PREFIX_LEN (CURRENT_FILE_NAME) < name_length
- && CURRENT_FILE_NAME[name_length - 1] == '/')
- name_length--;
- CURRENT_FILE_NAME[name_length] = '\0';
-
- if (incremental_option)
- {
- /* Read the entry and delete files that aren't listed in the
- archive. */
-
- gnu_restore (skipcrud);
- }
- else if (typeflag == GNUTYPE_DUMPDIR)
- skip_member ();
-
- {
- struct stat st;
- if (stat (CURRENT_FILE_NAME, &st) != 0 || !S_ISDIR (st.st_mode))
- if (! prepare_to_extract (CURRENT_FILE_NAME))
- break;
- }
-
- mode = ((current_stat.st_mode
- | (we_are_root ? 0 : MODE_WXUSR))
- & MODE_RWX);
-
- again_dir:
- status = mkdir (CURRENT_FILE_NAME, mode);
-
- if (status != 0)
- {
- if (errno == EEXIST
- && (interdir_made
- || old_files_option == OVERWRITE_OLD_DIRS
- || old_files_option == OVERWRITE_OLD_FILES))
- {
- struct stat st;
- if (stat (CURRENT_FILE_NAME, &st) == 0)
- {
- if (interdir_made)
- {
- repair_delayed_set_stat (CURRENT_FILE_NAME, &st);
- break;
- }
- if (S_ISDIR (st.st_mode))
- {
- mode = st.st_mode & ~ current_umask;
- goto directory_exists;
- }
- }
- errno = EEXIST;
- }
-
- if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
- goto again_dir;
-
- if (errno != EEXIST)
- {
- mkdir_error (CURRENT_FILE_NAME);
- if (backup_option)
- undo_last_backup ();
- break;
- }
- }
-
- directory_exists:
- if (status == 0
- || old_files_option == OVERWRITE_OLD_DIRS
- || old_files_option == OVERWRITE_OLD_FILES)
- delay_set_stat (CURRENT_FILE_NAME, &current_stat,
- MODE_RWX & (mode ^ current_stat.st_mode),
- (status == 0
- ? ARCHIVED_PERMSTATUS
- : UNKNOWN_PERMSTATUS));
- break;
-
- case GNUTYPE_VOLHDR:
- if (verbose_option)
- fprintf (stdlis, _("Reading %s\n"), quote (current_file_name));
- break;
-
- case GNUTYPE_NAMES:
- extract_mangle ();
- break;
-
- case GNUTYPE_MULTIVOL:
- ERROR ((0, 0,
- _("%s: Cannot extract -- file is continued from another volume"),
- quotearg_colon (current_file_name)));
- skip_member ();
- if (backup_option)
- undo_last_backup ();
- break;
-
- case GNUTYPE_LONGNAME:
- case GNUTYPE_LONGLINK:
- ERROR ((0, 0, _("Visible long name error")));
- skip_member ();
- if (backup_option)
- undo_last_backup ();
- break;
-
- default:
- WARN ((0, 0,
- _("%s: Unknown file type '%c', extracted as normal file"),
- quotearg_colon (CURRENT_FILE_NAME), typeflag));
- goto again_file;
- }
-
-#undef CURRENT_FILE_NAME
-}
-
-/* Extract the symbolic links whose final extraction were delayed. */
-static void
-apply_delayed_symlinks (void)
-{
- struct delayed_symlink *ds;
-
- for (ds = delayed_symlink_head; ds; )
- {
- struct string_list *sources = ds->sources;
- char const *valid_source = 0;
-
- for (sources = ds->sources; sources; sources = sources->next)
- {
- char const *source = sources->string;
- struct stat st;
-
- /* Make sure the placeholder file is still there. If not,
- don't create a symlink, as the placeholder was probably
- removed by a later extraction. */
- if (lstat (source, &st) == 0
- && st.st_dev == ds->dev
- && st.st_ino == ds->ino
- && st.st_mtime == ds->mtime)
- {
- /* Unlink the placeholder, then create a hard link if possible,
- a symbolic link otherwise. */
- if (unlink (source) != 0)
- unlink_error (source);
- else if (valid_source && link (valid_source, source) == 0)
- ;
- else if (symlink (ds->target, source) != 0)
- symlink_error (ds->target, source);
- else
- {
- valid_source = source;
- st.st_uid = ds->uid;
- st.st_gid = ds->gid;
- set_stat (source, &st, 0, 0, 0, SYMTYPE);
- }
- }
- }
-
- for (sources = ds->sources; sources; )
- {
- struct string_list *next = sources->next;
- free (sources);
- sources = next;
- }
-
- {
- struct delayed_symlink *next = ds->next;
- free (ds);
- ds = next;
- }
- }
-
- delayed_symlink_head = 0;
-}
-
-/* Finish the extraction of an archive. */
-void
-extract_finish (void)
-{
- /* First, fix the status of ordinary directories that need fixing. */
- apply_nonancestor_delayed_set_stat ("", 0);
-
- /* Then, apply delayed symlinks, so that they don't affect delayed
- directory status-setting for ordinary directories. */
- apply_delayed_symlinks ();
-
- /* Finally, fix the status of directories that are ancestors
- of delayed symlinks. */
- apply_nonancestor_delayed_set_stat ("", 1);
-}
-
-void
-fatal_exit (void)
-{
- extract_finish ();
- error (TAREXIT_FAILURE, 0, _("Error is not recoverable: exiting now"));
- abort ();
-}
diff --git a/contrib/tar/src/incremen.c b/contrib/tar/src/incremen.c
deleted file mode 100644
index 7dd43e9..0000000
--- a/contrib/tar/src/incremen.c
+++ /dev/null
@@ -1,584 +0,0 @@
-/* GNU dump extensions to tar.
-
- Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
- Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "system.h"
-#include <getline.h>
-#include <hash.h>
-#include <quotearg.h>
-#include "common.h"
-
-/* Variable sized generic character buffers. */
-
-struct accumulator
-{
- size_t allocated;
- size_t length;
- char *pointer;
-};
-
-/* Amount of space guaranteed just after a reallocation. */
-#define ACCUMULATOR_SLACK 50
-
-/* Return the accumulated data from an ACCUMULATOR buffer. */
-static char *
-get_accumulator (struct accumulator *accumulator)
-{
- return accumulator->pointer;
-}
-
-/* Allocate and return a new accumulator buffer. */
-static struct accumulator *
-new_accumulator (void)
-{
- struct accumulator *accumulator
- = xmalloc (sizeof (struct accumulator));
-
- accumulator->allocated = ACCUMULATOR_SLACK;
- accumulator->pointer = xmalloc (ACCUMULATOR_SLACK);
- accumulator->length = 0;
- return accumulator;
-}
-
-/* Deallocate an ACCUMULATOR buffer. */
-static void
-delete_accumulator (struct accumulator *accumulator)
-{
- free (accumulator->pointer);
- free (accumulator);
-}
-
-/* At the end of an ACCUMULATOR buffer, add a DATA block of SIZE bytes. */
-static void
-add_to_accumulator (struct accumulator *accumulator,
- const char *data, size_t size)
-{
- if (accumulator->length + size > accumulator->allocated)
- {
- accumulator->allocated = accumulator->length + size + ACCUMULATOR_SLACK;
- accumulator->pointer =
- xrealloc (accumulator->pointer, accumulator->allocated);
- }
- memcpy (accumulator->pointer + accumulator->length, data, size);
- accumulator->length += size;
-}
-
-/* Incremental dump specialities. */
-
-/* Which child files to save under a directory. */
-enum children {NO_CHILDREN, CHANGED_CHILDREN, ALL_CHILDREN};
-
-/* Directory attributes. */
-struct directory
- {
- dev_t device_number; /* device number for directory */
- ino_t inode_number; /* inode number for directory */
- enum children children;
- char nfs;
- char found;
- char name[1]; /* path name of directory */
- };
-
-static Hash_table *directory_table;
-
-#if HAVE_ST_FSTYPE_STRING
- static char const nfs_string[] = "nfs";
-# define NFS_FILE_STAT(st) (strcmp ((st).st_fstype, nfs_string) == 0)
-#else
-# define ST_DEV_MSB(st) (~ (dev_t) 0 << (sizeof (st).st_dev * CHAR_BIT - 1))
-# define NFS_FILE_STAT(st) (((st).st_dev & ST_DEV_MSB (st)) != 0)
-#endif
-
-/* Calculate the hash of a directory. */
-static unsigned
-hash_directory (void const *entry, unsigned n_buckets)
-{
- struct directory const *directory = entry;
- return hash_string (directory->name, n_buckets);
-}
-
-/* Compare two directories for equality. */
-static bool
-compare_directories (void const *entry1, void const *entry2)
-{
- struct directory const *directory1 = entry1;
- struct directory const *directory2 = entry2;
- return strcmp (directory1->name, directory2->name) == 0;
-}
-
-/* Create and link a new directory entry for directory NAME, having a
- device number DEV and an inode number INO, with NFS indicating
- whether it is an NFS device and FOUND indicating whether we have
- found that the directory exists. */
-static struct directory *
-note_directory (char const *name, dev_t dev, ino_t ino, bool nfs, bool found)
-{
- size_t size = offsetof (struct directory, name) + strlen (name) + 1;
- struct directory *directory = xmalloc (size);
-
- directory->device_number = dev;
- directory->inode_number = ino;
- directory->children = CHANGED_CHILDREN;
- directory->nfs = nfs;
- directory->found = found;
- strcpy (directory->name, name);
-
- if (! ((directory_table
- || (directory_table = hash_initialize (0, 0, hash_directory,
- compare_directories, 0)))
- && hash_insert (directory_table, directory)))
- xalloc_die ();
-
- return directory;
-}
-
-/* Return a directory entry for a given path NAME, or zero if none found. */
-static struct directory *
-find_directory (char *name)
-{
- if (! directory_table)
- return 0;
- else
- {
- size_t size = offsetof (struct directory, name) + strlen (name) + 1;
- struct directory *dir = alloca (size);
- strcpy (dir->name, name);
- return hash_lookup (directory_table, dir);
- }
-}
-
-static int
-compare_dirents (const void *first, const void *second)
-{
- return strcmp ((*(char *const *) first) + 1,
- (*(char *const *) second) + 1);
-}
-
-char *
-get_directory_contents (char *path, dev_t device)
-{
- struct accumulator *accumulator;
-
- /* Recursively scan the given PATH. */
-
- {
- char *dirp = savedir (path); /* for scanning directory */
- char const *entry; /* directory entry being scanned */
- size_t entrylen; /* length of directory entry */
- char *name_buffer; /* directory, `/', and directory member */
- size_t name_buffer_size; /* allocated size of name_buffer, minus 2 */
- size_t name_length; /* used length in name_buffer */
- struct directory *directory; /* for checking if already already seen */
- enum children children;
-
- if (! dirp)
- savedir_error (path);
- errno = 0;
-
- name_buffer_size = strlen (path) + NAME_FIELD_SIZE;
- name_buffer = xmalloc (name_buffer_size + 2);
- strcpy (name_buffer, path);
- if (! ISSLASH (path[strlen (path) - 1]))
- strcat (name_buffer, "/");
- name_length = strlen (name_buffer);
-
- directory = find_directory (path);
- children = directory ? directory->children : CHANGED_CHILDREN;
-
- accumulator = new_accumulator ();
-
- if (children != NO_CHILDREN)
- for (entry = dirp;
- (entrylen = strlen (entry)) != 0;
- entry += entrylen + 1)
- {
- if (name_buffer_size <= entrylen + name_length)
- {
- do
- name_buffer_size += NAME_FIELD_SIZE;
- while (name_buffer_size <= entrylen + name_length);
- name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
- }
- strcpy (name_buffer + name_length, entry);
-
- if (excluded_name (name_buffer))
- add_to_accumulator (accumulator, "N", 1);
- else
- {
- struct stat stat_data;
-
- if (deref_stat (dereference_option, name_buffer, &stat_data))
- {
- if (ignore_failed_read_option)
- stat_warn (name_buffer);
- else
- stat_error (name_buffer);
- continue;
- }
-
- if (S_ISDIR (stat_data.st_mode))
- {
- bool nfs = NFS_FILE_STAT (stat_data);
-
- if (directory = find_directory (name_buffer), directory)
- {
- /* With NFS, the same file can have two different devices
- if an NFS directory is mounted in multiple locations,
- which is relatively common when automounting.
- To avoid spurious incremental redumping of
- directories, consider all NFS devices as equal,
- relying on the i-node to establish differences. */
-
- if (! (((directory->nfs & nfs)
- || directory->device_number == stat_data.st_dev)
- && directory->inode_number == stat_data.st_ino))
- {
- if (verbose_option)
- WARN ((0, 0, _("%s: Directory has been renamed"),
- quotearg_colon (name_buffer)));
- directory->children = ALL_CHILDREN;
- directory->nfs = nfs;
- directory->device_number = stat_data.st_dev;
- directory->inode_number = stat_data.st_ino;
- }
- directory->found = 1;
- }
- else
- {
- if (verbose_option)
- WARN ((0, 0, _("%s: Directory is new"),
- quotearg_colon (name_buffer)));
- directory = note_directory (name_buffer,
- stat_data.st_dev,
- stat_data.st_ino, nfs, 1);
- directory->children =
- ((listed_incremental_option
- || newer_mtime_option <= stat_data.st_mtime
- || (after_date_option &&
- newer_ctime_option <= stat_data.st_ctime))
- ? ALL_CHILDREN
- : CHANGED_CHILDREN);
- }
-
- if (one_file_system_option && device != stat_data.st_dev)
- directory->children = NO_CHILDREN;
- else if (children == ALL_CHILDREN)
- directory->children = ALL_CHILDREN;
-
- add_to_accumulator (accumulator, "D", 1);
- }
-
- else if (one_file_system_option && device != stat_data.st_dev)
- add_to_accumulator (accumulator, "N", 1);
-
-#ifdef S_ISHIDDEN
- else if (S_ISHIDDEN (stat_data.st_mode))
- {
- add_to_accumulator (accumulator, "D", 1);
- add_to_accumulator (accumulator, entry, entrylen);
- add_to_accumulator (accumulator, "A", 2);
- continue;
- }
-#endif
-
- else
- if (children == CHANGED_CHILDREN
- && stat_data.st_mtime < newer_mtime_option
- && (!after_date_option
- || stat_data.st_ctime < newer_ctime_option))
- add_to_accumulator (accumulator, "N", 1);
- else
- add_to_accumulator (accumulator, "Y", 1);
- }
-
- add_to_accumulator (accumulator, entry, entrylen + 1);
- }
-
- add_to_accumulator (accumulator, "\000\000", 2);
-
- free (name_buffer);
- free (dirp);
- }
-
- /* Sort the contents of the directory, now that we have it all. */
-
- {
- char *pointer = get_accumulator (accumulator);
- size_t counter;
- char *cursor;
- char *buffer;
- char **array;
- char **array_cursor;
-
- counter = 0;
- for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
- counter++;
-
- if (! counter)
- {
- delete_accumulator (accumulator);
- return 0;
- }
-
- array = xmalloc (sizeof (char *) * (counter + 1));
-
- array_cursor = array;
- for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
- *array_cursor++ = cursor;
- *array_cursor = 0;
-
- qsort (array, counter, sizeof (char *), compare_dirents);
-
- buffer = xmalloc (cursor - pointer + 2);
-
- cursor = buffer;
- for (array_cursor = array; *array_cursor; array_cursor++)
- {
- char *string = *array_cursor;
-
- while ((*cursor++ = *string++))
- continue;
- }
- *cursor = '\0';
-
- delete_accumulator (accumulator);
- free (array);
- return buffer;
- }
-}
-
-static FILE *listed_incremental_stream;
-
-void
-read_directory_file (void)
-{
- int fd;
- FILE *fp;
- char *buf = 0;
- size_t bufsize;
-
- /* Open the file for both read and write. That way, we can write
- it later without having to reopen it, and don't have to worry if
- we chdir in the meantime. */
- fd = open (listed_incremental_option, O_RDWR | O_CREAT, MODE_RW);
- if (fd < 0)
- {
- open_error (listed_incremental_option);
- return;
- }
-
- fp = fdopen (fd, "r+");
- if (! fp)
- {
- open_error (listed_incremental_option);
- close (fd);
- return;
- }
-
- listed_incremental_stream = fp;
-
- if (0 < getline (&buf, &bufsize, fp))
- {
- char *ebuf;
- int n;
- long lineno = 1;
- unsigned long u = (errno = 0, strtoul (buf, &ebuf, 10));
- time_t t = u;
- if (buf == ebuf || (u == 0 && errno == EINVAL))
- ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
- _("Invalid time stamp")));
- else if (t != u || (u == -1 && errno == ERANGE))
- ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
- _("Time stamp out of range")));
- else
- newer_mtime_option = t;
-
- while (0 < (n = getline (&buf, &bufsize, fp)))
- {
- dev_t dev;
- ino_t ino;
- int nfs = buf[0] == '+';
- char *strp = buf + nfs;
-
- lineno++;
-
- if (buf[n - 1] == '\n')
- buf[n - 1] = '\0';
-
- errno = 0;
- dev = u = strtoul (strp, &ebuf, 10);
- if (strp == ebuf || (u == 0 && errno == EINVAL))
- ERROR ((0, 0, "%s:%ld: %s",
- quotearg_colon (listed_incremental_option), lineno,
- _("Invalid device number")));
- else if (dev != u || (u == -1 && errno == ERANGE))
- ERROR ((0, 0, "%s:%ld: %s",
- quotearg_colon (listed_incremental_option), lineno,
- _("Device number out of range")));
- strp = ebuf;
-
- errno = 0;
- ino = u = strtoul (strp, &ebuf, 10);
- if (strp == ebuf || (u == 0 && errno == EINVAL))
- ERROR ((0, 0, "%s:%ld: %s",
- quotearg_colon (listed_incremental_option), lineno,
- _("Invalid inode number")));
- else if (ino != u || (u == -1 && errno == ERANGE))
- ERROR ((0, 0, "%s:%ld: %s",
- quotearg_colon (listed_incremental_option), lineno,
- _("Inode number out of range")));
- strp = ebuf;
-
- strp++;
- unquote_string (strp);
- note_directory (strp, dev, ino, nfs, 0);
- }
- }
-
- if (ferror (fp))
- read_error (listed_incremental_option);
- if (buf)
- free (buf);
-}
-
-/* Output incremental data for the directory ENTRY to the file DATA.
- Return nonzero if successful, preserving errno on write failure. */
-static bool
-write_directory_file_entry (void *entry, void *data)
-{
- struct directory const *directory = entry;
- FILE *fp = data;
-
- if (directory->found)
- {
- int e;
- char *str = quote_copy_string (directory->name);
- fprintf (fp, "+%lu %lu %s\n" + ! directory->nfs,
- (unsigned long) directory->device_number,
- (unsigned long) directory->inode_number,
- str ? str : directory->name);
- e = errno;
- if (str)
- free (str);
- errno = e;
- }
-
- return ! ferror (fp);
-}
-
-void
-write_directory_file (void)
-{
- FILE *fp = listed_incremental_stream;
-
- if (! fp)
- return;
-
- if (fseek (fp, 0L, SEEK_SET) != 0)
- seek_error (listed_incremental_option);
- if (ftruncate (fileno (fp), (off_t) 0) != 0)
- truncate_error (listed_incremental_option);
-
- fprintf (fp, "%lu\n", (unsigned long) start_time);
- if (! ferror (fp) && directory_table)
- hash_do_for_each (directory_table, write_directory_file_entry, fp);
- if (ferror (fp))
- write_error (listed_incremental_option);
- if (fclose (fp) != 0)
- close_error (listed_incremental_option);
-}
-
-/* Restoration of incremental dumps. */
-
-void
-gnu_restore (size_t skipcrud)
-{
- char *archive_dir;
- char *current_dir;
- char *cur, *arc;
- size_t size;
- size_t copied;
- union block *data_block;
- char *to;
-
-#define CURRENT_FILE_NAME (skipcrud + current_file_name)
-
- current_dir = savedir (CURRENT_FILE_NAME);
-
- if (!current_dir)
- {
- /* The directory doesn't exist now. It'll be created. In any
- case, we don't have to delete any files out of it. */
-
- skip_member ();
- return;
- }
-
- size = current_stat.st_size;
- if (size != current_stat.st_size)
- xalloc_die ();
- archive_dir = xmalloc (size);
- to = archive_dir;
- for (; size > 0; size -= copied)
- {
- data_block = find_next_block ();
- if (!data_block)
- {
- ERROR ((0, 0, _("Unexpected EOF in archive")));
- break; /* FIXME: What happens then? */
- }
- copied = available_space_after (data_block);
- if (copied > size)
- copied = size;
- memcpy (to, data_block->buffer, copied);
- to += copied;
- set_next_block_after ((union block *)
- (data_block->buffer + copied - 1));
- }
-
- for (cur = current_dir; *cur; cur += strlen (cur) + 1)
- {
- for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
- {
- arc++;
- if (!strcmp (arc, cur))
- break;
- }
- if (*arc == '\0')
- {
- char *p = new_name (CURRENT_FILE_NAME, cur);
- if (! interactive_option || confirm ("delete", p))
- {
- if (verbose_option)
- fprintf (stdlis, _("%s: Deleting %s\n"),
- program_name, quote (p));
- if (! remove_any_file (p, 1))
- {
- int e = errno;
- ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
- }
- }
- free (p);
- }
-
- }
- free (current_dir);
- free (archive_dir);
-
-#undef CURRENT_FILE_NAME
-}
diff --git a/contrib/tar/src/list.c b/contrib/tar/src/list.c
deleted file mode 100644
index 9c68ae9..0000000
--- a/contrib/tar/src/list.c
+++ /dev/null
@@ -1,1211 +0,0 @@
-/* List a tar archive, with support routines for reading a tar archive.
-
- Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
- 2001 Free Software Foundation, Inc.
-
- Written by John Gilmore, on 1985-08-26.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* $FreeBSD$ */
-
-/* Define to non-zero for forcing old ctime format instead of ISO format. */
-#undef USE_OLD_CTIME
-
-#include "system.h"
-#include <quotearg.h>
-#ifdef HAVE_LANGINFO_CODESET
-#include <langinfo.h>
-#endif
-
-#include "common.h"
-
-#define max(a, b) ((a) < (b) ? (b) : (a))
-
-union block *current_header; /* points to current archive header */
-struct stat current_stat; /* stat struct corresponding */
-enum archive_format current_format; /* recognized format */
-union block *recent_long_name; /* recent long name header and contents */
-union block *recent_long_link; /* likewise, for long link */
-size_t recent_long_name_blocks; /* number of blocks in recent_long_name */
-size_t recent_long_link_blocks; /* likewise, for long link */
-
-static uintmax_t from_header PARAMS ((const char *, size_t, const char *,
- uintmax_t, uintmax_t));
-
-/* Base 64 digits; see Internet RFC 2045 Table 1. */
-static char const base_64_digits[64] =
-{
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
-};
-
-/* Table of base-64 digit values indexed by unsigned chars.
- The value is 64 for unsigned chars that are not base-64 digits. */
-static char base64_map[UCHAR_MAX + 1];
-
-static void
-base64_init (void)
-{
- int i;
- memset (base64_map, 64, sizeof base64_map);
- for (i = 0; i < 64; i++)
- base64_map[(int) base_64_digits[i]] = i;
-}
-
-/* Main loop for reading an archive. */
-void
-read_and (void (*do_something) ())
-{
- enum read_header status = HEADER_STILL_UNREAD;
- enum read_header prev_status;
-
- base64_init ();
- name_gather ();
- open_archive (ACCESS_READ);
-
- while (1)
- {
- prev_status = status;
- status = read_header (0);
- /* check if the namelist got emptied during the course of reading */
- /* the tape, if so stop by setting status to EOF */
- if (namelist_freed)
- status = HEADER_END_OF_FILE;
- switch (status)
- {
- case HEADER_STILL_UNREAD:
- abort ();
-
- case HEADER_SUCCESS:
-
- /* Valid header. We should decode next field (mode) first.
- Ensure incoming names are null terminated. */
-
- if (! name_match (current_file_name)
- || (newer_mtime_option != TYPE_MINIMUM (time_t)
- /* FIXME: We get mtime now, and again later; this causes
- duplicate diagnostics if header.mtime is bogus. */
- && ((current_stat.st_mtime
- = TIME_FROM_HEADER (current_header->header.mtime))
- < newer_mtime_option))
- || excluded_name (current_file_name))
- {
- switch (current_header->header.typeflag)
- {
- case GNUTYPE_VOLHDR:
- case GNUTYPE_MULTIVOL:
- case GNUTYPE_NAMES:
- break;
-
- case DIRTYPE:
- if (show_omitted_dirs_option)
- WARN ((0, 0, _("%s: Omitting"),
- quotearg_colon (current_file_name)));
- /* Fall through. */
- default:
- skip_member ();
- continue;
- }
- }
-
- (*do_something) ();
- continue;
-
- case HEADER_ZERO_BLOCK:
- if (block_number_option)
- {
- char buf[UINTMAX_STRSIZE_BOUND];
- fprintf (stdlis, _("block %s: ** Block of NULs **\n"),
- STRINGIFY_BIGINT (current_block_ordinal (), buf));
- }
-
- set_next_block_after (current_header);
- status = prev_status;
- if (ignore_zeros_option)
- continue;
- break;
-
- case HEADER_END_OF_FILE:
- if (block_number_option)
- {
- char buf[UINTMAX_STRSIZE_BOUND];
- fprintf (stdlis, _("block %s: ** End of File **\n"),
- STRINGIFY_BIGINT (current_block_ordinal (), buf));
- }
- break;
-
- case HEADER_FAILURE:
- /* If the previous header was good, tell them that we are
- skipping bad ones. */
- set_next_block_after (current_header);
- switch (prev_status)
- {
- case HEADER_STILL_UNREAD:
- ERROR ((0, 0, _("This does not look like a tar archive")));
- /* Fall through. */
-
- case HEADER_ZERO_BLOCK:
- case HEADER_SUCCESS:
- ERROR ((0, 0, _("Skipping to next header")));
- break;
-
- case HEADER_END_OF_FILE:
- case HEADER_FAILURE:
- /* We are in the middle of a cascade of errors. */
- break;
- }
- continue;
- }
- break;
- }
-
- close_archive ();
- names_notfound (); /* print names not found */
-}
-
-/* Print a header block, based on tar options. */
-void
-list_archive (void)
-{
- /* Print the header block. */
-
- if (verbose_option)
- {
- if (verbose_option > 1)
- decode_header (current_header, &current_stat, &current_format, 0);
- print_header ();
- }
-
- if (incremental_option && current_header->header.typeflag == GNUTYPE_DUMPDIR)
- {
- off_t size;
- size_t written, check;
- union block *data_block;
-
- set_next_block_after (current_header);
- if (multi_volume_option)
- {
- assign_string (&save_name, current_file_name);
- save_totsize = current_stat.st_size;
- }
- for (size = current_stat.st_size; size > 0; size -= written)
- {
- if (multi_volume_option)
- save_sizeleft = size;
- data_block = find_next_block ();
- if (!data_block)
- {
- ERROR ((0, 0, _("Unexpected EOF in archive")));
- break; /* FIXME: What happens, then? */
- }
- written = available_space_after (data_block);
- if (written > size)
- written = size;
- errno = 0;
- check = fwrite (data_block->buffer, sizeof (char), written, stdlis);
- set_next_block_after ((union block *)
- (data_block->buffer + written - 1));
- if (check != written)
- {
- write_error_details (current_file_name, check, written);
- skip_file (size - written);
- break;
- }
- }
- if (multi_volume_option)
- assign_string (&save_name, 0);
- fputc ('\n', stdlis);
- fflush (stdlis);
- return;
-
- }
-
- if (multi_volume_option)
- assign_string (&save_name, current_file_name);
-
- skip_member ();
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
-}
-
-/* Read a block that's supposed to be a header block. Return its
- address in "current_header", and if it is good, the file's size in
- current_stat.st_size.
-
- Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
- block full of zeros (EOF marker).
-
- If RAW_EXTENDED_HEADERS is nonzero, do not automagically fold the
- GNU long name and link headers into later headers.
-
- You must always set_next_block_after(current_header) to skip past
- the header which this routine reads. */
-
-/* The standard BSD tar sources create the checksum by adding up the
- bytes in the header as type char. I think the type char was unsigned
- on the PDP-11, but it's signed on the Next and Sun. It looks like the
- sources to BSD tar were never changed to compute the checksum
- correctly, so both the Sun and Next add the bytes of the header as
- signed chars. This doesn't cause a problem until you get a file with
- a name containing characters with the high bit set. So read_header
- computes two checksums -- signed and unsigned. */
-
-enum read_header
-read_header (bool raw_extended_headers)
-{
- size_t i;
- int unsigned_sum; /* the POSIX one :-) */
- int signed_sum; /* the Sun one :-( */
- int recorded_sum;
- uintmax_t parsed_sum;
- char *p;
- union block *header;
- union block *header_copy;
- char *bp;
- union block *data_block;
- size_t size, written;
- union block *next_long_name = 0;
- union block *next_long_link = 0;
- size_t next_long_name_blocks;
- size_t next_long_link_blocks;
-
- while (1)
- {
- header = find_next_block ();
- current_header = header;
- if (!header)
- return HEADER_END_OF_FILE;
-
- unsigned_sum = 0;
- signed_sum = 0;
- p = header->buffer;
- for (i = sizeof *header; i-- != 0;)
- {
- unsigned_sum += (unsigned char) *p;
- signed_sum += (signed char) (*p++);
- }
-
- if (unsigned_sum == 0)
- return HEADER_ZERO_BLOCK;
-
- /* Adjust checksum to count the "chksum" field as blanks. */
-
- for (i = sizeof header->header.chksum; i-- != 0;)
- {
- unsigned_sum -= (unsigned char) header->header.chksum[i];
- signed_sum -= (signed char) (header->header.chksum[i]);
- }
- unsigned_sum += ' ' * sizeof header->header.chksum;
- signed_sum += ' ' * sizeof header->header.chksum;
-
- parsed_sum = from_header (header->header.chksum,
- sizeof header->header.chksum, 0,
- (uintmax_t) 0,
- (uintmax_t) TYPE_MAXIMUM (int));
- if (parsed_sum == (uintmax_t) -1)
- return HEADER_FAILURE;
-
- recorded_sum = parsed_sum;
-
- if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
- return HEADER_FAILURE;
-
- /* Good block. Decode file size and return. */
-
- if (header->header.typeflag == LNKTYPE)
- current_stat.st_size = 0; /* links 0 size on tape */
- else
- current_stat.st_size = OFF_FROM_HEADER (header->header.size);
-
- if (header->header.typeflag == GNUTYPE_LONGNAME
- || header->header.typeflag == GNUTYPE_LONGLINK)
- {
- if (raw_extended_headers)
- return HEADER_SUCCESS_EXTENDED;
- else
- {
- size_t name_size = current_stat.st_size;
- size = name_size - name_size % BLOCKSIZE + 2 * BLOCKSIZE;
- if (name_size != current_stat.st_size || size < name_size)
- xalloc_die ();
- }
-
- header_copy = xmalloc (size + 1);
-
- if (header->header.typeflag == GNUTYPE_LONGNAME)
- {
- if (next_long_name)
- free (next_long_name);
- next_long_name = header_copy;
- next_long_name_blocks = size / BLOCKSIZE;
- }
- else
- {
- if (next_long_link)
- free (next_long_link);
- next_long_link = header_copy;
- next_long_link_blocks = size / BLOCKSIZE;
- }
-
- set_next_block_after (header);
- *header_copy = *header;
- bp = header_copy->buffer + BLOCKSIZE;
-
- for (size -= BLOCKSIZE; size > 0; size -= written)
- {
- data_block = find_next_block ();
- if (! data_block)
- {
- ERROR ((0, 0, _("Unexpected EOF in archive")));
- break;
- }
- written = available_space_after (data_block);
- if (written > size)
- written = size;
-
- memcpy (bp, data_block->buffer, written);
- bp += written;
- set_next_block_after ((union block *)
- (data_block->buffer + written - 1));
- }
-
- *bp = '\0';
-
- /* Loop! */
-
- }
- else
- {
- char const *name;
- struct posix_header const *h = &current_header->header;
- char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
-
- if (recent_long_name)
- free (recent_long_name);
-
- if (next_long_name)
- {
- name = next_long_name->buffer + BLOCKSIZE;
- recent_long_name = next_long_name;
- recent_long_name_blocks = next_long_name_blocks;
- }
- else
- {
- /* Accept file names as specified by POSIX.1-1996
- section 10.1.1. */
- char *np = namebuf;
-
- if (h->prefix[0] && strcmp (h->magic, TMAGIC) == 0)
- {
- memcpy (np, h->prefix, sizeof h->prefix);
- np[sizeof h->prefix] = '\0';
- np += strlen (np);
- *np++ = '/';
-
- /* Prevent later references to current_header from
- mistakenly treating this as an old GNU header.
- This assignment invalidates h->prefix. */
- current_header->oldgnu_header.isextended = 0;
- }
- memcpy (np, h->name, sizeof h->name);
- np[sizeof h->name] = '\0';
- name = namebuf;
- recent_long_name = 0;
- recent_long_name_blocks = 0;
- }
- assign_string (&current_file_name, name);
-
- if (recent_long_link)
- free (recent_long_link);
-
- if (next_long_link)
- {
- name = next_long_link->buffer + BLOCKSIZE;
- recent_long_link = next_long_link;
- recent_long_link_blocks = next_long_link_blocks;
- }
- else
- {
- memcpy (namebuf, h->linkname, sizeof h->linkname);
- namebuf[sizeof h->linkname] = '\0';
- name = namebuf;
- recent_long_link = 0;
- recent_long_link_blocks = 0;
- }
- assign_string (&current_link_name, name);
-
- return HEADER_SUCCESS;
- }
- }
-}
-
-/* Decode things from a file HEADER block into STAT_INFO, also setting
- *FORMAT_POINTER depending on the header block format. If
- DO_USER_GROUP, decode the user/group information (this is useful
- for extraction, but waste time when merely listing).
-
- read_header() has already decoded the checksum and length, so we don't.
-
- This routine should *not* be called twice for the same block, since
- the two calls might use different DO_USER_GROUP values and thus
- might end up with different uid/gid for the two calls. If anybody
- wants the uid/gid they should decode it first, and other callers
- should decode it without uid/gid before calling a routine,
- e.g. print_header, that assumes decoded data. */
-void
-decode_header (union block *header, struct stat *stat_info,
- enum archive_format *format_pointer, int do_user_group)
-{
- enum archive_format format;
-
- if (strcmp (header->header.magic, TMAGIC) == 0)
- format = POSIX_FORMAT;
- else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
- format = OLDGNU_FORMAT;
- else
- format = V7_FORMAT;
- *format_pointer = format;
-
- stat_info->st_mode = MODE_FROM_HEADER (header->header.mode);
- stat_info->st_mtime = TIME_FROM_HEADER (header->header.mtime);
-
- if (format == OLDGNU_FORMAT && incremental_option)
- {
- stat_info->st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime);
- stat_info->st_ctime = TIME_FROM_HEADER (header->oldgnu_header.ctime);
- }
-
- if (format == V7_FORMAT)
- {
- stat_info->st_uid = UID_FROM_HEADER (header->header.uid);
- stat_info->st_gid = GID_FROM_HEADER (header->header.gid);
- stat_info->st_rdev = 0;
- }
- else
- {
- if (do_user_group)
- {
- /* FIXME: Decide if this should somewhat depend on -p. */
-
- if (numeric_owner_option
- || !*header->header.uname
- || !uname_to_uid (header->header.uname, &stat_info->st_uid))
- stat_info->st_uid = UID_FROM_HEADER (header->header.uid);
-
- if (numeric_owner_option
- || !*header->header.gname
- || !gname_to_gid (header->header.gname, &stat_info->st_gid))
- stat_info->st_gid = GID_FROM_HEADER (header->header.gid);
- }
- switch (header->header.typeflag)
- {
- case BLKTYPE:
- stat_info->st_rdev
- = makedev (MAJOR_FROM_HEADER (header->header.devmajor),
- MINOR_FROM_HEADER (header->header.devminor));
- break;
-
- case CHRTYPE:
- stat_info->st_rdev
- = makedev (MAJOR_FROM_HEADER (header->header.devmajor),
- MINOR_FROM_HEADER (header->header.devminor));
- break;
-
- default:
- stat_info->st_rdev = 0;
- }
- }
-}
-
-/* Convert buffer at WHERE0 of size DIGS from external format to
- uintmax_t. The data is of type TYPE. The buffer must represent a
- value in the range -MINUS_MINVAL through MAXVAL. DIGS must be
- positive. Return -1 on error, diagnosing the error if TYPE is
- nonzero. */
-static uintmax_t
-from_header (char const *where0, size_t digs, char const *type,
- uintmax_t minus_minval, uintmax_t maxval)
-{
- uintmax_t value;
- char const *where = where0;
- char const *lim = where + digs;
- int negative = 0;
-
- /* Accommodate buggy tar of unknown vintage, which outputs leading
- NUL if the previous field overflows. */
- where += !*where;
-
- /* Accommodate older tars, which output leading spaces. */
- for (;;)
- {
- if (where == lim)
- {
- if (type)
- ERROR ((0, 0,
- _("Blanks in header where numeric %s value expected"),
- type));
- return -1;
- }
- if (!ISSPACE ((unsigned char) *where))
- break;
- where++;
- }
-
- value = 0;
- if (ISODIGIT (*where))
- {
- char const *where1 = where;
- uintmax_t overflow = 0;
-
- for (;;)
- {
- value += *where++ - '0';
- if (where == lim || ! ISODIGIT (*where))
- break;
- overflow |= value ^ (value << LG_8 >> LG_8);
- value <<= LG_8;
- }
-
- /* Parse the output of older, unportable tars, which generate
- negative values in two's complement octal. If the leading
- nonzero digit is 1, we can't recover the original value
- reliably; so do this only if the digit is 2 or more. This
- catches the common case of 32-bit negative time stamps. */
- if ((overflow || maxval < value) && '2' <= *where1 && type)
- {
- /* Compute the negative of the input value, assuming two's
- complement. */
- int digit = (*where1 - '0') | 4;
- overflow = 0;
- value = 0;
- where = where1;
- for (;;)
- {
- value += 7 - digit;
- where++;
- if (where == lim || ! ISODIGIT (*where))
- break;
- digit = *where - '0';
- overflow |= value ^ (value << LG_8 >> LG_8);
- value <<= LG_8;
- }
- value++;
- overflow |= !value;
-
- if (!overflow && value <= minus_minval)
- {
- WARN ((0, 0,
- _("Archive octal value %.*s is out of %s range; assuming two's complement"),
- (int) (where - where1), where1, type));
- negative = 1;
- }
- }
-
- if (overflow)
- {
- if (type)
- ERROR ((0, 0,
- _("Archive octal value %.*s is out of %s range"),
- (int) (where - where1), where1, type));
- return -1;
- }
- }
- else if (*where == '-' || *where == '+')
- {
- /* Parse base-64 output produced only by tar test versions
- 1.13.6 (1999-08-11) through 1.13.11 (1999-08-23).
- Support for this will be withdrawn in future releases. */
- int dig;
- static int warned_once;
- if (! warned_once)
- {
- warned_once = 1;
- WARN ((0, 0,
- _("Archive contains obsolescent base-64 headers")));
- }
- negative = *where++ == '-';
- while (where != lim
- && (dig = base64_map[(unsigned char) *where]) < 64)
- {
- if (value << LG_64 >> LG_64 != value)
- {
- char *string = alloca (digs + 1);
- memcpy (string, where0, digs);
- string[digs] = '\0';
- if (type)
- ERROR ((0, 0,
- _("Archive signed base-64 string %s is out of %s range"),
- quote (string), type));
- return -1;
- }
- value = (value << LG_64) | dig;
- where++;
- }
- }
- else if (*where == '\200' /* positive base-256 */
- || *where == '\377' /* negative base-256 */)
- {
- /* Parse base-256 output. A nonnegative number N is
- represented as (256**DIGS)/2 + N; a negative number -N is
- represented as (256**DIGS) - N, i.e. as two's complement.
- The representation guarantees that the leading bit is
- always on, so that we don't confuse this format with the
- others (assuming ASCII bytes of 8 bits or more). */
- int signbit = *where & (1 << (LG_256 - 2));
- uintmax_t topbits = (((uintmax_t) - signbit)
- << (CHAR_BIT * sizeof (uintmax_t)
- - LG_256 - (LG_256 - 2)));
- value = (*where++ & ((1 << (LG_256 - 2)) - 1)) - signbit;
- for (;;)
- {
- value = (value << LG_256) + (unsigned char) *where++;
- if (where == lim)
- break;
- if (((value << LG_256 >> LG_256) | topbits) != value)
- {
- if (type)
- ERROR ((0, 0,
- _("Archive base-256 value is out of %s range"),
- type));
- return -1;
- }
- }
- negative = signbit;
- if (negative)
- value = -value;
- }
-
- if (where != lim && *where && !ISSPACE ((unsigned char) *where))
- {
- if (type)
- {
- char buf[1000]; /* Big enough to represent any header. */
- static struct quoting_options *o;
-
- if (!o)
- {
- o = clone_quoting_options (0);
- set_quoting_style (o, locale_quoting_style);
- }
-
- while (where0 != lim && ! lim[-1])
- lim--;
- quotearg_buffer (buf, sizeof buf, where0, lim - where, o);
- ERROR ((0, 0,
- _("Archive contains %.*s where numeric %s value expected"),
- (int) sizeof buf, buf, type));
- }
-
- return -1;
- }
-
- if (value <= (negative ? minus_minval : maxval))
- return negative ? -value : value;
-
- if (type)
- {
- char minval_buf[UINTMAX_STRSIZE_BOUND + 1];
- char maxval_buf[UINTMAX_STRSIZE_BOUND];
- char value_buf[UINTMAX_STRSIZE_BOUND + 1];
- char *minval_string = STRINGIFY_BIGINT (minus_minval, minval_buf + 1);
- char *value_string = STRINGIFY_BIGINT (value, value_buf + 1);
- if (negative)
- *--value_string = '-';
- if (minus_minval)
- *--minval_string = '-';
- ERROR ((0, 0, _("Archive value %s is out of %s range %s..%s"),
- value_string, type,
- minval_string, STRINGIFY_BIGINT (maxval, maxval_buf)));
- }
-
- return -1;
-}
-
-gid_t
-gid_from_header (const char *p, size_t s)
-{
- return from_header (p, s, "gid_t",
- - (uintmax_t) TYPE_MINIMUM (gid_t),
- (uintmax_t) TYPE_MAXIMUM (gid_t));
-}
-
-major_t
-major_from_header (const char *p, size_t s)
-{
- return from_header (p, s, "major_t",
- - (uintmax_t) TYPE_MINIMUM (major_t),
- (uintmax_t) TYPE_MAXIMUM (major_t));
-}
-
-minor_t
-minor_from_header (const char *p, size_t s)
-{
- return from_header (p, s, "minor_t",
- - (uintmax_t) TYPE_MINIMUM (minor_t),
- (uintmax_t) TYPE_MAXIMUM (minor_t));
-}
-
-mode_t
-mode_from_header (const char *p, size_t s)
-{
- /* Do not complain about unrecognized mode bits. */
- unsigned u = from_header (p, s, "mode_t",
- - (uintmax_t) TYPE_MINIMUM (mode_t),
- TYPE_MAXIMUM (uintmax_t));
- return ((u & TSUID ? S_ISUID : 0)
- | (u & TSGID ? S_ISGID : 0)
- | (u & TSVTX ? S_ISVTX : 0)
- | (u & TUREAD ? S_IRUSR : 0)
- | (u & TUWRITE ? S_IWUSR : 0)
- | (u & TUEXEC ? S_IXUSR : 0)
- | (u & TGREAD ? S_IRGRP : 0)
- | (u & TGWRITE ? S_IWGRP : 0)
- | (u & TGEXEC ? S_IXGRP : 0)
- | (u & TOREAD ? S_IROTH : 0)
- | (u & TOWRITE ? S_IWOTH : 0)
- | (u & TOEXEC ? S_IXOTH : 0));
-}
-
-off_t
-off_from_header (const char *p, size_t s)
-{
- /* Negative offsets are not allowed in tar files, so invoke
- from_header with minimum value 0, not TYPE_MINIMUM (off_t). */
- return from_header (p, s, "off_t", (uintmax_t) 0,
- (uintmax_t) TYPE_MAXIMUM (off_t));
-}
-
-size_t
-size_from_header (const char *p, size_t s)
-{
- return from_header (p, s, "size_t", (uintmax_t) 0,
- (uintmax_t) TYPE_MAXIMUM (size_t));
-}
-
-time_t
-time_from_header (const char *p, size_t s)
-{
- return from_header (p, s, "time_t",
- - (uintmax_t) TYPE_MINIMUM (time_t),
- (uintmax_t) TYPE_MAXIMUM (time_t));
-}
-
-uid_t
-uid_from_header (const char *p, size_t s)
-{
- return from_header (p, s, "uid_t",
- - (uintmax_t) TYPE_MINIMUM (uid_t),
- (uintmax_t) TYPE_MAXIMUM (uid_t));
-}
-
-uintmax_t
-uintmax_from_header (const char *p, size_t s)
-{
- return from_header (p, s, "uintmax_t", (uintmax_t) 0,
- TYPE_MAXIMUM (uintmax_t));
-}
-
-
-/* Format O as a null-terminated decimal string into BUF _backwards_;
- return pointer to start of result. */
-char *
-stringify_uintmax_t_backwards (uintmax_t o, char *buf)
-{
- *--buf = '\0';
- do
- *--buf = '0' + (int) (o % 10);
- while ((o /= 10) != 0);
- return buf;
-}
-
-/* Return a printable representation of T. The result points to
- static storage that can be reused in the next call to this
- function, to ctime, or to asctime. */
-char const *
-tartime (time_t t)
-{
-#if !defined(__FreeBSD__) || !defined(HAVE_LANGINFO_CODESET)
- static char buffer[max (UINTMAX_STRSIZE_BOUND + 1,
- INT_STRLEN_BOUND (int) + 16)];
- char *p;
-
-#if USE_OLD_CTIME
- p = ctime (&t);
- if (p)
- {
- char const *time_stamp = p + 4;
- for (p += 16; p[3] != '\n'; p++)
- p[0] = p[3];
- p[0] = '\0';
- return time_stamp;
- }
-#else
- /* Use ISO 8610 format. See:
- http://www.cl.cam.ac.uk/~mgk25/iso-time.html */
- struct tm *tm = localtime (&t);
- if (tm)
- {
- sprintf (buffer, "%04d-%02d-%02d %02d:%02d:%02d",
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
- return buffer;
- }
-#endif
-
- /* The time stamp cannot be broken down, most likely because it
- is out of range. Convert it as an integer,
- right-adjusted in a field with the same width as the usual
- 19-byte 4-year ISO time format. */
- p = stringify_uintmax_t_backwards (t < 0 ? - (uintmax_t) t : (uintmax_t) t,
- buffer + sizeof buffer);
- if (t < 0)
- *--p = '-';
- while (buffer + sizeof buffer - 19 - 1 < p)
- *--p = ' ';
- return p;
-#else /* __FreeBSD__ */
- static char buffer[80];
- static int d_first = -1;
-
- if (d_first < 0)
- d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
- strftime(buffer, sizeof(buffer), d_first ? "%e %b %R %Y" : "%b %e %R %Y",
- localtime(&t));
- return buffer;
-#endif /* __FreeBSD__ */
-}
-
-/* Actually print it.
-
- Plain and fancy file header block logging. Non-verbose just prints
- the name, e.g. for "tar t" or "tar x". This should just contain
- file names, so it can be fed back into tar with xargs or the "-T"
- option. The verbose option can give a bunch of info, one line per
- file. I doubt anybody tries to parse its format, or if they do,
- they shouldn't. Unix tar is pretty random here anyway. */
-
-
-/* FIXME: Note that print_header uses the globals HEAD, HSTAT, and
- HEAD_STANDARD, which must be set up in advance. Not very clean... */
-
-/* UGSWIDTH starts with 18, so with user and group names <= 8 chars, the
- columns never shift during the listing. */
-#define UGSWIDTH 18
-static int ugswidth = UGSWIDTH; /* maximum width encountered so far */
-
-/* DATEWIDTH is the number of columns taken by the date and time fields. */
-#if USE_OLD_CDATE
-# define DATEWIDTH 19
-#else
-# define DATEWIDTH 18
-#endif
-
-void
-print_header (void)
-{
- char modes[11];
- char const *time_stamp;
- /* These hold formatted ints. */
- char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND];
- char *user, *group;
- char size[2 * UINTMAX_STRSIZE_BOUND];
- /* holds formatted size or major,minor */
- char uintbuf[UINTMAX_STRSIZE_BOUND];
- int pad;
-
- if (block_number_option)
- {
- char buf[UINTMAX_STRSIZE_BOUND];
- fprintf (stdlis, _("block %s: "),
- STRINGIFY_BIGINT (current_block_ordinal (), buf));
- }
-
- if (verbose_option <= 1)
- {
- /* Just the fax, mam. */
- fprintf (stdlis, "%s\n", quotearg (current_file_name));
- }
- else
- {
- /* File type and modes. */
-
- modes[0] = '?';
- switch (current_header->header.typeflag)
- {
- case GNUTYPE_VOLHDR:
- modes[0] = 'V';
- break;
-
- case GNUTYPE_MULTIVOL:
- modes[0] = 'M';
- break;
-
- case GNUTYPE_NAMES:
- modes[0] = 'N';
- break;
-
- case GNUTYPE_LONGNAME:
- case GNUTYPE_LONGLINK:
- ERROR ((0, 0, _("Visible longname error")));
- break;
-
- case GNUTYPE_SPARSE:
- case REGTYPE:
- case AREGTYPE:
- case LNKTYPE:
- modes[0] = '-';
- if (current_file_name[strlen (current_file_name) - 1] == '/')
- modes[0] = 'd';
- break;
- case GNUTYPE_DUMPDIR:
- modes[0] = 'd';
- break;
- case DIRTYPE:
- modes[0] = 'd';
- break;
- case SYMTYPE:
- modes[0] = 'l';
- break;
- case BLKTYPE:
- modes[0] = 'b';
- break;
- case CHRTYPE:
- modes[0] = 'c';
- break;
- case FIFOTYPE:
- modes[0] = 'p';
- break;
- case CONTTYPE:
- modes[0] = 'C';
- break;
- }
-
- decode_mode (current_stat.st_mode, modes + 1);
-
- /* Time stamp. */
-
- time_stamp = tartime (current_stat.st_mtime);
-
- /* User and group names. */
-
- if (*current_header->header.uname && current_format != V7_FORMAT
- && !numeric_owner_option)
- user = current_header->header.uname;
- else
- {
- /* Try parsing it as an unsigned integer first, and as a
- uid_t if that fails. This method can list positive user
- ids that are too large to fit in a uid_t. */
- uintmax_t u = from_header (current_header->header.uid,
- sizeof current_header->header.uid, 0,
- (uintmax_t) 0,
- (uintmax_t) TYPE_MAXIMUM (uintmax_t));
- if (u != -1)
- user = STRINGIFY_BIGINT (u, uform);
- else
- {
- sprintf (uform, "%ld",
- (long) UID_FROM_HEADER (current_header->header.uid));
- user = uform;
- }
- }
-
- if (*current_header->header.gname && current_format != V7_FORMAT
- && !numeric_owner_option)
- group = current_header->header.gname;
- else
- {
- /* Try parsing it as an unsigned integer first, and as a
- gid_t if that fails. This method can list positive group
- ids that are too large to fit in a gid_t. */
- uintmax_t g = from_header (current_header->header.gid,
- sizeof current_header->header.gid, 0,
- (uintmax_t) 0,
- (uintmax_t) TYPE_MAXIMUM (uintmax_t));
- if (g != -1)
- group = STRINGIFY_BIGINT (g, gform);
- else
- {
- sprintf (gform, "%ld",
- (long) GID_FROM_HEADER (current_header->header.gid));
- group = gform;
- }
- }
-
- /* Format the file size or major/minor device numbers. */
-
- switch (current_header->header.typeflag)
- {
- case CHRTYPE:
- case BLKTYPE:
- strcpy (size,
- STRINGIFY_BIGINT (major (current_stat.st_rdev), uintbuf));
- strcat (size, ",");
- strcat (size,
- STRINGIFY_BIGINT (minor (current_stat.st_rdev), uintbuf));
- break;
- case GNUTYPE_SPARSE:
- strcpy (size,
- STRINGIFY_BIGINT
- (UINTMAX_FROM_HEADER (current_header
- ->oldgnu_header.realsize),
- uintbuf));
- break;
- default:
- strcpy (size, STRINGIFY_BIGINT (current_stat.st_size, uintbuf));
- break;
- }
-
- /* Figure out padding and print the whole line. */
-
- pad = strlen (user) + strlen (group) + strlen (size) + 1;
- if (pad > ugswidth)
- ugswidth = pad;
-
- fprintf (stdlis, "%s %s/%s %*s%s %s",
- modes, user, group, ugswidth - pad, "", size, time_stamp);
-
- fprintf (stdlis, " %s", quotearg (current_file_name));
-
- switch (current_header->header.typeflag)
- {
- case SYMTYPE:
- fprintf (stdlis, " -> %s\n", quotearg (current_link_name));
- break;
-
- case LNKTYPE:
- fprintf (stdlis, _(" link to %s\n"), quotearg (current_link_name));
- break;
-
- default:
- {
- char type_string[2];
- type_string[0] = current_header->header.typeflag;
- type_string[1] = '\0';
- fprintf (stdlis, _(" unknown file type %s\n"),
- quote (type_string));
- }
- break;
-
- case AREGTYPE:
- case REGTYPE:
- case GNUTYPE_SPARSE:
- case CHRTYPE:
- case BLKTYPE:
- case DIRTYPE:
- case FIFOTYPE:
- case CONTTYPE:
- case GNUTYPE_DUMPDIR:
- putc ('\n', stdlis);
- break;
-
- case GNUTYPE_VOLHDR:
- fprintf (stdlis, _("--Volume Header--\n"));
- break;
-
- case GNUTYPE_MULTIVOL:
- strcpy (size,
- STRINGIFY_BIGINT
- (UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset),
- uintbuf));
- fprintf (stdlis, _("--Continued at byte %s--\n"), size);
- break;
-
- case GNUTYPE_NAMES:
- fprintf (stdlis, _("--Mangled file names--\n"));
- break;
- }
- }
- fflush (stdlis);
-}
-
-/* Print a similar line when we make a directory automatically. */
-void
-print_for_mkdir (char *pathname, int length, mode_t mode)
-{
- char modes[11];
-
- if (verbose_option > 1)
- {
- /* File type and modes. */
-
- modes[0] = 'd';
- decode_mode (mode, modes + 1);
-
- if (block_number_option)
- {
- char buf[UINTMAX_STRSIZE_BOUND];
- fprintf (stdlis, _("block %s: "),
- STRINGIFY_BIGINT (current_block_ordinal (), buf));
- }
-
- fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
- _("Creating directory:"), length, quotearg (pathname));
- }
-}
-
-/* Skip over SIZE bytes of data in blocks in the archive. */
-void
-skip_file (off_t size)
-{
- union block *x;
-
- if (multi_volume_option)
- {
- save_totsize = size;
- save_sizeleft = size;
- }
-
- while (size > 0)
- {
- x = find_next_block ();
- if (! x)
- FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
-
- set_next_block_after (x);
- size -= BLOCKSIZE;
- if (multi_volume_option)
- save_sizeleft -= BLOCKSIZE;
- }
-}
-
-/* Skip the current member in the archive. */
-void
-skip_member (void)
-{
- char save_typeflag = current_header->header.typeflag;
- set_next_block_after (current_header);
-
- if (current_header->oldgnu_header.isextended)
- {
- union block *exhdr;
- do
- {
- exhdr = find_next_block ();
- if (!exhdr)
- FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
- set_next_block_after (exhdr);
- }
- while (exhdr->sparse_header.isextended);
- }
-
- if (save_typeflag != DIRTYPE)
- skip_file (current_stat.st_size);
-}
diff --git a/contrib/tar/src/mangle.c b/contrib/tar/src/mangle.c
deleted file mode 100644
index 204bf7c..0000000
--- a/contrib/tar/src/mangle.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* Encode long filenames for GNU tar.
- Copyright 1988, 92, 94, 96, 97, 99, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "system.h"
-#include "common.h"
-#include <quotearg.h>
-
-struct mangled
- {
- struct mangled *next;
- int type;
- char mangled[NAME_FIELD_SIZE];
- char *linked_to;
- char normal[1];
- };
-
-/* Extract a GNUTYPE_NAMES record contents. It seems that such are
- not produced anymore by GNU tar, but we leave the reading code
- around nevertheless, for salvaging old tapes. */
-void
-extract_mangle (void)
-{
- off_t size = current_stat.st_size;
- char *buffer = xmalloc ((size_t) (size + 1));
- char *copy = buffer;
- char *cursor = buffer;
-
- if (size != (size_t) size || size == (size_t) -1)
- xalloc_die ();
-
- buffer[size] = '\0';
-
- while (size > 0)
- {
- union block *block = find_next_block ();
- size_t available;
-
- if (!block)
- {
- ERROR ((0, 0, _("Unexpected EOF in mangled names")));
- return;
- }
- available = available_space_after (block);
- if (available > size)
- available = size;
- memcpy (copy, block->buffer, available);
- copy += available;
- size -= available;
- set_next_block_after ((union block *) (block->buffer + available - 1));
- }
-
- while (*cursor)
- {
- char *next_cursor;
- char *name;
- char *name_end;
-
- next_cursor = strchr (cursor, '\n');
- *next_cursor++ = '\0';
-
- if (!strncmp (cursor, "Rename ", 7))
- {
-
- name = cursor + 7;
- name_end = strchr (name, ' ');
- while (strncmp (name_end, " to ", 4))
- {
- name_end++;
- name_end = strchr (name_end, ' ');
- }
- *name_end = '\0';
- if (next_cursor[-2] == '/')
- next_cursor[-2] = '\0';
- unquote_string (name_end + 4);
- if (rename (name, name_end + 4))
- ERROR ((0, errno, _("%s: Cannot rename to %s"),
- quotearg_colon (name), quote_n (1, name_end + 4)));
- else if (verbose_option)
- WARN ((0, 0, _("Renamed %s to %s"), name, name_end + 4));
- }
-#ifdef HAVE_SYMLINK
- else if (!strncmp (cursor, "Symlink ", 8))
- {
- name = cursor + 8;
- name_end = strchr (name, ' ');
- while (strncmp (name_end, " to ", 4))
- {
- name_end++;
- name_end = strchr (name_end, ' ');
- }
- *name_end = '\0';
- unquote_string (name);
- unquote_string (name_end + 4);
- if (symlink (name, name_end + 4)
- && (unlink (name_end + 4) || symlink (name, name_end + 4)))
- ERROR ((0, errno, _("%s: Cannot symlink to %s"),
- quotearg_colon (name), quote_n (1, name_end + 4)));
- else if (verbose_option)
- WARN ((0, 0, _("Symlinked %s to %s"), name, name_end + 4));
- }
-#endif
- else
- ERROR ((0, 0, _("Unknown demangling command %s"), cursor));
-
- cursor = next_cursor;
- }
-}
diff --git a/contrib/tar/src/misc.c b/contrib/tar/src/misc.c
deleted file mode 100644
index 8ece9c6..0000000
--- a/contrib/tar/src/misc.c
+++ /dev/null
@@ -1,854 +0,0 @@
-/* Miscellaneous functions, not really specific to GNU tar.
-
- Copyright 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001 Free
- Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* $FreeBSD$ */
-
-#include "system.h"
-#include "rmt.h"
-#include "common.h"
-#include <quotearg.h>
-#include <save-cwd.h>
-
-static void call_arg_fatal PARAMS ((char const *, char const *))
- __attribute__ ((noreturn));
-
-/* Handling strings. */
-
-/* Assign STRING to a copy of VALUE if not zero, or to zero. If
- STRING was nonzero, it is freed first. */
-void
-assign_string (char **string, const char *value)
-{
- if (*string)
- free (*string);
- *string = value ? xstrdup (value) : 0;
-}
-
-/* Allocate a copy of the string quoted as in C, and returns that. If
- the string does not have to be quoted, it returns a null pointer.
- The allocated copy should normally be freed with free() after the
- caller is done with it.
-
- This is used in one context only: generating the directory file in
- incremental dumps. The quoted string is not intended for human
- consumption; it is intended only for unquote_string. The quoting
- is locale-independent, so that users needn't worry about locale
- when reading directory files. This means that we can't use
- quotearg, as quotearg is locale-dependent and is meant for human
- consumption. */
-char *
-quote_copy_string (const char *string)
-{
- const char *source = string;
- char *destination = 0;
- char *buffer = 0;
- int copying = 0;
-
- while (*source)
- {
- int character = *source++;
-
- switch (character)
- {
- case '\n': case '\\':
- if (!copying)
- {
- size_t length = (source - string) - 1;
-
- copying = 1;
- buffer = xmalloc (length + 2 + 2 * strlen (source) + 1);
- memcpy (buffer, string, length);
- destination = buffer + length;
- }
- *destination++ = '\\';
- *destination++ = character == '\\' ? '\\' : 'n';
- break;
-
- default:
- if (copying)
- *destination++ = character;
- break;
- }
- }
- if (copying)
- {
- *destination = '\0';
- return buffer;
- }
- return 0;
-}
-
-/* Takes a quoted C string (like those produced by quote_copy_string)
- and turns it back into the un-quoted original. This is done in
- place. Returns 0 only if the string was not properly quoted, but
- completes the unquoting anyway.
-
- This is used for reading the saved directory file in incremental
- dumps. It is used for decoding old `N' records (demangling names).
- But also, it is used for decoding file arguments, would they come
- from the shell or a -T file, and for decoding the --exclude
- argument. */
-int
-unquote_string (char *string)
-{
- int result = 1;
- char *source = string;
- char *destination = string;
-
- /* Escape sequences other than \\ and \n are no longer generated by
- quote_copy_string, but accept them for backwards compatibility,
- and also because unquote_string is used for purposes other than
- parsing the output of quote_copy_string. */
-
- while (*source)
- if (*source == '\\')
- switch (*++source)
- {
- case '\\':
- *destination++ = '\\';
- source++;
- break;
-
- case 'n':
- *destination++ = '\n';
- source++;
- break;
-
- case 't':
- *destination++ = '\t';
- source++;
- break;
-
- case 'f':
- *destination++ = '\f';
- source++;
- break;
-
- case 'b':
- *destination++ = '\b';
- source++;
- break;
-
- case 'r':
- *destination++ = '\r';
- source++;
- break;
-
- case '?':
- *destination++ = 0177;
- source++;
- break;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- {
- int value = *source++ - '0';
-
- if (*source < '0' || *source > '7')
- {
- *destination++ = value;
- break;
- }
- value = value * 8 + *source++ - '0';
- if (*source < '0' || *source > '7')
- {
- *destination++ = value;
- break;
- }
- value = value * 8 + *source++ - '0';
- *destination++ = value;
- break;
- }
-
- default:
- result = 0;
- *destination++ = '\\';
- if (*source)
- *destination++ = *source++;
- break;
- }
- else if (source != destination)
- *destination++ = *source++;
- else
- source++, destination++;
-
- if (source != destination)
- *destination = '\0';
- return result;
-}
-
-/* Return nonzero if NAME contains ".." as a path name component. */
-int
-contains_dot_dot (char const *name)
-{
- char const *p = name + FILESYSTEM_PREFIX_LEN (name);
-
- for (;;)
- {
- if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
- return 1;
-
- do
- {
- if (! *p++)
- return 0;
- }
- while (! ISSLASH (*p));
-
- do
- {
- if (! *p++)
- return 0;
- }
- while ( ISSLASH (*p));
- }
-}
-
-/* File handling. */
-
-/* Saved names in case backup needs to be undone. */
-static char *before_backup_name;
-static char *after_backup_name;
-
-/* Some implementations of rmdir let you remove the working directory.
- Report an error with errno set to zero for obvious cases of this;
- otherwise call rmdir. */
-static int
-safer_rmdir (const char *path)
-{
- while (path[0] == '.' && ISSLASH (path[1]))
- {
- path++;
-
- do path++;
- while (ISSLASH (*path));
- }
-
- if (! path[0] || (path[0] == '.' && ! path[1]))
- {
- errno = 0;
- return -1;
- }
-
- return rmdir (path);
-}
-
-/* Remove PATH. If PATH is a directory, then if RECURSE is set remove
- it recursively; otherwise, remove it only if it is empty. Return 0
- on error, with errno set; if PATH is obviously the working
- directory return zero with errno set to zero. */
-int
-remove_any_file (const char *path, int recurse)
-{
- /* Try unlink first if we are not root, as this saves us a system
- call in the common case where we're removing a non-directory. */
- if (! we_are_root)
- {
- if (unlink (path) == 0)
- return 1;
- if (errno != EPERM)
- return 0;
- }
-
- if (safer_rmdir (path) == 0)
- return 1;
-
- switch (errno)
- {
- case ENOTDIR:
- return we_are_root && unlink (path) == 0;
-
- case 0:
- case EEXIST:
-#if defined ENOTEMPTY && ENOTEMPTY != EEXIST
- case ENOTEMPTY:
-#endif
- if (recurse)
- {
- char *directory = savedir (path);
- char const *entry;
- size_t entrylen;
-
- if (! directory)
- return 0;
-
- for (entry = directory;
- (entrylen = strlen (entry)) != 0;
- entry += entrylen + 1)
- {
- char *path_buffer = new_name (path, entry);
- int r = remove_any_file (path_buffer, 1);
- int e = errno;
- free (path_buffer);
-
- if (! r)
- {
- free (directory);
- errno = e;
- return 0;
- }
- }
-
- free (directory);
- return safer_rmdir (path) == 0;
- }
- break;
- }
-
- return 0;
-}
-
-/* Check if PATH already exists and make a backup of it right now.
- Return success (nonzero) only if the backup in either unneeded, or
- successful. For now, directories are considered to never need
- backup. If ARCHIVE is nonzero, this is the archive and so, we do
- not have to backup block or character devices, nor remote entities. */
-int
-maybe_backup_file (const char *path, int archive)
-{
- struct stat file_stat;
-
- /* Check if we really need to backup the file. */
-
- if (archive && _remdev (path))
- return 1;
-
- if (stat (path, &file_stat))
- {
- if (errno == ENOENT)
- return 1;
-
- stat_error (path);
- return 0;
- }
-
- if (S_ISDIR (file_stat.st_mode))
- return 1;
-
- if (archive && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
- return 1;
-
- assign_string (&before_backup_name, path);
-
- /* A run situation may exist between Emacs or other GNU programs trying to
- make a backup for the same file simultaneously. If theoretically
- possible, real problems are unlikely. Doing any better would require a
- convention, GNU-wide, for all programs doing backups. */
-
- assign_string (&after_backup_name, 0);
- after_backup_name = find_backup_file_name (path, backup_type);
- if (! after_backup_name)
- xalloc_die ();
-
- if (rename (before_backup_name, after_backup_name) == 0)
- {
- if (verbose_option)
- fprintf (stdlis, _("Renaming %s to %s\n"),
- quote_n (0, before_backup_name),
- quote_n (1, after_backup_name));
- return 1;
- }
- else
- {
- /* The backup operation failed. */
- int e = errno;
- ERROR ((0, e, _("%s: Cannot rename to %s"),
- quotearg_colon (before_backup_name),
- quote_n (1, after_backup_name)));
- assign_string (&after_backup_name, 0);
- return 0;
- }
-}
-
-/* Try to restore the recently backed up file to its original name.
- This is usually only needed after a failed extraction. */
-void
-undo_last_backup (void)
-{
- if (after_backup_name)
- {
- if (rename (after_backup_name, before_backup_name) != 0)
- {
- int e = errno;
- ERROR ((0, e, _("%s: Cannot rename to %s"),
- quotearg_colon (after_backup_name),
- quote_n (1, before_backup_name)));
- }
- if (verbose_option)
- fprintf (stdlis, _("Renaming %s back to %s\n"),
- quote_n (0, after_backup_name),
- quote_n (1, before_backup_name));
- assign_string (&after_backup_name, 0);
- }
-}
-
-/* Depending on DEREF, apply either stat or lstat to (NAME, BUF). */
-int
-deref_stat (int deref, char const *name, struct stat *buf)
-{
- return deref ? stat (name, buf) : lstat (name, buf);
-}
-
-/* A description of a working directory. */
-struct wd
-{
- char const *name;
- int saved;
- struct saved_cwd saved_cwd;
-};
-
-/* A vector of chdir targets. wd[0] is the initial working directory. */
-static struct wd *wd;
-
-/* The number of working directories in the vector. */
-static size_t wds;
-
-/* The allocated size of the vector. */
-static size_t wd_alloc;
-
-/* DIR is the operand of a -C option; add it to vector of chdir targets,
- and return the index of its location. */
-int
-chdir_arg (char const *dir)
-{
- if (wds == wd_alloc)
- {
- wd_alloc = 2 * (wd_alloc + 1);
- wd = xrealloc (wd, sizeof *wd * wd_alloc);
- if (! wds)
- {
- wd[wds].name = ".";
- wd[wds].saved = 0;
- wds++;
- }
- }
-
- /* Optimize the common special case of the working directory,
- or the working directory as a prefix. */
- if (dir[0])
- {
- while (dir[0] == '.' && ISSLASH (dir[1]))
- for (dir += 2; ISSLASH (*dir); dir++)
- continue;
- if (! dir[dir[0] == '.'])
- return wds - 1;
- }
-
- wd[wds].name = dir;
- wd[wds].saved = 0;
- return wds++;
-}
-
-/* Change to directory I. If I is 0, change to the initial working
- directory; otherwise, I must be a value returned by chdir_arg. */
-void
-chdir_do (int i)
-{
- static int previous;
-
- if (previous != i)
- {
- struct wd *prev = &wd[previous];
- struct wd *curr = &wd[i];
-
- if (! prev->saved)
- {
- prev->saved = 1;
- if (save_cwd (&prev->saved_cwd) != 0)
- FATAL_ERROR ((0, 0, _("Cannot save working directory")));
- }
-
- if (curr->saved)
- {
- if (restore_cwd (&curr->saved_cwd, curr->name, prev->name))
- FATAL_ERROR ((0, 0, _("Cannot change working directory")));
- }
- else
- {
- if (i && ! ISSLASH (curr->name[0]))
- chdir_do (i - 1);
- if (chdir (curr->name) != 0)
- chdir_fatal (curr->name);
- }
-
- previous = i;
- }
-}
-
-/* Decode MODE from its binary form in a stat structure, and encode it
- into a 9-byte string STRING, terminated with a NUL. */
-
-void
-decode_mode (mode_t mode, char *string)
-{
- *string++ = mode & S_IRUSR ? 'r' : '-';
- *string++ = mode & S_IWUSR ? 'w' : '-';
- *string++ = (mode & S_ISUID
- ? (mode & S_IXUSR ? 's' : 'S')
- : (mode & S_IXUSR ? 'x' : '-'));
- *string++ = mode & S_IRGRP ? 'r' : '-';
- *string++ = mode & S_IWGRP ? 'w' : '-';
- *string++ = (mode & S_ISGID
- ? (mode & S_IXGRP ? 's' : 'S')
- : (mode & S_IXGRP ? 'x' : '-'));
- *string++ = mode & S_IROTH ? 'r' : '-';
- *string++ = mode & S_IWOTH ? 'w' : '-';
- *string++ = (mode & S_ISVTX
- ? (mode & S_IXOTH ? 't' : 'T')
- : (mode & S_IXOTH ? 'x' : '-'));
- *string = '\0';
-}
-
-/* Report an error associated with the system call CALL and the
- optional name NAME. */
-static void
-call_arg_error (char const *call, char const *name)
-{
- int e = errno;
- ERROR ((0, e, _("%s: Cannot %s"), quotearg_colon (name), call));
-}
-
-/* Report a fatal error associated with the system call CALL and
- the optional file name NAME. */
-static void
-call_arg_fatal (char const *call, char const *name)
-{
- int e = errno;
- FATAL_ERROR ((0, e, _("%s: Cannot %s"), quotearg_colon (name), call));
-}
-
-/* Report a warning associated with the system call CALL and
- the optional file name NAME. */
-static void
-call_arg_warn (char const *call, char const *name)
-{
- int e = errno;
- WARN ((0, e, _("%s: Warning: Cannot %s"), quotearg_colon (name), call));
-}
-
-void
-chdir_fatal (char const *name)
-{
- call_arg_fatal ("chdir", name);
-}
-
-void
-chmod_error_details (char const *name, mode_t mode)
-{
- int e = errno;
- ERROR ((0, e, _("%s: Cannot change mode to 0%o"),
- quotearg_colon (name), mode));
-}
-
-void
-chown_error_details (char const *name, uid_t uid, gid_t gid)
-{
- int e = errno;
- ERROR ((0, e, _("%s: Cannot change ownership to uid %lu, gid %lu"),
- quotearg_colon (name), (unsigned long) uid, (unsigned long) gid));
-}
-
-void
-close_error (char const *name)
-{
- call_arg_error ("close", name);
-}
-
-void
-close_fatal (char const *name)
-{
- call_arg_fatal ("close", name);
-}
-
-void
-close_warn (char const *name)
-{
- call_arg_warn ("close", name);
-}
-
-void
-exec_fatal (char const *name)
-{
- call_arg_fatal ("exec", name);
-}
-
-void
-link_error (char const *target, char const *source)
-{
- int e = errno;
- ERROR ((0, e, _("%s: Cannot hard link to %s"),
- quotearg_colon (source), quote_n (1, target)));
-}
-
-void
-mkdir_error (char const *name)
-{
- call_arg_error ("mkdir", name);
-}
-
-void
-mkfifo_error (char const *name)
-{
- call_arg_error ("mkfifo", name);
-}
-
-void
-mknod_error (char const *name)
-{
- call_arg_error ("mknod", name);
-}
-
-void
-open_error (char const *name)
-{
- call_arg_error ("open", name);
-}
-
-void
-open_fatal (char const *name)
-{
- call_arg_fatal ("open", name);
-}
-
-void
-open_warn (char const *name)
-{
- call_arg_warn ("open", name);
-}
-
-void
-read_error (char const *name)
-{
- call_arg_error ("read", name);
-}
-
-void
-read_error_details (char const *name, off_t offset, size_t size)
-{
- char buf[UINTMAX_STRSIZE_BOUND];
- int e = errno;
- ERROR ((0, e,
- _("%s: Read error at byte %s, reading %lu bytes"),
- quotearg_colon (name), STRINGIFY_BIGINT (offset, buf),
- (unsigned long) size));
-}
-
-void
-read_warn_details (char const *name, off_t offset, size_t size)
-{
- char buf[UINTMAX_STRSIZE_BOUND];
- int e = errno;
- WARN ((0, e,
- _("%s: Warning: Read error at byte %s, reading %lu bytes"),
- quotearg_colon (name), STRINGIFY_BIGINT (offset, buf),
- (unsigned long) size));
-}
-
-void
-read_fatal (char const *name)
-{
- call_arg_fatal ("read", name);
-}
-
-void
-read_fatal_details (char const *name, off_t offset, size_t size)
-{
- char buf[UINTMAX_STRSIZE_BOUND];
- int e = errno;
- FATAL_ERROR ((0, e,
- _("%s: Read error at byte %s, reading %lu bytes"),
- quotearg_colon (name), STRINGIFY_BIGINT (offset, buf),
- (unsigned long) size));
-}
-
-void
-readlink_error (char const *name)
-{
- call_arg_error ("readlink", name);
-}
-
-void
-readlink_warn (char const *name)
-{
- call_arg_warn ("readlink", name);
-}
-
-void
-savedir_error (char const *name)
-{
- call_arg_error ("savedir", name);
-}
-
-void
-savedir_warn (char const *name)
-{
- call_arg_warn ("savedir", name);
-}
-
-void
-seek_error (char const *name)
-{
- call_arg_error ("seek", name);
-}
-
-void
-seek_error_details (char const *name, off_t offset)
-{
- char buf[UINTMAX_STRSIZE_BOUND];
- int e = errno;
- ERROR ((0, e, _("%s: Cannot seek to %s"),
- quotearg_colon (name),
- STRINGIFY_BIGINT (offset, buf)));
-}
-
-void
-seek_warn (char const *name)
-{
- call_arg_warn ("seek", name);
-}
-
-void
-seek_warn_details (char const *name, off_t offset)
-{
- char buf[UINTMAX_STRSIZE_BOUND];
- int e = errno;
- WARN ((0, e, _("%s: Warning: Cannot seek to %s"),
- quotearg_colon (name),
- STRINGIFY_BIGINT (offset, buf)));
-}
-
-void
-symlink_error (char const *contents, char const *name)
-{
- int e = errno;
- ERROR ((0, e, _("%s: Cannot create symlink to %s"),
- quotearg_colon (name), quote_n (1, contents)));
-}
-
-void
-stat_error (char const *name)
-{
- call_arg_error ("stat", name);
-}
-
-void
-stat_warn (char const *name)
-{
- call_arg_warn ("stat", name);
-}
-
-void
-truncate_error (char const *name)
-{
- call_arg_error ("truncate", name);
-}
-
-void
-truncate_warn (char const *name)
-{
- call_arg_warn ("truncate", name);
-}
-
-void
-unlink_error (char const *name)
-{
- call_arg_error ("unlink", name);
-}
-
-void
-utime_error (char const *name)
-{
- call_arg_error ("utime", name);
-}
-
-void
-waitpid_error (char const *name)
-{
- call_arg_error ("waitpid", name);
-}
-
-void
-write_error (char const *name)
-{
- call_arg_error ("write", name);
-}
-
-void
-write_error_details (char const *name, ssize_t status, size_t size)
-{
- if (status < 0)
- write_error (name);
- else
- ERROR ((0, 0, _("%s: Wrote only %lu of %lu bytes"),
- name, (unsigned long) status, (unsigned long) record_size));
-}
-
-void
-write_fatal (char const *name)
-{
- call_arg_fatal ("write", name);
-}
-
-void
-write_fatal_details (char const *name, ssize_t status, size_t size)
-{
- write_error_details (name, status, size);
- fatal_exit ();
-}
-
-
-/* Fork, aborting if unsuccessful. */
-pid_t
-xfork (void)
-{
- pid_t p = fork ();
- if (p == (pid_t) -1)
- call_arg_fatal ("fork", _("child process"));
- return p;
-}
-
-/* Create a pipe, aborting if unsuccessful. */
-void
-xpipe (int fd[2])
-{
- if (pipe (fd) < 0)
- call_arg_fatal ("pipe", _("interprocess channel"));
-}
-
-/* Return an unambiguous printable representation, allocated in slot N,
- for NAME, suitable for diagnostics. */
-char const *
-quote_n (int n, char const *name)
-{
- return quotearg_n_style (n, locale_quoting_style, name);
-}
-
-/* Return an unambiguous printable representation of NAME, suitable
- for diagnostics. */
-char const *
-quote (char const *name)
-{
- return quote_n (0, name);
-}
diff --git a/contrib/tar/src/names.c b/contrib/tar/src/names.c
deleted file mode 100644
index 2642515..0000000
--- a/contrib/tar/src/names.c
+++ /dev/null
@@ -1,976 +0,0 @@
-/* Various processing of names.
-
- Copyright 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001 Free
- Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* $FreeBSD$ */
-
-#include "system.h"
-
-#include <fnmatch.h>
-#include <grp.h>
-#include <hash.h>
-#include <pwd.h>
-#include <quotearg.h>
-
-#include "common.h"
-
-/* User and group names. */
-
-struct group *getgrnam ();
-struct passwd *getpwnam ();
-#if ! HAVE_DECL_GETPWUID
-struct passwd *getpwuid ();
-#endif
-#if ! HAVE_DECL_GETGRGID
-struct group *getgrgid ();
-#endif
-
-/* Make sure you link with the proper libraries if you are running the
- Yellow Peril (thanks for the good laugh, Ian J.!), or, euh... NIS.
- This code should also be modified for non-UNIX systems to do something
- reasonable. */
-
-static char cached_uname[UNAME_FIELD_SIZE];
-static char cached_gname[GNAME_FIELD_SIZE];
-
-static uid_t cached_uid; /* valid only if cached_uname is not empty */
-static gid_t cached_gid; /* valid only if cached_gname is not empty */
-
-/* These variables are valid only if nonempty. */
-static char cached_no_such_uname[UNAME_FIELD_SIZE];
-static char cached_no_such_gname[GNAME_FIELD_SIZE];
-
-/* These variables are valid only if nonzero. It's not worth optimizing
- the case for weird systems where 0 is not a valid uid or gid. */
-static uid_t cached_no_such_uid;
-static gid_t cached_no_such_gid;
-
-/* Given UID, find the corresponding UNAME. */
-void
-uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
-{
- struct passwd *passwd;
-
- if (uid != 0 && uid == cached_no_such_uid)
- {
- *uname = '\0';
- return;
- }
-
- if (!cached_uname[0] || uid != cached_uid)
- {
- passwd = getpwuid (uid);
- if (passwd)
- {
- cached_uid = uid;
- strncpy (cached_uname, passwd->pw_name, UNAME_FIELD_SIZE);
- }
- else
- {
- cached_no_such_uid = uid;
- *uname = '\0';
- return;
- }
- }
- strncpy (uname, cached_uname, UNAME_FIELD_SIZE);
-}
-
-/* Given GID, find the corresponding GNAME. */
-void
-gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
-{
- struct group *group;
-
- if (gid != 0 && gid == cached_no_such_gid)
- {
- *gname = '\0';
- return;
- }
-
- if (!cached_gname[0] || gid != cached_gid)
- {
- group = getgrgid (gid);
- if (group)
- {
- cached_gid = gid;
- strncpy (cached_gname, group->gr_name, GNAME_FIELD_SIZE);
- }
- else
- {
- cached_no_such_gid = gid;
- *gname = '\0';
- return;
- }
- }
- strncpy (gname, cached_gname, GNAME_FIELD_SIZE);
-}
-
-/* Given UNAME, set the corresponding UID and return 1, or else, return 0. */
-int
-uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
-{
- struct passwd *passwd;
-
- if (cached_no_such_uname[0]
- && strncmp (uname, cached_no_such_uname, UNAME_FIELD_SIZE) == 0)
- return 0;
-
- if (!cached_uname[0]
- || uname[0] != cached_uname[0]
- || strncmp (uname, cached_uname, UNAME_FIELD_SIZE) != 0)
- {
- passwd = getpwnam (uname);
- if (passwd)
- {
- cached_uid = passwd->pw_uid;
- strncpy (cached_uname, uname, UNAME_FIELD_SIZE);
- }
- else
- {
- strncpy (cached_no_such_uname, uname, UNAME_FIELD_SIZE);
- return 0;
- }
- }
- *uidp = cached_uid;
- return 1;
-}
-
-/* Given GNAME, set the corresponding GID and return 1, or else, return 0. */
-int
-gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp)
-{
- struct group *group;
-
- if (cached_no_such_gname[0]
- && strncmp (gname, cached_no_such_gname, GNAME_FIELD_SIZE) == 0)
- return 0;
-
- if (!cached_gname[0]
- || gname[0] != cached_gname[0]
- || strncmp (gname, cached_gname, GNAME_FIELD_SIZE) != 0)
- {
- group = getgrnam (gname);
- if (group)
- {
- cached_gid = group->gr_gid;
- strncpy (cached_gname, gname, GNAME_FIELD_SIZE);
- }
- else
- {
- strncpy (cached_no_such_gname, gname, GNAME_FIELD_SIZE);
- return 0;
- }
- }
- *gidp = cached_gid;
- return 1;
-}
-
-/* Names from the command call. */
-
-static struct name *namelist; /* first name in list, if any */
-static struct name **nametail = &namelist; /* end of name list */
-static const char **name_array; /* store an array of names */
-static int allocated_names; /* how big is the array? */
-static int names; /* how many entries does it have? */
-static int name_index; /* how many of the entries have we scanned? */
-
-/* Initialize structures. */
-void
-init_names (void)
-{
- allocated_names = 10;
- name_array = xmalloc (sizeof (const char *) * allocated_names);
- names = 0;
-}
-
-/* Add NAME at end of name_array, reallocating it as necessary. */
-void
-name_add (const char *name)
-{
- if (names == allocated_names)
- {
- allocated_names *= 2;
- name_array =
- xrealloc (name_array, sizeof (const char *) * allocated_names);
- }
- name_array[names++] = name;
-}
-
-/* Names from external name file. */
-
-static FILE *name_file; /* file to read names from */
-static char *name_buffer; /* buffer to hold the current file name */
-static size_t name_buffer_length; /* allocated length of name_buffer */
-
-/* FIXME: I should better check more closely. It seems at first glance that
- is_pattern is only used when reading a file, and ignored for all
- command line arguments. */
-
-static inline int
-is_pattern (const char *string)
-{
- return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
-}
-
-/* Set up to gather file names for tar. They can either come from a
- file or were saved from decoding arguments. */
-void
-name_init (int argc, char *const *argv)
-{
- name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
- name_buffer_length = NAME_FIELD_SIZE;
-
- if (files_from_option)
- {
- if (!strcmp (files_from_option, "-"))
- {
- request_stdin ("-T");
- name_file = stdin;
- }
- else if (name_file = fopen (files_from_option, "r"), !name_file)
- open_fatal (files_from_option);
- }
-}
-
-void
-name_term (void)
-{
- free (name_buffer);
- free (name_array);
-}
-
-/* Read the next filename from name_file and null-terminate it. Put
- it into name_buffer, reallocating and adjusting name_buffer_length
- if necessary. Return 0 at end of file, 1 otherwise. */
-static int
-read_name_from_file (void)
-{
- int character;
- size_t counter = 0;
-
- /* FIXME: getc may be called even if character was EOF the last time here. */
-
- /* FIXME: This + 2 allocation might serve no purpose. */
-
- while (character = getc (name_file),
- character != EOF && character != filename_terminator)
- {
- if (counter == name_buffer_length)
- {
- if (name_buffer_length * 2 < name_buffer_length)
- xalloc_die ();
- name_buffer_length *= 2;
- name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
- }
- name_buffer[counter++] = character;
- }
-
- if (counter == 0 && character == EOF)
- return 0;
-
- if (counter == name_buffer_length)
- {
- if (name_buffer_length * 2 < name_buffer_length)
- xalloc_die ();
- name_buffer_length *= 2;
- name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
- }
- name_buffer[counter] = '\0';
-
- return 1;
-}
-
-/* Get the next name from ARGV or the file of names. Result is in
- static storage and can't be relied upon across two calls.
-
- If CHANGE_DIRS is true, treat a filename of the form "-C" as
- meaning that the next filename is the name of a directory to change
- to. If filename_terminator is NUL, CHANGE_DIRS is effectively
- always false. */
-char *
-name_next (int change_dirs)
-{
- const char *source;
- char *cursor;
- int chdir_flag = 0;
-
- if (filename_terminator == '\0')
- change_dirs = 0;
-
- while (1)
- {
- /* Get a name, either from file or from saved arguments. */
-
- if (name_index == names)
- {
- if (! name_file)
- break;
- if (! read_name_from_file ())
- break;
- }
- else
- {
- size_t source_len;
- source = name_array[name_index++];
- source_len = strlen (source);
- if (name_buffer_length < source_len)
- {
- do
- {
- name_buffer_length *= 2;
- if (! name_buffer_length)
- xalloc_die ();
- }
- while (name_buffer_length < source_len);
-
- free (name_buffer);
- name_buffer = xmalloc (name_buffer_length + 2);
- }
- strcpy (name_buffer, source);
- }
-
- /* Zap trailing slashes. */
-
- cursor = name_buffer + strlen (name_buffer) - 1;
- while (cursor > name_buffer && ISSLASH (*cursor))
- *cursor-- = '\0';
-
- if (chdir_flag)
- {
- if (chdir (name_buffer) < 0)
- chdir_fatal (name_buffer);
- chdir_flag = 0;
- }
- else if (change_dirs && strcmp (name_buffer, "-C") == 0)
- chdir_flag = 1;
- else
- {
- unquote_string (name_buffer);
- return name_buffer;
- }
- }
-
- /* No more names in file. */
-
- if (name_file && chdir_flag)
- FATAL_ERROR ((0, 0, _("Missing file name after -C")));
-
- return 0;
-}
-
-/* Close the name file, if any. */
-void
-name_close (void)
-{
- if (name_file && name_file != stdin)
- if (fclose (name_file) != 0)
- close_error (name_buffer);
-}
-
-/* Gather names in a list for scanning. Could hash them later if we
- really care.
-
- If the names are already sorted to match the archive, we just read
- them one by one. name_gather reads the first one, and it is called
- by name_match as appropriate to read the next ones. At EOF, the
- last name read is just left in the buffer. This option lets users
- of small machines extract an arbitrary number of files by doing
- "tar t" and editing down the list of files. */
-
-void
-name_gather (void)
-{
- /* Buffer able to hold a single name. */
- static struct name *buffer;
- static size_t allocated_size;
-
- char const *name;
-
- if (same_order_option)
- {
- static int change_dir;
-
- if (allocated_size == 0)
- {
- allocated_size = offsetof (struct name, name) + NAME_FIELD_SIZE + 1;
- buffer = xmalloc (allocated_size);
- /* FIXME: This memset is overkill, and ugly... */
- memset (buffer, 0, allocated_size);
- }
-
- while ((name = name_next (0)) && strcmp (name, "-C") == 0)
- {
- char const *dir = name_next (0);
- if (! dir)
- FATAL_ERROR ((0, 0, _("Missing file name after -C")));
- change_dir = chdir_arg (xstrdup (dir));
- }
-
- if (name)
- {
- size_t needed_size;
- buffer->length = strlen (name);
- needed_size = offsetof (struct name, name) + buffer->length + 1;
- if (allocated_size < needed_size)
- {
- do
- {
- allocated_size *= 2;
- if (! allocated_size)
- xalloc_die ();
- }
- while (allocated_size < needed_size);
-
- buffer = xrealloc (buffer, allocated_size);
- }
- buffer->change_dir = change_dir;
- strcpy (buffer->name, name);
- buffer->next = 0;
- buffer->found = 0;
-
- namelist = buffer;
- nametail = &namelist->next;
- }
- }
- else
- {
- /* Non sorted names -- read them all in. */
- int change_dir = 0;
-
- for (;;)
- {
- int change_dir0 = change_dir;
- while ((name = name_next (0)) && strcmp (name, "-C") == 0)
- {
- char const *dir = name_next (0);
- if (! dir)
- FATAL_ERROR ((0, 0, _("Missing file name after -C")));
- change_dir = chdir_arg (xstrdup (dir));
- }
- if (name)
- addname (name, change_dir);
- else
- {
- if (change_dir != change_dir0)
- addname (0, change_dir);
- break;
- }
- }
- }
-}
-
-/* Add a name to the namelist. */
-struct name *
-addname (char const *string, int change_dir)
-{
- size_t length = string ? strlen (string) : 0;
- struct name *name = xmalloc (offsetof (struct name, name) + length + 1);
-
- if (string)
- {
- name->fake = 0;
- strcpy (name->name, string);
- }
- else
- {
- name->fake = 1;
-
- /* FIXME: This initialization (and the byte of memory that it
- initializes) is probably not needed, but we are currently in
- bug-fix mode so we'll leave it in for now. */
- name->name[0] = 0;
- }
-
- name->next = 0;
- name->length = length;
- name->found = 0;
- name->regexp = 0; /* assume not a regular expression */
- name->firstch = 1; /* assume first char is literal */
- name->change_dir = change_dir;
- name->dir_contents = 0;
-
- if (string && is_pattern (string))
- {
- name->regexp = 1;
- if (string[0] == '*' || string[0] == '[' || string[0] == '?')
- name->firstch = 0;
- }
-
- *nametail = name;
- nametail = &name->next;
- return name;
-}
-
-/* Find a match for PATH (whose string length is LENGTH) in the name
- list. */
-static struct name *
-namelist_match (char const *path, size_t length)
-{
- struct name *p;
-
- for (p = namelist; p; p = p->next)
- {
- /* If first chars don't match, quick skip. */
-
- if (p->firstch && p->name[0] != path[0])
- continue;
-
- if (p->regexp
- ? fnmatch (p->name, path, recursion_option) == 0
- : (p->length <= length
- && (path[p->length] == '\0' || ISSLASH (path[p->length]))
- && memcmp (path, p->name, p->length) == 0))
- return p;
- }
-
- return 0;
-}
-
-/* Return true if and only if name PATH (from an archive) matches any
- name from the namelist. */
-int
-name_match (const char *path)
-{
- size_t length = strlen (path);
-
- while (1)
- {
- struct name *cursor = namelist;
- struct name *tmpnlp;
-
- if (!cursor)
- return ! files_from_option;
-
- if (cursor->fake)
- {
- chdir_do (cursor->change_dir);
- namelist = 0;
- nametail = &namelist;
- return ! files_from_option;
- }
-
- cursor = namelist_match (path, length);
- if (cursor)
- {
- cursor->found = 1; /* remember it matched */
- if (starting_file_option)
- {
- free (namelist);
- namelist = 0;
- nametail = &namelist;
- }
- chdir_do (cursor->change_dir);
- if (fast_read_option)
- {
- /* remove the current entry, since we found a match */
- if (namelist->next == NULL)
- {
- /* the list contains one element */
- free(namelist);
- namelist = 0;
- nametail = &namelist;
- /* set a boolean to decide wether we started with a */
- /* non-empty namelist, that was emptied */
- namelist_freed = 1;
- }
- else
- {
- if (cursor == namelist)
- {
- /* the first element is the one */
- tmpnlp = namelist->next;
- free(namelist);
- namelist = tmpnlp;
- }
- else
- {
- tmpnlp = namelist;
- while (tmpnlp->next != cursor)
- tmpnlp = tmpnlp->next;
- tmpnlp->next = cursor->next;
- free(cursor);
- }
- }
- }
-
- /* We got a match. */
- return 1;
- }
-
- /* Filename from archive not found in namelist. If we have the whole
- namelist here, just return 0. Otherwise, read the next name in and
- compare it. If this was the last name, namelist->found will remain
- on. If not, we loop to compare the newly read name. */
-
- if (same_order_option && namelist->found)
- {
- name_gather (); /* read one more */
- if (namelist->found)
- return 0;
- }
- else
- return 0;
- }
-}
-
-/* Print the names of things in the namelist that were not matched. */
-void
-names_notfound (void)
-{
- struct name const *cursor;
-
- for (cursor = namelist; cursor; cursor = cursor->next)
- if (!cursor->found && !cursor->fake)
- ERROR ((0, 0, _("%s: Not found in archive"),
- quotearg_colon (cursor->name)));
-
- /* Don't bother freeing the name list; we're about to exit. */
- namelist = 0;
- nametail = &namelist;
-
- if (same_order_option)
- {
- char *name;
-
- while (name = name_next (1), name)
- ERROR ((0, 0, _("%s: Not found in archive"),
- quotearg_colon (name)));
- }
-}
-
-/* Sorting name lists. */
-
-/* Sort linked LIST of names, of given LENGTH, using COMPARE to order
- names. Return the sorted list. Apart from the type `struct name'
- and the definition of SUCCESSOR, this is a generic list-sorting
- function, but it's too painful to make it both generic and portable
- in C. */
-
-static struct name *
-merge_sort (struct name *list, int length,
- int (*compare) (struct name const*, struct name const*))
-{
- struct name *first_list;
- struct name *second_list;
- int first_length;
- int second_length;
- struct name *result;
- struct name **merge_point;
- struct name *cursor;
- int counter;
-
-# define SUCCESSOR(name) ((name)->next)
-
- if (length == 1)
- return list;
-
- if (length == 2)
- {
- if ((*compare) (list, SUCCESSOR (list)) > 0)
- {
- result = SUCCESSOR (list);
- SUCCESSOR (result) = list;
- SUCCESSOR (list) = 0;
- return result;
- }
- return list;
- }
-
- first_list = list;
- first_length = (length + 1) / 2;
- second_length = length / 2;
- for (cursor = list, counter = first_length - 1;
- counter;
- cursor = SUCCESSOR (cursor), counter--)
- continue;
- second_list = SUCCESSOR (cursor);
- SUCCESSOR (cursor) = 0;
-
- first_list = merge_sort (first_list, first_length, compare);
- second_list = merge_sort (second_list, second_length, compare);
-
- merge_point = &result;
- while (first_list && second_list)
- if ((*compare) (first_list, second_list) < 0)
- {
- cursor = SUCCESSOR (first_list);
- *merge_point = first_list;
- merge_point = &SUCCESSOR (first_list);
- first_list = cursor;
- }
- else
- {
- cursor = SUCCESSOR (second_list);
- *merge_point = second_list;
- merge_point = &SUCCESSOR (second_list);
- second_list = cursor;
- }
- if (first_list)
- *merge_point = first_list;
- else
- *merge_point = second_list;
-
- return result;
-
-#undef SUCCESSOR
-}
-
-/* A comparison function for sorting names. Put found names last;
- break ties by string comparison. */
-
-static int
-compare_names (struct name const *n1, struct name const *n2)
-{
- int found_diff = n2->found - n1->found;
- return found_diff ? found_diff : strcmp (n1->name, n2->name);
-}
-
-/* Add all the dirs under NAME, which names a directory, to the namelist.
- If any of the files is a directory, recurse on the subdirectory.
- DEVICE is the device not to leave, if the -l option is specified. */
-
-static void
-add_hierarchy_to_namelist (struct name *name, dev_t device)
-{
- char *path = name->name;
- char *buffer = get_directory_contents (path, device);
-
- if (! buffer)
- name->dir_contents = "\0\0\0\0";
- else
- {
- size_t name_length = name->length;
- size_t allocated_length = (name_length >= NAME_FIELD_SIZE
- ? name_length + NAME_FIELD_SIZE
- : NAME_FIELD_SIZE);
- char *name_buffer = xmalloc (allocated_length + 1);
- /* FIXME: + 2 above? */
- char *string;
- size_t string_length;
- int change_dir = name->change_dir;
-
- name->dir_contents = buffer;
- strcpy (name_buffer, path);
- if (! ISSLASH (name_buffer[name_length - 1]))
- {
- name_buffer[name_length++] = '/';
- name_buffer[name_length] = '\0';
- }
-
- for (string = buffer; *string; string += string_length + 1)
- {
- string_length = strlen (string);
- if (*string == 'D')
- {
- if (allocated_length <= name_length + string_length)
- {
- do
- {
- allocated_length *= 2;
- if (! allocated_length)
- xalloc_die ();
- }
- while (allocated_length <= name_length + string_length);
-
- name_buffer = xrealloc (name_buffer, allocated_length + 1);
- }
- strcpy (name_buffer + name_length, string + 1);
- add_hierarchy_to_namelist (addname (name_buffer, change_dir),
- device);
- }
- }
-
- free (name_buffer);
- }
-}
-
-/* Collect all the names from argv[] (or whatever), expand them into a
- directory tree, and sort them. This gets only subdirectories, not
- all files. */
-
-void
-collect_and_sort_names (void)
-{
- struct name *name;
- struct name *next_name;
- int num_names;
- struct stat statbuf;
-
- name_gather ();
-
- if (listed_incremental_option)
- read_directory_file ();
-
- if (!namelist)
- addname (".", 0);
-
- for (name = namelist; name; name = next_name)
- {
- next_name = name->next;
- if (name->found || name->dir_contents)
- continue;
- if (name->regexp) /* FIXME: just skip regexps for now */
- continue;
- chdir_do (name->change_dir);
- if (name->fake)
- continue;
-
- if (deref_stat (dereference_option, name->name, &statbuf) != 0)
- {
- if (ignore_failed_read_option)
- stat_warn (name->name);
- else
- stat_error (name->name);
- continue;
- }
- if (S_ISDIR (statbuf.st_mode))
- {
- name->found = 1;
- add_hierarchy_to_namelist (name, statbuf.st_dev);
- }
- }
-
- num_names = 0;
- for (name = namelist; name; name = name->next)
- num_names++;
- namelist = merge_sort (namelist, num_names, compare_names);
-
- for (name = namelist; name; name = name->next)
- name->found = 0;
-}
-
-/* This is like name_match, except that it returns a pointer to the
- name it matched, and doesn't set FOUND in structure. The caller
- will have to do that if it wants to. Oh, and if the namelist is
- empty, it returns null, unlike name_match, which returns TRUE. */
-struct name *
-name_scan (const char *path)
-{
- size_t length = strlen (path);
-
- while (1)
- {
- struct name *cursor = namelist_match (path, length);
- if (cursor)
- return cursor;
-
- /* Filename from archive not found in namelist. If we have the whole
- namelist here, just return 0. Otherwise, read the next name in and
- compare it. If this was the last name, namelist->found will remain
- on. If not, we loop to compare the newly read name. */
-
- if (same_order_option && namelist && namelist->found)
- {
- name_gather (); /* read one more */
- if (namelist->found)
- return 0;
- }
- else
- return 0;
- }
-}
-
-/* This returns a name from the namelist which doesn't have ->found
- set. It sets ->found before returning, so successive calls will
- find and return all the non-found names in the namelist. */
-struct name *gnu_list_name;
-
-char *
-name_from_list (void)
-{
- if (!gnu_list_name)
- gnu_list_name = namelist;
- while (gnu_list_name && (gnu_list_name->found | gnu_list_name->fake))
- gnu_list_name = gnu_list_name->next;
- if (gnu_list_name)
- {
- gnu_list_name->found = 1;
- chdir_do (gnu_list_name->change_dir);
- return gnu_list_name->name;
- }
- return 0;
-}
-
-void
-blank_name_list (void)
-{
- struct name *name;
-
- gnu_list_name = 0;
- for (name = namelist; name; name = name->next)
- name->found = 0;
-}
-
-/* Yield a newly allocated file name consisting of PATH concatenated to
- NAME, with an intervening slash if PATH does not already end in one. */
-char *
-new_name (const char *path, const char *name)
-{
- size_t pathlen = strlen (path);
- size_t namesize = strlen (name) + 1;
- int slash = pathlen && ! ISSLASH (path[pathlen - 1]);
- char *buffer = xmalloc (pathlen + slash + namesize);
- memcpy (buffer, path, pathlen);
- buffer[pathlen] = '/';
- memcpy (buffer + pathlen + slash, name, namesize);
- return buffer;
-}
-
-/* Return nonzero if file NAME is excluded. Exclude a name if its
- prefix matches a pattern that contains slashes, or if one of its
- components matches a pattern that contains no slashes. */
-bool
-excluded_name (char const *name)
-{
- return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name));
-}
-
-/* Names to avoid dumping. */
-static Hash_table *avoided_name_table;
-
-/* Calculate the hash of an avoided name. */
-static unsigned
-hash_avoided_name (void const *name, unsigned n_buckets)
-{
- return hash_string (name, n_buckets);
-}
-
-/* Compare two avoided names for equality. */
-static bool
-compare_avoided_names (void const *name1, void const *name2)
-{
- return strcmp (name1, name2) == 0;
-}
-
-/* Remember to not archive NAME. */
-void
-add_avoided_name (char const *name)
-{
- if (! ((avoided_name_table
- || (avoided_name_table = hash_initialize (0, 0, hash_avoided_name,
- compare_avoided_names, 0)))
- && hash_insert (avoided_name_table, xstrdup (name))))
- xalloc_die ();
-}
-
-/* Should NAME be avoided when archiving? */
-int
-is_avoided_name (char const *name)
-{
- return avoided_name_table && hash_lookup (avoided_name_table, name);
-}
diff --git a/contrib/tar/src/rmt.c b/contrib/tar/src/rmt.c
deleted file mode 100644
index 0fe166b..0000000
--- a/contrib/tar/src/rmt.c
+++ /dev/null
@@ -1,576 +0,0 @@
-/* Remote connection server.
-
- Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001 Free Software
- Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* Copyright (C) 1983 Regents of the University of California.
- All rights reserved.
-
- Redistribution and use in source and binary forms are permitted provided
- that the above copyright notice and this paragraph are duplicated in all
- such forms and that any documentation, advertising materials, and other
- materials related to such distribution and use acknowledge that the
- software was developed by the University of California, Berkeley. The
- name of the University may not be used to endorse or promote products
- derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
-
-#include "system.h"
-#include <print-copyr.h>
-#include <localedir.h>
-#include <safe-read.h>
-#include <full-write.h>
-
-#include <getopt.h>
-#include <sys/socket.h>
-
-#ifndef EXIT_FAILURE
-# define EXIT_FAILURE 1
-#endif
-#ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
-#endif
-
-/* Maximum size of a string from the requesting program. */
-#define STRING_SIZE 64
-
-/* Name of executing program. */
-const char *program_name;
-
-/* File descriptor of the tape device, or negative if none open. */
-static int tape = -1;
-
-/* Buffer containing transferred data, and its allocated size. */
-static char *record_buffer;
-static size_t allocated_size;
-
-/* Buffer for constructing the reply. */
-static char reply_buffer[BUFSIZ];
-
-/* Debugging tools. */
-
-static FILE *debug_file;
-
-#define DEBUG(File) \
- if (debug_file) fprintf(debug_file, File)
-
-#define DEBUG1(File, Arg) \
- if (debug_file) fprintf(debug_file, File, Arg)
-
-#define DEBUG2(File, Arg1, Arg2) \
- if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
-
-/* Return an error string, given an error number. */
-#if HAVE_STRERROR
-# ifndef strerror
-char *strerror ();
-# endif
-#else
-static char *
-private_strerror (int errnum)
-{
- extern char *sys_errlist[];
- extern int sys_nerr;
-
- if (errnum > 0 && errnum <= sys_nerr)
- return _(sys_errlist[errnum]);
- return _("Unknown system error");
-}
-# define strerror private_strerror
-#endif
-
-static void
-report_error_message (const char *string)
-{
- DEBUG1 ("rmtd: E 0 (%s)\n", string);
-
- sprintf (reply_buffer, "E0\n%s\n", string);
- full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
-}
-
-static void
-report_numbered_error (int num)
-{
- DEBUG2 ("rmtd: E %d (%s)\n", num, strerror (num));
-
- sprintf (reply_buffer, "E%d\n%s\n", num, strerror (num));
- full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
-}
-
-static void
-get_string (char *string)
-{
- int counter;
-
- for (counter = 0; counter < STRING_SIZE; counter++)
- {
- if (safe_read (STDIN_FILENO, string + counter, 1) != 1)
- exit (EXIT_SUCCESS);
-
- if (string[counter] == '\n')
- break;
- }
- string[counter] = '\0';
-}
-
-static void
-prepare_record_buffer (size_t size)
-{
- if (size <= allocated_size)
- return;
-
- if (record_buffer)
- free (record_buffer);
-
- record_buffer = malloc (size);
-
- if (! record_buffer)
- {
- DEBUG (_("rmtd: Cannot allocate buffer space\n"));
-
- report_error_message (N_("Cannot allocate buffer space"));
- exit (EXIT_FAILURE); /* exit status used to be 4 */
- }
-
- allocated_size = size;
-
-#ifdef SO_RCVBUF
- while (size > 1024 &&
- (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_RCVBUF,
- (char *) &size, sizeof size)
- < 0))
- size -= 1024;
-#else
- /* FIXME: I do not see any purpose to the following line... Sigh! */
- size = 1 + ((size - 1) % 1024);
-#endif
-}
-
-/* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
- OFLAG_STRING should contain an optional integer, followed by an optional
- symbolic representation of an open flag using only '|' to separate its
- components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
- representation if available, falling back on the numeric
- representation, or to zero if both formats are absent.
-
- This function should be the inverse of encode_oflag. The numeric
- representation is not portable from one host to another, but it is
- for backward compatibility with old-fashioned clients that do not
- emit symbolic open flags. */
-
-static int
-decode_oflag (char const *oflag_string)
-{
- char *oflag_num_end;
- int numeric_oflag = strtol (oflag_string, &oflag_num_end, 10);
- int symbolic_oflag = 0;
-
- oflag_string = oflag_num_end;
- while (ISSPACE ((unsigned char) *oflag_string))
- oflag_string++;
-
- do
- {
- struct name_value_pair { char const *name; int value; };
- static struct name_value_pair const table[] =
- {
-#ifdef O_APPEND
- {"APPEND", O_APPEND},
-#endif
- {"CREAT", O_CREAT},
-#ifdef O_DSYNC
- {"DSYNC", O_DSYNC},
-#endif
- {"EXCL", O_EXCL},
-#ifdef O_LARGEFILE
- {"LARGEFILE", O_LARGEFILE}, /* LFS extension for opening large files */
-#endif
-#ifdef O_NOCTTY
- {"NOCTTY", O_NOCTTY},
-#endif
-#ifdef O_NONBLOCK
- {"NONBLOCK", O_NONBLOCK},
-#endif
- {"RDONLY", O_RDONLY},
- {"RDWR", O_RDWR},
-#ifdef O_RSYNC
- {"RSYNC", O_RSYNC},
-#endif
-#ifdef O_SYNC
- {"SYNC", O_SYNC},
-#endif
- {"TRUNC", O_TRUNC},
- {"WRONLY", O_WRONLY}
- };
- struct name_value_pair const *t;
- size_t s;
-
- if (*oflag_string++ != 'O' || *oflag_string++ != '_')
- return numeric_oflag;
-
- for (t = table;
- (strncmp (oflag_string, t->name, s = strlen (t->name)) != 0
- || (oflag_string[s]
- && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
- oflag_string[s])));
- t++)
- if (t == table + sizeof table / sizeof *table - 1)
- return numeric_oflag;
-
- symbolic_oflag |= t->value;
- oflag_string += s;
- }
- while (*oflag_string++ == '|');
-
- return symbolic_oflag;
-}
-
-static struct option const long_opts[] =
-{
- {"help", no_argument, 0, 'h'},
- {"version", no_argument, 0, 'v'},
- {0, 0, 0, 0}
-};
-
-static void
-usage (int status)
-{
- if (status != EXIT_SUCCESS)
- fprintf (stderr, _("Try `%s --help' for more information.\n"),
- program_name);
- else
- {
- printf (_("\
-Usage: %s [OPTION]\n\
-Manipulate a tape drive, accepting commands from a remote process.\n\
-\n\
- --version Output version info.\n\
- --help Output this help.\n"),
- program_name);
- fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout);
- }
-
- exit (status);
-}
-
-int
-main (int argc, char *const *argv)
-{
- char command;
- ssize_t status;
-
- /* FIXME: Localization is meaningless, unless --help and --version are
- locally used. Localization would be best accomplished by the calling
- tar, on messages found within error packets. */
-
- program_name = argv[0];
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
-
- switch (getopt_long (argc, argv, "", long_opts, NULL))
- {
- default:
- usage (EXIT_FAILURE);
-
- case 'h':
- usage (EXIT_SUCCESS);
-
- case 'v':
- {
- printf ("rmt (GNU %s) %s\n", PACKAGE, VERSION);
- print_copyright ("2001 Free Software Foundation, Inc.");
- puts (_("\
-This program comes with NO WARRANTY, to the extent permitted by law.\n\
-You may redistribute it under the terms of the GNU General Public License;\n\
-see the file named COPYING for details."));
- }
- return EXIT_SUCCESS;
-
- case -1:
- break;
- }
-
- if (optind < argc)
- {
- if (optind != argc - 1)
- usage (EXIT_FAILURE);
- debug_file = fopen (argv[optind], "w");
- if (debug_file == 0)
- {
- report_numbered_error (errno);
- exit (EXIT_FAILURE);
- }
- setbuf (debug_file, 0);
- }
-
-top:
- errno = 0;
- status = 0;
- if (safe_read (STDIN_FILENO, &command, 1) != 1)
- return EXIT_SUCCESS;
-
- switch (command)
- {
- /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
-
- case 'O':
- {
- char device_string[STRING_SIZE];
- char oflag_string[STRING_SIZE];
-
- get_string (device_string);
- get_string (oflag_string);
- DEBUG2 ("rmtd: O %s %s\n", device_string, oflag_string);
-
- if (tape >= 0)
- close (tape);
-
- tape = open (device_string, decode_oflag (oflag_string), MODE_RW);
- if (tape < 0)
- goto ioerror;
- goto respond;
- }
-
- case 'C':
- {
- char device_string[STRING_SIZE];
-
- get_string (device_string); /* discard */
- DEBUG ("rmtd: C\n");
-
- if (close (tape) < 0)
- goto ioerror;
- tape = -1;
- goto respond;
- }
-
- case 'L':
- {
- char count_string[STRING_SIZE];
- char position_string[STRING_SIZE];
- off_t count = 0;
- int negative;
- int whence;
- char *p;
-
- get_string (count_string);
- get_string (position_string);
- DEBUG2 ("rmtd: L %s %s\n", count_string, position_string);
-
- /* Parse count_string, taking care to check for overflow.
- We can't use standard functions,
- since off_t might be longer than long. */
-
- for (p = count_string; *p == ' ' || *p == '\t'; p++)
- continue;
-
- negative = *p == '-';
- p += negative || *p == '+';
-
- for (;;)
- {
- int digit = *p++ - '0';
- if (9 < (unsigned) digit)
- break;
- else
- {
- off_t c10 = 10 * count;
- off_t nc = negative ? c10 - digit : c10 + digit;
- if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
- {
- report_error_message (N_("Seek offset out of range"));
- exit (EXIT_FAILURE);
- }
- count = nc;
- }
- }
-
- switch (atoi (position_string))
- {
- case 0: whence = SEEK_SET; break;
- case 1: whence = SEEK_CUR; break;
- case 2: whence = SEEK_END; break;
- default:
- report_error_message (N_("Seek direction out of range"));
- exit (EXIT_FAILURE);
- }
- count = lseek (tape, count, whence);
- if (count < 0)
- goto ioerror;
-
- /* Convert count back to string for reply.
- We can't use sprintf, since off_t might be longer than long. */
- p = count_string + sizeof count_string;
- *--p = '\0';
- do
- *--p = '0' + (int) (count % 10);
- while ((count /= 10) != 0);
-
- DEBUG1 ("rmtd: A %s\n", p);
-
- sprintf (reply_buffer, "A%s\n", p);
- full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
- goto top;
- }
-
- case 'W':
- {
- char count_string[STRING_SIZE];
- size_t size;
- size_t counter;
-
- get_string (count_string);
- size = atol (count_string);
- DEBUG1 ("rmtd: W %s\n", count_string);
-
- prepare_record_buffer (size);
- for (counter = 0; counter < size; counter += status)
- {
- status = safe_read (STDIN_FILENO, &record_buffer[counter],
- size - counter);
- if (status <= 0)
- {
- DEBUG (_("rmtd: Premature eof\n"));
-
- report_error_message (N_("Premature end of file"));
- exit (EXIT_FAILURE); /* exit status used to be 2 */
- }
- }
- status = full_write (tape, record_buffer, size);
- if (status < 0)
- goto ioerror;
- goto respond;
- }
-
- case 'R':
- {
- char count_string[STRING_SIZE];
- size_t size;
-
- get_string (count_string);
- DEBUG1 ("rmtd: R %s\n", count_string);
-
- size = atol (count_string);
- prepare_record_buffer (size);
- status = safe_read (tape, record_buffer, size);
- if (status < 0)
- goto ioerror;
- sprintf (reply_buffer, "A%ld\n", (long) status);
- full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
- full_write (STDOUT_FILENO, record_buffer, status);
- goto top;
- }
-
- case 'I':
- {
- char operation_string[STRING_SIZE];
- char count_string[STRING_SIZE];
-
- get_string (operation_string);
- get_string (count_string);
- DEBUG2 ("rmtd: I %s %s\n", operation_string, count_string);
-
-#ifdef MTIOCTOP
- {
- struct mtop mtop;
- const char *p;
- off_t count = 0;
- int negative;
-
- /* Parse count_string, taking care to check for overflow.
- We can't use standard functions,
- since off_t might be longer than long. */
-
- for (p = count_string; *p == ' ' || *p == '\t'; p++)
- continue;
-
- negative = *p == '-';
- p += negative || *p == '+';
-
- for (;;)
- {
- int digit = *p++ - '0';
- if (9 < (unsigned) digit)
- break;
- else
- {
- off_t c10 = 10 * count;
- off_t nc = negative ? c10 - digit : c10 + digit;
- if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
- {
- report_error_message (N_("Seek offset out of range"));
- exit (EXIT_FAILURE);
- }
- count = nc;
- }
- }
-
- mtop.mt_count = count;
- if (mtop.mt_count != count)
- {
- report_error_message (N_("Seek offset out of range"));
- exit (EXIT_FAILURE);
- }
- mtop.mt_op = atoi (operation_string);
-
- if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
- goto ioerror;
- }
-#endif
- goto respond;
- }
-
- case 'S': /* status */
- {
- DEBUG ("rmtd: S\n");
-
-#ifdef MTIOCGET
- {
- struct mtget operation;
-
- if (ioctl (tape, MTIOCGET, (char *) &operation) < 0)
- goto ioerror;
- status = sizeof operation;
- sprintf (reply_buffer, "A%ld\n", (long) status);
- full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
- full_write (STDOUT_FILENO, (char *) &operation, sizeof operation);
- }
-#endif
- goto top;
- }
-
- default:
- DEBUG1 (_("rmtd: Garbage command %c\n"), command);
-
- report_error_message (N_("Garbage command"));
- exit (EXIT_FAILURE); /* exit status used to be 3 */
- }
-
-respond:
- DEBUG1 ("rmtd: A %ld\n", (long) status);
-
- sprintf (reply_buffer, "A%ld\n", (long) status);
- full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
- goto top;
-
-ioerror:
- report_numbered_error (errno);
- goto top;
-}
diff --git a/contrib/tar/src/rmt.h b/contrib/tar/src/rmt.h
deleted file mode 100644
index b851045..0000000
--- a/contrib/tar/src/rmt.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Definitions for communicating with a remote tape drive.
- Copyright 1988, 1992, 1996, 1997, 2001 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-extern char *rmt_path__;
-
-int rmt_open__ PARAMS ((const char *, int, int, const char *));
-int rmt_close__ PARAMS ((int));
-ssize_t rmt_read__ PARAMS ((int, char *, size_t));
-ssize_t rmt_write__ PARAMS ((int, char *, size_t));
-off_t rmt_lseek__ PARAMS ((int, off_t, int));
-int rmt_ioctl__ PARAMS ((int, int, char *));
-
-/* A filename is remote if it contains a colon not preceded by a slash,
- to take care of `/:/' which is a shorthand for `/.../<CELL-NAME>/fs'
- on machines running OSF's Distributing Computing Environment (DCE) and
- Distributed File System (DFS). However, when --force-local, a
- filename is never remote. */
-
-#define _remdev(Path) \
- (!force_local_option && (rmt_path__ = strchr (Path, ':')) \
- && rmt_path__ > (Path) && ! memchr (Path, rmt_path__ - (Path), '/'))
-
-#define _isrmt(Fd) \
- ((Fd) >= __REM_BIAS)
-
-#define __REM_BIAS (1 << 30)
-
-#ifndef O_CREAT
-# define O_CREAT 01000
-#endif
-
-#define rmtopen(Path, Oflag, Mode, Command) \
- (_remdev (Path) ? rmt_open__ (Path, Oflag, __REM_BIAS, Command) \
- : open (Path, Oflag, Mode))
-
-#define rmtaccess(Path, Amode) \
- (_remdev (Path) ? 0 : access (Path, Amode))
-
-#define rmtstat(Path, Buffer) \
- (_remdev (Path) ? (errno = EOPNOTSUPP), -1 : stat (Path, Buffer))
-
-#define rmtcreat(Path, Mode, Command) \
- (_remdev (Path) \
- ? rmt_open__ (Path, 1 | O_CREAT, __REM_BIAS, Command) \
- : creat (Path, Mode))
-
-#define rmtlstat(Path, Buffer) \
- (_remdev (Path) ? (errno = EOPNOTSUPP), -1 : lstat (Path, Buffer))
-
-#define rmtread(Fd, Buffer, Length) \
- (_isrmt (Fd) ? rmt_read__ (Fd - __REM_BIAS, Buffer, Length) \
- : safe_read (Fd, Buffer, Length))
-
-#define rmtwrite(Fd, Buffer, Length) \
- (_isrmt (Fd) ? rmt_write__ (Fd - __REM_BIAS, Buffer, Length) \
- : full_write (Fd, Buffer, Length))
-
-#define rmtlseek(Fd, Offset, Where) \
- (_isrmt (Fd) ? rmt_lseek__ (Fd - __REM_BIAS, Offset, Where) \
- : lseek (Fd, Offset, Where))
-
-#define rmtclose(Fd) \
- (_isrmt (Fd) ? rmt_close__ (Fd - __REM_BIAS) : close (Fd))
-
-#define rmtioctl(Fd, Request, Argument) \
- (_isrmt (Fd) ? rmt_ioctl__ (Fd - __REM_BIAS, Request, Argument) \
- : ioctl (Fd, Request, Argument))
-
-#define rmtdup(Fd) \
- (_isrmt (Fd) ? (errno = EOPNOTSUPP), -1 : dup (Fd))
-
-#define rmtfstat(Fd, Buffer) \
- (_isrmt (Fd) ? (errno = EOPNOTSUPP), -1 : fstat (Fd, Buffer))
-
-#define rmtfcntl(Fd, Command, Argument) \
- (_isrmt (Fd) ? (errno = EOPNOTSUPP), -1 : fcntl (Fd, Command, Argument))
-
-#define rmtisatty(Fd) \
- (_isrmt (Fd) ? 0 : isatty (Fd))
diff --git a/contrib/tar/src/rtapelib.c b/contrib/tar/src/rtapelib.c
deleted file mode 100644
index 295974e..0000000
--- a/contrib/tar/src/rtapelib.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/* Functions for communicating with a remote tape drive.
-
- Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001 Free Software
- Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* The man page rmt(8) for /etc/rmt documents the remote mag tape protocol
- which rdump and rrestore use. Unfortunately, the man page is *WRONG*.
- The author of the routines I'm including originally wrote his code just
- based on the man page, and it didn't work, so he went to the rdump source
- to figure out why. The only thing he had to change was to check for the
- 'F' return code in addition to the 'E', and to separate the various
- arguments with \n instead of a space. I personally don't think that this
- is much of a problem, but I wanted to point it out. -- Arnold Robbins
-
- Originally written by Jeff Lee, modified some by Arnold Robbins. Redone
- as a library that can replace open, read, write, etc., by Fred Fish, with
- some additional work by Arnold Robbins. Modified to make all rmt* calls
- into macros for speed by Jay Fenlason. Use -DWITH_REXEC for rexec
- code, courtesy of Dan Kegel. */
-
-/* $FreeBSD$ */
-
-#include "system.h"
-
-#include <safe-read.h>
-#include <full-write.h>
-
-/* Try hard to get EOPNOTSUPP defined. 486/ISC has it in net/errno.h,
- 3B2/SVR3 has it in sys/inet.h. Otherwise, like on MSDOS, use EINVAL. */
-
-#ifndef EOPNOTSUPP
-# if HAVE_NET_ERRNO_H
-# include <net/errno.h>
-# endif
-# if HAVE_SYS_INET_H
-# include <sys/inet.h>
-# endif
-# ifndef EOPNOTSUPP
-# define EOPNOTSUPP EINVAL
-# endif
-#endif
-
-#include <signal.h>
-
-#if HAVE_NETDB_H
-# include <netdb.h>
-#endif
-
-#include "rmt.h"
-
-/* Exit status if exec errors. */
-#define EXIT_ON_EXEC_ERROR 128
-
-/* FIXME: Size of buffers for reading and writing commands to rmt. */
-#define COMMAND_BUFFER_SIZE 64
-
-#ifndef RETSIGTYPE
-# define RETSIGTYPE void
-#endif
-
-/* FIXME: Maximum number of simultaneous remote tape connections. */
-#define MAXUNIT 4
-
-#define PREAD 0 /* read file descriptor from pipe() */
-#define PWRITE 1 /* write file descriptor from pipe() */
-
-/* Return the parent's read side of remote tape connection Fd. */
-#define READ_SIDE(Fd) (from_remote[Fd][PREAD])
-
-/* Return the parent's write side of remote tape connection Fd. */
-#define WRITE_SIDE(Fd) (to_remote[Fd][PWRITE])
-
-/* The pipes for receiving data from remote tape drives. */
-static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
-
-/* The pipes for sending data to remote tape drives. */
-static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
-
-/* Temporary variable used by macros in rmt.h. */
-char *rmt_path__;
-
-
-/* Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE. */
-static void
-_rmt_shutdown (int handle, int errno_value)
-{
- close (READ_SIDE (handle));
- close (WRITE_SIDE (handle));
- READ_SIDE (handle) = -1;
- WRITE_SIDE (handle) = -1;
- errno = errno_value;
-}
-
-/* Attempt to perform the remote tape command specified in BUFFER on
- remote tape connection HANDLE. Return 0 if successful, -1 on
- error. */
-static int
-do_command (int handle, const char *buffer)
-{
- /* Save the current pipe handler and try to make the request. */
-
- size_t length = strlen (buffer);
- RETSIGTYPE (*pipe_handler) () = signal (SIGPIPE, SIG_IGN);
- ssize_t written = full_write (WRITE_SIDE (handle), buffer, length);
- signal (SIGPIPE, pipe_handler);
-
- if (written == length)
- return 0;
-
- /* Something went wrong. Close down and go home. */
-
- _rmt_shutdown (handle, EIO);
- return -1;
-}
-
-static char *
-get_status_string (int handle, char *command_buffer)
-{
- char *cursor;
- int counter;
-
- /* Read the reply command line. */
-
- for (counter = 0, cursor = command_buffer;
- counter < COMMAND_BUFFER_SIZE;
- counter++, cursor++)
- {
- if (safe_read (READ_SIDE (handle), cursor, 1) != 1)
- {
- _rmt_shutdown (handle, EIO);
- return 0;
- }
- if (*cursor == '\n')
- {
- *cursor = '\0';
- break;
- }
- }
-
- if (counter == COMMAND_BUFFER_SIZE)
- {
- _rmt_shutdown (handle, EIO);
- return 0;
- }
-
- /* Check the return status. */
-
- for (cursor = command_buffer; *cursor; cursor++)
- if (*cursor != ' ')
- break;
-
- if (*cursor == 'E' || *cursor == 'F')
- {
- errno = atoi (cursor + 1);
-
- /* Skip the error message line. */
-
- /* FIXME: there is better to do than merely ignoring error messages
- coming from the remote end. Translate them, too... */
-
- {
- char character;
-
- while (safe_read (READ_SIDE (handle), &character, 1) == 1)
- if (character == '\n')
- break;
- }
-
- if (*cursor == 'F')
- _rmt_shutdown (handle, errno);
-
- return 0;
- }
-
- /* Check for mis-synced pipes. */
-
- if (*cursor != 'A')
- {
- _rmt_shutdown (handle, EIO);
- return 0;
- }
-
- /* Got an `A' (success) response. */
-
- return cursor + 1;
-}
-
-/* Read and return the status from remote tape connection HANDLE. If
- an error occurred, return -1 and set errno. */
-static long
-get_status (int handle)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- const char *status = get_status_string (handle, command_buffer);
- return status ? atol (status) : -1L;
-}
-
-static off_t
-get_status_off (int handle)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- const char *status = get_status_string (handle, command_buffer);
-
- if (! status)
- return -1;
- else
- {
- /* Parse status, taking care to check for overflow.
- We can't use standard functions,
- since off_t might be longer than long. */
-
- off_t count = 0;
- int negative;
-
- for (; *status == ' ' || *status == '\t'; status++)
- continue;
-
- negative = *status == '-';
- status += negative || *status == '+';
-
- for (;;)
- {
- int digit = *status++ - '0';
- if (9 < (unsigned) digit)
- break;
- else
- {
- off_t c10 = 10 * count;
- off_t nc = negative ? c10 - digit : c10 + digit;
- if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
- return -1;
- count = nc;
- }
- }
-
- return count;
- }
-}
-
-#if WITH_REXEC
-
-/* Execute /etc/rmt as user USER on remote system HOST using rexec.
- Return a file descriptor of a bidirectional socket for stdin and
- stdout. If USER is zero, use the current username.
-
- By default, this code is not used, since it requires that the user
- have a .netrc file in his/her home directory, or that the
- application designer be willing to have rexec prompt for login and
- password info. This may be unacceptable, and .rhosts files for use
- with rsh are much more common on BSD systems. */
-static int
-_rmt_rexec (char *host, char *user)
-{
- int saved_stdin = dup (STDIN_FILENO);
- int saved_stdout = dup (STDOUT_FILENO);
- struct servent *rexecserv;
- int result;
-
- /* When using cpio -o < filename, stdin is no longer the tty. But the
- rexec subroutine reads the login and the passwd on stdin, to allow
- remote execution of the command. So, reopen stdin and stdout on
- /dev/tty before the rexec and give them back their original value
- after. */
-
- if (! freopen ("/dev/tty", "r", stdin))
- freopen ("/dev/null", "r", stdin);
- if (! freopen ("/dev/tty", "w", stdout))
- freopen ("/dev/null", "w", stdout);
-
- if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
- error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
-
- result = rexec (&host, rexecserv->s_port, user, 0, "/etc/rmt", 0);
- if (fclose (stdin) == EOF)
- error (0, errno, _("stdin"));
- fdopen (saved_stdin, "r");
- if (fclose (stdout) == EOF)
- error (0, errno, _("stdout"));
- fdopen (saved_stdout, "w");
-
- return result;
-}
-
-#endif /* WITH_REXEC */
-
-/* Place into BUF a string representing OFLAG, which must be suitable
- as argument 2 of `open'. BUF must be large enough to hold the
- result. This function should generate a string that decode_oflag
- can parse. */
-static void
-encode_oflag (char *buf, int oflag)
-{
- sprintf (buf, "%d ", oflag);
-
- switch (oflag & O_ACCMODE)
- {
- case O_RDONLY: strcat (buf, "O_RDONLY"); break;
- case O_RDWR: strcat (buf, "O_RDWR"); break;
- case O_WRONLY: strcat (buf, "O_WRONLY"); break;
- default: abort ();
- }
-
-#ifdef O_APPEND
- if (oflag & O_APPEND) strcat (buf, "|O_APPEND");
-#endif
- if (oflag & O_CREAT) strcat (buf, "|O_CREAT");
-#ifdef O_DSYNC
- if (oflag & O_DSYNC) strcat (buf, "|O_DSYNC");
-#endif
- if (oflag & O_EXCL) strcat (buf, "|O_EXCL");
-#ifdef O_LARGEFILE
- if (oflag & O_LARGEFILE) strcat (buf, "|O_LARGEFILE");
-#endif
-#ifdef O_NOCTTY
- if (oflag & O_NOCTTY) strcat (buf, "|O_NOCTTY");
-#endif
-#ifdef O_NONBLOCK
- if (oflag & O_NONBLOCK) strcat (buf, "|O_NONBLOCK");
-#endif
-#ifdef O_RSYNC
- if (oflag & O_RSYNC) strcat (buf, "|O_RSYNC");
-#endif
-#ifdef O_SYNC
- if (oflag & O_SYNC) strcat (buf, "|O_SYNC");
-#endif
- if (oflag & O_TRUNC) strcat (buf, "|O_TRUNC");
-}
-
-/* Open a file (a magnetic tape device?) on the system specified in
- PATH, as the given user. PATH has the form `[USER@]HOST:FILE'.
- OPEN_MODE is O_RDONLY, O_WRONLY, etc. If successful, return the
- remote pipe number plus BIAS. REMOTE_SHELL may be overridden. On
- error, return -1. */
-int
-rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
-{
- int remote_pipe_number; /* pseudo, biased file descriptor */
- char *path_copy ; /* copy of path string */
- char *remote_host; /* remote host name */
- char *remote_file; /* remote file name (often a device) */
- char *remote_user; /* remote user name */
-
- /* Find an unused pair of file descriptors. */
-
- for (remote_pipe_number = 0;
- remote_pipe_number < MAXUNIT;
- remote_pipe_number++)
- if (READ_SIDE (remote_pipe_number) == -1
- && WRITE_SIDE (remote_pipe_number) == -1)
- break;
-
- if (remote_pipe_number == MAXUNIT)
- {
- errno = EMFILE;
- return -1;
- }
-
- /* Pull apart the system and device, and optional user. */
-
- {
- char *cursor;
-
- path_copy = xstrdup (path);
- remote_host = path_copy;
- remote_user = 0;
- remote_file = 0;
-
- for (cursor = path_copy; *cursor; cursor++)
- switch (*cursor)
- {
- default:
- break;
-
- case '\n':
- /* Do not allow newlines in the path, since the protocol
- uses newline delimiters. */
- free (path_copy);
- errno = ENOENT;
- return -1;
-
- case '@':
- if (!remote_user)
- {
- remote_user = remote_host;
- *cursor = '\0';
- remote_host = cursor + 1;
- }
- break;
-
- case ':':
- if (!remote_file)
- {
- *cursor = '\0';
- remote_file = cursor + 1;
- }
- break;
- }
- }
-
- /* FIXME: Should somewhat validate the decoding, here. */
-
- if (remote_user && *remote_user == '\0')
- remote_user = 0;
-
-#if WITH_REXEC
-
- /* Execute the remote command using rexec. */
-
- READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user);
- if (READ_SIDE (remote_pipe_number) < 0)
- {
- int e = errno;
- free (path_copy);
- errno = e;
- return -1;
- }
-
- WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
-
-#else /* not WITH_REXEC */
- {
- const char *remote_shell_basename;
- pid_t status;
-
- /* Identify the remote command to be executed. */
-
- if (!remote_shell)
- remote_shell = getenv("TAR_RSH");
-
- if (!remote_shell)
- {
-#ifdef REMOTE_SHELL
- remote_shell = REMOTE_SHELL;
-#else
- free (path_copy);
- errno = EIO;
- return -1;
-#endif
- }
- remote_shell_basename = base_name (remote_shell);
-
- /* Set up the pipes for the `rsh' command, and fork. */
-
- if (pipe (to_remote[remote_pipe_number]) == -1
- || pipe (from_remote[remote_pipe_number]) == -1)
- {
- int e = errno;
- free (path_copy);
- errno = e;
- return -1;
- }
-
- status = fork ();
- if (status == -1)
- {
- int e = errno;
- free (path_copy);
- errno = e;
- return -1;
- }
-
- if (status == 0)
- {
- /* Child. */
-
- close (STDIN_FILENO);
- dup (to_remote[remote_pipe_number][PREAD]);
- close (to_remote[remote_pipe_number][PREAD]);
- close (to_remote[remote_pipe_number][PWRITE]);
-
- close (STDOUT_FILENO);
- dup (from_remote[remote_pipe_number][PWRITE]);
- close (from_remote[remote_pipe_number][PREAD]);
- close (from_remote[remote_pipe_number][PWRITE]);
-
-#if !MSDOS
- setuid (getuid ());
- setgid (getgid ());
-#endif
-
- if (remote_user)
- execlp (remote_shell, remote_shell_basename, "-l", remote_user,
- remote_host, "/etc/rmt", (char *) 0);
- else
- execlp (remote_shell, remote_shell_basename, remote_host,
- "/etc/rmt", (char *) 0);
-
- /* Bad problems if we get here. */
-
- /* In a previous version, _exit was used here instead of exit. */
- error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell"));
- }
-
- /* Parent. */
-
- close (from_remote[remote_pipe_number][PWRITE]);
- close (to_remote[remote_pipe_number][PREAD]);
- }
-#endif /* not WITH_REXEC */
-
- /* Attempt to open the tape device. */
-
- {
- size_t remote_file_len = strlen (remote_file);
- char *command_buffer = xmalloc (remote_file_len + 1000);
- sprintf (command_buffer, "O%s\n", remote_file);
- encode_oflag (command_buffer + remote_file_len + 2, open_mode);
- strcat (command_buffer, "\n");
- if (do_command (remote_pipe_number, command_buffer) == -1
- || get_status (remote_pipe_number) == -1)
- {
- int e = errno;
- free (command_buffer);
- free (path_copy);
- _rmt_shutdown (remote_pipe_number, e);
- return -1;
- }
- free (command_buffer);
- }
-
- free (path_copy);
- return remote_pipe_number + bias;
-}
-
-/* Close remote tape connection HANDLE and shut down. Return 0 if
- successful, -1 on error. */
-int
-rmt_close__ (int handle)
-{
- int status;
-
- if (do_command (handle, "C\n") == -1)
- return -1;
-
- status = get_status (handle);
- _rmt_shutdown (handle, errno);
- return status;
-}
-
-/* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.
- Return the number of bytes read on success, -1 on error. */
-ssize_t
-rmt_read__ (int handle, char *buffer, size_t length)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- ssize_t status, rlen;
- size_t counter;
-
- sprintf (command_buffer, "R%lu\n", (unsigned long) length);
- if (do_command (handle, command_buffer) == -1
- || (status = get_status (handle)) == -1)
- return -1;
-
- for (counter = 0; counter < status; counter += rlen, buffer += rlen)
- {
- rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
- if (rlen <= 0)
- {
- _rmt_shutdown (handle, EIO);
- return -1;
- }
- }
-
- return status;
-}
-
-/* Write LENGTH bytes from BUFFER to remote tape connection HANDLE.
- Return the number of bytes written on success, -1 on error. */
-ssize_t
-rmt_write__ (int handle, char *buffer, size_t length)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- RETSIGTYPE (*pipe_handler) ();
- size_t written;
-
- sprintf (command_buffer, "W%lu\n", (unsigned long) length);
- if (do_command (handle, command_buffer) == -1)
- return -1;
-
- pipe_handler = signal (SIGPIPE, SIG_IGN);
- written = full_write (WRITE_SIDE (handle), buffer, length);
- signal (SIGPIPE, pipe_handler);
- if (written == length)
- return get_status (handle);
-
- /* Write error. */
-
- _rmt_shutdown (handle, EIO);
- return -1;
-}
-
-/* Perform an imitation lseek operation on remote tape connection
- HANDLE. Return the new file offset if successful, -1 if on error. */
-off_t
-rmt_lseek__ (int handle, off_t offset, int whence)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- char operand_buffer[UINTMAX_STRSIZE_BOUND];
- uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
- char *p = operand_buffer + sizeof operand_buffer;
-
- do
- *--p = '0' + (int) (u % 10);
- while ((u /= 10) != 0);
- if (offset < 0)
- *--p = '-';
-
- switch (whence)
- {
- case SEEK_SET: whence = 0; break;
- case SEEK_CUR: whence = 1; break;
- case SEEK_END: whence = 2; break;
- default: abort ();
- }
-
- sprintf (command_buffer, "L%s\n%d\n", p, whence);
-
- if (do_command (handle, command_buffer) == -1)
- return -1;
-
- return get_status_off (handle);
-}
-
-/* Perform a raw tape operation on remote tape connection HANDLE.
- Return the results of the ioctl, or -1 on error. */
-int
-rmt_ioctl__ (int handle, int operation, char *argument)
-{
- switch (operation)
- {
- default:
- errno = EOPNOTSUPP;
- return -1;
-
-#ifdef MTIOCTOP
- case MTIOCTOP:
- {
- char command_buffer[COMMAND_BUFFER_SIZE];
- char operand_buffer[UINTMAX_STRSIZE_BOUND];
- uintmax_t u = (((struct mtop *) argument)->mt_count < 0
- ? - (uintmax_t) ((struct mtop *) argument)->mt_count
- : (uintmax_t) ((struct mtop *) argument)->mt_count);
- char *p = operand_buffer + sizeof operand_buffer;
-
- do
- *--p = '0' + (int) (u % 10);
- while ((u /= 10) != 0);
- if (((struct mtop *) argument)->mt_count < 0)
- *--p = '-';
-
- /* MTIOCTOP is the easy one. Nothing is transferred in binary. */
-
- sprintf (command_buffer, "I%d\n%s\n",
- ((struct mtop *) argument)->mt_op, p);
- if (do_command (handle, command_buffer) == -1)
- return -1;
-
- return get_status (handle);
- }
-#endif /* MTIOCTOP */
-
-#ifdef MTIOCGET
- case MTIOCGET:
- {
- ssize_t status;
- ssize_t counter;
-
- /* Grab the status and read it directly into the structure. This
- assumes that the status buffer is not padded and that 2 shorts
- fit in a long without any word alignment problems; i.e., the
- whole struct is contiguous. NOTE - this is probably NOT a good
- assumption. */
-
- if (do_command (handle, "S") == -1
- || (status = get_status (handle), status == -1))
- return -1;
-
- for (; status > 0; status -= counter, argument += counter)
- {
- counter = safe_read (READ_SIDE (handle), argument, status);
- if (counter <= 0)
- {
- _rmt_shutdown (handle, EIO);
- return -1;
- }
- }
-
- /* Check for byte position. mt_type (or mt_model) is a small integer
- field (normally) so we will check its magnitude. If it is larger
- than 256, we will assume that the bytes are swapped and go through
- and reverse all the bytes. */
-
- if (((struct mtget *) argument)->MTIO_CHECK_FIELD < 256)
- return 0;
-
- for (counter = 0; counter < status; counter += 2)
- {
- char copy = argument[counter];
-
- argument[counter] = argument[counter + 1];
- argument[counter + 1] = copy;
- }
-
- return 0;
- }
-#endif /* MTIOCGET */
-
- }
-}
diff --git a/contrib/tar/src/system.h b/contrib/tar/src/system.h
deleted file mode 100644
index 8e88159..0000000
--- a/contrib/tar/src/system.h
+++ /dev/null
@@ -1,587 +0,0 @@
-/* System dependent definitions for GNU tar.
-
- Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software
- Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-/* Declare alloca. AIX requires this to be the first thing in the file. */
-
-#if __GNUC__
-# define alloca __builtin_alloca
-#else
-# if HAVE_ALLOCA_H
-# include <alloca.h>
-# else
-# ifdef _AIX
- #pragma alloca
-# else
-# ifndef alloca
-char *alloca ();
-# endif
-# endif
-# endif
-#endif
-
-#ifndef __attribute__
-/* This feature is available in gcc versions 2.5 and later. */
-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
-# define __attribute__(Spec) /* empty */
-# endif
-#endif
-
-#include <sys/types.h>
-#include <ctype.h>
-
-#if HAVE_STDDEF_H
-# include <stddef.h>
-#endif
-#ifndef offsetof
-# define offsetof(type, ident) ((size_t) &((type *) 0)->ident)
-#endif
-
-/* IN_CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
- as an argument to <ctype.h> macros like `isspace'. */
-#if STDC_HEADERS
-# define IN_CTYPE_DOMAIN(c) 1
-#else
-# define IN_CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
-#endif
-
-#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
-#define ISODIGIT(c) ((unsigned) (c) - '0' <= 7)
-#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
-#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
-
-/* Declare string and memory handling routines. Take care that an ANSI
- string.h and pre-ANSI memory.h might conflict, and that memory.h and
- strings.h conflict on some systems. */
-
-#if STDC_HEADERS || HAVE_STRING_H
-# include <string.h>
-# if !STDC_HEADERS && HAVE_MEMORY_H
-# include <memory.h>
-# endif
-#else
-# include <strings.h>
-# ifndef strchr
-# define strchr index
-# endif
-# ifndef strrchr
-# define strrchr rindex
-# endif
-# ifndef memcpy
-# define memcpy(d, s, n) bcopy ((char const *) (s), (char *) (d), n)
-# endif
-# ifndef memcmp
-# define memcmp(a, b, n) bcmp ((char const *) (a), (char const *) (b), n)
-# endif
-#endif
-
-/* Declare errno. */
-
-#include <errno.h>
-#ifndef errno
-extern int errno;
-#endif
-
-/* Declare open parameters. */
-
-#if HAVE_FCNTL_H
-# include <fcntl.h>
-#else
-# include <sys/file.h>
-#endif
- /* Pick only one of the next three: */
-#ifndef O_RDONLY
-# define O_RDONLY 0 /* only allow read */
-#endif
-#ifndef O_WRONLY
-# define O_WRONLY 1 /* only allow write */
-#endif
-#ifndef O_RDWR
-# define O_RDWR 2 /* both are allowed */
-#endif
-#ifndef O_ACCMODE
-# define O_ACCMODE (O_RDONLY | O_RDWR | O_WRONLY)
-#endif
- /* The rest can be OR-ed in to the above: */
-#ifndef O_CREAT
-# define O_CREAT 8 /* create file if needed */
-#endif
-#ifndef O_EXCL
-# define O_EXCL 16 /* file cannot already exist */
-#endif
-#ifndef O_TRUNC
-# define O_TRUNC 32 /* truncate file on open */
-#endif
- /* MS-DOG forever, with my love! */
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-/* Declare file status routines and bits. */
-
-#include <sys/stat.h>
-
-#if !HAVE_LSTAT && !defined lstat
-# define lstat stat
-#endif
-
-#if STX_HIDDEN && !_LARGE_FILES /* AIX */
-# ifdef stat
-# undef stat
-# endif
-# define stat(path, buf) statx (path, buf, STATSIZE, STX_HIDDEN)
-# ifdef lstat
-# undef lstat
-# endif
-# define lstat(path, buf) statx (path, buf, STATSIZE, STX_HIDDEN | STX_LINK)
-#endif
-
-#if STAT_MACROS_BROKEN
-# undef S_ISBLK
-# undef S_ISCHR
-# undef S_ISCTG
-# undef S_ISDIR
-# undef S_ISFIFO
-# undef S_ISLNK
-# undef S_ISREG
-# undef S_ISSOCK
-#endif
-
-/* On MSDOS, there are missing things from <sys/stat.h>. */
-#if MSDOS
-# define S_ISUID 0
-# define S_ISGID 0
-# define S_ISVTX 0
-#endif
-
-#ifndef S_ISDIR
-# define S_ISDIR(Mode) (((Mode) & S_IFMT) == S_IFDIR)
-#endif
-#ifndef S_ISREG
-# define S_ISREG(Mode) (((Mode) & S_IFMT) == S_IFREG)
-#endif
-
-#ifndef S_ISBLK
-# ifdef S_IFBLK
-# define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
-# else
-# define S_ISBLK(Mode) 0
-# endif
-#endif
-#ifndef S_ISCHR
-# ifdef S_IFCHR
-# define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
-# else
-# define S_ISCHR(Mode) 0
-# endif
-#endif
-#ifndef S_ISCTG
-# ifdef S_IFCTG
-# define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
-# else
-# define S_ISCTG(Mode) 0
-# endif
-#endif
-#ifndef S_ISDOOR
-# define S_ISDOOR(Mode) 0
-#endif
-#ifndef S_ISFIFO
-# ifdef S_IFIFO
-# define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
-# else
-# define S_ISFIFO(Mode) 0
-# endif
-#endif
-#ifndef S_ISLNK
-# ifdef S_IFLNK
-# define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
-# else
-# define S_ISLNK(Mode) 0
-# endif
-#endif
-#ifndef S_ISSOCK
-# ifdef S_IFSOCK
-# define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
-# else
-# define S_ISSOCK(Mode) 0
-# endif
-#endif
-
-#if !HAVE_MKFIFO && !defined mkfifo && defined S_IFIFO
-# define mkfifo(Path, Mode) (mknod (Path, (Mode) | S_IFIFO, 0))
-#endif
-
-#ifndef S_ISUID
-# define S_ISUID 0004000
-#endif
-#ifndef S_ISGID
-# define S_ISGID 0002000
-#endif
-#ifndef S_ISVTX
-# define S_ISVTX 0001000
-#endif
-#ifndef S_IRUSR
-# define S_IRUSR 0000400
-#endif
-#ifndef S_IWUSR
-# define S_IWUSR 0000200
-#endif
-#ifndef S_IXUSR
-# define S_IXUSR 0000100
-#endif
-#ifndef S_IRGRP
-# define S_IRGRP 0000040
-#endif
-#ifndef S_IWGRP
-# define S_IWGRP 0000020
-#endif
-#ifndef S_IXGRP
-# define S_IXGRP 0000010
-#endif
-#ifndef S_IROTH
-# define S_IROTH 0000004
-#endif
-#ifndef S_IWOTH
-# define S_IWOTH 0000002
-#endif
-#ifndef S_IXOTH
-# define S_IXOTH 0000001
-#endif
-
-#define MODE_WXUSR (S_IWUSR | S_IXUSR)
-#define MODE_R (S_IRUSR | S_IRGRP | S_IROTH)
-#define MODE_RW (S_IWUSR | S_IWGRP | S_IWOTH | MODE_R)
-#define MODE_RWX (S_IXUSR | S_IXGRP | S_IXOTH | MODE_RW)
-#define MODE_ALL (S_ISUID | S_ISGID | S_ISVTX | MODE_RWX)
-
-#ifndef _POSIX_SOURCE
-# include <sys/param.h>
-#endif
-
-/* Include <unistd.h> before any preprocessor test of _POSIX_VERSION. */
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifndef SEEK_SET
-# define SEEK_SET 0
-#endif
-#ifndef SEEK_CUR
-# define SEEK_CUR 1
-#endif
-#ifndef SEEK_END
-# define SEEK_END 2
-#endif
-
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif
-#ifndef STDERR_FILENO
-# define STDERR_FILENO 2
-#endif
-
-/* Declare make device, major and minor. Since major is a function on
- SVR4, we have to resort to GOT_MAJOR instead of just testing if
- major is #define'd. */
-
-#if MAJOR_IN_MKDEV
-# include <sys/mkdev.h>
-# define GOT_MAJOR
-#endif
-
-#if MAJOR_IN_SYSMACROS
-# include <sys/sysmacros.h>
-# define GOT_MAJOR
-#endif
-
-/* Some <sys/types.h> defines the macros. */
-#ifdef major
-# define GOT_MAJOR
-#endif
-
-#ifndef GOT_MAJOR
-# if MSDOS
-# define major(Device) (Device)
-# define minor(Device) (Device)
-# define makedev(Major, Minor) (((Major) << 8) | (Minor))
-# define GOT_MAJOR
-# endif
-#endif
-
-/* For HP-UX before HP-UX 8, major/minor are not in <sys/sysmacros.h>. */
-#ifndef GOT_MAJOR
-# if defined(hpux) || defined(__hpux__) || defined(__hpux)
-# include <sys/mknod.h>
-# define GOT_MAJOR
-# endif
-#endif
-
-#ifndef GOT_MAJOR
-# define major(Device) (((Device) >> 8) & 0xff)
-# define minor(Device) ((Device) & 0xff)
-# define makedev(Major, Minor) (((Major) << 8) | (Minor))
-#endif
-
-#undef GOT_MAJOR
-
-/* Declare wait status. */
-
-#if HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(s) (((s) >> 8) & 0xff)
-#endif
-#ifndef WIFSIGNALED
-# define WIFSIGNALED(s) (((s) & 0xffff) - 1 < (unsigned) 0xff)
-#endif
-#ifndef WTERMSIG
-# define WTERMSIG(s) ((s) & 0x7f)
-#endif
-
-/* FIXME: It is wrong to use BLOCKSIZE for buffers when the logical block
- size is greater than 512 bytes; so ST_BLKSIZE code below, in preparation
- for some cleanup in this area, later. */
-
-/* Get or fake the disk device blocksize. Usually defined by sys/param.h
- (if at all). */
-
-#if !defined(DEV_BSIZE) && defined(BSIZE)
-# define DEV_BSIZE BSIZE
-#endif
-#if !defined(DEV_BSIZE) && defined(BBSIZE) /* SGI */
-# define DEV_BSIZE BBSIZE
-#endif
-#ifndef DEV_BSIZE
-# define DEV_BSIZE 4096
-#endif
-
-/* Extract or fake data from a `struct stat'. ST_BLKSIZE gives the
- optimal I/O blocksize for the file, in bytes. Some systems, like
- Sequents, return st_blksize of 0 on pipes. */
-
-#if !HAVE_ST_BLKSIZE
-# define ST_BLKSIZE(Statbuf) DEV_BSIZE
-#else
-# define ST_BLKSIZE(Statbuf) \
- ((Statbuf).st_blksize > 0 ? (Statbuf).st_blksize : DEV_BSIZE)
-#endif
-
-/* Extract or fake data from a `struct stat'. ST_NBLOCKS gives the
- number of ST_NBLOCKSIZE-byte blocks in the file (including indirect blocks).
- HP-UX counts st_blocks in 1024-byte units,
- this loses when mixing HP-UX and BSD filesystems with NFS. AIX PS/2
- counts st_blocks in 4K units. */
-
-#if !HAVE_ST_BLOCKS
-# if defined(_POSIX_SOURCE) || !defined(BSIZE)
-# define ST_NBLOCKS(Statbuf) ((Statbuf).st_size / ST_NBLOCKSIZE + ((Statbuf).st_size % ST_NBLOCKSIZE != 0))
-# else
- off_t st_blocks ();
-# define ST_NBLOCKS(Statbuf) (st_blocks ((Statbuf).st_size))
-# endif
-#else
-# define ST_NBLOCKS(Statbuf) ((Statbuf).st_blocks)
-# if defined(hpux) || defined(__hpux__) || defined(__hpux)
-# define ST_NBLOCKSIZE 1024
-# else
-# if defined(_AIX) && defined(_I386)
-# define ST_NBLOCKSIZE (4 * 1024)
-# endif
-# endif
-#endif
-
-#ifndef ST_NBLOCKSIZE
-#define ST_NBLOCKSIZE 512
-#endif
-
-/* This is a real challenge to properly get MTIO* symbols :-(. ISC uses
- <sys/gentape.h>. SCO and BSDi uses <sys/tape.h>; BSDi also requires
- <sys/tprintf.h> and <sys/device.h> for defining tp_dev and tpr_t. It
- seems that the rest use <sys/mtio.h>, which itself requires other files,
- depending on systems. Pyramid defines _IOW in <sgtty.h>, for example. */
-
-#if HAVE_SYS_GENTAPE_H
-# include <sys/gentape.h>
-#else
-# if HAVE_SYS_TAPE_H
-# if HAVE_SYS_DEVICE_H
-# include <sys/device.h>
-# endif
-# if HAVE_SYS_BUF_H
-# include <sys/buf.h>
-# endif
-# if HAVE_SYS_TPRINTF_H
-# include <sys/tprintf.h>
-# endif
-# include <sys/tape.h>
-# else
-# if HAVE_SYS_MTIO_H
-# include <sys/ioctl.h>
-# if HAVE_SGTTY_H
-# include <sgtty.h>
-# endif
-# if HAVE_SYS_IO_TRIOCTL_H
-# include <sys/io/trioctl.h>
-# endif
-# include <sys/mtio.h>
-# endif
-# endif
-#endif
-
-/* Declare standard functions. */
-
-#if STDC_HEADERS
-# include <stdlib.h>
-#else
-void *malloc ();
-void *realloc ();
-char *getenv ();
-#endif
-
-#if HAVE_STDBOOL_H
-# include <stdbool.h>
-#else
-typedef enum {false = 0, true = 1} bool;
-#endif
-
-#include <stdio.h>
-
-#ifndef _POSIX_VERSION
-# if MSDOS
-# include <io.h>
-# else
-off_t lseek ();
-# endif
-#endif
-
-#if WITH_DMALLOC
-# undef HAVE_VALLOC
-# define DMALLOC_FUNC_CHECK
-# include <dmalloc.h>
-#endif
-
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#ifndef CHAR_BIT
-# define CHAR_BIT 8
-#endif
-
-#ifndef CHAR_MAX
-# define CHAR_MAX TYPE_MAXIMUM (char)
-#endif
-
-#ifndef UCHAR_MAX
-# define UCHAR_MAX TYPE_MAXIMUM (unsigned char)
-#endif
-
-#ifndef LONG_MAX
-# define LONG_MAX TYPE_MAXIMUM (long)
-#endif
-
-#ifndef MB_LEN_MAX
-# define MB_LEN_MAX 1
-#endif
-
-#if HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-
-/* These macros work even on ones'-complement hosts (!).
- The extra casts work around common compiler bugs. */
-#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
-#define TYPE_MINIMUM(t) (TYPE_SIGNED (t) \
- ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \
- : (t) 0)
-#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
-
-/* Bound on length of the string representing an integer value of type t.
- Subtract one for the sign bit if t is signed;
- 302 / 1000 is log10 (2) rounded up;
- add one for integer division truncation;
- add one more for a minus sign if t is signed. */
-#define INT_STRLEN_BOUND(t) \
- ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
- + 1 + TYPE_SIGNED (t))
-
-#define UINTMAX_STRSIZE_BOUND (INT_STRLEN_BOUND (uintmax_t) + 1)
-
-/* Prototypes for external functions. */
-
-#ifndef PARAMS
-# if PROTOTYPES
-# define PARAMS(Args) Args
-# else
-# define PARAMS(Args) ()
-# endif
-#endif
-
-#if HAVE_LOCALE_H
-# include <locale.h>
-#endif
-#if !HAVE_SETLOCALE
-# define setlocale(Category, Locale) /* empty */
-#endif
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# undef bindtextdomain
-# define bindtextdomain(Domain, Directory) /* empty */
-# undef textdomain
-# define textdomain(Domain) /* empty */
-# define _(Text) Text
-#endif
-#define N_(Text) Text
-
-#include <time.h>
-#ifndef time
-time_t time ();
-#endif
-
-/* Library modules. */
-
-#include <dirname.h>
-#include <error.h>
-#include <savedir.h>
-#include <xalloc.h>
-
-#if !HAVE_STRSTR
-char *strstr PARAMS ((const char *, const char *));
-#endif
-
-#if HAVE_VALLOC
-# ifndef valloc
-void *valloc ();
-# endif
-#else
-# define valloc(Size) malloc (Size)
-#endif
-
-char *xstrdup PARAMS ((char const *));
diff --git a/contrib/tar/src/tar.c b/contrib/tar/src/tar.c
deleted file mode 100644
index 7d872fa..0000000
--- a/contrib/tar/src/tar.c
+++ /dev/null
@@ -1,1366 +0,0 @@
-/* A tar (tape archiver) program.
-
- Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001
- Free Software Foundation, Inc.
-
- Written by John Gilmore, starting 1985-08-25.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* $FreeBSD$ */
-
-#include "system.h"
-
-#include <fnmatch.h>
-#include <getopt.h>
-
-#include <signal.h>
-#if ! defined SIGCHLD && defined SIGCLD
-# define SIGCHLD SIGCLD
-#endif
-
-/* The following causes "common.h" to produce definitions of all the global
- variables, rather than just "extern" declarations of them. GNU tar does
- depend on the system loader to preset all GLOBAL variables to neutral (or
- zero) values; explicit initialization is usually not done. */
-#define GLOBAL
-#include "common.h"
-
-#include <print-copyr.h>
-#include <localedir.h>
-#include <prepargs.h>
-#include <quotearg.h>
-#include <xstrtol.h>
-
-time_t get_date ();
-
-/* Local declarations. */
-
-#ifndef DEFAULT_ARCHIVE
-# define DEFAULT_ARCHIVE "tar.out"
-#endif
-
-#ifndef DEFAULT_BLOCKING
-# define DEFAULT_BLOCKING 20
-#endif
-
-static void usage PARAMS ((int)) __attribute__ ((noreturn));
-
-/* Miscellaneous. */
-
-/* Name of option using stdin. */
-static const char *stdin_used_by;
-
-/* Doesn't return if stdin already requested. */
-void
-request_stdin (const char *option)
-{
- if (stdin_used_by)
- USAGE_ERROR ((0, 0, _("Options `-%s' and `-%s' both want standard input"),
- stdin_used_by, option));
-
- stdin_used_by = option;
-}
-
-/* Returns true if and only if the user typed 'y' or 'Y'. */
-int
-confirm (const char *message_action, const char *message_name)
-{
- static FILE *confirm_file;
- static int confirm_file_EOF;
-
- if (!confirm_file)
- {
- if (archive == 0 || stdin_used_by)
- {
- confirm_file = fopen (TTY_NAME, "r");
- if (! confirm_file)
- open_fatal (TTY_NAME);
- }
- else
- {
- request_stdin ("-w");
- confirm_file = stdin;
- }
- }
-
- fprintf (stdlis, "%s %s?", message_action, quote (message_name));
- fflush (stdlis);
-
- {
- int reply = confirm_file_EOF ? EOF : getc (confirm_file);
- int character;
-
- for (character = reply;
- character != '\n';
- character = getc (confirm_file))
- if (character == EOF)
- {
- confirm_file_EOF = 1;
- fputc ('\n', stdlis);
- fflush (stdlis);
- break;
- }
- return reply == 'y' || reply == 'Y';
- }
-}
-
-/* Options. */
-
-/* For long options that unconditionally set a single flag, we have getopt
- do it. For the others, we share the code for the equivalent short
- named option, the name of which is stored in the otherwise-unused `val'
- field of the `struct option'; for long options that have no equivalent
- short option, we use non-characters as pseudo short options,
- starting at CHAR_MAX + 1 and going upwards. */
-
-enum
-{
- ANCHORED_OPTION = CHAR_MAX + 1,
- BACKUP_OPTION,
- DELETE_OPTION,
- EXCLUDE_OPTION,
- GROUP_OPTION,
- IGNORE_CASE_OPTION,
- MODE_OPTION,
- NEWER_MTIME_OPTION,
- NO_ANCHORED_OPTION,
- NO_IGNORE_CASE_OPTION,
- NO_WILDCARDS_OPTION,
- NO_WILDCARDS_MATCH_SLASH_OPTION,
- NULL_OPTION,
- OVERWRITE_OPTION,
- OVERWRITE_DIR_OPTION,
- OWNER_OPTION,
- POSIX_OPTION,
- PRESERVE_OPTION,
- RECORD_SIZE_OPTION,
- RSH_COMMAND_OPTION,
- SUFFIX_OPTION,
- USE_COMPRESS_PROGRAM_OPTION,
- VOLNO_FILE_OPTION,
- WILDCARDS_OPTION,
- WILDCARDS_MATCH_SLASH_OPTION,
-
- /* Some cleanup is being made in GNU tar long options. Using old names is
- allowed for a while, but will also send a warning to stderr. Take old
- names out in 1.14, or in summer 1997, whichever happens last. */
-
- OBSOLETE_ABSOLUTE_NAMES,
- OBSOLETE_BLOCK_COMPRESS,
- OBSOLETE_BLOCKING_FACTOR,
- OBSOLETE_BLOCK_NUMBER,
- OBSOLETE_READ_FULL_RECORDS,
- OBSOLETE_TOUCH,
- OBSOLETE_VERSION_CONTROL
-};
-
-/* If nonzero, display usage information and exit. */
-static int show_help;
-
-/* If nonzero, print the version on standard output and exit. */
-static int show_version;
-
-static struct option long_options[] =
-{
- {"absolute-names", no_argument, 0, 'P'},
- {"absolute-paths", no_argument, 0, OBSOLETE_ABSOLUTE_NAMES},
- {"after-date", required_argument, 0, 'N'},
- {"anchored", no_argument, 0, ANCHORED_OPTION},
- {"append", no_argument, 0, 'r'},
- {"atime-preserve", no_argument, &atime_preserve_option, 1},
- {"backup", optional_argument, 0, BACKUP_OPTION},
- {"block-compress", no_argument, 0, OBSOLETE_BLOCK_COMPRESS},
- {"block-number", no_argument, 0, 'R'},
- {"block-size", required_argument, 0, OBSOLETE_BLOCKING_FACTOR},
- {"blocking-factor", required_argument, 0, 'b'},
- {"bzip", no_argument, 0, 'j'},
- {"bzip2", no_argument, 0, 'j'},
- {"bunzip2", no_argument, 0, 'j'},
- {"catenate", no_argument, 0, 'A'},
- {"checkpoint", no_argument, &checkpoint_option, 1},
- {"compare", no_argument, 0, 'd'},
- {"compress", no_argument, 0, 'Z'},
- {"concatenate", no_argument, 0, 'A'},
- {"confirmation", no_argument, 0, 'w'},
- /* FIXME: --selective as a synonym for --confirmation? */
- {"create", no_argument, 0, 'c'},
- {"delete", no_argument, 0, DELETE_OPTION},
- {"dereference", no_argument, 0, 'h'},
- {"diff", no_argument, 0, 'd'},
- {"directory", required_argument, 0, 'C'},
- {"exclude", required_argument, 0, EXCLUDE_OPTION},
- {"exclude-from", required_argument, 0, 'X'},
- {"extract", no_argument, 0, 'x'},
- {"fast-read", no_argument, &fast_read_option, 1},
- {"file", required_argument, 0, 'f'},
- {"files-from", required_argument, 0, 'T'},
- {"force-local", no_argument, &force_local_option, 1},
- {"get", no_argument, 0, 'x'},
- {"group", required_argument, 0, GROUP_OPTION},
- {"gunzip", no_argument, 0, 'z'},
- {"gzip", no_argument, 0, 'z'},
- {"help", no_argument, &show_help, 1},
- {"ignore-case", no_argument, 0, IGNORE_CASE_OPTION},
- {"ignore-failed-read", no_argument, &ignore_failed_read_option, 1},
- {"ignore-zeros", no_argument, 0, 'i'},
- /* FIXME: --ignore-end as a new name for --ignore-zeros? */
- {"incremental", no_argument, 0, 'G'},
- {"info-script", required_argument, 0, 'F'},
- {"interactive", no_argument, 0, 'w'},
- {"keep-old-files", no_argument, 0, 'k'},
- {"label", required_argument, 0, 'V'},
- {"list", no_argument, 0, 't'},
- {"listed-incremental", required_argument, 0, 'g'},
- {"mode", required_argument, 0, MODE_OPTION},
- {"modification-time", no_argument, 0, OBSOLETE_TOUCH},
- {"multi-volume", no_argument, 0, 'M'},
- {"new-volume-script", required_argument, 0, 'F'},
- {"newer", required_argument, 0, 'N'},
- {"newer-mtime", required_argument, 0, NEWER_MTIME_OPTION},
- {"null", no_argument, 0, NULL_OPTION},
- {"no-anchored", no_argument, 0, NO_ANCHORED_OPTION},
- {"no-ignore-case", no_argument, 0, NO_IGNORE_CASE_OPTION},
- {"no-wildcards", no_argument, 0, NO_WILDCARDS_OPTION},
- {"no-wildcards-match-slash", no_argument, 0, NO_WILDCARDS_MATCH_SLASH_OPTION},
- {"norecurse", no_argument, &recursion_option, 0},
- {"no-recursion", no_argument, &recursion_option, 0},
- {"no-same-owner", no_argument, &same_owner_option, -1},
- {"no-same-permissions", no_argument, &same_permissions_option, -1},
- {"numeric-owner", no_argument, &numeric_owner_option, 1},
- {"old-archive", no_argument, 0, 'o'},
- {"one-file-system", no_argument, 0, 'l'},
- {"overwrite", no_argument, 0, OVERWRITE_OPTION},
- {"overwrite-dir", no_argument, 0, OVERWRITE_DIR_OPTION},
- {"owner", required_argument, 0, OWNER_OPTION},
- {"portability", no_argument, 0, 'o'},
- {"posix", no_argument, 0, POSIX_OPTION},
- {"preserve", no_argument, 0, PRESERVE_OPTION},
- {"preserve-order", no_argument, 0, 's'},
- {"preserve-permissions", no_argument, 0, 'p'},
- {"recursion", no_argument, &recursion_option, FNM_LEADING_DIR},
- {"recursive-unlink", no_argument, &recursive_unlink_option, 1},
- {"read-full-blocks", no_argument, 0, OBSOLETE_READ_FULL_RECORDS},
- {"read-full-records", no_argument, 0, 'B'},
- /* FIXME: --partial-blocks might be a synonym for --read-full-records? */
- {"record-number", no_argument, 0, OBSOLETE_BLOCK_NUMBER},
- {"record-size", required_argument, 0, RECORD_SIZE_OPTION},
- {"remove-files", no_argument, &remove_files_option, 1},
- {"rsh-command", required_argument, 0, RSH_COMMAND_OPTION},
- {"same-order", no_argument, 0, 's'},
- {"same-owner", no_argument, &same_owner_option, 1},
- {"same-permissions", no_argument, 0, 'p'},
- {"show-omitted-dirs", no_argument, &show_omitted_dirs_option, 1},
- {"sparse", no_argument, 0, 'S'},
- {"starting-file", required_argument, 0, 'K'},
- {"suffix", required_argument, 0, SUFFIX_OPTION},
- {"tape-length", required_argument, 0, 'L'},
- {"to-stdout", no_argument, 0, 'O'},
- {"totals", no_argument, &totals_option, 1},
- {"touch", no_argument, 0, 'm'},
- {"uncompress", no_argument, 0, 'Z'},
- {"ungzip", no_argument, 0, 'z'},
- {"unlink", no_argument, 0, 'U'},
- {"unlink-first", no_argument, 0, 'U'},
- {"update", no_argument, 0, 'u'},
- {"use-compress-program", required_argument, 0, USE_COMPRESS_PROGRAM_OPTION},
- {"verbose", no_argument, 0, 'v'},
- {"verify", no_argument, 0, 'W'},
- {"version", no_argument, &show_version, 1},
- {"version-control", required_argument, 0, OBSOLETE_VERSION_CONTROL},
- {"volno-file", required_argument, 0, VOLNO_FILE_OPTION},
- {"wildcards", no_argument, 0, WILDCARDS_OPTION},
- {"wildcards-match-slash", no_argument, 0, WILDCARDS_MATCH_SLASH_OPTION},
-
- {0, 0, 0, 0}
-};
-
-/* Print a usage message and exit with STATUS. */
-static void
-usage (int status)
-{
- if (status != TAREXIT_SUCCESS)
- fprintf (stderr, _("Try `%s --help' for more information.\n"),
- program_name);
- else
- {
- fputs (_("\
-GNU `tar' saves many files together into a single tape or disk archive, and\n\
-can restore individual files from the archive.\n"),
- stdout);
- printf (_("\nUsage: %s [OPTION]... [FILE]...\n\
-\n\
-Examples:\n\
- %s -cf archive.tar foo bar # Create archive.tar from files foo and bar.\n\
- %s -tvf archive.tar # List all files in archive.tar verbosely.\n\
- %s -xf archive.tar # Extract all files from archive.tar.\n"),
- program_name, program_name, program_name, program_name);
- fputs (_("\
-\n\
-If a long option shows an argument as mandatory, then it is mandatory\n\
-for the equivalent short option also. Similarly for optional arguments.\n"),
- stdout);
- fputs(_("\
-\n\
-Main operation mode:\n\
- -t, --list list the contents of an archive\n\
- -x, --extract, --get extract files from an archive\n\
- -c, --create create a new archive\n\
- -d, --diff, --compare find differences between archive and file system\n\
- -r, --append append files to the end of an archive\n\
- -u, --update only append files newer than copy in archive\n\
- -A, --catenate append tar files to an archive\n\
- --concatenate same as -A\n\
- --delete delete from the archive (not on mag tapes!)\n"),
- stdout);
- fputs (_("\
-\n\
-Operation modifiers:\n\
- -W, --verify attempt to verify the archive after writing it\n\
- --remove-files remove files after adding them to the archive\n\
- -k, --keep-old-files don't replace existing files when extracting\n\
- --overwrite overwrite existing files when extracting\n\
- --overwrite-dir overwrite directory metadata when extracting\n\
- -U, --unlink,\n\
- --unlink-first remove each file prior to extracting over it\n\
- --recursive-unlink empty hierarchies prior to extracting directory\n\
- -S, --sparse handle sparse files efficiently\n\
- -O, --to-stdout extract files to standard output\n\
- -G, --incremental handle old GNU-format incremental backup\n\
- -g, --listed-incremental=FILE\n\
- handle new GNU-format incremental backup\n\
- --ignore-failed-read do not exit with nonzero on unreadable files\n\
- --fast-read stop after desired names in archive have been found\n"),
- stdout);
- fputs (_("\
-\n\
-Handling of file attributes:\n\
- --owner=NAME force NAME as owner for added files\n\
- --group=NAME force NAME as group for added files\n\
- --mode=CHANGES force (symbolic) mode CHANGES for added files\n\
- --atime-preserve don't change access times on dumped files\n\
- -m, --modification-time don't extract file modified time\n\
- --same-owner try extracting files with the same ownership\n\
- --show-omitted-dirs show omitted directories while processing the\n\
- archive\n\
- --no-same-owner extract files as yourself\n\
- --numeric-owner always use numbers for user/group names\n\
- -p, --same-permissions extract permissions information\n\
- --no-same-permissions do not extract permissions information\n\
- --preserve-permissions same as -p\n\
- -s, --same-order sort names to extract to match archive\n\
- --preserve-order same as -s\n\
- --preserve same as both -p and -s\n"),
- stdout);
- fputs (_("\
-\n\
-Device selection and switching:\n\
- -f, --file=ARCHIVE use archive file or device ARCHIVE\n\
- --force-local archive file is local even if it has a colon\n\
- --rsh-command=COMMAND use remote COMMAND instead of rsh\n\
- -[0-7][lmh] specify drive and density\n\
- -M, --multi-volume create/list/extract multi-volume archive\n\
- -L, --tape-length=NUM change tape after writing NUM x 1024 bytes\n\
- -F, --info-script=FILE run script at end of each tape (implies -M)\n\
- --new-volume-script=FILE same as -F FILE\n\
- --volno-file=FILE use/update the volume number in FILE\n"),
- stdout);
- fputs (_("\
-\n\
-Device blocking:\n\
- -b, --blocking-factor=BLOCKS BLOCKS x 512 bytes per record\n\
- --record-size=SIZE SIZE bytes per record, multiple of 512\n\
- -i, --ignore-zeros ignore zeroed blocks in archive (means EOF)\n\
- -B, --read-full-records reblock as we read (for 4.2BSD pipes)\n"),
- stdout);
- fputs (_("\
-\n\
-Archive format selection:\n\
- -V, --label=NAME create archive with volume name NAME\n\
- PATTERN at list/extract time, a globbing PATTERN\n\
- -o, --old-archive, --portability write a V7 format archive\n\
- --posix write a POSIX format archive\n\
- -j, -y, --bzip, --bzip2, --bunzip2 filter the archive through bzip2\n\
- -z, --gzip, --ungzip filter the archive through gzip\n\
- -Z, --compress, --uncompress filter the archive through compress\n\
- --use-compress-program=PROG filter through PROG (must accept -d)\n"),
- stdout);
- fputs (_("\
-\n\
-Local file selection:\n\
- -C, --directory=DIR change to directory DIR\n\
- -T, -I, --files-from=NAME get names to extract or create from file NAME\n\
- --null -T reads null-terminated names, disable -C\n\
- --exclude=PATTERN exclude files, given as a a globbing PATTERN\n\
- -X, --exclude-from=FILE exclude patterns listed in FILE\n\
- --anchored exclude patterns match file name start (default)\n\
- --no-anchored exclude patterns match after any /\n\
- --ignore-case exclusion ignores case\n\
- --no-ignore-case exclusion is case sensitive (default)\n\
- --wildcards exclude patterns use wildcards (default)\n\
- --no-wildcards exclude patterns are plain strings\n\
- --wildcards-match-slash exclude pattern wildcards match '/' (default)\n\
- --no-wildcards-match-slash exclude pattern wildcards do not match '/'\n\
- -P, --absolute-names don't strip leading `/'s from file names\n\
- -h, --dereference dump instead the files symlinks point to\n\
- -n, --norecurse\n\
- --no-recursion avoid descending automatically in directories\n\
- -l, --one-file-system stay in local file system when creating archive\n\
- -K, --starting-file=NAME begin at file NAME in the archive\n"),
- stdout);
-#if !MSDOS
- fputs (_("\
- -N, --newer=DATE only store files with creation time newer than\n\
- DATE\n\
- --newer-mtime=DATE only store files with modification time newer\n\
- than DATE\n\
- --after-date=DATE same as -N\n"),
- stdout);
-#endif
- fputs (_("\
- --backup[=CONTROL] backup before removal, choose version control\n\
- --suffix=SUFFIX backup before removal, override usual suffix\n"),
- stdout);
- fputs (_("\
-\n\
-Informative output:\n\
- --help print this help, then exit\n\
- --version print tar program version number, then exit\n\
- -v, --verbose verbosely list files processed\n\
- --checkpoint print number of buffer reads/writes\n\
- --totals print total bytes written while creating archive\n\
- -R, --block-number show block number within archive with each message\n\
- -w, --interactive ask for confirmation for every action\n\
- --confirmation same as -w\n"),
- stdout);
- fputs (_("\
-\n\
-The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
-The version control may be set with --backup or VERSION_CONTROL, values are:\n\
-\n\
- t, numbered make numbered backups\n\
- nil, existing numbered if numbered backups exist, simple otherwise\n\
- never, simple always make simple backups\n"),
- stdout);
- printf (_("\
-\n\
-GNU tar cannot read nor produce `--posix' archives. If POSIXLY_CORRECT\n\
-is set in the environment, GNU extensions are disallowed with `--posix'.\n\
-Support for POSIX is only partially implemented, don't count on it yet.\n\
-ARCHIVE may be FILE, HOST:FILE or USER@HOST:FILE; DATE may be a textual date\n\
-or a file name starting with `/' or `.', in which case the file's date is used.\n\
-*This* `tar' defaults to `-f%s -b%d'.\n"),
- DEFAULT_ARCHIVE, DEFAULT_BLOCKING);
- fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout);
- }
- exit (status);
-}
-
-/* Parse the options for tar. */
-
-/* Available option letters are DEHIJQY and aenqy. Some are reserved:
-
- e exit immediately with a nonzero exit status if unexpected errors occur
- E use extended headers (draft POSIX headers, that is)
- I same as T (for compatibility with Solaris tar)
- n the archive is quickly seekable, so don't worry about random seeks
- q stop after extracting the first occurrence of the named file
- y per-file gzip compression
- Y per-block gzip compression */
-
-#define OPTION_STRING \
- "-01234567ABC:F:GI:K:L:MnN:OPRST:UV:WX:Zb:cdf:g:hijklmoprstuvwxyz"
-
-static void
-set_subcommand_option (enum subcommand subcommand)
-{
- if (subcommand_option != UNKNOWN_SUBCOMMAND
- && subcommand_option != subcommand)
- USAGE_ERROR ((0, 0,
- _("You may not specify more than one `-Acdtrux' option")));
-
- subcommand_option = subcommand;
-}
-
-static void
-set_use_compress_program_option (const char *string)
-{
- if (use_compress_program_option && strcmp (use_compress_program_option, string) != 0)
- USAGE_ERROR ((0, 0, _("Conflicting compression options")));
-
- use_compress_program_option = string;
-}
-
-static void
-decode_options (int argc, char **argv)
-{
- int optchar; /* option letter */
- int input_files; /* number of input files */
- const char *backup_suffix_string;
- const char *version_control_string = 0;
- int exclude_options = EXCLUDE_WILDCARDS;
-
- /* Set some default option values. */
-
- subcommand_option = UNKNOWN_SUBCOMMAND;
- archive_format = DEFAULT_FORMAT;
- blocking_factor = DEFAULT_BLOCKING;
- record_size = DEFAULT_BLOCKING * BLOCKSIZE;
- excluded = new_exclude ();
- newer_mtime_option = TYPE_MINIMUM (time_t);
- recursion_option = FNM_LEADING_DIR;
- namelist_freed = 0;
-
- owner_option = -1;
- group_option = -1;
-
- backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
-
- /* Convert old-style tar call by exploding option element and rearranging
- options accordingly. */
-
- if (argc > 1 && argv[1][0] != '-')
- {
- int new_argc; /* argc value for rearranged arguments */
- char **new_argv; /* argv value for rearranged arguments */
- char *const *in; /* cursor into original argv */
- char **out; /* cursor into rearranged argv */
- const char *letter; /* cursor into old option letters */
- char buffer[3]; /* constructed option buffer */
- const char *cursor; /* cursor in OPTION_STRING */
-
- /* Initialize a constructed option. */
-
- buffer[0] = '-';
- buffer[2] = '\0';
-
- /* Allocate a new argument array, and copy program name in it. */
-
- new_argc = argc - 1 + strlen (argv[1]);
- new_argv = xmalloc ((new_argc + 1) * sizeof (char *));
- in = argv;
- out = new_argv;
- *out++ = *in++;
-
- /* Copy each old letter option as a separate option, and have the
- corresponding argument moved next to it. */
-
- for (letter = *in++; *letter; letter++)
- {
- buffer[1] = *letter;
- *out++ = xstrdup (buffer);
- cursor = strchr (OPTION_STRING, *letter);
- if (cursor && cursor[1] == ':')
- {
- if (in < argv + argc)
- *out++ = *in++;
- else
- USAGE_ERROR ((0, 0, _("Old option `%c' requires an argument."),
- *letter));
- }
- }
-
- /* Copy all remaining options. */
-
- while (in < argv + argc)
- *out++ = *in++;
-
- /* And NULL terminate the argv[] array */
- *out++ = NULL;
-
- /* Replace the old option list by the new one. */
-
- argc = new_argc;
- argv = new_argv;
- }
-
- /* Parse all options and non-options as they appear. */
-
- input_files = 0;
-
- prepend_default_options (getenv ("TAR_OPTIONS"), &argc, &argv);
-
- while (optchar = getopt_long (argc, argv, OPTION_STRING, long_options, 0),
- optchar != -1)
- switch (optchar)
- {
- case '?':
- usage (TAREXIT_FAILURE);
-
- case 0:
- break;
-
- case 1:
- /* File name or non-parsed option, because of RETURN_IN_ORDER
- ordering triggered by the leading dash in OPTION_STRING. */
-
- name_add (optarg);
- input_files++;
- break;
-
- case 'A':
- set_subcommand_option (CAT_SUBCOMMAND);
- break;
-
- case OBSOLETE_BLOCK_COMPRESS:
- WARN ((0, 0, _("Obsolete option, now implied by --blocking-factor")));
- break;
-
- case OBSOLETE_BLOCKING_FACTOR:
- WARN ((0, 0, _("Obsolete option name replaced by --blocking-factor")));
- /* Fall through. */
-
- case 'b':
- {
- uintmax_t u;
- if (! (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK
- && u == (blocking_factor = u)
- && 0 < blocking_factor
- && u == (record_size = u * BLOCKSIZE) / BLOCKSIZE))
- USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
- _("Invalid blocking factor")));
- }
- break;
-
- case OBSOLETE_READ_FULL_RECORDS:
- WARN ((0, 0,
- _("Obsolete option name replaced by --read-full-records")));
- /* Fall through. */
-
- case 'B':
- /* Try to reblock input records. For reading 4.2BSD pipes. */
-
- /* It would surely make sense to exchange -B and -R, but it seems
- that -B has been used for a long while in Sun tar ans most
- BSD-derived systems. This is a consequence of the block/record
- terminology confusion. */
-
- read_full_records_option = 1;
- break;
-
- case 'c':
- set_subcommand_option (CREATE_SUBCOMMAND);
- break;
-
- case 'C':
- name_add ("-C");
- name_add (optarg);
- break;
-
- case 'd':
- set_subcommand_option (DIFF_SUBCOMMAND);
- break;
-
- case 'f':
- if (archive_names == allocated_archive_names)
- {
- allocated_archive_names *= 2;
- archive_name_array =
- xrealloc (archive_name_array,
- sizeof (const char *) * allocated_archive_names);
- }
- archive_name_array[archive_names++] = optarg;
- break;
-
- case 'F':
- /* Since -F is only useful with -M, make it implied. Run this
- script at the end of each tape. */
-
- info_script_option = optarg;
- multi_volume_option = 1;
- break;
-
- case 'g':
- listed_incremental_option = optarg;
- after_date_option = 1;
- /* Fall through. */
-
- case 'G':
- /* We are making an incremental dump (FIXME: are we?); save
- directories at the beginning of the archive, and include in each
- directory its contents. */
-
- incremental_option = 1;
- break;
-
- case 'h':
- /* Follow symbolic links. */
-
- dereference_option = 1;
- break;
-
- case 'i':
- /* Ignore zero blocks (eofs). This can't be the default,
- because Unix tar writes two blocks of zeros, then pads out
- the record with garbage. */
-
- ignore_zeros_option = 1;
- break;
-
- case 'j':
- case 'y':
- set_use_compress_program_option ("bzip2");
- break;
-
- case 'k':
- /* Don't replace existing files. */
- old_files_option = KEEP_OLD_FILES;
- break;
-
- case 'K':
- starting_file_option = 1;
- addname (optarg, 0);
- break;
-
- case 'l':
- /* When dumping directories, don't dump files/subdirectories
- that are on other filesystems. */
-
- one_file_system_option = 1;
- break;
-
- case 'L':
- {
- uintmax_t u;
- if (xstrtoumax (optarg, 0, 10, &u, "") != LONGINT_OK)
- USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
- _("Invalid tape length")));
- tape_length_option = 1024 * (tarlong) u;
- multi_volume_option = 1;
- }
- break;
-
- case OBSOLETE_TOUCH:
- WARN ((0, 0, _("Obsolete option name replaced by --touch")));
- /* Fall through. */
-
- case 'm':
- touch_option = 1;
- break;
-
- case 'M':
- /* Make multivolume archive: when we can't write any more into
- the archive, re-open it, and continue writing. */
-
- multi_volume_option = 1;
- break;
-
- case 'n':
- recursion_option = 0;
- break;
-
-#if !MSDOS
- case 'N':
- after_date_option = 1;
- /* Fall through. */
-
- case NEWER_MTIME_OPTION:
- if (newer_mtime_option != TYPE_MINIMUM (time_t))
- USAGE_ERROR ((0, 0, _("More than one threshold date")));
-
- if (FILESYSTEM_PREFIX_LEN (optarg) != 0
- || ISSLASH (*optarg)
- || *optarg == '.')
- {
- struct stat st;
- if (deref_stat (dereference_option, optarg, &st) != 0)
- {
- stat_error (optarg);
- USAGE_ERROR ((0, 0, _("Date file not found")));
- }
- newer_mtime_option = st.st_mtime;
- }
- else
- {
- newer_mtime_option = get_date (optarg, 0);
- if (newer_mtime_option == (time_t) -1)
- WARN ((0, 0, _("Substituting %s for unknown date format %s"),
- tartime (newer_mtime_option), quote (optarg)));
- }
-
- break;
-#endif /* not MSDOS */
-
- case 'o':
- if (archive_format == DEFAULT_FORMAT)
- archive_format = V7_FORMAT;
- else if (archive_format != V7_FORMAT)
- USAGE_ERROR ((0, 0, _("Conflicting archive format options")));
- break;
-
- case 'O':
- to_stdout_option = 1;
- break;
-
- case 'p':
- same_permissions_option = 1;
- break;
-
- case OBSOLETE_ABSOLUTE_NAMES:
- WARN ((0, 0, _("Obsolete option name replaced by --absolute-names")));
- /* Fall through. */
-
- case 'P':
- absolute_names_option = 1;
- break;
-
- case 'r':
- set_subcommand_option (APPEND_SUBCOMMAND);
- break;
-
- case OBSOLETE_BLOCK_NUMBER:
- WARN ((0, 0, _("Obsolete option name replaced by --block-number")));
- /* Fall through. */
-
- case 'R':
- /* Print block numbers for debugging bad tar archives. */
-
- /* It would surely make sense to exchange -B and -R, but it seems
- that -B has been used for a long while in Sun tar ans most
- BSD-derived systems. This is a consequence of the block/record
- terminology confusion. */
-
- block_number_option = 1;
- break;
-
- case 's':
- /* Names to extr are sorted. */
-
- same_order_option = 1;
- break;
-
- case 'S':
- sparse_option = 1;
- break;
-
- case 't':
- set_subcommand_option (LIST_SUBCOMMAND);
- verbose_option++;
- break;
-
- case 'T':
- case 'I':
- files_from_option = optarg;
- break;
-
- case 'u':
- set_subcommand_option (UPDATE_SUBCOMMAND);
- break;
-
- case 'U':
- old_files_option = UNLINK_FIRST_OLD_FILES;
- break;
-
- case 'v':
- verbose_option++;
- break;
-
- case 'V':
- volume_label_option = optarg;
- break;
-
- case 'w':
- interactive_option = 1;
- break;
-
- case 'W':
- verify_option = 1;
- break;
-
- case 'x':
- set_subcommand_option (EXTRACT_SUBCOMMAND);
- break;
-
- case 'X':
- if (add_exclude_file (add_exclude, excluded, optarg,
- exclude_options | recursion_option, '\n')
- != 0)
- {
- int e = errno;
- FATAL_ERROR ((0, e, "%s", quotearg_colon (optarg)));
- }
- break;
-
- case 'z':
- set_use_compress_program_option ("gzip");
- break;
-
- case 'Z':
- set_use_compress_program_option ("compress");
- break;
-
- case OBSOLETE_VERSION_CONTROL:
- WARN ((0, 0, _("Obsolete option name replaced by --backup")));
- /* Fall through. */
-
- case ANCHORED_OPTION:
- exclude_options |= EXCLUDE_ANCHORED;
- break;
-
- case BACKUP_OPTION:
- backup_option = 1;
- if (optarg)
- version_control_string = optarg;
- break;
-
- case DELETE_OPTION:
- set_subcommand_option (DELETE_SUBCOMMAND);
- break;
-
- case EXCLUDE_OPTION:
- add_exclude (excluded, optarg, exclude_options | recursion_option);
- break;
-
- case IGNORE_CASE_OPTION:
- exclude_options |= FNM_CASEFOLD;
- break;
-
- case GROUP_OPTION:
- if (! (strlen (optarg) < GNAME_FIELD_SIZE
- && gname_to_gid (optarg, &group_option)))
- {
- uintmax_t g;
- if (xstrtoumax (optarg, 0, 10, &g, "") == LONGINT_OK
- && g == (gid_t) g)
- group_option = g;
- else
- FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
- _("%s: Invalid group")));
- }
- break;
-
- case MODE_OPTION:
- mode_option
- = mode_compile (optarg,
- MODE_MASK_EQUALS | MODE_MASK_PLUS | MODE_MASK_MINUS);
- if (mode_option == MODE_INVALID)
- FATAL_ERROR ((0, 0, _("Invalid mode given on option")));
- if (mode_option == MODE_MEMORY_EXHAUSTED)
- xalloc_die ();
- break;
-
- case NO_ANCHORED_OPTION:
- exclude_options &= ~ EXCLUDE_ANCHORED;
- break;
-
- case NO_IGNORE_CASE_OPTION:
- exclude_options &= ~ FNM_CASEFOLD;
- break;
-
- case NO_WILDCARDS_OPTION:
- exclude_options &= ~ EXCLUDE_WILDCARDS;
- break;
-
- case NO_WILDCARDS_MATCH_SLASH_OPTION:
- exclude_options |= FNM_FILE_NAME;
- break;
-
- case NULL_OPTION:
- filename_terminator = '\0';
- break;
-
- case OVERWRITE_OPTION:
- old_files_option = OVERWRITE_OLD_FILES;
- break;
-
- case OVERWRITE_DIR_OPTION:
- old_files_option = OVERWRITE_OLD_DIRS;
- break;
-
- case OWNER_OPTION:
- if (! (strlen (optarg) < UNAME_FIELD_SIZE
- && uname_to_uid (optarg, &owner_option)))
- {
- uintmax_t u;
- if (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK
- && u == (uid_t) u)
- owner_option = u;
- else
- FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
- _("Invalid owner")));
- }
- break;
-
- case POSIX_OPTION:
-#if OLDGNU_COMPATIBILITY
- if (archive_format == DEFAULT_FORMAT)
- archive_format = GNU_FORMAT;
- else if (archive_format != GNU_FORMAT)
- USAGE_ERROR ((0, 0, _("Conflicting archive format options")));
-#else
- if (archive_format == DEFAULT_FORMAT)
- archive_format = POSIX_FORMAT;
- else if (archive_format != POSIX_FORMAT)
- USAGE_ERROR ((0, 0, _("Conflicting archive format options")));
-#endif
- break;
-
- case PRESERVE_OPTION:
- same_permissions_option = 1;
- same_order_option = 1;
- break;
-
- case RECORD_SIZE_OPTION:
- {
- uintmax_t u;
- if (! (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK
- && u == (size_t) u))
- USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
- _("Invalid record size")));
- record_size = u;
- if (record_size % BLOCKSIZE != 0)
- USAGE_ERROR ((0, 0, _("Record size must be a multiple of %d."),
- BLOCKSIZE));
- blocking_factor = record_size / BLOCKSIZE;
- }
- break;
-
- case RSH_COMMAND_OPTION:
- rsh_command_option = optarg;
- break;
-
- case SUFFIX_OPTION:
- backup_option = 1;
- backup_suffix_string = optarg;
- break;
-
- case USE_COMPRESS_PROGRAM_OPTION:
- set_use_compress_program_option (optarg);
- break;
-
- case VOLNO_FILE_OPTION:
- volno_file_option = optarg;
- break;
-
- case WILDCARDS_OPTION:
- exclude_options |= EXCLUDE_WILDCARDS;
- break;
-
- case WILDCARDS_MATCH_SLASH_OPTION:
- exclude_options &= ~ FNM_FILE_NAME;
- break;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
-
-#ifdef DEVICE_PREFIX
- {
- int device = optchar - '0';
- int density;
- static char buf[sizeof DEVICE_PREFIX + 10];
- char *cursor;
-
- density = getopt_long (argc, argv, "lmh", 0, 0);
- strcpy (buf, DEVICE_PREFIX);
- cursor = buf + strlen (buf);
-
-#ifdef DENSITY_LETTER
-
- sprintf (cursor, "%d%c", device, density);
-
-#else /* not DENSITY_LETTER */
-
- switch (density)
- {
- case 'l':
-#ifdef LOW_NUM
- device += LOW_NUM;
-#endif
- break;
-
- case 'm':
-#ifdef MID_NUM
- device += MID_NUM;
-#else
- device += 8;
-#endif
- break;
-
- case 'h':
-#ifdef HGH_NUM
- device += HGH_NUM;
-#else
- device += 16;
-#endif
- break;
-
- default:
- usage (TAREXIT_FAILURE);
- }
- sprintf (cursor, "%d", device);
-
-#endif /* not DENSITY_LETTER */
-
- if (archive_names == allocated_archive_names)
- {
- allocated_archive_names *= 2;
- archive_name_array =
- xrealloc (archive_name_array,
- sizeof (const char *) * allocated_archive_names);
- }
- archive_name_array[archive_names++] = buf;
-
- /* FIXME: How comes this works for many archives when buf is
- not xstrdup'ed? */
- }
- break;
-
-#else /* not DEVICE_PREFIX */
-
- USAGE_ERROR ((0, 0,
- _("Options `-[0-7][lmh]' not supported by *this* tar")));
-
-#endif /* not DEVICE_PREFIX */
- }
-
- /* Handle operands after any "--" argument. */
- for (; optind < argc; optind++)
- {
- name_add (argv[optind]);
- input_files++;
- }
-
- /* Process trivial options. */
-
- if (show_version)
- {
- printf ("tar (GNU %s) %s\n", PACKAGE, VERSION);
- print_copyright ("2001 Free Software Foundation, Inc.");
- puts (_("\
-This program comes with NO WARRANTY, to the extent permitted by law.\n\
-You may redistribute it under the terms of the GNU General Public License;\n\
-see the file named COPYING for details."));
-
- puts (_("Written by John Gilmore and Jay Fenlason."));
-
- exit (TAREXIT_SUCCESS);
- }
-
- if (show_help)
- usage (TAREXIT_SUCCESS);
-
- /* Derive option values and check option consistency. */
-
- if (archive_format == DEFAULT_FORMAT)
- {
-#if OLDGNU_COMPATIBILITY
- archive_format = OLDGNU_FORMAT;
-#else
- archive_format = GNU_FORMAT;
-#endif
- }
-
- if (archive_format == GNU_FORMAT && getenv ("POSIXLY_CORRECT"))
- archive_format = POSIX_FORMAT;
-
- if ((volume_label_option
- || incremental_option || multi_volume_option || sparse_option)
- && archive_format != OLDGNU_FORMAT && archive_format != GNU_FORMAT)
- USAGE_ERROR ((0, 0,
- _("GNU features wanted on incompatible archive format")));
-
- if (archive_names == 0)
- {
- /* If no archive file name given, try TAPE from the environment, or
- else, DEFAULT_ARCHIVE from the configuration process. */
-
- archive_names = 1;
- archive_name_array[0] = getenv ("TAPE");
- if (! archive_name_array[0])
- archive_name_array[0] = DEFAULT_ARCHIVE;
- }
-
- /* Allow multiple archives only with `-M'. */
-
- if (archive_names > 1 && !multi_volume_option)
- USAGE_ERROR ((0, 0,
- _("Multiple archive files requires `-M' option")));
-
- if (listed_incremental_option
- && newer_mtime_option != TYPE_MINIMUM (time_t))
- USAGE_ERROR ((0, 0,
- _("Cannot combine --listed-incremental with --newer")));
-
- if (volume_label_option)
- {
- size_t volume_label_max_len =
- (sizeof current_header->header.name
- - 1 /* for trailing '\0' */
- - (multi_volume_option
- ? (sizeof " Volume "
- - 1 /* for null at end of " Volume " */
- + INT_STRLEN_BOUND (int) /* for volume number */
- - 1 /* for sign, as 0 <= volno */)
- : 0));
- if (volume_label_max_len < strlen (volume_label_option))
- USAGE_ERROR ((0, 0,
- _("%s: Volume label is too long (limit is %lu bytes)"),
- quotearg_colon (volume_label_option),
- (unsigned long) volume_label_max_len));
- }
-
- /* If ready to unlink hierarchies, so we are for simpler files. */
- if (recursive_unlink_option)
- old_files_option = UNLINK_FIRST_OLD_FILES;
-
- /* Forbid using -c with no input files whatsoever. Check that `-f -',
- explicit or implied, is used correctly. */
-
- switch (subcommand_option)
- {
- case CREATE_SUBCOMMAND:
- if (input_files == 0 && !files_from_option)
- USAGE_ERROR ((0, 0,
- _("Cowardly refusing to create an empty archive")));
- break;
-
- case EXTRACT_SUBCOMMAND:
- case LIST_SUBCOMMAND:
- case DIFF_SUBCOMMAND:
- for (archive_name_cursor = archive_name_array;
- archive_name_cursor < archive_name_array + archive_names;
- archive_name_cursor++)
- if (!strcmp (*archive_name_cursor, "-"))
- request_stdin ("-f");
- break;
-
- case CAT_SUBCOMMAND:
- case UPDATE_SUBCOMMAND:
- case APPEND_SUBCOMMAND:
- for (archive_name_cursor = archive_name_array;
- archive_name_cursor < archive_name_array + archive_names;
- archive_name_cursor++)
- if (!strcmp (*archive_name_cursor, "-"))
- USAGE_ERROR ((0, 0,
- _("Options `-Aru' are incompatible with `-f -'")));
-
- default:
- break;
- }
-
- archive_name_cursor = archive_name_array;
-
- /* Prepare for generating backup names. */
-
- if (backup_suffix_string)
- simple_backup_suffix = xstrdup (backup_suffix_string);
-
- if (backup_option)
- backup_type = xget_version ("--backup", version_control_string);
-}
-
-/* Tar proper. */
-
-/* Main routine for tar. */
-int
-main (int argc, char **argv)
-{
-#if HAVE_CLOCK_GETTIME
- if (clock_gettime (CLOCK_REALTIME, &start_timespec) != 0)
-#endif
- start_time = time (0);
- program_name = argv[0];
- (void) setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
-
- exit_status = TAREXIT_SUCCESS;
- filename_terminator = '\n';
- set_quoting_style (0, escape_quoting_style);
-
- /* Pre-allocate a few structures. */
-
- allocated_archive_names = 10;
- archive_name_array =
- xmalloc (sizeof (const char *) * allocated_archive_names);
- archive_names = 0;
-
-#ifdef SIGCHLD
- /* System V fork+wait does not work if SIGCHLD is ignored. */
- signal (SIGCHLD, SIG_DFL);
-#endif
-
- init_names ();
-
- /* Decode options. */
-
- decode_options (argc, argv);
- name_init (argc, argv);
-
- /* Main command execution. */
-
- if (volno_file_option)
- init_volume_number ();
-
- switch (subcommand_option)
- {
- case UNKNOWN_SUBCOMMAND:
- USAGE_ERROR ((0, 0,
- _("You must specify one of the `-Acdtrux' options")));
-
- case CAT_SUBCOMMAND:
- case UPDATE_SUBCOMMAND:
- case APPEND_SUBCOMMAND:
- update_archive ();
- break;
-
- case DELETE_SUBCOMMAND:
- delete_archive_members ();
- break;
-
- case CREATE_SUBCOMMAND:
- create_archive ();
- name_close ();
-
- if (totals_option)
- print_total_written ();
- break;
-
- case EXTRACT_SUBCOMMAND:
- extr_init ();
- read_and (extract_archive);
- extract_finish ();
- break;
-
- case LIST_SUBCOMMAND:
- read_and (list_archive);
- break;
-
- case DIFF_SUBCOMMAND:
- diff_init ();
- read_and (diff_archive);
- break;
- }
-
- if (volno_file_option)
- closeout_volume_number ();
-
- /* Dispose of allocated memory, and return. */
-
- free (archive_name_array);
- name_term ();
-
- if (stdlis == stdout && (ferror (stdout) || fclose (stdout) != 0))
- FATAL_ERROR ((0, 0, _("Error in writing to standard output")));
- if (exit_status == TAREXIT_FAILURE)
- error (0, 0, _("Error exit delayed from previous errors"));
- exit (exit_status);
-}
diff --git a/contrib/tar/src/tar.h b/contrib/tar/src/tar.h
deleted file mode 100644
index ff2977b..0000000
--- a/contrib/tar/src/tar.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/* GNU tar Archive Format description.
-
- Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 2000, 2001 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* If OLDGNU_COMPATIBILITY is not zero, tar produces archives which, by
- default, are readable by older versions of GNU tar. This can be
- overriden by using --posix; in this case, POSIXLY_CORRECT in environment
- may be set for enforcing stricter conformance. If OLDGNU_COMPATIBILITY
- is zero or undefined, tar will eventually produces archives which, by
- default, POSIX compatible; then either using --posix or defining
- POSIXLY_CORRECT enforces stricter conformance.
-
- This #define will disappear in a few years. FP, June 1995. */
-#define OLDGNU_COMPATIBILITY 1
-
-/* tar Header Block, from POSIX 1003.1-1990. */
-
-/* POSIX header. */
-
-struct posix_header
-{ /* byte offset */
- char name[100]; /* 0 */
- char mode[8]; /* 100 */
- char uid[8]; /* 108 */
- char gid[8]; /* 116 */
- char size[12]; /* 124 */
- char mtime[12]; /* 136 */
- char chksum[8]; /* 148 */
- char typeflag; /* 156 */
- char linkname[100]; /* 157 */
- char magic[6]; /* 257 */
- char version[2]; /* 263 */
- char uname[32]; /* 265 */
- char gname[32]; /* 297 */
- char devmajor[8]; /* 329 */
- char devminor[8]; /* 337 */
- char prefix[155]; /* 345 */
- /* 500 */
-};
-
-#define TMAGIC "ustar" /* ustar and a null */
-#define TMAGLEN 6
-#define TVERSION "00" /* 00 and no null */
-#define TVERSLEN 2
-
-/* Values used in typeflag field. */
-#define REGTYPE '0' /* regular file */
-#define AREGTYPE '\0' /* regular file */
-#define LNKTYPE '1' /* link */
-#define SYMTYPE '2' /* reserved */
-#define CHRTYPE '3' /* character special */
-#define BLKTYPE '4' /* block special */
-#define DIRTYPE '5' /* directory */
-#define FIFOTYPE '6' /* FIFO special */
-#define CONTTYPE '7' /* reserved */
-
-/* Bits used in the mode field, values in octal. */
-#define TSUID 04000 /* set UID on execution */
-#define TSGID 02000 /* set GID on execution */
-#define TSVTX 01000 /* reserved */
- /* file permissions */
-#define TUREAD 00400 /* read by owner */
-#define TUWRITE 00200 /* write by owner */
-#define TUEXEC 00100 /* execute/search by owner */
-#define TGREAD 00040 /* read by group */
-#define TGWRITE 00020 /* write by group */
-#define TGEXEC 00010 /* execute/search by group */
-#define TOREAD 00004 /* read by other */
-#define TOWRITE 00002 /* write by other */
-#define TOEXEC 00001 /* execute/search by other */
-
-/* tar Header Block, GNU extensions. */
-
-/* In GNU tar, SYMTYPE is for to symbolic links, and CONTTYPE is for
- contiguous files, so maybe disobeying the `reserved' comment in POSIX
- header description. I suspect these were meant to be used this way, and
- should not have really been `reserved' in the published standards. */
-
-/* *BEWARE* *BEWARE* *BEWARE* that the following information is still
- boiling, and may change. Even if the OLDGNU format description should be
- accurate, the so-called GNU format is not yet fully decided. It is
- surely meant to use only extensions allowed by POSIX, but the sketch
- below repeats some ugliness from the OLDGNU format, which should rather
- go away. Sparse files should be saved in such a way that they do *not*
- require two passes at archive creation time. Huge files get some POSIX
- fields to overflow, alternate solutions have to be sought for this. */
-
-/* Descriptor for a single file hole. */
-
-struct sparse
-{ /* byte offset */
- char offset[12]; /* 0 */
- char numbytes[12]; /* 12 */
- /* 24 */
-};
-
-/* Sparse files are not supported in POSIX ustar format. For sparse files
- with a POSIX header, a GNU extra header is provided which holds overall
- sparse information and a few sparse descriptors. When an old GNU header
- replaces both the POSIX header and the GNU extra header, it holds some
- sparse descriptors too. Whether POSIX or not, if more sparse descriptors
- are still needed, they are put into as many successive sparse headers as
- necessary. The following constants tell how many sparse descriptors fit
- in each kind of header able to hold them. */
-
-#define SPARSES_IN_EXTRA_HEADER 16
-#define SPARSES_IN_OLDGNU_HEADER 4
-#define SPARSES_IN_SPARSE_HEADER 21
-
-/* The GNU extra header contains some information GNU tar needs, but not
- foreseen in POSIX header format. It is only used after a POSIX header
- (and never with old GNU headers), and immediately follows this POSIX
- header, when typeflag is a letter rather than a digit, so signaling a GNU
- extension. */
-
-struct extra_header
-{ /* byte offset */
- char atime[12]; /* 0 */
- char ctime[12]; /* 12 */
- char offset[12]; /* 24 */
- char realsize[12]; /* 36 */
- char longnames[4]; /* 48 */
- char unused_pad1[68]; /* 52 */
- struct sparse sp[SPARSES_IN_EXTRA_HEADER];
- /* 120 */
- char isextended; /* 504 */
- /* 505 */
-};
-
-/* Extension header for sparse files, used immediately after the GNU extra
- header, and used only if all sparse information cannot fit into that
- extra header. There might even be many such extension headers, one after
- the other, until all sparse information has been recorded. */
-
-struct sparse_header
-{ /* byte offset */
- struct sparse sp[SPARSES_IN_SPARSE_HEADER];
- /* 0 */
- char isextended; /* 504 */
- /* 505 */
-};
-
-/* The old GNU format header conflicts with POSIX format in such a way that
- POSIX archives may fool old GNU tar's, and POSIX tar's might well be
- fooled by old GNU tar archives. An old GNU format header uses the space
- used by the prefix field in a POSIX header, and cumulates information
- normally found in a GNU extra header. With an old GNU tar header, we
- never see any POSIX header nor GNU extra header. Supplementary sparse
- headers are allowed, however. */
-
-struct oldgnu_header
-{ /* byte offset */
- char unused_pad1[345]; /* 0 */
- char atime[12]; /* 345 */
- char ctime[12]; /* 357 */
- char offset[12]; /* 369 */
- char longnames[4]; /* 381 */
- char unused_pad2; /* 385 */
- struct sparse sp[SPARSES_IN_OLDGNU_HEADER];
- /* 386 */
- char isextended; /* 482 */
- char realsize[12]; /* 483 */
- /* 495 */
-};
-
-/* OLDGNU_MAGIC uses both magic and version fields, which are contiguous.
- Found in an archive, it indicates an old GNU header format, which will be
- hopefully become obsolescent. With OLDGNU_MAGIC, uname and gname are
- valid, though the header is not truly POSIX conforming. */
-#define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
-
-/* The standards committee allows only capital A through capital Z for
- user-defined expansion. */
-
-/* This is a dir entry that contains the names of files that were in the
- dir at the time the dump was made. */
-#define GNUTYPE_DUMPDIR 'D'
-
-/* Identifies the *next* file on the tape as having a long linkname. */
-#define GNUTYPE_LONGLINK 'K'
-
-/* Identifies the *next* file on the tape as having a long name. */
-#define GNUTYPE_LONGNAME 'L'
-
-/* This is the continuation of a file that began on another volume. */
-#define GNUTYPE_MULTIVOL 'M'
-
-/* For storing filenames that do not fit into the main header. */
-#define GNUTYPE_NAMES 'N'
-
-/* This is for sparse files. */
-#define GNUTYPE_SPARSE 'S'
-
-/* This file is a tape/volume header. Ignore it on extraction. */
-#define GNUTYPE_VOLHDR 'V'
-
-/* tar Header Block, overall structure. */
-
-/* tar files are made in basic blocks of this size. */
-#define BLOCKSIZE 512
-
-enum archive_format
-{
- DEFAULT_FORMAT, /* format to be decided later */
- V7_FORMAT, /* old V7 tar format */
- OLDGNU_FORMAT, /* GNU format as per before tar 1.12 */
- POSIX_FORMAT, /* restricted, pure POSIX format */
- GNU_FORMAT /* POSIX format with GNU extensions */
-};
-
-union block
-{
- char buffer[BLOCKSIZE];
- struct posix_header header;
- struct extra_header extra_header;
- struct oldgnu_header oldgnu_header;
- struct sparse_header sparse_header;
-};
-
-/* End of Format description. */
diff --git a/contrib/tar/src/update.c b/contrib/tar/src/update.c
deleted file mode 100644
index 754d321..0000000
--- a/contrib/tar/src/update.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/* Update a tar archive.
-
- Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001 Free
- Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* Implement the 'r', 'u' and 'A' options for tar. 'A' means that the
- file names are tar files, and they should simply be appended to the end
- of the archive. No attempt is made to record the reads from the args; if
- they're on raw tape or something like that, it'll probably lose... */
-
-#include "system.h"
-#include <quotearg.h>
-#include "common.h"
-
-/* FIXME: This module should not directly handle the following variable,
- instead, this should be done in buffer.c only. */
-extern union block *current_block;
-
-/* We've hit the end of the old stuff, and its time to start writing new
- stuff to the tape. This involves seeking back one record and
- re-writing the current record (which has been changed). */
-int time_to_start_writing;
-
-/* Pointer to where we started to write in the first record we write out.
- This is used if we can't backspace the output and have to null out the
- first part of the record. */
-char *output_start;
-
-/* Catenate file PATH to the archive without creating a header for it.
- It had better be a tar file or the archive is screwed. */
-static void
-append_file (char *path)
-{
- int handle = open (path, O_RDONLY | O_BINARY);
- struct stat stat_data;
-
- if (handle < 0)
- {
- open_error (path);
- return;
- }
-
- if (fstat (handle, &stat_data) != 0)
- stat_error (path);
- else
- {
- off_t bytes_left = stat_data.st_size;
-
- while (bytes_left > 0)
- {
- union block *start = find_next_block ();
- size_t buffer_size = available_space_after (start);
- ssize_t status;
- char buf[UINTMAX_STRSIZE_BOUND];
-
- if (bytes_left < buffer_size)
- {
- buffer_size = bytes_left;
- status = buffer_size % BLOCKSIZE;
- if (status)
- memset (start->buffer + bytes_left, 0, BLOCKSIZE - status);
- }
-
- status = safe_read (handle, start->buffer, buffer_size);
- if (status < 0)
- read_fatal_details (path, stat_data.st_size - bytes_left,
- buffer_size);
- if (status == 0)
- FATAL_ERROR ((0, 0, _("%s: File shrank by %s bytes"),
- quotearg_colon (path),
- STRINGIFY_BIGINT (bytes_left, buf)));
-
- bytes_left -= status;
-
- set_next_block_after (start + (status - 1) / BLOCKSIZE);
- }
- }
-
- if (close (handle) != 0)
- close_error (path);
-}
-
-/* Implement the 'r' (add files to end of archive), and 'u' (add files
- to end of archive if they aren't there, or are more up to date than
- the version in the archive) commands. */
-void
-update_archive (void)
-{
- enum read_header previous_status = HEADER_STILL_UNREAD;
- int found_end = 0;
-
- name_gather ();
- open_archive (ACCESS_UPDATE);
-
- while (!found_end)
- {
- enum read_header status = read_header (0);
-
- switch (status)
- {
- case HEADER_STILL_UNREAD:
- abort ();
-
- case HEADER_SUCCESS:
- {
- struct name *name;
-
- if (subcommand_option == UPDATE_SUBCOMMAND
- && (name = name_scan (current_file_name), name))
- {
- struct stat s;
- enum archive_format unused;
-
- decode_header (current_header, &current_stat, &unused, 0);
- chdir_do (name->change_dir);
- if (deref_stat (dereference_option, current_file_name, &s) == 0
- && s.st_mtime <= current_stat.st_mtime)
- add_avoided_name (current_file_name);
- }
- skip_member ();
- break;
- }
-
- case HEADER_ZERO_BLOCK:
- current_block = current_header;
- found_end = 1;
- break;
-
- case HEADER_END_OF_FILE:
- found_end = 1;
- break;
-
- case HEADER_FAILURE:
- set_next_block_after (current_header);
- switch (previous_status)
- {
- case HEADER_STILL_UNREAD:
- WARN ((0, 0, _("This does not look like a tar archive")));
- /* Fall through. */
-
- case HEADER_SUCCESS:
- case HEADER_ZERO_BLOCK:
- ERROR ((0, 0, _("Skipping to next header")));
- /* Fall through. */
-
- case HEADER_FAILURE:
- break;
-
- case HEADER_END_OF_FILE:
- abort ();
- }
- break;
- }
-
- previous_status = status;
- }
-
- reset_eof ();
- time_to_start_writing = 1;
- output_start = current_block->buffer;
-
- {
- char *path;
-
- while (path = name_from_list (), path)
- {
- if (excluded_name (path))
- continue;
- if (interactive_option && !confirm ("add", path))
- continue;
- if (subcommand_option == CAT_SUBCOMMAND)
- append_file (path);
- else
- dump_file (path, 1, (dev_t) 0);
- }
- }
-
- write_eot ();
- close_archive ();
- names_notfound ();
-}
OpenPOWER on IntegriCloud