From 5b1df7b55e9a77587984511e222b70d01b637205 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Fri, 11 Nov 2005 00:24:52 +0000 Subject: [PATCH] (flush_write,flush_read): Change data type. (flush_archive): Compute actual buffer fill level before calling low level function. (close_archive): Call flush_archive again if the first call resulted in partially filled buffer. (try_new_volume): Rewritten handling of initial headers. (add_chunk_header): New function. Write an additional header before the continuation chunk. The purpose of the header is to allow third-party tars to extract the member. (simple_flush_write): Take an argument. (_gnu_flush_write): Correctly handle partially filled buffers. --- src/buffer.c | 185 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 128 insertions(+), 57 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index f5ebfb7..f8fe2ea 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -84,6 +84,9 @@ extern bool time_to_start_writing; bool write_archive_to_stdout; +void (*flush_write_ptr) (size_t); +void (*flush_read_ptr) (void); + char *volume_label; char *continued_file_name; @@ -674,6 +677,7 @@ _flush_read (void) void flush_archive (void) { + size_t buffer_level = current_block->buffer - record_start->buffer; record_start_block += record_end - record_start; current_block = record_start; record_end = record_start + blocking_factor; @@ -692,7 +696,7 @@ flush_archive (void) break; case ACCESS_WRITE: - flush_write (); + flush_write_ptr (buffer_level); break; case ACCESS_UPDATE: @@ -784,7 +788,11 @@ void close_archive (void) { if (time_to_start_writing || access_mode == ACCESS_WRITE) - flush_archive (); + { + flush_archive (); + if (current_block > record_start) + flush_archive (); + } sys_drain_input_pipe (); @@ -1021,13 +1029,26 @@ new_volume (enum access_mode mode) return true; } - + +static bool +read_header0 () +{ + enum read_header rc = read_header (false); + + if (rc == HEADER_SUCCESS) + { + set_next_block_after (current_header); + return true; + } + ERROR ((0, 0, _("This does not look like a tar archive"))); + return false; +} + bool try_new_volume () { size_t status; - enum read_header rc; - union block *block; + union block *header; switch (subcommand_option) { @@ -1051,49 +1072,51 @@ try_new_volume () if (status != record_size) short_read (status); - again: - block = current_block; - rc = read_header (true); - switch (rc) + header = find_next_block (); + if (!header) + return false; + switch (header->header.typeflag) { - case HEADER_SUCCESS_EXTENDED: - if (current_header->header.typeflag == XGLTYPE) - { - struct tar_stat_info dummy; - xheader_read (current_header, - OFF_FROM_HEADER (current_header->header.size)); - xheader_decode_global (); - xheader_destroy (&extended_header); - tar_stat_init (&dummy); - xheader_decode (&dummy); /* decodes values from the global header */ - tar_stat_destroy (&dummy); - } - break; + case XGLTYPE: + { + struct tar_stat_info dummy; + if (!read_header0 ()) + return false; + tar_stat_init (&dummy); + xheader_decode (&dummy); /* decodes values from the global header */ + tar_stat_destroy (&dummy); + if (!real_s_name) + { + /* We have read the extended header of the first member in + this volume. Put it back, so next read_header works as + expected. */ + current_block = record_start; + } + break; + } - case HEADER_SUCCESS: - if (current_header->header.typeflag == GNUTYPE_VOLHDR) - assign_string (&volume_label, current_header->header.name); - else if (current_header->header.typeflag == GNUTYPE_MULTIVOL) - { - 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); - } - else + case GNUTYPE_VOLHDR: + if (!read_header0 ()) + return false; + assign_string (&volume_label, current_header->header.name); + set_next_block_after (header); + header = find_next_block (); + if (header->header.typeflag != GNUTYPE_MULTIVOL) break; - set_next_block_after (current_header); - goto again; - - case HEADER_ZERO_BLOCK: - case HEADER_END_OF_FILE: - case HEADER_FAILURE: - current_block = block; + /* FALL THROUGH */ + + case GNUTYPE_MULTIVOL: + if (!read_header0 ()) + return false; + 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: - abort (); + break; } if (real_s_name) @@ -1219,6 +1242,38 @@ add_volume_label (void) free (s); } +static void +add_chunk_header () +{ + if (archive_format == POSIX_FORMAT) + { + off_t block_ordinal; + union block *blk; + struct tar_stat_info st; + static size_t real_s_part_no; /* FIXME */ + + real_s_part_no++; + memset (&st, 0, sizeof st); + st.orig_file_name = st.file_name = real_s_name; + st.stat.st_mode = S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; + st.stat.st_uid = getuid (); + st.stat.st_gid = getgid (); + st.orig_file_name = xheader_format_name (&st, + "%d/GNUFileParts.%p/%f.%n", + 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); + } +} + + /* Add a volume label to the current archive */ static void write_volume_label (void) @@ -1350,7 +1405,7 @@ simple_flush_read (void) /* Simple flush write (no multi-volume or label extensions) */ static void -simple_flush_write (void) +simple_flush_write (size_t level __attribute__((unused))) { ssize_t status; @@ -1431,20 +1486,20 @@ _gnu_flush_read (void) static void gnu_flush_read (void) { - flush_read = simple_flush_read; /* Avoid recursion */ + flush_read_ptr = simple_flush_read; /* Avoid recursion */ _gnu_flush_read (); - flush_read = gnu_flush_read; + flush_read_ptr = gnu_flush_read; } static void -_gnu_flush_write (void) +_gnu_flush_write (size_t buffer_level) { ssize_t status; union block *header; char *copy_ptr; size_t copy_size; size_t bufsize; - + status = _flush_write (); if (status != record_size && !multi_volume_option) archive_write_error (status); @@ -1476,7 +1531,7 @@ _gnu_flush_write (void) bytes_written = 0; copy_ptr = record_start->buffer + status; - copy_size = record_size - status; + copy_size = buffer_level - status; /* Switch to the next buffer */ record_index = !record_index; init_buffer (); @@ -1487,7 +1542,10 @@ _gnu_flush_write (void) if (real_s_name) add_multi_volume_header (); - header = write_extended (XGLTYPE, NULL, find_next_block ()); + write_extended (true, NULL, find_next_block ()); + if (real_s_name) + add_chunk_header (); + header = find_next_block (); bufsize = available_space_after (header); while (bufsize < copy_size) { @@ -1505,18 +1563,30 @@ _gnu_flush_write (void) } static void -gnu_flush_write (void) +gnu_flush_write (size_t buffer_level) { - flush_write = simple_flush_write; /* Avoid recursion */ - _gnu_flush_write (); - flush_write = gnu_flush_write; + flush_write_ptr = simple_flush_write; /* Avoid recursion */ + _gnu_flush_write (buffer_level); + flush_write_ptr = gnu_flush_write; } - + +void +flush_read () +{ + flush_read_ptr (); +} + +void +flush_write () +{ + flush_write_ptr (record_size); +} + void open_archive (enum access_mode wanted_access) { - flush_read = gnu_flush_read; - flush_write = gnu_flush_write; + flush_read_ptr = gnu_flush_read; + flush_write_ptr = gnu_flush_write; _open_archive (wanted_access); switch (wanted_access) @@ -1533,3 +1603,4 @@ open_archive (enum access_mode wanted_access) break; } } + -- 2.44.0