X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fbuffer.c;h=1ad48f0657e9adf549333d75f7745cf9f4b819fa;hb=aa985330d59a033156b0d793f880de952eafa4e5;hp=067339b835287692528cf8137ac5c80be78b9259;hpb=27e87f4f2f4d49328c328fd55fa087d8a4507168;p=chaz%2Ftar diff --git a/src/buffer.c b/src/buffer.c index 067339b..1ad48f0 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,5 +1,5 @@ /* Buffer management for tar. - Copyright (C) 1988, 92, 93, 94, 96, 97 Free Software Foundation, Inc. + Copyright (C) 1988, 92, 93, 94, 96, 97, 1999 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 @@ -14,7 +14,7 @@ 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 Place - Suite 330, Boston, MA 02111-1307, USA. */ + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "system.h" @@ -39,9 +39,6 @@ time_t time (); #define DEBUG_FORK 0 /* if nonzero, childs are born stopped */ -#define STDIN 0 /* standard input file descriptor */ -#define STDOUT 1 /* standard output file descriptor */ - #define PREAD 0 /* read file descriptor from pipe() */ #define PWRITE 1 /* write file descriptor from pipe() */ @@ -66,7 +63,7 @@ union block *current_block; /* current block of archive */ enum access_mode access_mode; /* how do we handle the archive */ static struct stat archive_stat; /* stat block for archive file */ -static long record_start_block; /* block ordinal at record_start */ +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. */ @@ -74,7 +71,7 @@ FILE *stdlis; static void backspace_output PARAMS ((void)); static int new_volume PARAMS ((enum access_mode)); -static void write_error PARAMS ((int)); +static void write_error PARAMS ((ssize_t)); static void read_error PARAMS ((void)); #if !MSDOS @@ -84,7 +81,7 @@ ino_t ar_ino; #endif /* PID of child program, if compress_option or remote archive access. */ -static int child_pid = 0; +static pid_t child_pid; /* Error recovery stuff */ static int read_error_count; @@ -116,9 +113,9 @@ static int global_volno = 1; /* volume number to print in external volume. (From Pierce Cantrell, 1991-08-13.) */ char *save_name; /* name of the file we are currently writing */ -long save_totsize; /* total size of file we are writing, only +off_t save_totsize; /* total size of file we are writing, only valid if save_name is non NULL */ -long save_sizeleft; /* where we are in the file we are writing, +off_t save_sizeleft; /* where we are in the file we are writing, only valid if save_name is nonzero */ int write_archive_to_stdout = 0; @@ -126,8 +123,8 @@ int write_archive_to_stdout = 0; /* Used by flush_read and flush_write to store the real info about saved names. */ static char *real_s_name = NULL; -static long real_s_totsize; -static long real_s_sizeleft; +static off_t real_s_totsize; +static off_t real_s_sizeleft; /* Functions. */ @@ -166,7 +163,7 @@ print_total_written (void) | Compute and return the block ordinal at current_block. | `--------------------------------------------------------*/ -long +off_t current_block_ordinal (void) { return record_start_block + (current_block - record_start); @@ -238,10 +235,10 @@ set_next_block_after (union block *block) | always) the result previous find_next_block call. | `------------------------------------------------------------------------*/ -int +size_t available_space_after (union block *pointer) { - return (int) (record_end->buffer - pointer->buffer); + return record_end->buffer - pointer->buffer; } /*------------------------------------------------------------------. @@ -319,6 +316,24 @@ is_regular_file (const char *name) return 0; } +static ssize_t +write_archive_buffer (void) +{ + ssize_t status; + ssize_t written = 0; + + while (0 <= (status = rmtwrite (archive, record_start->buffer + written, + record_size - written))) + { + written += status; + if (written == record_size + || _isrmt (archive) || ! S_ISFIFO (archive_stat.st_mode)) + break; + } + + return written ? written : status; +} + /*-------------------------------------------------------. | Set ARCHIVE for writing, then compressing an archive. | `-------------------------------------------------------*/ @@ -328,7 +343,7 @@ child_open_for_compress (void) { int parent_pipe[2]; int child_pipe[2]; - int grandchild_pid; + pid_t grandchild_pid; if (pipe (parent_pipe) < 0) FATAL_ERROR ((0, errno, _("Cannot open pipe"))); @@ -350,7 +365,7 @@ child_open_for_compress (void) program_name = _("tar (child)"); - xdup2 (parent_pipe[PREAD], STDIN, _("(child) Pipe to stdin")); + xdup2 (parent_pipe[PREAD], STDIN_FILENO, _("(child) Pipe to stdin")); xclose (parent_pipe[PWRITE]); /* Check if we need a grandchild tar. This happens only if either: @@ -378,7 +393,7 @@ child_open_for_compress (void) FATAL_ERROR ((0, saved_errno, _("Cannot open archive %s"), archive_name_array[0])); } - xdup2 (archive, STDOUT, _("Archive to stdout")); + xdup2 (archive, STDOUT_FILENO, _("Archive to stdout")); execlp (use_compress_program_option, use_compress_program_option, (char *) 0); FATAL_ERROR ((0, errno, _("Cannot exec %s"), @@ -398,7 +413,8 @@ child_open_for_compress (void) { /* The child tar is still here! Launch the compressor. */ - xdup2 (child_pipe[PWRITE], STDOUT, _("((child)) Pipe to stdout")); + xdup2 (child_pipe[PWRITE], STDOUT_FILENO, + _("((child)) Pipe to stdout")); xclose (child_pipe[PREAD]); execlp (use_compress_program_option, use_compress_program_option, (char *) 0); @@ -412,11 +428,11 @@ child_open_for_compress (void) /* Prepare for reblocking the data from the compressor into the archive. */ - xdup2 (child_pipe[PREAD], STDIN, _("(grandchild) Pipe to stdin")); + xdup2 (child_pipe[PREAD], STDIN_FILENO, _("(grandchild) Pipe to stdin")); xclose (child_pipe[PWRITE]); if (strcmp (archive_name_array[0], "-") == 0) - archive = STDOUT; + archive = STDOUT_FILENO; else archive = rmtcreat (archive_name_array[0], 0666, rsh_command_option); if (archive < 0) @@ -427,9 +443,9 @@ child_open_for_compress (void) while (1) { - int status = 0; + ssize_t status = 0; char *cursor; - int length; + size_t length; /* Assemble a record. */ @@ -437,11 +453,11 @@ child_open_for_compress (void) length < record_size; length += status, cursor += status) { - int size = record_size - length; + size_t size = record_size - length; if (size < BLOCKSIZE) size = BLOCKSIZE; - status = read (STDIN, cursor, (size_t) size); + status = full_read (STDIN_FILENO, cursor, size); if (status <= 0) break; } @@ -459,10 +475,8 @@ child_open_for_compress (void) if (length > 0) { - memset (record_start->buffer + length, 0, - (size_t) record_size - length); - status = rmtwrite (archive, record_start->buffer, - (unsigned int) record_size); + memset (record_start->buffer + length, 0, record_size - length); + status = write_archive_buffer (); if (status != record_size) write_error (status); } @@ -471,8 +485,7 @@ child_open_for_compress (void) break; } - status = rmtwrite (archive, record_start->buffer, - (unsigned int) record_size); + status = write_archive_buffer (); if (status != record_size) write_error (status); } @@ -492,7 +505,7 @@ child_open_for_uncompress (void) { int parent_pipe[2]; int child_pipe[2]; - int grandchild_pid; + pid_t grandchild_pid; if (pipe (parent_pipe) < 0) FATAL_ERROR ((0, errno, _("Cannot open pipe"))); @@ -515,7 +528,7 @@ child_open_for_uncompress (void) program_name = _("tar (child)"); - xdup2 (parent_pipe[PWRITE], STDOUT, _("(child) Pipe to stdout")); + xdup2 (parent_pipe[PWRITE], STDOUT_FILENO, _("(child) Pipe to stdout")); xclose (parent_pipe[PREAD]); /* Check if we need a grandchild tar. This happens only if either: @@ -534,7 +547,7 @@ child_open_for_uncompress (void) if (archive < 0) FATAL_ERROR ((0, errno, _("Cannot open archive %s"), archive_name_array[0])); - xdup2 (archive, STDIN, _("Archive to stdin")); + xdup2 (archive, STDIN_FILENO, _("Archive to stdin")); execlp (use_compress_program_option, use_compress_program_option, "-d", (char *) 0); FATAL_ERROR ((0, errno, _("Cannot exec %s"), @@ -554,7 +567,7 @@ child_open_for_uncompress (void) { /* The child tar is still here! Launch the uncompressor. */ - xdup2 (child_pipe[PREAD], STDIN, _("((child)) Pipe to stdin")); + xdup2 (child_pipe[PREAD], STDIN_FILENO, _("((child)) Pipe to stdin")); xclose (child_pipe[PWRITE]); execlp (use_compress_program_option, use_compress_program_option, "-d", (char *) 0); @@ -568,11 +581,11 @@ child_open_for_uncompress (void) /* Prepare for unblocking the data from the archive into the uncompressor. */ - xdup2 (child_pipe[PWRITE], STDOUT, _("(grandchild) Pipe to stdout")); + xdup2 (child_pipe[PWRITE], STDOUT_FILENO, _("(grandchild) Pipe to stdout")); xclose (child_pipe[PREAD]); if (strcmp (archive_name_array[0], "-") == 0) - archive = STDIN; + archive = STDIN_FILENO; else archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY, 0666, rsh_command_option); @@ -585,15 +598,14 @@ child_open_for_uncompress (void) while (1) { char *cursor; - int maximum; - int count; - int status; + size_t maximum; + size_t count; + ssize_t status; read_error_count = 0; error_loop: - status = rmtread (archive, record_start->buffer, - (unsigned int) (record_size)); + status = rmtread (archive, record_start->buffer, record_size); if (status < 0) { read_error (); @@ -606,7 +618,7 @@ child_open_for_uncompress (void) while (maximum) { count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE; - status = write (STDOUT, cursor, (size_t) count); + status = full_write (STDOUT_FILENO, cursor, count); if (status < 0) FATAL_ERROR ((0, errno, _("\ Cannot write to compression program"))); @@ -614,8 +626,8 @@ Cannot write to compression program"))); if (status != count) { ERROR ((0, 0, _("\ -Write to compression program short %d bytes"), - count - status)); +Write to compression program short %lu bytes"), + (unsigned long) (count - status))); count = status; } @@ -695,12 +707,12 @@ open_archive (enum access_mode access) if (multi_volume_option) { record_start - = (union block *) valloc ((unsigned) (record_size + (2 * BLOCKSIZE))); + = (union block *) valloc (record_size + (2 * BLOCKSIZE)); if (record_start) record_start += 2; } else - record_start = (union block *) valloc ((unsigned) record_size); + record_start = (union block *) valloc (record_size); if (!record_start) FATAL_ERROR ((0, 0, _("Could not allocate memory for blocking factor %d"), blocking_factor)); @@ -747,16 +759,16 @@ open_archive (enum access_mode access) switch (access) { case ACCESS_READ: - archive = STDIN; + archive = STDIN_FILENO; break; case ACCESS_WRITE: - archive = STDOUT; + archive = STDOUT_FILENO; stdlis = stderr; break; case ACCESS_UPDATE: - archive = STDIN; + archive = STDIN_FILENO; stdlis = stderr; write_archive_to_stdout = 1; break; @@ -788,7 +800,8 @@ open_archive (enum access_mode access) break; } - if (archive < 0) + if (archive < 0 + || (! _isrmt (archive) && fstat (archive, &archive_stat) < 0)) { int saved_errno = errno; @@ -800,15 +813,17 @@ open_archive (enum access_mode access) #if !MSDOS - fstat (archive, &archive_stat); - /* Detect if outputting to "/dev/null". */ { + static char const dev_null[] = "/dev/null"; struct stat dev_null_stat; - stat ("/dev/null", &dev_null_stat); - dev_null_output = (S_ISCHR (archive_stat.st_mode) - && archive_stat.st_rdev == dev_null_stat.st_rdev); + dev_null_output = + (strcmp (archive_name_array[0], dev_null) == 0 + || (! _isrmt (archive) + && stat (dev_null, &dev_null_stat) == 0 + && S_ISCHR (archive_stat.st_mode) + && archive_stat.st_rdev == dev_null_stat.st_rdev)); } if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode)) @@ -816,6 +831,8 @@ open_archive (enum access_mode access) ar_dev = archive_stat.st_dev; ar_ino = archive_stat.st_ino; } + else + ar_dev = 0; #endif /* not MSDOS */ @@ -856,7 +873,7 @@ open_archive (enum access_mode access) assign_string (¤t_file_name, record_start->header.name); record_start->header.typeflag = GNUTYPE_VOLHDR; - to_oct (time (0), 1 + 12, record_start->header.mtime); + TIME_TO_OCT (time (0), record_start->header.mtime); finish_header (record_start); #if 0 current_block++; @@ -874,7 +891,7 @@ void flush_write (void) { int copy_back; - int status; + ssize_t status; if (checkpoint_option && !(++checkpoint % 10)) WARN ((0, 0, _("Write checkpoint %d"), checkpoint)); @@ -888,8 +905,7 @@ flush_write (void) else if (dev_null_output) status = record_size; else - status = rmtwrite (archive, record_start->buffer, - (unsigned int) record_size); + status = write_archive_buffer (); if (status != record_size && !multi_volume_option) write_error (status); else if (totals_option) @@ -957,7 +973,7 @@ flush_write (void) { memset ((void *) record_start, 0, BLOCKSIZE); sprintf (record_start->header.name, "%s Volume %d", volume_label_option, volno); - to_oct (time (0), 1 + 12, record_start->header.mtime); + TIME_TO_OCT (time (0), record_start->header.mtime); record_start->header.typeflag = GNUTYPE_VOLHDR; finish_header (record_start); } @@ -977,10 +993,9 @@ flush_write (void) strcpy (record_start->header.name, real_s_name); record_start->header.typeflag = GNUTYPE_MULTIVOL; - to_oct ((long) real_s_sizeleft, 1 + 12, - record_start->header.size); - to_oct ((long) real_s_totsize - real_s_sizeleft, - 1 + 12, record_start->oldgnu_header.offset); + OFF_TO_OCT (real_s_sizeleft, record_start->header.size); + OFF_TO_OCT (real_s_totsize - real_s_sizeleft, + record_start->oldgnu_header.offset); tmp = verbose_option; verbose_option = 0; finish_header (record_start); @@ -990,8 +1005,7 @@ flush_write (void) record_start--; } - status = rmtwrite (archive, record_start->buffer, - (unsigned int) record_size); + status = write_archive_buffer (); if (status != record_size) write_error (status); else if (totals_option) @@ -1036,7 +1050,7 @@ flush_write (void) `---------------------------------------------------------------------*/ static void -write_error (int status) +write_error (ssize_t status) { int saved_errno = errno; @@ -1049,8 +1063,9 @@ write_error (int status) FATAL_ERROR ((0, saved_errno, _("Cannot write to %s"), *archive_name_cursor)); else - FATAL_ERROR ((0, 0, _("Only wrote %u of %u bytes to %s"), - status, record_size, *archive_name_cursor)); + FATAL_ERROR ((0, 0, _("Only wrote %lu of %lu bytes to %s"), + (unsigned long) status, (unsigned long) record_size, + *archive_name_cursor)); } /*-------------------------------------------------------------------. @@ -1081,8 +1096,8 @@ read_error (void) void flush_read (void) { - int status; /* result from system call */ - int left; /* bytes left */ + 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)) @@ -1095,7 +1110,7 @@ flush_read (void) if (write_archive_to_stdout && record_start_block != 0) { - status = rmtwrite (1, record_start->buffer, (unsigned int) record_size); + status = write_archive_buffer (); if (status != record_size) write_error (status); } @@ -1123,7 +1138,7 @@ flush_read (void) } error_loop: - status = rmtread (archive, record_start->buffer, (unsigned int) record_size); + status = rmtread (archive, record_start->buffer, record_size); if (status == record_size) return; @@ -1151,8 +1166,7 @@ error_loop: } vol_error: - status = rmtread (archive, record_start->buffer, - (unsigned int) record_size); + status = rmtread (archive, record_start->buffer, record_size); if (status < 0) { read_error (); @@ -1185,6 +1199,7 @@ error_loop: if (real_s_name[0]) { + uintmax_t s1, s2; if (cursor->header.typeflag != GNUTYPE_MULTIVOL || strcmp (cursor->header.name, real_s_name)) { @@ -1194,20 +1209,25 @@ error_loop: global_volno--; goto try_volume; } - if (real_s_totsize - != (from_oct (1 + 12, cursor->header.size) - + from_oct (1 + 12, cursor->oldgnu_header.offset))) + s1 = UINTMAX_FROM_OCT (cursor->header.size); + s2 = UINTMAX_FROM_OCT (cursor->oldgnu_header.offset); + if (real_s_totsize != s1 + s2 || s1 + s2 < s2) { - WARN ((0, 0, _("%s is the wrong size (%ld != %ld + %ld)"), - cursor->header.name, save_totsize, - from_oct (1 + 12, cursor->header.size), - from_oct (1 + 12, cursor->oldgnu_header.offset))); + 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)"), + 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 - != from_oct (1 + 12, cursor->oldgnu_header.offset)) + != OFF_FROM_OCT (cursor->oldgnu_header.offset)) { WARN ((0, 0, _("This volume is out of sequence"))); volno--; @@ -1230,17 +1250,17 @@ short_read: left = record_size - status; again: - if ((unsigned) left % BLOCKSIZE == 0) + if (left % BLOCKSIZE == 0) { /* 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 = %d blocks"), status / BLOCKSIZE)); + WARN ((0, 0, _("Record size = %lu blocks"), + (unsigned long) (status / BLOCKSIZE))); - record_end - = record_start + ((unsigned) (record_size - left)) / BLOCKSIZE; + record_end = record_start + (record_size - left) / BLOCKSIZE; return; } @@ -1251,7 +1271,7 @@ again: if (left > 0) { error2loop: - status = rmtread (archive, more, (unsigned int) left); + status = rmtread (archive, more, left); if (status < 0) { read_error (); @@ -1266,8 +1286,8 @@ again: } } else - FATAL_ERROR ((0, 0, _("Only read %d bytes from archive %s"), - status, *archive_name_cursor)); + FATAL_ERROR ((0, 0, _("Only read %lu bytes from archive %s"), + (unsigned long) status, *archive_name_cursor)); } /*-----------------------------------------------. @@ -1338,7 +1358,7 @@ backspace_output (void) #endif { - off_t position = rmtlseek (archive, 0L, 1); + off_t position = rmtlseek (archive, (off_t) 0, 1); /* Seek back to the beginning of this record and start writing there. */ @@ -1376,22 +1396,25 @@ close_archive (void) 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 (access_mode == ACCESS_READ && S_ISFIFO (archive_stat.st_mode)) - while (rmtread (archive, record_start->buffer, (unsigned int) record_size) - > 0) + if (access_mode == ACCESS_READ + && ! _isrmt (archive) + && S_ISFIFO (archive_stat.st_mode) + && ! ending_file_option) + while (rmtread (archive, record_start->buffer, record_size) > 0) continue; #endif - if (subcommand_option == DELETE_SUBCOMMAND) + if (! _isrmt (archive) && subcommand_option == DELETE_SUBCOMMAND) { - off_t pos; - - pos = rmtlseek (archive, 0L, 1); #if MSDOS - rmtwrite (archive, "", 0); + int status = write (archive, "", 0); #else - ftruncate (archive, (size_t) pos); + off_t pos = lseek (archive, (off_t) 0, 1); + int status = pos == -1 ? -1 : ftruncate (archive, pos); #endif + if (status != 0) + WARN ((0, errno, _("WARNING: Cannot truncate %s"), + *archive_name_cursor)); } if (verify_option) verify_volume (); @@ -1409,7 +1432,7 @@ close_archive (void) if (child_pid) { WAIT_T wait_status; - int child; + pid_t child; /* Loop waiting for the right child to die, or for no more kids. */ @@ -1506,7 +1529,7 @@ new_volume (enum access_mode access) if (!read_file && !info_script_option) /* FIXME: if fopen is used, it will never be closed. */ - read_file = archive == STDIN ? fopen (TTY_NAME, "r") : stdin; + read_file = archive == STDIN_FILENO ? fopen (TTY_NAME, "r") : stdin; if (now_verifying) return 0; @@ -1542,8 +1565,9 @@ tryagain: { char input_buffer[80]; + fputc ('\007', stderr); fprintf (stderr, - _("\007Prepare volume #%d for %s and hit return: "), + _("Prepare volume #%d for %s and hit return: "), global_volno, *archive_name_cursor); fflush (stderr);