X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fbuffer.c;h=cd70c732aa1493c0be8a959bf5fe0fc50ce713bf;hb=9dfad74683d23094732a36429aeac720210a0c1d;hp=586b1f9536fc444605e9c8ac6897aa65a0b0cd1c;hpb=ffc4fb7bdd03d095c46233770eb1a40fcaa3999c;p=chaz%2Ftar diff --git a/src/buffer.c b/src/buffer.c index 586b1f9..cd70c73 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,7 +1,7 @@ /* Buffer management for tar. Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, - 2003, 2004, 2005 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-25. @@ -20,10 +20,13 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include +#include #include +#include #include +#include #include #include @@ -41,6 +44,7 @@ static tarlong prev_written; /* bytes written on previous volumes */ static tarlong bytes_written; /* bytes written on this volume */ static void *record_buffer[2]; /* allocated memory */ +union block *record_buffer_aligned[2]; static int record_index; /* FIXME: The following variables should ideally be static to this @@ -366,10 +370,11 @@ xclose (int fd) static void init_buffer () { - if (!record_buffer[record_index]) - page_aligned_alloc (&record_buffer[record_index], record_size); - - record_start = record_buffer[record_index]; + if (! record_buffer_aligned[record_index]) + record_buffer_aligned[record_index] = + page_aligned_alloc (&record_buffer[record_index], record_size); + + record_start = record_buffer_aligned[record_index]; current_block = record_start; record_end = record_start + blocking_factor; } @@ -383,9 +388,10 @@ _open_archive (enum access_mode wanted_access) if (index_file_name) { - stdlis = fopen (index_file_name, "w"); + stdlis = freopen (index_file_name, "w", stdout); if (! stdlis) open_error (index_file_name); + close_stdout_set_file_name (index_file_name); } else stdlis = to_stdout_option ? stderr : stdout; @@ -402,7 +408,7 @@ _open_archive (enum access_mode wanted_access) record_index = 0; init_buffer (); - + /* When updating the archive, we start with reading. */ access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access; @@ -447,7 +453,7 @@ _open_archive (enum access_mode wanted_access) archive = STDIN_FILENO; - type = check_compressed_archive (archive); + type = check_compressed_archive (); if (type != ct_none) FATAL_ERROR ((0, 0, _("Archive is compressed. Use %s option"), @@ -868,27 +874,28 @@ change_tape_menu (FILE *read_file) { char *input_buffer = NULL; size_t size = 0; - - while (1) + bool stop = false; + + while (!stop) { fputc ('\007', stderr); fprintf (stderr, _("Prepare volume #%d for %s and hit return: "), global_volno + 1, quote (*archive_name_cursor)); fflush (stderr); - + if (getline (&input_buffer, &size, 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') @@ -899,7 +906,7 @@ change_tape_menu (FILE *read_file) case '?': { fprintf (stderr, _("\ - n [name] Give a new file name for the next (and subsequent) volume(s)\n\ + n name Give a new file name for the next (and subsequent) volume(s)\n\ q Abort tar\n\ y or newline Continue operation\n")); if (!restrict_option) @@ -910,37 +917,44 @@ change_tape_menu (FILE *read_file) 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; char *cursor; - + for (name = input_buffer + 1; *name == ' ' || *name == '\t'; name++) ; - + for (cursor = name; *cursor && *cursor != '\n'; cursor++) ; *cursor = '\0'; - - /* FIXME: the following allocation is never reclaimed. */ - *archive_name_cursor = xstrdup (name); + + if (name[0]) + { + /* FIXME: the following allocation is never reclaimed. */ + *archive_name_cursor = xstrdup (name); + stop = true; + } + else + fprintf (stderr, "%s", + _("File name not specified. Try again.\n")); } break; - + case '!': if (!restrict_option) { @@ -964,6 +978,7 @@ new_volume (enum access_mode mode) { static FILE *read_file; static int looped; + int prompt; if (!read_file && !info_script_option) /* FIXME: if fopen is used, it will never be closed. */ @@ -977,7 +992,7 @@ new_volume (enum access_mode mode) assign_string (&volume_label, NULL); assign_string (&continued_file_name, NULL); continued_file_size = continued_file_offset = 0; - + if (rmtclose (archive) != 0) close_warn (*archive_name_cursor); @@ -987,9 +1002,10 @@ new_volume (enum access_mode mode) archive_name_cursor = archive_name_array; looped = 1; } + prompt = looped; tryagain: - if (looped) + if (prompt) { /* We have to prompt from now on. */ @@ -1039,6 +1055,7 @@ new_volume (enum access_mode mode) open_warn (*archive_name_cursor); if (!verify_option && mode == ACCESS_WRITE && backup_option) undo_last_backup (); + prompt = 1; goto tryagain; } @@ -1048,10 +1065,12 @@ new_volume (enum access_mode mode) } static bool -read_header0 () +read_header0 (struct tar_stat_info *info) { - enum read_header rc = read_header (false); + enum read_header rc; + tar_stat_init (info); + rc = read_header_primitive (false, info); if (rc == HEADER_SUCCESS) { set_next_block_after (current_header); @@ -1066,7 +1085,8 @@ try_new_volume () { size_t status; union block *header; - + struct tar_stat_info dummy; + switch (subcommand_option) { case APPEND_SUBCOMMAND: @@ -1092,14 +1112,13 @@ try_new_volume () header = find_next_block (); if (!header) return false; + switch (header->header.typeflag) { case XGLTYPE: { - struct tar_stat_info dummy; - if (!read_header0 ()) + if (!read_header0 (&dummy)) return false; - tar_stat_init (&dummy); xheader_decode (&dummy); /* decodes values from the global header */ tar_stat_destroy (&dummy); if (!real_s_name) @@ -1111,27 +1130,29 @@ try_new_volume () } break; } - + case GNUTYPE_VOLHDR: - if (!read_header0 ()) + if (!read_header0 (&dummy)) return false; + tar_stat_destroy (&dummy); assign_string (&volume_label, current_header->header.name); set_next_block_after (header); header = find_next_block (); if (header->header.typeflag != GNUTYPE_MULTIVOL) break; /* FALL THROUGH */ - + case GNUTYPE_MULTIVOL: - if (!read_header0 ()) + if (!read_header0 (&dummy)) return false; + tar_stat_destroy (&dummy); assign_string (&continued_file_name, current_header->header.name); continued_file_size = UINTMAX_FROM_HEADER (current_header->header.size); continued_file_offset = UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset); break; - + default: break; } @@ -1139,12 +1160,22 @@ try_new_volume () if (real_s_name) { uintmax_t s; - if (!continued_file_name + if (!continued_file_name || strcmp (continued_file_name, real_s_name)) { - WARN ((0, 0, _("%s is not continued on this volume"), - quote (real_s_name))); - return false; + if ((archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT) + && strlen (real_s_name) >= NAME_FIELD_SIZE + && strncmp (continued_file_name, real_s_name, + NAME_FIELD_SIZE) == 0) + WARN ((0, 0, + _("%s is possibly continued on this volume: header contains truncated name"), + quote (real_s_name))); + else + { + WARN ((0, 0, _("%s is not continued on this volume"), + quote (real_s_name))); + return false; + } } s = continued_file_size + continued_file_offset; @@ -1162,7 +1193,7 @@ try_new_volume () STRINGIFY_BIGINT (continued_file_offset, s2buf))); return false; } - + if (real_s_totsize - real_s_sizeleft != continued_file_offset) { WARN ((0, 0, _("This volume is out of sequence"))); @@ -1228,7 +1259,7 @@ _write_volume_label (const char *str) else { union block *label = find_next_block (); - + memset (label, 0, BLOCKSIZE); strcpy (label->header.name, volume_label_option); @@ -1280,13 +1311,13 @@ add_chunk_header () real_s_part_no); st.file_name = st.orig_file_name; st.archive_file_size = st.stat.st_size = real_s_sizeleft; - + block_ordinal = current_block_ordinal (); blk = start_header (&st); - free (st.orig_file_name); if (!blk) abort (); /* FIXME */ finish_header (&st, blk, block_ordinal); + free (st.orig_file_name); } } @@ -1307,25 +1338,25 @@ gnu_add_multi_volume_header (void) { int tmp; union block *block = find_next_block (); - + if (strlen (real_s_name) > NAME_FIELD_SIZE) WARN ((0, 0, _("%s: file name too long to be stored in a GNU multivolume header, truncated"), quotearg_colon (real_s_name))); - + memset (block, 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. */ - + strncpy (block->header.name, real_s_name, NAME_FIELD_SIZE); block->header.typeflag = GNUTYPE_MULTIVOL; - + OFF_TO_CHARS (real_s_sizeleft, block->header.size); OFF_TO_CHARS (real_s_totsize - real_s_sizeleft, block->oldgnu_header.offset); - + tmp = verbose_option; verbose_option = 0; finish_header (¤t_stat_info, block, -1); @@ -1401,7 +1432,7 @@ simple_flush_read (void) if (status != record_size) archive_write_error (status); } - + for (;;) { status = rmtread (archive, record_start->buffer, record_size); @@ -1493,7 +1524,7 @@ _gnu_flush_read (void) else if (status == SAFE_READ_ERROR) { archive_read_error (); - continue; + continue; } break; } @@ -1505,7 +1536,7 @@ gnu_flush_read (void) { flush_read_ptr = simple_flush_read; /* Avoid recursion */ _gnu_flush_read (); - flush_read_ptr = gnu_flush_read; + flush_read_ptr = gnu_flush_read; } static void @@ -1516,7 +1547,7 @@ _gnu_flush_write (size_t buffer_level) char *copy_ptr; size_t copy_size; size_t bufsize; - + status = _flush_write (); if (status != record_size && !multi_volume_option) archive_write_error (status); @@ -1552,7 +1583,7 @@ _gnu_flush_write (size_t buffer_level) /* Switch to the next buffer */ record_index = !record_index; init_buffer (); - + if (volume_label_option) add_volume_label (); @@ -1584,7 +1615,7 @@ gnu_flush_write (size_t buffer_level) { flush_write_ptr = simple_flush_write; /* Avoid recursion */ _gnu_flush_write (buffer_level); - flush_write_ptr = gnu_flush_write; + flush_write_ptr = gnu_flush_write; } void @@ -1597,7 +1628,7 @@ void flush_write () { flush_write_ptr (record_size); -} +} void open_archive (enum access_mode wanted_access) @@ -1618,6 +1649,8 @@ open_archive (enum access_mode wanted_access) if (volume_label_option) write_volume_label (); break; + + default: + break; } } -