static tarlong prev_written; /* bytes written on previous volumes */
static tarlong bytes_written; /* bytes written on this volume */
+static void *record_buffer; /* allocated memory */
/* FIXME: The following variables should ideally be static to this
module. However, this cannot be done yet. The cleanup continues! */
Declared in update.c
As least EXTERN like this one as possible. (?? --gray)
- FIXME: Either eliminate it or move it to common.h.
+ FIXME: Either eliminate it or move it to common.h.
*/
extern bool time_to_start_writing;
/* Functions. */
void
-clear_read_error_count ()
+clear_read_error_count (void)
{
read_error_count = 0;
}
+\f
+/* Time-related functions */
+
+double duration;
+
void
-print_total_written (void)
+set_start_time ()
{
- tarlong written = prev_written + bytes_written;
- char bytes[sizeof (tarlong) * CHAR_BIT];
- 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
+ if (clock_gettime (CLOCK_REALTIME, &start_timespec) != 0)
+#endif
+ start_time = time (0);
+}
+void
+compute_duration ()
+{
#if HAVE_CLOCK_GETTIME
struct timespec now;
if (clock_gettime (CLOCK_REALTIME, &now) == 0)
- seconds = ((now.tv_sec - start_timespec.tv_sec)
- + (now.tv_nsec - start_timespec.tv_nsec) / 1e9);
+ duration += ((now.tv_sec - start_timespec.tv_sec)
+ + (now.tv_nsec - start_timespec.tv_nsec) / 1e9);
else
#endif
- seconds = time (0) - start_time;
+ duration += time (NULL) - start_time;
+ set_start_time ();
+}
+
+\f
+
+void
+print_total_written (void)
+{
+ tarlong written = prev_written + bytes_written;
+ 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);
/* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*". */
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 (written / seconds, rate, human_opts, 1, 1)
+ (0 < duration && written / duration < (uintmax_t) -1
+ ? human_readable (written / duration, rate, human_opts, 1, 1)
: "?"));
}
save_name = 0;
real_s_name = 0;
+ record_start =
+ page_aligned_alloc (&record_buffer,
+ (record_size
+ + (multi_volume_option ? 2 * BLOCKSIZE : 0)));
if (multi_volume_option)
- {
- record_start = valloc (record_size + (2 * BLOCKSIZE));
- if (record_start)
- record_start += 2;
- }
- else
- record_start = valloc (record_size);
- if (!record_start)
- FATAL_ERROR ((0, 0, _("Cannot allocate memory for blocking factor %d"),
- blocking_factor));
+ record_start += 2;
current_block = record_start;
record_end = record_start + blocking_factor;
}
else if (strcmp (archive_name_array[0], "-") == 0)
{
- read_full_records_option = 1; /* could be a pipe, be safe */
+ read_full_records_option = true; /* could be a pipe, be safe */
if (verify_option)
FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
else
strcpy (record_start->header.name, volume_label_option);
- 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);
+ 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);
if (volume_label_option)
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"),
+ quotearg_colon (real_s_name)));
+
memset (record_start, 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. */
- strcpy (record_start->header.name, real_s_name);
+ strncpy (record_start->header.name, real_s_name, NAME_FIELD_SIZE);
record_start->header.typeflag = GNUTYPE_MULTIVOL;
OFF_TO_CHARS (real_s_sizeleft, record_start->header.size);
OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
}
static void
-short_read (ssize_t status)
+short_read (size_t status)
{
size_t left; /* bytes left */
char *more; /* pointer to next byte to read */
|| (left && status && read_full_records_option))
{
if (status)
- while ((status = rmtread (archive, more, left)) < 0)
+ while ((status = rmtread (archive, more, left)) == SAFE_READ_ERROR)
archive_read_error ();
if (status == 0)
{
char buf[UINTMAX_STRSIZE_BOUND];
-
+
WARN((0, 0, _("Read %s bytes from %s"),
STRINGIFY_BIGINT (record_size - left, buf),
*archive_name_cursor));
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",
/* 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)
+ if (!read_full_records_option && verbose_option > 1
+ && record_start_block == 0 && status != 0)
{
unsigned long rsize = (record_size - left) / BLOCKSIZE;
WARN ((0, 0,
void
flush_read (void)
{
- ssize_t status; /* result from system call */
+ size_t status; /* result from system call */
if (checkpoint_option && !(++checkpoint % 10))
WARN ((0, 0, _("Read checkpoint %d"), checkpoint));
return;
}
+ /* The condition below used to include
+ || (status > 0 && !read_full_records_option)
+ This is incorrect since even if new_volume() succeeds, the
+ subsequent call to rmtread will overwrite the chunk of data
+ already read in the buffer, so the processing will fail */
+
if ((status == 0
- || (status < 0 && errno == ENOSPC)
- || (status > 0 && !read_full_records_option))
+ || (status == SAFE_READ_ERROR && errno == ENOSPC))
&& multi_volume_option)
{
union block *cursor;
break;
}
- while ((status =
- rmtread (archive, record_start->buffer, record_size)) < 0)
+ while ((status = rmtread (archive, record_start->buffer, record_size))
+ == SAFE_READ_ERROR)
archive_read_error ();
-
+
if (status != record_size)
- short_read (status);
+ short_read (status);
cursor = record_start;
{
uintmax_t s1, s2;
if (cursor->header.typeflag != GNUTYPE_MULTIVOL
- || strcmp (cursor->header.name, real_s_name))
+ || strncmp (cursor->header.name, real_s_name, NAME_FIELD_SIZE))
{
WARN ((0, 0, _("%s is not continued on this volume"),
quote (real_s_name)));
records_read++;
return;
}
- else if (status < 0)
+ else if (status == SAFE_READ_ERROR)
{
archive_read_error ();
goto error_loop; /* try again */
}
}
+off_t
+seek_archive (off_t size)
+{
+ off_t start = current_block_ordinal ();
+ 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);
+ if (offset < 0)
+ return offset;
+
+ if (offset % record_size)
+ FATAL_ERROR ((0, 0, _("rmtlseek not stopped at a record boundary")));
+
+ /* Convert to number of records */
+ offset /= BLOCKSIZE;
+ /* Compute number of skipped blocks */
+ nblk = offset - start;
+
+ /* Update buffering info */
+ records_read += nblk / blocking_factor;
+ record_start_block = offset - blocking_factor;
+ current_block = record_end;
+
+ return nblk;
+}
+
/* Close the archive file. */
void
close_archive (void)
flush_archive ();
sys_drain_input_pipe ();
-
- if (verify_option)
+
+ compute_duration ();
+ if (verify_option)
verify_volume ();
if (rmtclose (archive) != 0)
close_warn (*archive_name_cursor);
sys_wait_for_child (child_pid);
-
+
tar_stat_destroy (¤t_stat_info);
if (save_name)
free (save_name);
if (real_s_name)
free (real_s_name);
- free (multi_volume_option ? record_start - 2 : record_start);
+ free (record_buffer);
}
/* Called to initialize the global volume number. */
Return nonzero on success.
*/
static bool
-new_volume (enum access_mode access)
+new_volume (enum access_mode mode)
{
static FILE *read_file;
static int looped;
archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,
rsh_command_option);
else
- switch (access)
+ switch (mode)
{
case ACCESS_READ:
archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
if (archive < 0)
{
open_warn (*archive_name_cursor);
- if (!verify_option && access == ACCESS_WRITE && backup_option)
+ if (!verify_option && mode == ACCESS_WRITE && backup_option)
undo_last_backup ();
goto tryagain;
}