/* Buffer management for tar.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
- 2003, 2004 Free Software Foundation, Inc.
+ 2003, 2004, 2005 Free Software Foundation, Inc.
Written by John Gilmore, on 1985-08-25.
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 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <system.h>
static int checkpoint;
static bool read_full_records = false;
-static bool reading_from_pipe = false;
/* We're reading, but we just read the last block and it's time to update.
Declared in update.c
void
set_start_time ()
{
-#if HAVE_CLOCK_GETTIME
- if (clock_gettime (CLOCK_REALTIME, &start_timespec) != 0)
-#endif
- start_time = time (0);
+ gettime (&start_time);
}
void
compute_duration ()
{
-#if HAVE_CLOCK_GETTIME
struct timespec now;
- if (clock_gettime (CLOCK_REALTIME, &now) == 0)
- duration += ((now.tv_sec - start_timespec.tv_sec)
- + (now.tv_nsec - start_timespec.tv_nsec) / 1e9);
- else
-#endif
- duration += time (NULL) - start_time;
+ gettime (&now);
+ duration += ((now.tv_sec - start_time.tv_sec)
+ + (now.tv_nsec - start_time.tv_nsec) / 1e9);
set_start_time ();
}
struct zip_magic
{
enum compress_type type;
- unsigned char *magic;
size_t length;
+ char *magic;
char *program;
char *option;
};
-static struct zip_magic magic[] = {
+static struct zip_magic const magic[] = {
{ ct_none, },
- { ct_compress, "\037\235", 2, "compress", "-Z" },
- { ct_gzip, "\037\213", 2, "gzip", "-z" },
- { ct_bzip2, "BZh", 3, "bzip2", "-j" },
+ { ct_compress, 2, "\037\235", "compress", "-Z" },
+ { ct_gzip, 2, "\037\213", "gzip", "-z" },
+ { ct_bzip2, 3, "BZh", "bzip2", "-j" },
};
#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
#define compress_option(t) magic[t].option
#define compress_program(t) magic[t].program
-/* Check if the file FD is a compressed archive. FD is guaranteed to
- represent a local file */
-enum compress_type
-check_compressed_archive (int fd)
+/* Check if the file ARCHIVE is a compressed archive. */
+enum compress_type
+check_compressed_archive ()
{
- struct zip_magic *p;
- size_t status;
- union block buf;
-
- status = read (fd, &buf, sizeof buf);
- if (status != sizeof buf)
- {
- archive_read_error ();
- FATAL_ERROR ((0, 0, _("Quitting now.")));
- }
+ struct zip_magic const *p;
+ bool sfr;
- lseek (fd, 0, SEEK_SET); /* This will fail if fd==0, but that does not
- matter, since we do not handle compressed
- stdin anyway */
-
- if (tar_checksum (&buf) == HEADER_SUCCESS)
+ /* 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 ();
+
+ /* Restore global values */
+ read_full_records = sfr;
+
+ if (tar_checksum (record_start, true) == HEADER_SUCCESS)
/* Probably a valid header */
return ct_none;
for (p = magic + 1; p < magic + NMAGIC; p++)
- if (memcmp (buf.buffer, p->magic, p->length) == 0)
+ if (memcmp (record_start->buffer, p->magic, p->length) == 0)
return p->type;
-
+
return ct_none;
}
int
open_compressed_archive ()
{
- enum compress_type type;
- int fd = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
- MODE_RW, rsh_command_option);
- if (fd == -1 || _isrmt (fd))
- return fd;
-
- type = check_compressed_archive (fd);
-
- if (type == ct_none)
+ archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
+ MODE_RW, rsh_command_option);
+ if (archive == -1)
+ return archive;
+
+ if (!multi_volume_option)
{
- if (rmtlseek (fd, (off_t) 0, SEEK_CUR) != 0)
- {
- /* Archive may be not seekable. Reopen it. */
- rmtclose (fd);
- fd = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
- MODE_RW, rsh_command_option);
- }
- return fd;
- }
+ enum compress_type type = check_compressed_archive ();
+
+ if (type == ct_none)
+ return archive;
- /* FD is not needed any more */
- rmtclose (fd);
+ /* FD is not needed any more */
+ rmtclose (archive);
- /* Open compressed archive */
- use_compress_program_option = compress_program (type);
- child_pid = sys_child_open_for_uncompress ();
- read_full_records = reading_from_pipe = true;
+ hit_eof = false; /* It might have been set by find_next_block in
+ check_compressed_archive */
+
+ /* Open compressed archive */
+ use_compress_program_option = compress_program (type);
+ child_pid = sys_child_open_for_uncompress ();
+ read_full_records = true;
+ }
+
+ records_read = 0;
+ record_end = record_start; /* set up for 1st record = # 0 */
return archive;
}
char bytes[sizeof (tarlong) * CHAR_BIT];
char abbr[LONGEST_HUMAN_READABLE + 1];
char rate[LONGEST_HUMAN_READABLE + 1];
-
+
int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
sprintf (bytes, TARLONG_FORMAT, written);
access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
read_full_records = read_full_records_option;
- reading_from_pipe = false;
-
+
+ records_read = 0;
+
if (use_compress_program_option)
{
switch (wanted_access)
{
case ACCESS_READ:
child_pid = sys_child_open_for_uncompress ();
- read_full_records = reading_from_pipe = true;
+ read_full_records = true;
+ record_end = record_start; /* set up for 1st record = # 0 */
break;
case ACCESS_WRITE:
case ACCESS_READ:
{
enum compress_type type;
-
+
archive = STDIN_FILENO;
type = check_compressed_archive (archive);
{
case ACCESS_UPDATE:
records_written = 0;
- case ACCESS_READ:
- records_read = 0;
record_end = record_start; /* set up for 1st record = # 0 */
+
+ case ACCESS_READ:
find_next_block (); /* read it in, check for EOF */
if (volume_label_option)
strip_trailing_slashes (current_stat_info.file_name);
record_start->header.typeflag = GNUTYPE_VOLHDR;
- TIME_TO_CHARS (start_time, record_start->header.mtime);
+ TIME_TO_CHARS (start_time.tv_sec, record_start->header.mtime);
finish_header (¤t_stat_info, record_start, -1);
}
break;
ssize_t status;
if (checkpoint_option && !(++checkpoint % 10))
+ /* 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 %d"), checkpoint));
if (tape_length_option && tape_length_option <= bytes_written)
{
if (save_name)
{
- assign_string (&real_s_name, safer_name_suffix (save_name, false));
+ assign_string (&real_s_name,
+ safer_name_suffix (save_name, false,
+ absolute_names_option));
real_s_totsize = save_totsize;
real_s_sizeleft = save_sizeleft;
}
memset (record_start, 0, BLOCKSIZE);
sprintf (record_start->header.name, "%s Volume %d",
volume_label_option, volno);
- TIME_TO_CHARS (start_time, record_start->header.mtime);
+ TIME_TO_CHARS (start_time.tv_sec, record_start->header.mtime);
record_start->header.typeflag = GNUTYPE_VOLHDR;
finish_header (¤t_stat_info, record_start, -1);
}
record_start++;
if (strlen (real_s_name) > NAME_FIELD_SIZE)
- FATAL_ERROR ((0, 0,
- _("%s: file name too long to be stored in a GNU multivolume header"),
+ WARN ((0, 0,
+ _("%s: file name too long to be stored in a GNU multivolume header, truncated"),
quotearg_colon (real_s_name)));
-
+
memset (record_start, 0, BLOCKSIZE);
/* FIXME: Michael P Urban writes: [a long name file] is being written
OFF_TO_CHARS (real_s_sizeleft, record_start->header.size);
OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
record_start->oldgnu_header.offset);
-
+
tmp = verbose_option;
verbose_option = 0;
finish_header (¤t_stat_info, record_start, -1);
assign_string (&real_s_name, 0);
else
{
- assign_string (&real_s_name, safer_name_suffix (save_name, false));
+ assign_string (&real_s_name,
+ safer_name_suffix (save_name, false,
+ absolute_names_option));
real_s_sizeleft = save_sizeleft;
real_s_totsize = save_totsize;
}
archive_read_error ();
if (status == 0)
- {
- if (!reading_from_pipe)
- {
- char buf[UINTMAX_STRSIZE_BOUND];
-
- WARN((0, 0, _("Read %s bytes from %s"),
- STRINGIFY_BIGINT (record_size - left, buf),
- *archive_name_cursor));
- }
- break;
- }
+ break;
if (! read_full_records)
{
size_t status; /* result from system call */
if (checkpoint_option && !(++checkpoint % 10))
+ /* 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 %d"), checkpoint));
/* Clear the count of errors. This only applies to a single call to
{
if (save_name)
{
- assign_string (&real_s_name, safer_name_suffix (save_name, false));
+ assign_string (&real_s_name,
+ safer_name_suffix (save_name, false,
+ absolute_names_option));
real_s_sizeleft = save_sizeleft;
real_s_totsize = save_totsize;
}
off_t offset;
off_t nrec, nblk;
off_t skipped = (blocking_factor - (current_block - record_start));
-
+
size -= skipped * BLOCKSIZE;
-
+
if (size < record_size)
return 0;
/* FIXME: flush? */
-
+
/* Compute number of records to skip */
nrec = size / record_size;
offset = rmtlseek (archive, nrec * record_size, SEEK_CUR);
records_read += nblk / blocking_factor;
record_start_block = offset - blocking_factor;
current_block = record_end;
-
+
return nblk;
}
sys_drain_input_pipe ();
compute_duration ();
- if (verify_option)
+ if (verify_option)
verify_volume ();
if (rmtclose (archive) != 0)
if (volno_file_option)
closeout_volume_number ();
if (system (info_script_option) != 0)
- FATAL_ERROR ((0, 0, _("`%s' command failed"), info_script_option));
+ FATAL_ERROR ((0, 0, _("%s command failed"),
+ quote (info_script_option)));
}
else
while (1)
return true;
}
-