diff options
author | ru <ru@FreeBSD.org> | 2006-09-15 08:04:23 +0000 |
---|---|---|
committer | ru <ru@FreeBSD.org> | 2006-09-15 08:04:23 +0000 |
commit | 6b78b3a81dfd58cd5838b6fae2c4f76e95a5f930 (patch) | |
tree | 6f83030fb91083cd8f95441274f042914ff7d0c4 /contrib/tar/src | |
parent | 35f71d316ffcfbb768fb65dafa20f846cff14ba6 (diff) | |
download | FreeBSD-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.h | 27 | ||||
-rw-r--r-- | contrib/tar/src/buffer.c | 1619 | ||||
-rw-r--r-- | contrib/tar/src/common.h | 586 | ||||
-rw-r--r-- | contrib/tar/src/compare.c | 823 | ||||
-rw-r--r-- | contrib/tar/src/create.c | 1552 | ||||
-rw-r--r-- | contrib/tar/src/delete.c | 364 | ||||
-rw-r--r-- | contrib/tar/src/extract.c | 1333 | ||||
-rw-r--r-- | contrib/tar/src/incremen.c | 584 | ||||
-rw-r--r-- | contrib/tar/src/list.c | 1211 | ||||
-rw-r--r-- | contrib/tar/src/mangle.c | 121 | ||||
-rw-r--r-- | contrib/tar/src/misc.c | 854 | ||||
-rw-r--r-- | contrib/tar/src/names.c | 976 | ||||
-rw-r--r-- | contrib/tar/src/rmt.c | 576 | ||||
-rw-r--r-- | contrib/tar/src/rmt.h | 93 | ||||
-rw-r--r-- | contrib/tar/src/rtapelib.c | 723 | ||||
-rw-r--r-- | contrib/tar/src/system.h | 587 | ||||
-rw-r--r-- | contrib/tar/src/tar.c | 1366 | ||||
-rw-r--r-- | contrib/tar/src/tar.h | 235 | ||||
-rw-r--r-- | contrib/tar/src/update.c | 195 |
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 (¤t_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, ¤t_stat, ¤t_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 (¤t_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, ¤t_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, ¤t_stat); - - but since they'd interpret DIRTYPE blocks as regular - files, we'd better put the / on the name. */ - - header = start_header (namebuf, ¤t_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 (¤t_link_name, link_name); - - current_stat.st_size = 0; - header = start_header (p, ¤t_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, ¤t_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, ¤t_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 (¤t_link_name, buffer); - - current_stat.st_size = 0; /* force 0 size on symlink */ - header = start_header (p, ¤t_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, ¤t_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, - ¤t_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, ¤t_stat, ¤t_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 = ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_stat, ¤t_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 = ¤t_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 (¤t_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 (¤t_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, ¤t_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 (); -} |