/* 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.
#include <signal.h>
+#include <closeout.h>
#include <fnmatch.h>
#include <human.h>
#include <quotearg.h>
{
if (!record_buffer[record_index])
page_aligned_alloc (&record_buffer[record_index], record_size);
-
+
record_start = record_buffer[record_index];
current_block = record_start;
record_end = record_start + blocking_factor;
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;
record_index = 0;
init_buffer ();
-
+
/* When updating the archive, we start with reading. */
access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
volno++;
}
+void
+change_tape_menu (FILE *read_file)
+{
+ char *input_buffer = NULL;
+ size_t size = 0;
+
+ while (1)
+ {
+ 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')
+ break;
+
+ switch (input_buffer[0])
+ {
+ case '?':
+ {
+ fprintf (stderr, _("\
+ 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)
+ fprintf (stderr, _(" ! Spawn a subshell\n"));
+ fprintf (stderr, _(" ? Print this list\n"));
+ }
+ break;
+
+ 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);
+ }
+ break;
+
+ case '!':
+ if (!restrict_option)
+ {
+ sys_spawn_shell ();
+ break;
+ }
+ /* FALL THROUGH */
+
+ default:
+ fprintf (stderr, _("Invalid input. Type ? for help.\n"));
+ }
+ }
+ free (input_buffer);
+}
+
/* We've hit the end of the old volume. Close it and open the next one.
Return nonzero on success.
*/
{
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. */
read_file = archive == STDIN_FILENO ? fopen (TTY_NAME, "r") : stdin;
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);
archive_name_cursor = archive_name_array;
looped = 1;
}
-
+ prompt = looped;
+
tryagain:
- if (looped)
+ if (prompt)
{
/* We have to prompt from now on. */
{
if (volno_file_option)
closeout_volume_number ();
- if (sys_exec_info_script (*archive_name_cursor, global_volno+1))
+ if (sys_exec_info_script (archive_name_cursor, global_volno+1))
FATAL_ERROR ((0, 0, _("%s command failed"),
quote (info_script_option)));
}
else
- while (1)
- {
- char input_buffer[80];
-
- fputc ('\007', stderr);
- fprintf (stderr,
- _("Prepare volume #%d for %s and hit return: "),
- global_volno + 1, quote (*archive_name_cursor));
- fflush (stderr);
-
- if (fgets (input_buffer, sizeof input_buffer, 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')
- break;
-
- switch (input_buffer[0])
- {
- case '?':
- {
- /* FIXME: Might it be useful to disable the '!' command? */
- fprintf (stderr, _("\
- n [name] Give a new file name for the next (and subsequent) volume(s)\n\
- q Abort tar\n\
- ! Spawn a subshell\n\
- ? Print this list\n"));
- }
- break;
-
- 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 = &input_buffer[1];
- 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);
- }
- break;
-
- case '!':
- sys_spawn_shell ();
- break;
- }
- }
+ change_tape_menu (read_file);
}
if (strcmp (archive_name_cursor[0], "-") == 0)
open_warn (*archive_name_cursor);
if (!verify_option && mode == ACCESS_WRITE && backup_option)
undo_last_backup ();
+ prompt = 1;
goto tryagain;
}
}
break;
}
-
+
case GNUTYPE_VOLHDR:
if (!read_header0 ())
return false;
if (header->header.typeflag != GNUTYPE_MULTIVOL)
break;
/* FALL THROUGH */
-
+
case GNUTYPE_MULTIVOL:
if (!read_header0 ())
return false;
continued_file_offset =
UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset);
break;
-
+
default:
break;
}
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"),
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")));
else
{
union block *label = find_next_block ();
-
+
memset (label, 0, BLOCKSIZE);
strcpy (label->header.name, volume_label_option);
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);
}
}
{
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);
if (status != record_size)
archive_write_error (status);
}
-
+
for (;;)
{
status = rmtread (archive, record_start->buffer, record_size);
else if (status == SAFE_READ_ERROR)
{
archive_read_error ();
- continue;
+ continue;
}
break;
}
{
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
return;
xheader_destroy (&extended_header);
-
+
increase_volume_number ();
if (totals_option)
prev_written += bytes_written;
/* Switch to the next buffer */
record_index = !record_index;
init_buffer ();
-
+
if (volume_label_option)
add_volume_label ();
{
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
flush_write ()
{
flush_write_ptr (record_size);
-}
+}
void
open_archive (enum access_mode wanted_access)
if (volume_label_option)
write_volume_label ();
break;
+
+ default:
+ break;
}
}
-