/* Buffer management for tar.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
- 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007 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
+ Free Software Foundation; either version 3, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but
#include <closeout.h>
#include <fnmatch.h>
-#include <getline.h>
#include <human.h>
#include <quotearg.h>
/* Have we hit EOF yet? */
static bool hit_eof;
-/* Checkpointing counter */
-static unsigned checkpoint;
-
static bool read_full_records = false;
/* We're reading, but we just read the last block and it's time to update.
static off_t save_sizeleft; /* where we are in the file we are writing,
only valid if save_name is nonzero */
+\f
+static struct tar_stat_info dummy;
+
+void
+buffer_write_global_xheader ()
+{
+ xheader_write_global (&dummy.xhdr);
+}
+
void
mv_begin (struct tar_stat_info *st)
{
ct_none,
ct_compress,
ct_gzip,
- ct_bzip2
+ ct_bzip2,
+ ct_lzma
};
struct zip_magic
{ ct_compress, 2, "\037\235", "compress", "-Z" },
{ ct_gzip, 2, "\037\213", "gzip", "-z" },
{ ct_bzip2, 3, "BZh", "bzip2", "-j" },
+ { ct_lzma, 6, "\xFFLZMA", "lzma", "--lzma" }, /* FIXME: ???? */
};
#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
/* Check if the file ARCHIVE is a compressed archive. */
enum compress_type
-check_compressed_archive ()
+check_compressed_archive (bool *pshort)
{
struct zip_magic const *p;
bool sfr;
+ bool temp;
+ if (!pshort)
+ pshort = &temp;
+
/* Prepare global data needed for find_next_block: */
record_end = record_start; /* set up for 1st record = # 0 */
sfr = read_full_records;
read_full_records = true; /* Suppress fatal error on reading a partial
record */
- find_next_block ();
-
+ *pshort = find_next_block () == 0;
+
/* Restore global values */
read_full_records = sfr;
if (!multi_volume_option)
{
- enum compress_type type = check_compressed_archive ();
+ bool shortfile;
+ enum compress_type type = check_compressed_archive (&shortfile);
if (type == ct_none)
- return archive;
-
+ {
+ if (shortfile)
+ ERROR ((0, 0, _("This does not look like a tar archive")));
+ return archive;
+ }
+
/* FD is not needed any more */
rmtclose (archive);
print_stats (stderr, _("Total bytes read"),
records_read * record_size);
break;
+
+ default:
+ abort ();
}
}
{
int backed_up_flag = 0;
- if (index_file_name)
- {
- 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;
-
if (record_size == 0)
FATAL_ERROR ((0, 0, _("Invalid value for record_size")));
break;
}
- if (wanted_access == ACCESS_WRITE
+ if (!index_file_name
+ && wanted_access == ACCESS_WRITE
&& strcmp (archive_name_array[0], "-") == 0)
stdlis = stderr;
}
{
case ACCESS_READ:
{
+ bool shortfile;
enum compress_type type;
archive = STDIN_FILENO;
- type = check_compressed_archive ();
+ type = check_compressed_archive (&shortfile);
if (type != ct_none)
FATAL_ERROR ((0, 0,
_("Archive is compressed. Use %s option"),
compress_option (type)));
+ if (shortfile)
+ ERROR ((0, 0, _("This does not look like a tar archive")));
}
break;
case ACCESS_WRITE:
archive = STDOUT_FILENO;
- stdlis = stderr;
+ if (!index_file_name)
+ stdlis = stderr;
break;
case ACCESS_UPDATE:
archive = STDIN_FILENO;
- stdlis = stderr;
write_archive_to_stdout = true;
record_end = record_start; /* set up for 1st record = # 0 */
+ if (!index_file_name)
+ stdlis = stderr;
break;
}
}
O_RDWR | O_CREAT | O_BINARY,
MODE_RW, rsh_command_option);
- if (check_compressed_archive () != ct_none)
+ if (check_compressed_archive (NULL) != ct_none)
FATAL_ERROR ((0, 0,
_("Cannot update compressed archives")));
break;
}
}
-static void
-do_checkpoint (bool write)
-{
- if (checkpoint_option && !(++checkpoint % checkpoint_option))
- {
- switch (checkpoint_style)
- {
- case checkpoint_dot:
- fputc ('.', stdlis);
- fflush (stdlis);
- break;
-
- case checkpoint_text:
- if (write)
- /* TRANSLATORS: This is a ``checkpoint of write operation'',
- *not* ``Writing a checkpoint''.
- E.g. in Spanish ``Punto de comprobaci@'on de escritura'',
- *not* ``Escribiendo un punto de comprobaci@'on'' */
- WARN ((0, 0, _("Write checkpoint %u"), checkpoint));
- else
- /* TRANSLATORS: This is a ``checkpoint of read operation'',
- *not* ``Reading a checkpoint''.
- E.g. in Spanish ``Punto de comprobaci@'on de lectura'',
- *not* ``Leyendo un punto de comprobaci@'on'' */
- WARN ((0, 0, _("Read checkpoint %u"), checkpoint));
- break;
- }
- }
-}
-
/* Perform a write to flush the buffer. */
ssize_t
_flush_write (void)
{
ssize_t status;
- do_checkpoint (true);
+ checkpoint_run (true);
if (tape_length_option && tape_length_option <= bytes_written)
{
errno = ENOSPC;
status = record_size;
else
status = sys_write_archive_buffer ();
-
+
return status;
}
verify_volume ();
if (rmtclose (archive) != 0)
- close_warn (*archive_name_cursor);
+ close_error (*archive_name_cursor);
sys_wait_for_child (child_pid);
assign_string (&volume_label, NULL);
assign_string (&continued_file_name, NULL);
continued_file_size = continued_file_offset = 0;
-
+ current_block = record_start;
+
if (rmtclose (archive) != 0)
- close_warn (*archive_name_cursor);
+ close_error (*archive_name_cursor);
archive_name_cursor++;
if (archive_name_cursor == archive_name_array + archive_names)
{
size_t status;
union block *header;
- struct tar_stat_info dummy;
-
+ enum access_mode acc;
+
switch (subcommand_option)
{
case APPEND_SUBCOMMAND:
case CAT_SUBCOMMAND:
case UPDATE_SUBCOMMAND:
- if (!new_volume (ACCESS_UPDATE))
- return true;
+ acc = ACCESS_UPDATE;
break;
default:
- if (!new_volume (ACCESS_READ))
- return true;
+ acc = ACCESS_READ;
break;
}
+ if (!new_volume (acc))
+ return true;
+
while ((status = rmtread (archive, record_start->buffer, record_size))
== SAFE_READ_ERROR)
archive_read_error ();
_write_volume_label (const char *str)
{
if (archive_format == POSIX_FORMAT)
- xheader_store ("GNU.volume.label", NULL, str);
+ xheader_store ("GNU.volume.label", &dummy, str);
else
{
union block *label = find_next_block ();
if (archive_format == POSIX_FORMAT)
{
off_t d = real_s_totsize - real_s_sizeleft;
- xheader_store ("GNU.volume.filename", NULL, real_s_name);
- xheader_store ("GNU.volume.size", NULL, &real_s_sizeleft);
- xheader_store ("GNU.volume.offset", NULL, &d);
+ xheader_store ("GNU.volume.filename", &dummy, real_s_name);
+ xheader_store ("GNU.volume.size", &dummy, &real_s_sizeleft);
+ xheader_store ("GNU.volume.offset", &dummy, &d);
}
else
gnu_add_multi_volume_header ();
{
size_t status; /* result from system call */
- do_checkpoint (false);
+ checkpoint_run (false);
/* Clear the count of errors. This only applies to a single call to
flush_read. */
{
size_t status; /* result from system call */
- do_checkpoint (false);
+ checkpoint_run (false);
/* Clear the count of errors. This only applies to a single call to
flush_read. */
if (!new_volume (ACCESS_WRITE))
return;
- xheader_destroy (&extended_header);
+ tar_stat_destroy (&dummy);
increase_volume_number ();
prev_written += bytes_written;
if (real_s_name)
add_multi_volume_header ();
- write_extended (true, NULL, find_next_block ());
+ write_extended (true, &dummy, find_next_block ());
+ tar_stat_destroy (&dummy);
+
if (real_s_name)
add_chunk_header ();
header = find_next_block ();