X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fbuffer.c;h=fd16b6f1e39d4f42d34c8ba0ad761ea3c7a08f60;hb=91b2d65e9dccae981f308a659d6c7bdd32285598;hp=e531061d7036ee48e35f674d15fb9e8fdbf69c06;hpb=58e97f92d39e8e69bd2e98de29635a9a35c47994;p=chaz%2Ftar diff --git a/src/buffer.c b/src/buffer.c index e531061..fd16b6f 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,7 +1,7 @@ /* Buffer management for tar. - Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free - Software Foundation, Inc. + Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, + 2003 Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-25. @@ -52,26 +52,27 @@ static tarlong prev_written; /* bytes written on previous volumes */ static tarlong bytes_written; /* bytes written on this volume */ -/* FIXME: The following four variables should ideally be static to this - module. However, this cannot be done yet, as update.c uses the first - three a lot, and compare.c uses the fourth. The cleanup continues! */ +/* 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. */ +/* Where we write list messages (not errors, not interactions) to. */ 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)); +static void backspace_output (void); +static int new_volume (enum access_mode); +static void archive_write_error (ssize_t) __attribute__ ((noreturn)); +static void archive_read_error (void); #if !MSDOS /* Obnoxious test to see if dimwit is trying to dump the archive. */ @@ -117,7 +118,7 @@ off_t save_totsize; /* total size of file we are writing, only 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; +bool write_archive_to_stdout; /* Used by flush_read and flush_write to store the real info about saved names. */ @@ -135,6 +136,7 @@ print_total_written (void) char abbr[LONGEST_HUMAN_READABLE + 1]; char rate[LONGEST_HUMAN_READABLE + 1]; double seconds; + int human_opts = human_autoscale | human_base_1024 | human_SI | human_B; #if HAVE_CLOCK_GETTIME struct timespec now; @@ -148,10 +150,10 @@ print_total_written (void) 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), + fprintf (stderr, _("Total bytes written: %s (%s, %s/s)\n"), bytes, + human_readable (written, abbr, human_opts, 1, 1), (0 < seconds && written / seconds < (uintmax_t) -1 - ? human_readable ((uintmax_t) (written / seconds), rate, 1, -1024) + ? human_readable (written / seconds, rate, human_opts, 1, 1) : "?")); } @@ -299,7 +301,9 @@ write_archive_buffer (void) { written += status; if (written == record_size - || _isrmt (archive) || ! S_ISFIFO (archive_stat.st_mode)) + || _isrmt (archive) + || ! (S_ISFIFO (archive_stat.st_mode) + || S_ISSOCK (archive_stat.st_mode))) break; } @@ -415,8 +419,6 @@ child_open_for_compress (void) { size_t size = record_size - length; - if (size < BLOCKSIZE) - size = BLOCKSIZE; status = safe_read (STDIN_FILENO, cursor, size); if (status <= 0) break; @@ -652,7 +654,14 @@ open_archive (enum access_mode wanted_access) { int backed_up_flag = 0; - stdlis = to_stdout_option ? stderr : stdout; + if (index_file_name) + { + stdlis = fopen (index_file_name, "w"); + if (! stdlis) + open_error (index_file_name); + } + else + stdlis = to_stdout_option ? stderr : stdout; if (record_size == 0) FATAL_ERROR ((0, 0, _("Invalid value for record_size"))); @@ -660,8 +669,7 @@ open_archive (enum access_mode wanted_access) if (archive_names == 0) FATAL_ERROR ((0, 0, _("No archive name given"))); - current_file_name = 0; - current_link_name = 0; + destroy_stat (¤t_stat_info); save_name = 0; real_s_name = 0; @@ -804,8 +812,10 @@ open_archive (enum access_mode wanted_access) switch (wanted_access) { - case ACCESS_READ: 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 */ @@ -824,6 +834,7 @@ open_archive (enum access_mode wanted_access) break; case ACCESS_WRITE: + records_written = 0; if (volume_label_option) { memset (record_start, 0, BLOCKSIZE); @@ -833,11 +844,12 @@ open_archive (enum access_mode wanted_access) else strcpy (record_start->header.name, volume_label_option); - assign_string (¤t_file_name, record_start->header.name); + assign_string (¤t_stat_info.file_name, record_start->header.name); + current_stat_info.had_trailing_slash = strip_trailing_slashes (current_stat_info.file_name); record_start->header.typeflag = GNUTYPE_VOLHDR; TIME_TO_CHARS (start_time, record_start->header.mtime); - finish_header (record_start); + finish_header (record_start, -1); #if 0 current_block++; #endif @@ -869,29 +881,27 @@ flush_write (void) archive_write_error (status); if (status > 0) - bytes_written += status; + { + records_written++; + bytes_written += status; + } if (status == record_size) { if (multi_volume_option) { - char *cursor; - - if (!save_name) + if (save_name) + { + assign_string (&real_s_name, safer_name_suffix (save_name, 0)); + real_s_totsize = save_totsize; + real_s_sizeleft = save_sizeleft; + } + else { 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; } @@ -931,7 +941,7 @@ flush_write (void) volume_label_option, volno); TIME_TO_CHARS (start_time, record_start->header.mtime); record_start->header.typeflag = GNUTYPE_VOLHDR; - finish_header (record_start); + finish_header (record_start, -1); } if (real_s_name) @@ -954,7 +964,7 @@ flush_write (void) record_start->oldgnu_header.offset); tmp = verbose_option; verbose_option = 0; - finish_header (record_start); + finish_header (record_start, -1); verbose_option = tmp; if (volume_label_option) @@ -981,12 +991,7 @@ flush_write (void) 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); + assign_string (&real_s_name, safer_name_suffix (save_name, 0)); real_s_sizeleft = save_sizeleft; real_s_totsize = save_totsize; } @@ -1030,13 +1035,65 @@ archive_read_error (void) return; } +static void +short_read (ssize_t status) +{ + size_t left; /* bytes left */ + char *more; /* pointer to next byte to 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) + { + unsigned long rest = record_size - left; + + FATAL_ERROR ((0, 0, + ngettext ("Unaligned block (%lu byte) in archive", + "Unaligned block (%lu bytes) in archive", + rest), + rest)); + } + + /* 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) + { + unsigned long rsize = (record_size - left) / BLOCKSIZE; + WARN ((0, 0, + ngettext ("Record size = %lu block", + "Record size = %lu blocks", + rsize), + rsize)); + } + + record_end = record_start + (record_size - left) / BLOCKSIZE; + records_read++; +} + /* 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)); @@ -1058,12 +1115,7 @@ flush_read (void) { if (save_name) { - char *cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name); - - while (ISSLASH (*cursor)) - cursor++; - - assign_string (&real_s_name, cursor); + assign_string (&real_s_name, safer_name_suffix (save_name, 0)); real_s_sizeleft = save_sizeleft; real_s_totsize = save_totsize; } @@ -1078,7 +1130,10 @@ flush_read (void) error_loop: status = rmtread (archive, record_start->buffer, record_size); if (status == record_size) - return; + { + records_read++; + return; + } if ((status == 0 || (status < 0 && errno == ENOSPC) @@ -1111,7 +1166,7 @@ flush_read (void) goto vol_error; } if (status != record_size) - goto short_read; + short_read (status); cursor = record_start; @@ -1176,6 +1231,7 @@ flush_read (void) cursor++; } current_block = cursor; + records_read++; return; } else if (status < 0) @@ -1184,44 +1240,7 @@ flush_read (void) 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) - { - if (left % BLOCKSIZE != 0) - ERROR ((0, 0, _("%d garbage bytes ignored at end of archive"), - (int) ((record_size - left) % BLOCKSIZE))); - 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; + short_read (status); } /* Flush the current buffer to/from the archive. */ @@ -1322,7 +1341,7 @@ close_archive (void) if (access_mode == ACCESS_READ && ! _isrmt (archive) - && S_ISFIFO (archive_stat.st_mode)) + && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode))) while (rmtread (archive, record_start->buffer, record_size) > 0) continue; #endif @@ -1355,10 +1374,7 @@ close_archive (void) } #endif /* !MSDOS */ - if (current_file_name) - free (current_file_name); - if (current_link_name) - free (current_link_name); + destroy_stat (¤t_stat_info); if (save_name) free (save_name); if (real_s_name) @@ -1550,7 +1566,12 @@ new_volume (enum access_mode access) } } - if (verify_option) + if (strcmp (archive_name_cursor[0], "-") == 0) + { + read_full_records_option = true; + archive = STDIN_FILENO; + } + else if (verify_option) archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW, rsh_command_option); else @@ -1588,3 +1609,4 @@ new_volume (enum access_mode access) return 1; } +