| 1 | /* Buffer management for tar.
|
|---|
| 2 |
|
|---|
| 3 | Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
|
|---|
| 4 | 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
|---|
| 5 |
|
|---|
| 6 | Written by John Gilmore, on 1985-08-25.
|
|---|
| 7 |
|
|---|
| 8 | This program is free software; you can redistribute it and/or modify it
|
|---|
| 9 | under the terms of the GNU General Public License as published by the
|
|---|
| 10 | Free Software Foundation; either version 2, or (at your option) any later
|
|---|
| 11 | version.
|
|---|
| 12 |
|
|---|
| 13 | This program is distributed in the hope that it will be useful, but
|
|---|
| 14 | WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|---|
| 16 | Public License for more details.
|
|---|
| 17 |
|
|---|
| 18 | You should have received a copy of the GNU General Public License along
|
|---|
| 19 | with this program; if not, write to the Free Software Foundation, Inc.,
|
|---|
| 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
|---|
| 21 |
|
|---|
| 22 | #include <system.h>
|
|---|
| 23 | #include <system-ioctl.h>
|
|---|
| 24 |
|
|---|
| 25 | #include <signal.h>
|
|---|
| 26 |
|
|---|
| 27 | #include <closeout.h>
|
|---|
| 28 | #include <fnmatch.h>
|
|---|
| 29 | #include <getline.h>
|
|---|
| 30 | #include <human.h>
|
|---|
| 31 | #include <quotearg.h>
|
|---|
| 32 |
|
|---|
| 33 | #include "common.h"
|
|---|
| 34 | #include <rmt.h>
|
|---|
| 35 |
|
|---|
| 36 | /* Number of retries before giving up on read. */
|
|---|
| 37 | #define READ_ERROR_MAX 10
|
|---|
| 38 |
|
|---|
| 39 | /* Globbing pattern to append to volume label if initial match failed. */
|
|---|
| 40 | #define VOLUME_LABEL_APPEND " Volume [1-9]*"
|
|---|
| 41 |
|
|---|
| 42 | /* Variables. */
|
|---|
| 43 |
|
|---|
| 44 | static tarlong prev_written; /* bytes written on previous volumes */
|
|---|
| 45 | static tarlong bytes_written; /* bytes written on this volume */
|
|---|
| 46 | static void *record_buffer[2]; /* allocated memory */
|
|---|
| 47 | union block *record_buffer_aligned[2];
|
|---|
| 48 | static int record_index;
|
|---|
| 49 |
|
|---|
| 50 | /* FIXME: The following variables should ideally be static to this
|
|---|
| 51 | module. However, this cannot be done yet. The cleanup continues! */
|
|---|
| 52 |
|
|---|
| 53 | union block *record_start; /* start of record of archive */
|
|---|
| 54 | union block *record_end; /* last+1 block of archive record */
|
|---|
| 55 | union block *current_block; /* current block of archive */
|
|---|
| 56 | enum access_mode access_mode; /* how do we handle the archive */
|
|---|
| 57 | off_t records_read; /* number of records read from this archive */
|
|---|
| 58 | off_t records_written; /* likewise, for records written */
|
|---|
| 59 | extern off_t records_skipped; /* number of records skipped at the start
|
|---|
| 60 | of the archive, defined in delete.c */
|
|---|
| 61 |
|
|---|
| 62 | static off_t record_start_block; /* block ordinal at record_start */
|
|---|
| 63 |
|
|---|
| 64 | /* Where we write list messages (not errors, not interactions) to. */
|
|---|
| 65 | FILE *stdlis;
|
|---|
| 66 |
|
|---|
| 67 | static void backspace_output (void);
|
|---|
| 68 |
|
|---|
| 69 | /* PID of child program, if compress_option or remote archive access. */
|
|---|
| 70 | static pid_t child_pid;
|
|---|
| 71 |
|
|---|
| 72 | /* Error recovery stuff */
|
|---|
| 73 | static int read_error_count;
|
|---|
| 74 |
|
|---|
| 75 | /* Have we hit EOF yet? */
|
|---|
| 76 | static bool hit_eof;
|
|---|
| 77 |
|
|---|
| 78 | /* Checkpointing counter */
|
|---|
| 79 | static unsigned checkpoint;
|
|---|
| 80 |
|
|---|
| 81 | static bool read_full_records = false;
|
|---|
| 82 |
|
|---|
| 83 | /* We're reading, but we just read the last block and it's time to update.
|
|---|
| 84 | Declared in update.c
|
|---|
| 85 |
|
|---|
| 86 | As least EXTERN like this one as possible. (?? --gray)
|
|---|
| 87 | FIXME: Either eliminate it or move it to common.h.
|
|---|
| 88 | */
|
|---|
| 89 | extern bool time_to_start_writing;
|
|---|
| 90 |
|
|---|
| 91 | bool write_archive_to_stdout;
|
|---|
| 92 |
|
|---|
| 93 | void (*flush_write_ptr) (size_t);
|
|---|
| 94 | void (*flush_read_ptr) (void);
|
|---|
| 95 |
|
|---|
| 96 | |
|---|
| 97 |
|
|---|
| 98 | char *volume_label;
|
|---|
| 99 | char *continued_file_name;
|
|---|
| 100 | uintmax_t continued_file_size;
|
|---|
| 101 | uintmax_t continued_file_offset;
|
|---|
| 102 |
|
|---|
| 103 | |
|---|
| 104 |
|
|---|
| 105 | static int volno = 1; /* which volume of a multi-volume tape we're
|
|---|
| 106 | on */
|
|---|
| 107 | static int global_volno = 1; /* volume number to print in external
|
|---|
| 108 | messages */
|
|---|
| 109 |
|
|---|
| 110 | bool write_archive_to_stdout;
|
|---|
| 111 |
|
|---|
| 112 | /* Used by flush_read and flush_write to store the real info about saved
|
|---|
| 113 | names. */
|
|---|
| 114 | static char *real_s_name;
|
|---|
| 115 | static off_t real_s_totsize;
|
|---|
| 116 | static off_t real_s_sizeleft;
|
|---|
| 117 |
|
|---|
| 118 | |
|---|
| 119 |
|
|---|
| 120 | /* Multi-volume tracking support */
|
|---|
| 121 | static char *save_name; /* name of the file we are currently writing */
|
|---|
| 122 | static off_t save_totsize; /* total size of file we are writing, only
|
|---|
| 123 | valid if save_name is nonzero */
|
|---|
| 124 | static off_t save_sizeleft; /* where we are in the file we are writing,
|
|---|
| 125 | only valid if save_name is nonzero */
|
|---|
| 126 |
|
|---|
| 127 | void
|
|---|
| 128 | mv_begin (struct tar_stat_info *st)
|
|---|
| 129 | {
|
|---|
| 130 | if (multi_volume_option)
|
|---|
| 131 | {
|
|---|
| 132 | assign_string (&save_name, st->orig_file_name);
|
|---|
| 133 | save_totsize = save_sizeleft = st->stat.st_size;
|
|---|
| 134 | }
|
|---|
| 135 | }
|
|---|
| 136 |
|
|---|
| 137 | void
|
|---|
| 138 | mv_end ()
|
|---|
| 139 | {
|
|---|
| 140 | if (multi_volume_option)
|
|---|
| 141 | assign_string (&save_name, 0);
|
|---|
| 142 | }
|
|---|
| 143 |
|
|---|
| 144 | void
|
|---|
| 145 | mv_total_size (off_t size)
|
|---|
| 146 | {
|
|---|
| 147 | save_totsize = size;
|
|---|
| 148 | }
|
|---|
| 149 |
|
|---|
| 150 | void
|
|---|
| 151 | mv_size_left (off_t size)
|
|---|
| 152 | {
|
|---|
| 153 | save_sizeleft = size;
|
|---|
| 154 | }
|
|---|
| 155 |
|
|---|
| 156 | |
|---|
| 157 |
|
|---|
| 158 | /* Functions. */
|
|---|
| 159 |
|
|---|
| 160 | void
|
|---|
| 161 | clear_read_error_count (void)
|
|---|
| 162 | {
|
|---|
| 163 | read_error_count = 0;
|
|---|
| 164 | }
|
|---|
| 165 |
|
|---|
| 166 | |
|---|
| 167 |
|
|---|
| 168 | /* Time-related functions */
|
|---|
| 169 |
|
|---|
| 170 | double duration;
|
|---|
| 171 |
|
|---|
| 172 | void
|
|---|
| 173 | set_start_time ()
|
|---|
| 174 | {
|
|---|
| 175 | gettime (&start_time);
|
|---|
| 176 | volume_start_time = start_time;
|
|---|
| 177 | last_stat_time = start_time;
|
|---|
| 178 | }
|
|---|
| 179 |
|
|---|
| 180 | void
|
|---|
| 181 | set_volume_start_time ()
|
|---|
| 182 | {
|
|---|
| 183 | gettime (&volume_start_time);
|
|---|
| 184 | last_stat_time = volume_start_time;
|
|---|
| 185 | }
|
|---|
| 186 |
|
|---|
| 187 | void
|
|---|
| 188 | compute_duration ()
|
|---|
| 189 | {
|
|---|
| 190 | struct timespec now;
|
|---|
| 191 | gettime (&now);
|
|---|
| 192 | duration += ((now.tv_sec - last_stat_time.tv_sec)
|
|---|
| 193 | + (now.tv_nsec - last_stat_time.tv_nsec) / 1e9);
|
|---|
| 194 | gettime (&last_stat_time);
|
|---|
| 195 | }
|
|---|
| 196 |
|
|---|
| 197 | |
|---|
| 198 |
|
|---|
| 199 | /* Compression detection */
|
|---|
| 200 |
|
|---|
| 201 | enum compress_type {
|
|---|
| 202 | ct_none,
|
|---|
| 203 | ct_compress,
|
|---|
| 204 | ct_gzip,
|
|---|
| 205 | ct_bzip2
|
|---|
| 206 | };
|
|---|
| 207 |
|
|---|
| 208 | struct zip_magic
|
|---|
| 209 | {
|
|---|
| 210 | enum compress_type type;
|
|---|
| 211 | size_t length;
|
|---|
| 212 | char *magic;
|
|---|
| 213 | char *program;
|
|---|
| 214 | char *option;
|
|---|
| 215 | };
|
|---|
| 216 |
|
|---|
| 217 | static struct zip_magic const magic[] = {
|
|---|
| 218 | { ct_none, },
|
|---|
| 219 | { ct_compress, 2, "\037\235", "compress", "-Z" },
|
|---|
| 220 | { ct_gzip, 2, "\037\213", "gzip", "-z" },
|
|---|
| 221 | { ct_bzip2, 3, "BZh", "bzip2", "-j" },
|
|---|
| 222 | };
|
|---|
| 223 |
|
|---|
| 224 | #define NMAGIC (sizeof(magic)/sizeof(magic[0]))
|
|---|
| 225 |
|
|---|
| 226 | #define compress_option(t) magic[t].option
|
|---|
| 227 | #define compress_program(t) magic[t].program
|
|---|
| 228 |
|
|---|
| 229 | /* Check if the file ARCHIVE is a compressed archive. */
|
|---|
| 230 | enum compress_type
|
|---|
| 231 | check_compressed_archive ()
|
|---|
| 232 | {
|
|---|
| 233 | struct zip_magic const *p;
|
|---|
| 234 | bool sfr;
|
|---|
| 235 |
|
|---|
| 236 | /* Prepare global data needed for find_next_block: */
|
|---|
| 237 | record_end = record_start; /* set up for 1st record = # 0 */
|
|---|
| 238 | sfr = read_full_records;
|
|---|
| 239 | read_full_records = true; /* Suppress fatal error on reading a partial
|
|---|
| 240 | record */
|
|---|
| 241 | find_next_block ();
|
|---|
| 242 |
|
|---|
| 243 | /* Restore global values */
|
|---|
| 244 | read_full_records = sfr;
|
|---|
| 245 |
|
|---|
| 246 | if (tar_checksum (record_start, true) == HEADER_SUCCESS)
|
|---|
| 247 | /* Probably a valid header */
|
|---|
| 248 | return ct_none;
|
|---|
| 249 |
|
|---|
| 250 | for (p = magic + 1; p < magic + NMAGIC; p++)
|
|---|
| 251 | if (memcmp (record_start->buffer, p->magic, p->length) == 0)
|
|---|
| 252 | return p->type;
|
|---|
| 253 |
|
|---|
| 254 | return ct_none;
|
|---|
| 255 | }
|
|---|
| 256 |
|
|---|
| 257 | /* Open an archive named archive_name_array[0]. Detect if it is
|
|---|
| 258 | a compressed archive of known type and use corresponding decompression
|
|---|
| 259 | program if so */
|
|---|
| 260 | int
|
|---|
| 261 | open_compressed_archive ()
|
|---|
| 262 | {
|
|---|
| 263 | archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
|
|---|
| 264 | MODE_RW, rsh_command_option);
|
|---|
| 265 | if (archive == -1)
|
|---|
| 266 | return archive;
|
|---|
| 267 |
|
|---|
| 268 | if (!multi_volume_option)
|
|---|
| 269 | {
|
|---|
| 270 | enum compress_type type = check_compressed_archive ();
|
|---|
| 271 |
|
|---|
| 272 | if (type == ct_none)
|
|---|
| 273 | return archive;
|
|---|
| 274 |
|
|---|
| 275 | /* FD is not needed any more */
|
|---|
| 276 | rmtclose (archive);
|
|---|
| 277 |
|
|---|
| 278 | hit_eof = false; /* It might have been set by find_next_block in
|
|---|
| 279 | check_compressed_archive */
|
|---|
| 280 |
|
|---|
| 281 | /* Open compressed archive */
|
|---|
| 282 | use_compress_program_option = compress_program (type);
|
|---|
| 283 | child_pid = sys_child_open_for_uncompress ();
|
|---|
| 284 | read_full_records = true;
|
|---|
| 285 | }
|
|---|
| 286 |
|
|---|
| 287 | records_read = 0;
|
|---|
| 288 | record_end = record_start; /* set up for 1st record = # 0 */
|
|---|
| 289 |
|
|---|
| 290 | return archive;
|
|---|
| 291 | }
|
|---|
| 292 | |
|---|
| 293 |
|
|---|
| 294 |
|
|---|
| 295 | static void
|
|---|
| 296 | print_stats (FILE *fp, const char *text, tarlong numbytes)
|
|---|
| 297 | {
|
|---|
| 298 | char bytes[sizeof (tarlong) * CHAR_BIT];
|
|---|
| 299 | char abbr[LONGEST_HUMAN_READABLE + 1];
|
|---|
| 300 | char rate[LONGEST_HUMAN_READABLE + 1];
|
|---|
| 301 |
|
|---|
| 302 | int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
|
|---|
| 303 |
|
|---|
| 304 | sprintf (bytes, TARLONG_FORMAT, numbytes);
|
|---|
| 305 |
|
|---|
| 306 | fprintf (fp, "%s: %s (%s, %s/s)\n",
|
|---|
| 307 | text, bytes,
|
|---|
| 308 | human_readable (numbytes, abbr, human_opts, 1, 1),
|
|---|
| 309 | (0 < duration && numbytes / duration < (uintmax_t) -1
|
|---|
| 310 | ? human_readable (numbytes / duration, rate, human_opts, 1, 1)
|
|---|
| 311 | : "?"));
|
|---|
| 312 | }
|
|---|
| 313 |
|
|---|
| 314 | void
|
|---|
| 315 | print_total_stats ()
|
|---|
| 316 | {
|
|---|
| 317 | switch (subcommand_option)
|
|---|
| 318 | {
|
|---|
| 319 | case CREATE_SUBCOMMAND:
|
|---|
| 320 | case CAT_SUBCOMMAND:
|
|---|
| 321 | case UPDATE_SUBCOMMAND:
|
|---|
| 322 | case APPEND_SUBCOMMAND:
|
|---|
| 323 | /* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*". */
|
|---|
| 324 | print_stats (stderr, _("Total bytes written"),
|
|---|
| 325 | prev_written + bytes_written);
|
|---|
| 326 | break;
|
|---|
| 327 |
|
|---|
| 328 | case DELETE_SUBCOMMAND:
|
|---|
| 329 | {
|
|---|
| 330 | char buf[UINTMAX_STRSIZE_BOUND];
|
|---|
| 331 | print_stats (stderr, _("Total bytes read"),
|
|---|
| 332 | records_read * record_size);
|
|---|
| 333 | print_stats (stderr, _("Total bytes written"),
|
|---|
| 334 | prev_written + bytes_written);
|
|---|
| 335 | fprintf (stderr, _("Total bytes deleted: %s\n"),
|
|---|
| 336 | STRINGIFY_BIGINT ((records_read - records_skipped)
|
|---|
| 337 | * record_size
|
|---|
| 338 | - (prev_written + bytes_written), buf));
|
|---|
| 339 | }
|
|---|
| 340 | break;
|
|---|
| 341 |
|
|---|
| 342 | case EXTRACT_SUBCOMMAND:
|
|---|
| 343 | case LIST_SUBCOMMAND:
|
|---|
| 344 | case DIFF_SUBCOMMAND:
|
|---|
| 345 | print_stats (stderr, _("Total bytes read"),
|
|---|
| 346 | records_read * record_size);
|
|---|
| 347 | break;
|
|---|
| 348 |
|
|---|
| 349 | default:
|
|---|
| 350 | abort ();
|
|---|
| 351 | }
|
|---|
| 352 | }
|
|---|
| 353 |
|
|---|
| 354 | /* Compute and return the block ordinal at current_block. */
|
|---|
| 355 | off_t
|
|---|
| 356 | current_block_ordinal (void)
|
|---|
| 357 | {
|
|---|
| 358 | return record_start_block + (current_block - record_start);
|
|---|
| 359 | }
|
|---|
| 360 |
|
|---|
| 361 | /* If the EOF flag is set, reset it, as well as current_block, etc. */
|
|---|
| 362 | void
|
|---|
| 363 | reset_eof (void)
|
|---|
| 364 | {
|
|---|
| 365 | if (hit_eof)
|
|---|
| 366 | {
|
|---|
| 367 | hit_eof = false;
|
|---|
| 368 | current_block = record_start;
|
|---|
| 369 | record_end = record_start + blocking_factor;
|
|---|
| 370 | access_mode = ACCESS_WRITE;
|
|---|
| 371 | }
|
|---|
| 372 | }
|
|---|
| 373 |
|
|---|
| 374 | /* Return the location of the next available input or output block.
|
|---|
| 375 | Return zero for EOF. Once we have returned zero, we just keep returning
|
|---|
| 376 | it, to avoid accidentally going on to the next file on the tape. */
|
|---|
| 377 | union block *
|
|---|
| 378 | find_next_block (void)
|
|---|
| 379 | {
|
|---|
| 380 | if (current_block == record_end)
|
|---|
| 381 | {
|
|---|
| 382 | if (hit_eof)
|
|---|
| 383 | return 0;
|
|---|
| 384 | flush_archive ();
|
|---|
| 385 | if (current_block == record_end)
|
|---|
| 386 | {
|
|---|
| 387 | hit_eof = true;
|
|---|
| 388 | return 0;
|
|---|
| 389 | }
|
|---|
| 390 | }
|
|---|
| 391 | return current_block;
|
|---|
| 392 | }
|
|---|
| 393 |
|
|---|
| 394 | /* Indicate that we have used all blocks up thru BLOCK. */
|
|---|
| 395 | void
|
|---|
| 396 | set_next_block_after (union block *block)
|
|---|
| 397 | {
|
|---|
| 398 | while (block >= current_block)
|
|---|
| 399 | current_block++;
|
|---|
| 400 |
|
|---|
| 401 | /* Do *not* flush the archive here. If we do, the same argument to
|
|---|
| 402 | set_next_block_after could mean the next block (if the input record
|
|---|
| 403 | is exactly one block long), which is not what is intended. */
|
|---|
| 404 |
|
|---|
| 405 | if (current_block > record_end)
|
|---|
| 406 | abort ();
|
|---|
| 407 | }
|
|---|
| 408 |
|
|---|
| 409 | /* Return the number of bytes comprising the space between POINTER
|
|---|
| 410 | through the end of the current buffer of blocks. This space is
|
|---|
| 411 | available for filling with data, or taking data from. POINTER is
|
|---|
| 412 | usually (but not always) the result of previous find_next_block call. */
|
|---|
| 413 | size_t
|
|---|
| 414 | available_space_after (union block *pointer)
|
|---|
| 415 | {
|
|---|
| 416 | return record_end->buffer - pointer->buffer;
|
|---|
| 417 | }
|
|---|
| 418 |
|
|---|
| 419 | /* Close file having descriptor FD, and abort if close unsuccessful. */
|
|---|
| 420 | void
|
|---|
| 421 | xclose (int fd)
|
|---|
| 422 | {
|
|---|
| 423 | if (close (fd) != 0)
|
|---|
| 424 | close_error (_("(pipe)"));
|
|---|
| 425 | }
|
|---|
| 426 |
|
|---|
| 427 | static void
|
|---|
| 428 | init_buffer ()
|
|---|
| 429 | {
|
|---|
| 430 | if (! record_buffer_aligned[record_index])
|
|---|
| 431 | record_buffer_aligned[record_index] =
|
|---|
| 432 | page_aligned_alloc (&record_buffer[record_index], record_size);
|
|---|
| 433 |
|
|---|
| 434 | record_start = record_buffer_aligned[record_index];
|
|---|
| 435 | current_block = record_start;
|
|---|
| 436 | record_end = record_start + blocking_factor;
|
|---|
| 437 | }
|
|---|
| 438 |
|
|---|
| 439 | /* Open an archive file. The argument specifies whether we are
|
|---|
| 440 | reading or writing, or both. */
|
|---|
| 441 | static void
|
|---|
| 442 | _open_archive (enum access_mode wanted_access)
|
|---|
| 443 | {
|
|---|
| 444 | int backed_up_flag = 0;
|
|---|
| 445 |
|
|---|
| 446 | if (record_size == 0)
|
|---|
| 447 | FATAL_ERROR ((0, 0, _("Invalid value for record_size")));
|
|---|
| 448 |
|
|---|
| 449 | if (archive_names == 0)
|
|---|
| 450 | FATAL_ERROR ((0, 0, _("No archive name given")));
|
|---|
| 451 |
|
|---|
| 452 | tar_stat_destroy (¤t_stat_info);
|
|---|
| 453 | save_name = 0;
|
|---|
| 454 | real_s_name = 0;
|
|---|
| 455 |
|
|---|
| 456 | record_index = 0;
|
|---|
| 457 | init_buffer ();
|
|---|
| 458 |
|
|---|
| 459 | /* When updating the archive, we start with reading. */
|
|---|
| 460 | access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
|
|---|
| 461 |
|
|---|
| 462 | read_full_records = read_full_records_option;
|
|---|
| 463 |
|
|---|
| 464 | records_read = 0;
|
|---|
| 465 |
|
|---|
| 466 | if (use_compress_program_option)
|
|---|
| 467 | {
|
|---|
| 468 | switch (wanted_access)
|
|---|
| 469 | {
|
|---|
| 470 | case ACCESS_READ:
|
|---|
| 471 | child_pid = sys_child_open_for_uncompress ();
|
|---|
| 472 | read_full_records = true;
|
|---|
| 473 | record_end = record_start; /* set up for 1st record = # 0 */
|
|---|
| 474 | break;
|
|---|
| 475 |
|
|---|
| 476 | case ACCESS_WRITE:
|
|---|
| 477 | child_pid = sys_child_open_for_compress ();
|
|---|
| 478 | break;
|
|---|
| 479 |
|
|---|
| 480 | case ACCESS_UPDATE:
|
|---|
| 481 | abort (); /* Should not happen */
|
|---|
| 482 | break;
|
|---|
| 483 | }
|
|---|
| 484 |
|
|---|
| 485 | if (!index_file_name
|
|---|
| 486 | && wanted_access == ACCESS_WRITE
|
|---|
| 487 | && strcmp (archive_name_array[0], "-") == 0)
|
|---|
| 488 | stdlis = stderr;
|
|---|
| 489 | }
|
|---|
| 490 | else if (strcmp (archive_name_array[0], "-") == 0)
|
|---|
| 491 | {
|
|---|
| 492 | read_full_records = true; /* could be a pipe, be safe */
|
|---|
| 493 | if (verify_option)
|
|---|
| 494 | FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
|
|---|
| 495 |
|
|---|
| 496 | switch (wanted_access)
|
|---|
| 497 | {
|
|---|
| 498 | case ACCESS_READ:
|
|---|
| 499 | {
|
|---|
| 500 | enum compress_type type;
|
|---|
| 501 |
|
|---|
| 502 | archive = STDIN_FILENO;
|
|---|
| 503 |
|
|---|
| 504 | type = check_compressed_archive ();
|
|---|
| 505 | if (type != ct_none)
|
|---|
| 506 | FATAL_ERROR ((0, 0,
|
|---|
| 507 | _("Archive is compressed. Use %s option"),
|
|---|
| 508 | compress_option (type)));
|
|---|
| 509 | }
|
|---|
| 510 | break;
|
|---|
| 511 |
|
|---|
| 512 | case ACCESS_WRITE:
|
|---|
| 513 | archive = STDOUT_FILENO;
|
|---|
| 514 | if (!index_file_name)
|
|---|
| 515 | stdlis = stderr;
|
|---|
| 516 | break;
|
|---|
| 517 |
|
|---|
| 518 | case ACCESS_UPDATE:
|
|---|
| 519 | archive = STDIN_FILENO;
|
|---|
| 520 | write_archive_to_stdout = true;
|
|---|
| 521 | record_end = record_start; /* set up for 1st record = # 0 */
|
|---|
| 522 | if (!index_file_name)
|
|---|
| 523 | stdlis = stderr;
|
|---|
| 524 | break;
|
|---|
| 525 | }
|
|---|
| 526 | }
|
|---|
| 527 | else if (verify_option)
|
|---|
| 528 | archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
|
|---|
| 529 | MODE_RW, rsh_command_option);
|
|---|
| 530 | else
|
|---|
| 531 | switch (wanted_access)
|
|---|
| 532 | {
|
|---|
| 533 | case ACCESS_READ:
|
|---|
| 534 | archive = open_compressed_archive ();
|
|---|
| 535 | break;
|
|---|
| 536 |
|
|---|
| 537 | case ACCESS_WRITE:
|
|---|
| 538 | if (backup_option)
|
|---|
| 539 | {
|
|---|
| 540 | maybe_backup_file (archive_name_array[0], 1);
|
|---|
| 541 | backed_up_flag = 1;
|
|---|
| 542 | }
|
|---|
| 543 | archive = rmtcreat (archive_name_array[0], MODE_RW,
|
|---|
| 544 | rsh_command_option);
|
|---|
| 545 | break;
|
|---|
| 546 |
|
|---|
| 547 | case ACCESS_UPDATE:
|
|---|
| 548 | archive = rmtopen (archive_name_array[0],
|
|---|
| 549 | O_RDWR | O_CREAT | O_BINARY,
|
|---|
| 550 | MODE_RW, rsh_command_option);
|
|---|
| 551 |
|
|---|
| 552 | if (check_compressed_archive () != ct_none)
|
|---|
| 553 | FATAL_ERROR ((0, 0,
|
|---|
| 554 | _("Cannot update compressed archives")));
|
|---|
| 555 | break;
|
|---|
| 556 | }
|
|---|
| 557 |
|
|---|
| 558 | if (archive < 0
|
|---|
| 559 | || (! _isrmt (archive) && !sys_get_archive_stat ()))
|
|---|
| 560 | {
|
|---|
| 561 | int saved_errno = errno;
|
|---|
| 562 |
|
|---|
| 563 | if (backed_up_flag)
|
|---|
| 564 | undo_last_backup ();
|
|---|
| 565 | errno = saved_errno;
|
|---|
| 566 | open_fatal (archive_name_array[0]);
|
|---|
| 567 | }
|
|---|
| 568 |
|
|---|
| 569 | sys_detect_dev_null_output ();
|
|---|
| 570 | sys_save_archive_dev_ino ();
|
|---|
| 571 | SET_BINARY_MODE (archive);
|
|---|
| 572 |
|
|---|
| 573 | switch (wanted_access)
|
|---|
| 574 | {
|
|---|
| 575 | case ACCESS_READ:
|
|---|
| 576 | find_next_block (); /* read it in, check for EOF */
|
|---|
| 577 | break;
|
|---|
| 578 |
|
|---|
| 579 | case ACCESS_UPDATE:
|
|---|
| 580 | case ACCESS_WRITE:
|
|---|
| 581 | records_written = 0;
|
|---|
| 582 | break;
|
|---|
| 583 | }
|
|---|
| 584 | }
|
|---|
| 585 |
|
|---|
| 586 | static void
|
|---|
| 587 | do_checkpoint (bool write)
|
|---|
| 588 | {
|
|---|
| 589 | if (checkpoint_option && !(++checkpoint % checkpoint_option))
|
|---|
| 590 | {
|
|---|
| 591 | switch (checkpoint_style)
|
|---|
| 592 | {
|
|---|
| 593 | case checkpoint_dot:
|
|---|
| 594 | fputc ('.', stdlis);
|
|---|
| 595 | fflush (stdlis);
|
|---|
| 596 | break;
|
|---|
| 597 |
|
|---|
| 598 | case checkpoint_text:
|
|---|
| 599 | if (write)
|
|---|
| 600 | /* TRANSLATORS: This is a ``checkpoint of write operation'',
|
|---|
| 601 | *not* ``Writing a checkpoint''.
|
|---|
| 602 | E.g. in Spanish ``Punto de comprobaci@'on de escritura'',
|
|---|
| 603 | *not* ``Escribiendo un punto de comprobaci@'on'' */
|
|---|
| 604 | WARN ((0, 0, _("Write checkpoint %u"), checkpoint));
|
|---|
| 605 | else
|
|---|
| 606 | /* TRANSLATORS: This is a ``checkpoint of read operation'',
|
|---|
| 607 | *not* ``Reading a checkpoint''.
|
|---|
| 608 | E.g. in Spanish ``Punto de comprobaci@'on de lectura'',
|
|---|
| 609 | *not* ``Leyendo un punto de comprobaci@'on'' */
|
|---|
| 610 | WARN ((0, 0, _("Read checkpoint %u"), checkpoint));
|
|---|
| 611 | break;
|
|---|
| 612 | }
|
|---|
| 613 | }
|
|---|
| 614 | }
|
|---|
| 615 |
|
|---|
| 616 | /* Perform a write to flush the buffer. */
|
|---|
| 617 | ssize_t
|
|---|
| 618 | _flush_write (void)
|
|---|
| 619 | {
|
|---|
| 620 | ssize_t status;
|
|---|
| 621 |
|
|---|
| 622 | do_checkpoint (true);
|
|---|
| 623 | if (tape_length_option && tape_length_option <= bytes_written)
|
|---|
| 624 | {
|
|---|
| 625 | errno = ENOSPC;
|
|---|
| 626 | status = 0;
|
|---|
| 627 | }
|
|---|
| 628 | else if (dev_null_output)
|
|---|
| 629 | status = record_size;
|
|---|
| 630 | else
|
|---|
| 631 | status = sys_write_archive_buffer ();
|
|---|
| 632 |
|
|---|
| 633 | return status;
|
|---|
| 634 | }
|
|---|
| 635 |
|
|---|
| 636 | /* Handle write errors on the archive. Write errors are always fatal.
|
|---|
| 637 | Hitting the end of a volume does not cause a write error unless the
|
|---|
| 638 | write was the first record of the volume. */
|
|---|
| 639 | void
|
|---|
| 640 | archive_write_error (ssize_t status)
|
|---|
| 641 | {
|
|---|
| 642 | /* It might be useful to know how much was written before the error
|
|---|
| 643 | occurred. */
|
|---|
| 644 | if (totals_option)
|
|---|
| 645 | {
|
|---|
| 646 | int e = errno;
|
|---|
| 647 | print_total_stats ();
|
|---|
| 648 | errno = e;
|
|---|
| 649 | }
|
|---|
| 650 |
|
|---|
| 651 | write_fatal_details (*archive_name_cursor, status, record_size);
|
|---|
| 652 | }
|
|---|
| 653 |
|
|---|
| 654 | /* Handle read errors on the archive. If the read should be retried,
|
|---|
| 655 | return to the caller. */
|
|---|
| 656 | void
|
|---|
| 657 | archive_read_error (void)
|
|---|
| 658 | {
|
|---|
| 659 | read_error (*archive_name_cursor);
|
|---|
| 660 |
|
|---|
| 661 | if (record_start_block == 0)
|
|---|
| 662 | FATAL_ERROR ((0, 0, _("At beginning of tape, quitting now")));
|
|---|
| 663 |
|
|---|
| 664 | /* Read error in mid archive. We retry up to READ_ERROR_MAX times and
|
|---|
| 665 | then give up on reading the archive. */
|
|---|
| 666 |
|
|---|
| 667 | if (read_error_count++ > READ_ERROR_MAX)
|
|---|
| 668 | FATAL_ERROR ((0, 0, _("Too many errors, quitting")));
|
|---|
| 669 | return;
|
|---|
| 670 | }
|
|---|
| 671 |
|
|---|
| 672 | static void
|
|---|
| 673 | short_read (size_t status)
|
|---|
| 674 | {
|
|---|
| 675 | size_t left; /* bytes left */
|
|---|
| 676 | char *more; /* pointer to next byte to read */
|
|---|
| 677 |
|
|---|
| 678 | more = record_start->buffer + status;
|
|---|
| 679 | left = record_size - status;
|
|---|
| 680 |
|
|---|
| 681 | while (left % BLOCKSIZE != 0
|
|---|
| 682 | || (left && status && read_full_records))
|
|---|
| 683 | {
|
|---|
| 684 | if (status)
|
|---|
| 685 | while ((status = rmtread (archive, more, left)) == SAFE_READ_ERROR)
|
|---|
| 686 | archive_read_error ();
|
|---|
| 687 |
|
|---|
| 688 | if (status == 0)
|
|---|
| 689 | break;
|
|---|
| 690 |
|
|---|
| 691 | if (! read_full_records)
|
|---|
| 692 | {
|
|---|
| 693 | unsigned long rest = record_size - left;
|
|---|
| 694 |
|
|---|
| 695 | FATAL_ERROR ((0, 0,
|
|---|
| 696 | ngettext ("Unaligned block (%lu byte) in archive",
|
|---|
| 697 | "Unaligned block (%lu bytes) in archive",
|
|---|
| 698 | rest),
|
|---|
| 699 | rest));
|
|---|
| 700 | }
|
|---|
| 701 |
|
|---|
| 702 | /* User warned us about this. Fix up. */
|
|---|
| 703 |
|
|---|
| 704 | left -= status;
|
|---|
| 705 | more += status;
|
|---|
| 706 | }
|
|---|
| 707 |
|
|---|
| 708 | /* FIXME: for size=0, multi-volume support. On the first record, warn
|
|---|
| 709 | about the problem. */
|
|---|
| 710 |
|
|---|
| 711 | if (!read_full_records && verbose_option > 1
|
|---|
| 712 | && record_start_block == 0 && status != 0)
|
|---|
| 713 | {
|
|---|
| 714 | unsigned long rsize = (record_size - left) / BLOCKSIZE;
|
|---|
| 715 | WARN ((0, 0,
|
|---|
| 716 | ngettext ("Record size = %lu block",
|
|---|
| 717 | "Record size = %lu blocks",
|
|---|
| 718 | rsize),
|
|---|
| 719 | rsize));
|
|---|
| 720 | }
|
|---|
| 721 |
|
|---|
| 722 | record_end = record_start + (record_size - left) / BLOCKSIZE;
|
|---|
| 723 | records_read++;
|
|---|
| 724 | }
|
|---|
| 725 |
|
|---|
| 726 | /* Flush the current buffer to/from the archive. */
|
|---|
| 727 | void
|
|---|
| 728 | flush_archive (void)
|
|---|
| 729 | {
|
|---|
| 730 | size_t buffer_level = current_block->buffer - record_start->buffer;
|
|---|
| 731 | record_start_block += record_end - record_start;
|
|---|
| 732 | current_block = record_start;
|
|---|
| 733 | record_end = record_start + blocking_factor;
|
|---|
| 734 |
|
|---|
| 735 | if (access_mode == ACCESS_READ && time_to_start_writing)
|
|---|
| 736 | {
|
|---|
| 737 | access_mode = ACCESS_WRITE;
|
|---|
| 738 | time_to_start_writing = false;
|
|---|
| 739 | backspace_output ();
|
|---|
| 740 | }
|
|---|
| 741 |
|
|---|
| 742 | switch (access_mode)
|
|---|
| 743 | {
|
|---|
| 744 | case ACCESS_READ:
|
|---|
| 745 | flush_read ();
|
|---|
| 746 | break;
|
|---|
| 747 |
|
|---|
| 748 | case ACCESS_WRITE:
|
|---|
| 749 | flush_write_ptr (buffer_level);
|
|---|
| 750 | break;
|
|---|
| 751 |
|
|---|
| 752 | case ACCESS_UPDATE:
|
|---|
| 753 | abort ();
|
|---|
| 754 | }
|
|---|
| 755 | }
|
|---|
| 756 |
|
|---|
| 757 | /* Backspace the archive descriptor by one record worth. If it's a
|
|---|
| 758 | tape, MTIOCTOP will work. If it's something else, try to seek on
|
|---|
| 759 | it. If we can't seek, we lose! */
|
|---|
| 760 | static void
|
|---|
| 761 | backspace_output (void)
|
|---|
| 762 | {
|
|---|
| 763 | #ifdef MTIOCTOP
|
|---|
| 764 | {
|
|---|
| 765 | struct mtop operation;
|
|---|
| 766 |
|
|---|
| 767 | operation.mt_op = MTBSR;
|
|---|
| 768 | operation.mt_count = 1;
|
|---|
| 769 | if (rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
|
|---|
| 770 | return;
|
|---|
| 771 | if (errno == EIO && rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
|
|---|
| 772 | return;
|
|---|
| 773 | }
|
|---|
| 774 | #endif
|
|---|
| 775 |
|
|---|
| 776 | {
|
|---|
| 777 | off_t position = rmtlseek (archive, (off_t) 0, SEEK_CUR);
|
|---|
| 778 |
|
|---|
| 779 | /* Seek back to the beginning of this record and start writing there. */
|
|---|
| 780 |
|
|---|
| 781 | position -= record_size;
|
|---|
| 782 | if (position < 0)
|
|---|
| 783 | position = 0;
|
|---|
| 784 | if (rmtlseek (archive, position, SEEK_SET) != position)
|
|---|
| 785 | {
|
|---|
| 786 | /* Lseek failed. Try a different method. */
|
|---|
| 787 |
|
|---|
| 788 | WARN ((0, 0,
|
|---|
| 789 | _("Cannot backspace archive file; it may be unreadable without -i")));
|
|---|
| 790 |
|
|---|
| 791 | /* Replace the first part of the record with NULs. */
|
|---|
| 792 |
|
|---|
| 793 | if (record_start->buffer != output_start)
|
|---|
| 794 | memset (record_start->buffer, 0,
|
|---|
| 795 | output_start - record_start->buffer);
|
|---|
| 796 | }
|
|---|
| 797 | }
|
|---|
| 798 | }
|
|---|
| 799 |
|
|---|
| 800 | off_t
|
|---|
| 801 | seek_archive (off_t size)
|
|---|
| 802 | {
|
|---|
| 803 | off_t start = current_block_ordinal ();
|
|---|
| 804 | off_t offset;
|
|---|
| 805 | off_t nrec, nblk;
|
|---|
| 806 | off_t skipped = (blocking_factor - (current_block - record_start));
|
|---|
| 807 |
|
|---|
| 808 | size -= skipped * BLOCKSIZE;
|
|---|
| 809 |
|
|---|
| 810 | if (size < record_size)
|
|---|
| 811 | return 0;
|
|---|
| 812 | /* FIXME: flush? */
|
|---|
| 813 |
|
|---|
| 814 | /* Compute number of records to skip */
|
|---|
| 815 | nrec = size / record_size;
|
|---|
| 816 | offset = rmtlseek (archive, nrec * record_size, SEEK_CUR);
|
|---|
| 817 | if (offset < 0)
|
|---|
| 818 | return offset;
|
|---|
| 819 |
|
|---|
| 820 | if (offset % record_size)
|
|---|
| 821 | FATAL_ERROR ((0, 0, _("rmtlseek not stopped at a record boundary")));
|
|---|
| 822 |
|
|---|
| 823 | /* Convert to number of records */
|
|---|
| 824 | offset /= BLOCKSIZE;
|
|---|
| 825 | /* Compute number of skipped blocks */
|
|---|
| 826 | nblk = offset - start;
|
|---|
| 827 |
|
|---|
| 828 | /* Update buffering info */
|
|---|
| 829 | records_read += nblk / blocking_factor;
|
|---|
| 830 | record_start_block = offset - blocking_factor;
|
|---|
| 831 | current_block = record_end;
|
|---|
| 832 |
|
|---|
| 833 | return nblk;
|
|---|
| 834 | }
|
|---|
| 835 |
|
|---|
| 836 | /* Close the archive file. */
|
|---|
| 837 | void
|
|---|
| 838 | close_archive (void)
|
|---|
| 839 | {
|
|---|
| 840 | if (time_to_start_writing || access_mode == ACCESS_WRITE)
|
|---|
| 841 | {
|
|---|
| 842 | flush_archive ();
|
|---|
| 843 | if (current_block > record_start)
|
|---|
| 844 | flush_archive ();
|
|---|
| 845 | }
|
|---|
| 846 |
|
|---|
| 847 | sys_drain_input_pipe ();
|
|---|
| 848 |
|
|---|
| 849 | compute_duration ();
|
|---|
| 850 | if (verify_option)
|
|---|
| 851 | verify_volume ();
|
|---|
| 852 |
|
|---|
| 853 | if (rmtclose (archive) != 0)
|
|---|
| 854 | close_warn (*archive_name_cursor);
|
|---|
| 855 |
|
|---|
| 856 | sys_wait_for_child (child_pid);
|
|---|
| 857 |
|
|---|
| 858 | tar_stat_destroy (¤t_stat_info);
|
|---|
| 859 | if (save_name)
|
|---|
| 860 | free (save_name);
|
|---|
| 861 | if (real_s_name)
|
|---|
| 862 | free (real_s_name);
|
|---|
| 863 | free (record_buffer[0]);
|
|---|
| 864 | free (record_buffer[1]);
|
|---|
| 865 | }
|
|---|
| 866 |
|
|---|
| 867 | /* Called to initialize the global volume number. */
|
|---|
| 868 | void
|
|---|
| 869 | init_volume_number (void)
|
|---|
| 870 | {
|
|---|
| 871 | FILE *file = fopen (volno_file_option, "r");
|
|---|
| 872 |
|
|---|
| 873 | if (file)
|
|---|
| 874 | {
|
|---|
| 875 | if (fscanf (file, "%d", &global_volno) != 1
|
|---|
| 876 | || global_volno < 0)
|
|---|
| 877 | FATAL_ERROR ((0, 0, _("%s: contains invalid volume number"),
|
|---|
| 878 | quotearg_colon (volno_file_option)));
|
|---|
| 879 | if (ferror (file))
|
|---|
| 880 | read_error (volno_file_option);
|
|---|
| 881 | if (fclose (file) != 0)
|
|---|
| 882 | close_error (volno_file_option);
|
|---|
| 883 | }
|
|---|
| 884 | else if (errno != ENOENT)
|
|---|
| 885 | open_error (volno_file_option);
|
|---|
| 886 | }
|
|---|
| 887 |
|
|---|
| 888 | /* Called to write out the closing global volume number. */
|
|---|
| 889 | void
|
|---|
| 890 | closeout_volume_number (void)
|
|---|
| 891 | {
|
|---|
| 892 | FILE *file = fopen (volno_file_option, "w");
|
|---|
| 893 |
|
|---|
| 894 | if (file)
|
|---|
| 895 | {
|
|---|
| 896 | fprintf (file, "%d\n", global_volno);
|
|---|
| 897 | if (ferror (file))
|
|---|
| 898 | write_error (volno_file_option);
|
|---|
| 899 | if (fclose (file) != 0)
|
|---|
| 900 | close_error (volno_file_option);
|
|---|
| 901 | }
|
|---|
| 902 | else
|
|---|
| 903 | open_error (volno_file_option);
|
|---|
| 904 | }
|
|---|
| 905 |
|
|---|
| 906 | |
|---|
| 907 |
|
|---|
| 908 | static void
|
|---|
| 909 | increase_volume_number ()
|
|---|
| 910 | {
|
|---|
| 911 | global_volno++;
|
|---|
| 912 | if (global_volno < 0)
|
|---|
| 913 | FATAL_ERROR ((0, 0, _("Volume number overflow")));
|
|---|
| 914 | volno++;
|
|---|
| 915 | }
|
|---|
| 916 |
|
|---|
| 917 | void
|
|---|
| 918 | change_tape_menu (FILE *read_file)
|
|---|
| 919 | {
|
|---|
| 920 | char *input_buffer = NULL;
|
|---|
| 921 | size_t size = 0;
|
|---|
| 922 | bool stop = false;
|
|---|
| 923 |
|
|---|
| 924 | while (!stop)
|
|---|
| 925 | {
|
|---|
| 926 | fputc ('\007', stderr);
|
|---|
| 927 | fprintf (stderr,
|
|---|
| 928 | _("Prepare volume #%d for %s and hit return: "),
|
|---|
| 929 | global_volno + 1, quote (*archive_name_cursor));
|
|---|
| 930 | fflush (stderr);
|
|---|
| 931 |
|
|---|
| 932 | if (getline (&input_buffer, &size, read_file) <= 0)
|
|---|
| 933 | {
|
|---|
| 934 | WARN ((0, 0, _("EOF where user reply was expected")));
|
|---|
| 935 |
|
|---|
| 936 | if (subcommand_option != EXTRACT_SUBCOMMAND
|
|---|
| 937 | && subcommand_option != LIST_SUBCOMMAND
|
|---|
| 938 | && subcommand_option != DIFF_SUBCOMMAND)
|
|---|
| 939 | WARN ((0, 0, _("WARNING: Archive is incomplete")));
|
|---|
| 940 |
|
|---|
| 941 | fatal_exit ();
|
|---|
| 942 | }
|
|---|
| 943 |
|
|---|
| 944 | if (input_buffer[0] == '\n'
|
|---|
| 945 | || input_buffer[0] == 'y'
|
|---|
| 946 | || input_buffer[0] == 'Y')
|
|---|
| 947 | break;
|
|---|
| 948 |
|
|---|
| 949 | switch (input_buffer[0])
|
|---|
| 950 | {
|
|---|
| 951 | case '?':
|
|---|
| 952 | {
|
|---|
| 953 | fprintf (stderr, _("\
|
|---|
| 954 | n name Give a new file name for the next (and subsequent) volume(s)\n\
|
|---|
| 955 | q Abort tar\n\
|
|---|
| 956 | y or newline Continue operation\n"));
|
|---|
| 957 | if (!restrict_option)
|
|---|
| 958 | fprintf (stderr, _(" ! Spawn a subshell\n"));
|
|---|
| 959 | fprintf (stderr, _(" ? Print this list\n"));
|
|---|
| 960 | }
|
|---|
| 961 | break;
|
|---|
| 962 |
|
|---|
| 963 | case 'q':
|
|---|
| 964 | /* Quit. */
|
|---|
| 965 |
|
|---|
| 966 | WARN ((0, 0, _("No new volume; exiting.\n")));
|
|---|
| 967 |
|
|---|
| 968 | if (subcommand_option != EXTRACT_SUBCOMMAND
|
|---|
| 969 | && subcommand_option != LIST_SUBCOMMAND
|
|---|
| 970 | && subcommand_option != DIFF_SUBCOMMAND)
|
|---|
| 971 | WARN ((0, 0, _("WARNING: Archive is incomplete")));
|
|---|
| 972 |
|
|---|
| 973 | fatal_exit ();
|
|---|
| 974 |
|
|---|
| 975 | case 'n':
|
|---|
| 976 | /* Get new file name. */
|
|---|
| 977 |
|
|---|
| 978 | {
|
|---|
| 979 | char *name;
|
|---|
| 980 | char *cursor;
|
|---|
| 981 |
|
|---|
| 982 | for (name = input_buffer + 1;
|
|---|
| 983 | *name == ' ' || *name == '\t';
|
|---|
| 984 | name++)
|
|---|
| 985 | ;
|
|---|
| 986 |
|
|---|
| 987 | for (cursor = name; *cursor && *cursor != '\n'; cursor++)
|
|---|
| 988 | ;
|
|---|
| 989 | *cursor = '\0';
|
|---|
| 990 |
|
|---|
| 991 | if (name[0])
|
|---|
| 992 | {
|
|---|
| 993 | /* FIXME: the following allocation is never reclaimed. */
|
|---|
| 994 | *archive_name_cursor = xstrdup (name);
|
|---|
| 995 | stop = true;
|
|---|
| 996 | }
|
|---|
| 997 | else
|
|---|
| 998 | fprintf (stderr, "%s",
|
|---|
| 999 | _("File name not specified. Try again.\n"));
|
|---|
| 1000 | }
|
|---|
| 1001 | break;
|
|---|
| 1002 |
|
|---|
| 1003 | case '!':
|
|---|
| 1004 | if (!restrict_option)
|
|---|
| 1005 | {
|
|---|
| 1006 | sys_spawn_shell ();
|
|---|
| 1007 | break;
|
|---|
| 1008 | }
|
|---|
| 1009 | /* FALL THROUGH */
|
|---|
| 1010 |
|
|---|
| 1011 | default:
|
|---|
| 1012 | fprintf (stderr, _("Invalid input. Type ? for help.\n"));
|
|---|
| 1013 | }
|
|---|
| 1014 | }
|
|---|
| 1015 | free (input_buffer);
|
|---|
| 1016 | }
|
|---|
| 1017 |
|
|---|
| 1018 | /* We've hit the end of the old volume. Close it and open the next one.
|
|---|
| 1019 | Return nonzero on success.
|
|---|
| 1020 | */
|
|---|
| 1021 | static bool
|
|---|
| 1022 | new_volume (enum access_mode mode)
|
|---|
| 1023 | {
|
|---|
| 1024 | static FILE *read_file;
|
|---|
| 1025 | static int looped;
|
|---|
| 1026 | int prompt;
|
|---|
| 1027 |
|
|---|
| 1028 | if (!read_file && !info_script_option)
|
|---|
| 1029 | /* FIXME: if fopen is used, it will never be closed. */
|
|---|
| 1030 | read_file = archive == STDIN_FILENO ? fopen (TTY_NAME, "r") : stdin;
|
|---|
| 1031 |
|
|---|
| 1032 | if (now_verifying)
|
|---|
| 1033 | return false;
|
|---|
| 1034 | if (verify_option)
|
|---|
| 1035 | verify_volume ();
|
|---|
| 1036 |
|
|---|
| 1037 | assign_string (&volume_label, NULL);
|
|---|
| 1038 | assign_string (&continued_file_name, NULL);
|
|---|
| 1039 | continued_file_size = continued_file_offset = 0;
|
|---|
| 1040 | current_block = record_start;
|
|---|
| 1041 |
|
|---|
| 1042 | if (rmtclose (archive) != 0)
|
|---|
| 1043 | close_warn (*archive_name_cursor);
|
|---|
| 1044 |
|
|---|
| 1045 | archive_name_cursor++;
|
|---|
| 1046 | if (archive_name_cursor == archive_name_array + archive_names)
|
|---|
| 1047 | {
|
|---|
| 1048 | archive_name_cursor = archive_name_array;
|
|---|
| 1049 | looped = 1;
|
|---|
| 1050 | }
|
|---|
| 1051 | prompt = looped;
|
|---|
| 1052 |
|
|---|
| 1053 | tryagain:
|
|---|
| 1054 | if (prompt)
|
|---|
| 1055 | {
|
|---|
| 1056 | /* We have to prompt from now on. */
|
|---|
| 1057 |
|
|---|
| 1058 | if (info_script_option)
|
|---|
| 1059 | {
|
|---|
| 1060 | if (volno_file_option)
|
|---|
| 1061 | closeout_volume_number ();
|
|---|
| 1062 | if (sys_exec_info_script (archive_name_cursor, global_volno+1))
|
|---|
| 1063 | FATAL_ERROR ((0, 0, _("%s command failed"),
|
|---|
| 1064 | quote (info_script_option)));
|
|---|
| 1065 | }
|
|---|
| 1066 | else
|
|---|
| 1067 | change_tape_menu (read_file);
|
|---|
| 1068 | }
|
|---|
| 1069 |
|
|---|
| 1070 | if (strcmp (archive_name_cursor[0], "-") == 0)
|
|---|
| 1071 | {
|
|---|
| 1072 | read_full_records = true;
|
|---|
| 1073 | archive = STDIN_FILENO;
|
|---|
| 1074 | }
|
|---|
| 1075 | else if (verify_option)
|
|---|
| 1076 | archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,
|
|---|
| 1077 | rsh_command_option);
|
|---|
| 1078 | else
|
|---|
| 1079 | switch (mode)
|
|---|
| 1080 | {
|
|---|
| 1081 | case ACCESS_READ:
|
|---|
| 1082 | archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
|
|---|
| 1083 | rsh_command_option);
|
|---|
| 1084 | break;
|
|---|
| 1085 |
|
|---|
| 1086 | case ACCESS_WRITE:
|
|---|
| 1087 | if (backup_option)
|
|---|
| 1088 | maybe_backup_file (*archive_name_cursor, 1);
|
|---|
| 1089 | archive = rmtcreat (*archive_name_cursor, MODE_RW,
|
|---|
| 1090 | rsh_command_option);
|
|---|
| 1091 | break;
|
|---|
| 1092 |
|
|---|
| 1093 | case ACCESS_UPDATE:
|
|---|
| 1094 | archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,
|
|---|
| 1095 | rsh_command_option);
|
|---|
| 1096 | break;
|
|---|
| 1097 | }
|
|---|
| 1098 |
|
|---|
| 1099 | if (archive < 0)
|
|---|
| 1100 | {
|
|---|
| 1101 | open_warn (*archive_name_cursor);
|
|---|
| 1102 | if (!verify_option && mode == ACCESS_WRITE && backup_option)
|
|---|
| 1103 | undo_last_backup ();
|
|---|
| 1104 | prompt = 1;
|
|---|
| 1105 | goto tryagain;
|
|---|
| 1106 | }
|
|---|
| 1107 |
|
|---|
| 1108 | SET_BINARY_MODE (archive);
|
|---|
| 1109 |
|
|---|
| 1110 | return true;
|
|---|
| 1111 | }
|
|---|
| 1112 |
|
|---|
| 1113 | static bool
|
|---|
| 1114 | read_header0 (struct tar_stat_info *info)
|
|---|
| 1115 | {
|
|---|
| 1116 | enum read_header rc;
|
|---|
| 1117 |
|
|---|
| 1118 | tar_stat_init (info);
|
|---|
| 1119 | rc = read_header_primitive (false, info);
|
|---|
| 1120 | if (rc == HEADER_SUCCESS)
|
|---|
| 1121 | {
|
|---|
| 1122 | set_next_block_after (current_header);
|
|---|
| 1123 | return true;
|
|---|
| 1124 | }
|
|---|
| 1125 | ERROR ((0, 0, _("This does not look like a tar archive")));
|
|---|
| 1126 | return false;
|
|---|
| 1127 | }
|
|---|
| 1128 |
|
|---|
| 1129 | bool
|
|---|
| 1130 | try_new_volume ()
|
|---|
| 1131 | {
|
|---|
| 1132 | size_t status;
|
|---|
| 1133 | union block *header;
|
|---|
| 1134 | struct tar_stat_info dummy;
|
|---|
| 1135 | int access;
|
|---|
| 1136 |
|
|---|
| 1137 | switch (subcommand_option)
|
|---|
| 1138 | {
|
|---|
| 1139 | case APPEND_SUBCOMMAND:
|
|---|
| 1140 | case CAT_SUBCOMMAND:
|
|---|
| 1141 | case UPDATE_SUBCOMMAND:
|
|---|
| 1142 | access = ACCESS_UPDATE;
|
|---|
| 1143 | break;
|
|---|
| 1144 |
|
|---|
| 1145 | default:
|
|---|
| 1146 | access = ACCESS_READ;
|
|---|
| 1147 | break;
|
|---|
| 1148 | }
|
|---|
| 1149 |
|
|---|
| 1150 | if (!new_volume (access))
|
|---|
| 1151 | return true;
|
|---|
| 1152 |
|
|---|
| 1153 | while ((status = rmtread (archive, record_start->buffer, record_size))
|
|---|
| 1154 | == SAFE_READ_ERROR)
|
|---|
| 1155 | archive_read_error ();
|
|---|
| 1156 |
|
|---|
| 1157 | if (status != record_size)
|
|---|
| 1158 | short_read (status);
|
|---|
| 1159 |
|
|---|
| 1160 | header = find_next_block ();
|
|---|
| 1161 | if (!header)
|
|---|
| 1162 | return false;
|
|---|
| 1163 |
|
|---|
| 1164 | switch (header->header.typeflag)
|
|---|
| 1165 | {
|
|---|
| 1166 | case XGLTYPE:
|
|---|
| 1167 | {
|
|---|
| 1168 | if (!read_header0 (&dummy))
|
|---|
| 1169 | return false;
|
|---|
| 1170 | xheader_decode (&dummy); /* decodes values from the global header */
|
|---|
| 1171 | tar_stat_destroy (&dummy);
|
|---|
| 1172 | if (!real_s_name)
|
|---|
| 1173 | {
|
|---|
| 1174 | /* We have read the extended header of the first member in
|
|---|
| 1175 | this volume. Put it back, so next read_header works as
|
|---|
| 1176 | expected. */
|
|---|
| 1177 | current_block = record_start;
|
|---|
| 1178 | }
|
|---|
| 1179 | break;
|
|---|
| 1180 | }
|
|---|
| 1181 |
|
|---|
| 1182 | case GNUTYPE_VOLHDR:
|
|---|
| 1183 | if (!read_header0 (&dummy))
|
|---|
| 1184 | return false;
|
|---|
| 1185 | tar_stat_destroy (&dummy);
|
|---|
| 1186 | assign_string (&volume_label, current_header->header.name);
|
|---|
| 1187 | set_next_block_after (header);
|
|---|
| 1188 | header = find_next_block ();
|
|---|
| 1189 | if (header->header.typeflag != GNUTYPE_MULTIVOL)
|
|---|
| 1190 | break;
|
|---|
| 1191 | /* FALL THROUGH */
|
|---|
| 1192 |
|
|---|
| 1193 | case GNUTYPE_MULTIVOL:
|
|---|
| 1194 | if (!read_header0 (&dummy))
|
|---|
| 1195 | return false;
|
|---|
| 1196 | tar_stat_destroy (&dummy);
|
|---|
| 1197 | assign_string (&continued_file_name, current_header->header.name);
|
|---|
| 1198 | continued_file_size =
|
|---|
| 1199 | UINTMAX_FROM_HEADER (current_header->header.size);
|
|---|
| 1200 | continued_file_offset =
|
|---|
| 1201 | UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset);
|
|---|
| 1202 | break;
|
|---|
| 1203 |
|
|---|
| 1204 | default:
|
|---|
| 1205 | break;
|
|---|
| 1206 | }
|
|---|
| 1207 |
|
|---|
| 1208 | if (real_s_name)
|
|---|
| 1209 | {
|
|---|
| 1210 | uintmax_t s;
|
|---|
| 1211 | if (!continued_file_name
|
|---|
| 1212 | || strcmp (continued_file_name, real_s_name))
|
|---|
| 1213 | {
|
|---|
| 1214 | if ((archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT)
|
|---|
| 1215 | && strlen (real_s_name) >= NAME_FIELD_SIZE
|
|---|
| 1216 | && strncmp (continued_file_name, real_s_name,
|
|---|
| 1217 | NAME_FIELD_SIZE) == 0)
|
|---|
| 1218 | WARN ((0, 0,
|
|---|
| 1219 | _("%s is possibly continued on this volume: header contains truncated name"),
|
|---|
| 1220 | quote (real_s_name)));
|
|---|
| 1221 | else
|
|---|
| 1222 | {
|
|---|
| 1223 | WARN ((0, 0, _("%s is not continued on this volume"),
|
|---|
| 1224 | quote (real_s_name)));
|
|---|
| 1225 | return false;
|
|---|
| 1226 | }
|
|---|
| 1227 | }
|
|---|
| 1228 |
|
|---|
| 1229 | s = continued_file_size + continued_file_offset;
|
|---|
| 1230 |
|
|---|
| 1231 | if (real_s_totsize != s || s < continued_file_offset)
|
|---|
| 1232 | {
|
|---|
| 1233 | char totsizebuf[UINTMAX_STRSIZE_BOUND];
|
|---|
| 1234 | char s1buf[UINTMAX_STRSIZE_BOUND];
|
|---|
| 1235 | char s2buf[UINTMAX_STRSIZE_BOUND];
|
|---|
| 1236 |
|
|---|
| 1237 | WARN ((0, 0, _("%s is the wrong size (%s != %s + %s)"),
|
|---|
| 1238 | quote (continued_file_name),
|
|---|
| 1239 | STRINGIFY_BIGINT (save_totsize, totsizebuf),
|
|---|
| 1240 | STRINGIFY_BIGINT (continued_file_size, s1buf),
|
|---|
| 1241 | STRINGIFY_BIGINT (continued_file_offset, s2buf)));
|
|---|
| 1242 | return false;
|
|---|
| 1243 | }
|
|---|
| 1244 |
|
|---|
| 1245 | if (real_s_totsize - real_s_sizeleft != continued_file_offset)
|
|---|
| 1246 | {
|
|---|
| 1247 | WARN ((0, 0, _("This volume is out of sequence")));
|
|---|
| 1248 | return false;
|
|---|
| 1249 | }
|
|---|
| 1250 | }
|
|---|
| 1251 |
|
|---|
| 1252 | increase_volume_number ();
|
|---|
| 1253 | return true;
|
|---|
| 1254 | }
|
|---|
| 1255 |
|
|---|
| 1256 | |
|---|
| 1257 |
|
|---|
| 1258 | /* Check the LABEL block against the volume label, seen as a globbing
|
|---|
| 1259 | pattern. Return true if the pattern matches. In case of failure,
|
|---|
| 1260 | retry matching a volume sequence number before giving up in
|
|---|
| 1261 | multi-volume mode. */
|
|---|
| 1262 | static bool
|
|---|
| 1263 | check_label_pattern (union block *label)
|
|---|
| 1264 | {
|
|---|
| 1265 | char *string;
|
|---|
| 1266 | bool result;
|
|---|
| 1267 |
|
|---|
| 1268 | if (! memchr (label->header.name, '\0', sizeof label->header.name))
|
|---|
| 1269 | return false;
|
|---|
| 1270 |
|
|---|
| 1271 | if (fnmatch (volume_label_option, label->header.name, 0) == 0)
|
|---|
| 1272 | return true;
|
|---|
| 1273 |
|
|---|
| 1274 | if (!multi_volume_option)
|
|---|
| 1275 | return false;
|
|---|
| 1276 |
|
|---|
| 1277 | string = xmalloc (strlen (volume_label_option)
|
|---|
| 1278 | + sizeof VOLUME_LABEL_APPEND + 1);
|
|---|
| 1279 | strcpy (string, volume_label_option);
|
|---|
| 1280 | strcat (string, VOLUME_LABEL_APPEND);
|
|---|
| 1281 | result = fnmatch (string, label->header.name, 0) == 0;
|
|---|
| 1282 | free (string);
|
|---|
| 1283 | return result;
|
|---|
| 1284 | }
|
|---|
| 1285 |
|
|---|
| 1286 | /* Check if the next block contains a volume label and if this matches
|
|---|
| 1287 | the one given in the command line */
|
|---|
| 1288 | static void
|
|---|
| 1289 | match_volume_label (void)
|
|---|
| 1290 | {
|
|---|
| 1291 | union block *label = find_next_block ();
|
|---|
| 1292 |
|
|---|
| 1293 | if (!label)
|
|---|
| 1294 | FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),
|
|---|
| 1295 | quote (volume_label_option)));
|
|---|
| 1296 | if (!check_label_pattern (label))
|
|---|
| 1297 | FATAL_ERROR ((0, 0, _("Volume %s does not match %s"),
|
|---|
| 1298 | quote_n (0, label->header.name),
|
|---|
| 1299 | quote_n (1, volume_label_option)));
|
|---|
| 1300 | }
|
|---|
| 1301 |
|
|---|
| 1302 | /* Mark the archive with volume label STR. */
|
|---|
| 1303 | static void
|
|---|
| 1304 | _write_volume_label (const char *str)
|
|---|
| 1305 | {
|
|---|
| 1306 | if (archive_format == POSIX_FORMAT)
|
|---|
| 1307 | xheader_store ("GNU.volume.label", NULL, str);
|
|---|
| 1308 | else
|
|---|
| 1309 | {
|
|---|
| 1310 | union block *label = find_next_block ();
|
|---|
| 1311 |
|
|---|
| 1312 | memset (label, 0, BLOCKSIZE);
|
|---|
| 1313 |
|
|---|
| 1314 | strcpy (label->header.name, volume_label_option);
|
|---|
| 1315 | assign_string (¤t_stat_info.file_name,
|
|---|
| 1316 | label->header.name);
|
|---|
| 1317 | current_stat_info.had_trailing_slash =
|
|---|
| 1318 | strip_trailing_slashes (current_stat_info.file_name);
|
|---|
| 1319 |
|
|---|
| 1320 | label->header.typeflag = GNUTYPE_VOLHDR;
|
|---|
| 1321 | TIME_TO_CHARS (start_time.tv_sec, label->header.mtime);
|
|---|
| 1322 | finish_header (¤t_stat_info, label, -1);
|
|---|
| 1323 | set_next_block_after (label);
|
|---|
| 1324 | }
|
|---|
| 1325 | }
|
|---|
| 1326 |
|
|---|
| 1327 | #define VOL_SUFFIX "Volume"
|
|---|
| 1328 |
|
|---|
| 1329 | /* Add a volume label to a part of multi-volume archive */
|
|---|
| 1330 | static void
|
|---|
| 1331 | add_volume_label (void)
|
|---|
| 1332 | {
|
|---|
| 1333 | char buf[UINTMAX_STRSIZE_BOUND];
|
|---|
| 1334 | char *p = STRINGIFY_BIGINT (volno, buf);
|
|---|
| 1335 | char *s = xmalloc (strlen (volume_label_option) + sizeof VOL_SUFFIX
|
|---|
| 1336 | + strlen (p) + 2);
|
|---|
| 1337 | sprintf (s, "%s %s %s", volume_label_option, VOL_SUFFIX, p);
|
|---|
| 1338 | _write_volume_label (s);
|
|---|
| 1339 | free (s);
|
|---|
| 1340 | }
|
|---|
| 1341 |
|
|---|
| 1342 | static void
|
|---|
| 1343 | add_chunk_header ()
|
|---|
| 1344 | {
|
|---|
| 1345 | if (archive_format == POSIX_FORMAT)
|
|---|
| 1346 | {
|
|---|
| 1347 | off_t block_ordinal;
|
|---|
| 1348 | union block *blk;
|
|---|
| 1349 | struct tar_stat_info st;
|
|---|
| 1350 | static size_t real_s_part_no; /* FIXME */
|
|---|
| 1351 |
|
|---|
| 1352 | real_s_part_no++;
|
|---|
| 1353 | memset (&st, 0, sizeof st);
|
|---|
| 1354 | st.orig_file_name = st.file_name = real_s_name;
|
|---|
| 1355 | st.stat.st_mode = S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
|
|---|
| 1356 | st.stat.st_uid = getuid ();
|
|---|
| 1357 | st.stat.st_gid = getgid ();
|
|---|
| 1358 | st.orig_file_name = xheader_format_name (&st,
|
|---|
| 1359 | "%d/GNUFileParts.%p/%f.%n",
|
|---|
| 1360 | real_s_part_no);
|
|---|
| 1361 | st.file_name = st.orig_file_name;
|
|---|
| 1362 | st.archive_file_size = st.stat.st_size = real_s_sizeleft;
|
|---|
| 1363 |
|
|---|
| 1364 | block_ordinal = current_block_ordinal ();
|
|---|
| 1365 | blk = start_header (&st);
|
|---|
| 1366 | if (!blk)
|
|---|
| 1367 | abort (); /* FIXME */
|
|---|
| 1368 | finish_header (&st, blk, block_ordinal);
|
|---|
| 1369 | free (st.orig_file_name);
|
|---|
| 1370 | }
|
|---|
| 1371 | }
|
|---|
| 1372 |
|
|---|
| 1373 |
|
|---|
| 1374 | /* Add a volume label to the current archive */
|
|---|
| 1375 | static void
|
|---|
| 1376 | write_volume_label (void)
|
|---|
| 1377 | {
|
|---|
| 1378 | if (multi_volume_option)
|
|---|
| 1379 | add_volume_label ();
|
|---|
| 1380 | else
|
|---|
| 1381 | _write_volume_label (volume_label_option);
|
|---|
| 1382 | }
|
|---|
| 1383 |
|
|---|
| 1384 | /* Write GNU multi-volume header */
|
|---|
| 1385 | static void
|
|---|
| 1386 | gnu_add_multi_volume_header (void)
|
|---|
| 1387 | {
|
|---|
| 1388 | int tmp;
|
|---|
| 1389 | union block *block = find_next_block ();
|
|---|
| 1390 |
|
|---|
| 1391 | if (strlen (real_s_name) > NAME_FIELD_SIZE)
|
|---|
| 1392 | WARN ((0, 0,
|
|---|
| 1393 | _("%s: file name too long to be stored in a GNU multivolume header, truncated"),
|
|---|
| 1394 | quotearg_colon (real_s_name)));
|
|---|
| 1395 |
|
|---|
| 1396 | memset (block, 0, BLOCKSIZE);
|
|---|
| 1397 |
|
|---|
| 1398 | /* FIXME: Michael P Urban writes: [a long name file] is being written
|
|---|
| 1399 | when a new volume rolls around [...] Looks like the wrong value is
|
|---|
| 1400 | being preserved in real_s_name, though. */
|
|---|
| 1401 |
|
|---|
| 1402 | strncpy (block->header.name, real_s_name, NAME_FIELD_SIZE);
|
|---|
| 1403 | block->header.typeflag = GNUTYPE_MULTIVOL;
|
|---|
| 1404 |
|
|---|
| 1405 | OFF_TO_CHARS (real_s_sizeleft, block->header.size);
|
|---|
| 1406 | OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
|
|---|
| 1407 | block->oldgnu_header.offset);
|
|---|
| 1408 |
|
|---|
| 1409 | tmp = verbose_option;
|
|---|
| 1410 | verbose_option = 0;
|
|---|
| 1411 | finish_header (¤t_stat_info, block, -1);
|
|---|
| 1412 | verbose_option = tmp;
|
|---|
| 1413 | set_next_block_after (block);
|
|---|
| 1414 | }
|
|---|
| 1415 |
|
|---|
| 1416 | /* Add a multi volume header to the current archive. The exact header format
|
|---|
| 1417 | depends on the archive format. */
|
|---|
| 1418 | static void
|
|---|
| 1419 | add_multi_volume_header (void)
|
|---|
| 1420 | {
|
|---|
| 1421 | if (archive_format == POSIX_FORMAT)
|
|---|
| 1422 | {
|
|---|
| 1423 | off_t d = real_s_totsize - real_s_sizeleft;
|
|---|
| 1424 | xheader_store ("GNU.volume.filename", NULL, real_s_name);
|
|---|
| 1425 | xheader_store ("GNU.volume.size", NULL, &real_s_sizeleft);
|
|---|
| 1426 | xheader_store ("GNU.volume.offset", NULL, &d);
|
|---|
| 1427 | }
|
|---|
| 1428 | else
|
|---|
| 1429 | gnu_add_multi_volume_header ();
|
|---|
| 1430 | }
|
|---|
| 1431 |
|
|---|
| 1432 | /* Synchronize multi-volume globals */
|
|---|
| 1433 | static void
|
|---|
| 1434 | multi_volume_sync ()
|
|---|
| 1435 | {
|
|---|
| 1436 | if (multi_volume_option)
|
|---|
| 1437 | {
|
|---|
| 1438 | if (save_name)
|
|---|
| 1439 | {
|
|---|
| 1440 | assign_string (&real_s_name,
|
|---|
| 1441 | safer_name_suffix (save_name, false,
|
|---|
| 1442 | absolute_names_option));
|
|---|
| 1443 | real_s_totsize = save_totsize;
|
|---|
| 1444 | real_s_sizeleft = save_sizeleft;
|
|---|
| 1445 | }
|
|---|
| 1446 | else
|
|---|
| 1447 | {
|
|---|
| 1448 | assign_string (&real_s_name, 0);
|
|---|
| 1449 | real_s_totsize = 0;
|
|---|
| 1450 | real_s_sizeleft = 0;
|
|---|
| 1451 | }
|
|---|
| 1452 | }
|
|---|
| 1453 | }
|
|---|
| 1454 |
|
|---|
| 1455 | |
|---|
| 1456 |
|
|---|
| 1457 | /* Low-level flush functions */
|
|---|
| 1458 |
|
|---|
| 1459 | /* Simple flush read (no multi-volume or label extensions) */
|
|---|
| 1460 | static void
|
|---|
| 1461 | simple_flush_read (void)
|
|---|
| 1462 | {
|
|---|
| 1463 | size_t status; /* result from system call */
|
|---|
| 1464 |
|
|---|
| 1465 | do_checkpoint (false);
|
|---|
| 1466 |
|
|---|
| 1467 | /* Clear the count of errors. This only applies to a single call to
|
|---|
| 1468 | flush_read. */
|
|---|
| 1469 |
|
|---|
| 1470 | read_error_count = 0; /* clear error count */
|
|---|
| 1471 |
|
|---|
| 1472 | if (write_archive_to_stdout && record_start_block != 0)
|
|---|
| 1473 | {
|
|---|
| 1474 | archive = STDOUT_FILENO;
|
|---|
| 1475 | status = sys_write_archive_buffer ();
|
|---|
| 1476 | archive = STDIN_FILENO;
|
|---|
| 1477 | if (status != record_size)
|
|---|
| 1478 | archive_write_error (status);
|
|---|
| 1479 | }
|
|---|
| 1480 |
|
|---|
| 1481 | for (;;)
|
|---|
| 1482 | {
|
|---|
| 1483 | status = rmtread (archive, record_start->buffer, record_size);
|
|---|
| 1484 | if (status == record_size)
|
|---|
| 1485 | {
|
|---|
| 1486 | records_read++;
|
|---|
| 1487 | return;
|
|---|
| 1488 | }
|
|---|
| 1489 | if (status == SAFE_READ_ERROR)
|
|---|
| 1490 | {
|
|---|
| 1491 | archive_read_error ();
|
|---|
| 1492 | continue; /* try again */
|
|---|
| 1493 | }
|
|---|
| 1494 | break;
|
|---|
| 1495 | }
|
|---|
| 1496 | short_read (status);
|
|---|
| 1497 | }
|
|---|
| 1498 |
|
|---|
| 1499 | /* Simple flush write (no multi-volume or label extensions) */
|
|---|
| 1500 | static void
|
|---|
| 1501 | simple_flush_write (size_t level __attribute__((unused)))
|
|---|
| 1502 | {
|
|---|
| 1503 | ssize_t status;
|
|---|
| 1504 |
|
|---|
| 1505 | status = _flush_write ();
|
|---|
| 1506 | if (status != record_size)
|
|---|
| 1507 | archive_write_error (status);
|
|---|
| 1508 | else
|
|---|
| 1509 | {
|
|---|
| 1510 | records_written++;
|
|---|
| 1511 | bytes_written += status;
|
|---|
| 1512 | }
|
|---|
| 1513 | }
|
|---|
| 1514 |
|
|---|
| 1515 | |
|---|
| 1516 |
|
|---|
| 1517 | /* GNU flush functions. These support multi-volume and archive labels in
|
|---|
| 1518 | GNU and PAX archive formats. */
|
|---|
| 1519 |
|
|---|
| 1520 | static void
|
|---|
| 1521 | _gnu_flush_read (void)
|
|---|
| 1522 | {
|
|---|
| 1523 | size_t status; /* result from system call */
|
|---|
| 1524 |
|
|---|
| 1525 | do_checkpoint (false);
|
|---|
| 1526 |
|
|---|
| 1527 | /* Clear the count of errors. This only applies to a single call to
|
|---|
| 1528 | flush_read. */
|
|---|
| 1529 |
|
|---|
| 1530 | read_error_count = 0; /* clear error count */
|
|---|
| 1531 |
|
|---|
| 1532 | if (write_archive_to_stdout && record_start_block != 0)
|
|---|
| 1533 | {
|
|---|
| 1534 | archive = STDOUT_FILENO;
|
|---|
| 1535 | status = sys_write_archive_buffer ();
|
|---|
| 1536 | archive = STDIN_FILENO;
|
|---|
| 1537 | if (status != record_size)
|
|---|
| 1538 | archive_write_error (status);
|
|---|
| 1539 | }
|
|---|
| 1540 |
|
|---|
| 1541 | multi_volume_sync ();
|
|---|
| 1542 |
|
|---|
| 1543 | for (;;)
|
|---|
| 1544 | {
|
|---|
| 1545 | status = rmtread (archive, record_start->buffer, record_size);
|
|---|
| 1546 | if (status == record_size)
|
|---|
| 1547 | {
|
|---|
| 1548 | records_read++;
|
|---|
| 1549 | return;
|
|---|
| 1550 | }
|
|---|
| 1551 |
|
|---|
| 1552 | /* The condition below used to include
|
|---|
| 1553 | || (status > 0 && !read_full_records)
|
|---|
| 1554 | This is incorrect since even if new_volume() succeeds, the
|
|---|
| 1555 | subsequent call to rmtread will overwrite the chunk of data
|
|---|
| 1556 | already read in the buffer, so the processing will fail */
|
|---|
| 1557 | if ((status == 0
|
|---|
| 1558 | || (status == SAFE_READ_ERROR && errno == ENOSPC))
|
|---|
| 1559 | && multi_volume_option)
|
|---|
| 1560 | {
|
|---|
| 1561 | while (!try_new_volume ())
|
|---|
| 1562 | ;
|
|---|
| 1563 | return;
|
|---|
| 1564 | }
|
|---|
| 1565 | else if (status == SAFE_READ_ERROR)
|
|---|
| 1566 | {
|
|---|
| 1567 | archive_read_error ();
|
|---|
| 1568 | continue;
|
|---|
| 1569 | }
|
|---|
| 1570 | break;
|
|---|
| 1571 | }
|
|---|
| 1572 | short_read (status);
|
|---|
| 1573 | }
|
|---|
| 1574 |
|
|---|
| 1575 | static void
|
|---|
| 1576 | gnu_flush_read (void)
|
|---|
| 1577 | {
|
|---|
| 1578 | flush_read_ptr = simple_flush_read; /* Avoid recursion */
|
|---|
| 1579 | _gnu_flush_read ();
|
|---|
| 1580 | flush_read_ptr = gnu_flush_read;
|
|---|
| 1581 | }
|
|---|
| 1582 |
|
|---|
| 1583 | static void
|
|---|
| 1584 | _gnu_flush_write (size_t buffer_level)
|
|---|
| 1585 | {
|
|---|
| 1586 | ssize_t status;
|
|---|
| 1587 | union block *header;
|
|---|
| 1588 | char *copy_ptr;
|
|---|
| 1589 | size_t copy_size;
|
|---|
| 1590 | size_t bufsize;
|
|---|
| 1591 |
|
|---|
| 1592 | status = _flush_write ();
|
|---|
| 1593 | if (status != record_size && !multi_volume_option)
|
|---|
| 1594 | archive_write_error (status);
|
|---|
| 1595 | else
|
|---|
| 1596 | {
|
|---|
| 1597 | records_written++;
|
|---|
| 1598 | bytes_written += status;
|
|---|
| 1599 | }
|
|---|
| 1600 |
|
|---|
| 1601 | if (status == record_size)
|
|---|
| 1602 | {
|
|---|
| 1603 | multi_volume_sync ();
|
|---|
| 1604 | return;
|
|---|
| 1605 | }
|
|---|
| 1606 |
|
|---|
| 1607 | /* In multi-volume mode. */
|
|---|
| 1608 | /* ENXIO is for the UNIX PC. */
|
|---|
| 1609 | if (status < 0 && errno != ENOSPC && errno != EIO && errno != ENXIO)
|
|---|
| 1610 | archive_write_error (status);
|
|---|
| 1611 |
|
|---|
| 1612 | if (!new_volume (ACCESS_WRITE))
|
|---|
| 1613 | return;
|
|---|
| 1614 |
|
|---|
| 1615 | xheader_destroy (&extended_header);
|
|---|
| 1616 |
|
|---|
| 1617 | increase_volume_number ();
|
|---|
| 1618 | prev_written += bytes_written;
|
|---|
| 1619 | bytes_written = 0;
|
|---|
| 1620 |
|
|---|
| 1621 | copy_ptr = record_start->buffer + status;
|
|---|
| 1622 | copy_size = buffer_level - status;
|
|---|
| 1623 | /* Switch to the next buffer */
|
|---|
| 1624 | record_index = !record_index;
|
|---|
| 1625 | init_buffer ();
|
|---|
| 1626 |
|
|---|
| 1627 | if (volume_label_option)
|
|---|
| 1628 | add_volume_label ();
|
|---|
| 1629 |
|
|---|
| 1630 | if (real_s_name)
|
|---|
| 1631 | add_multi_volume_header ();
|
|---|
| 1632 |
|
|---|
| 1633 | write_extended (true, NULL, find_next_block ());
|
|---|
| 1634 | if (real_s_name)
|
|---|
| 1635 | add_chunk_header ();
|
|---|
| 1636 | header = find_next_block ();
|
|---|
| 1637 | bufsize = available_space_after (header);
|
|---|
| 1638 | while (bufsize < copy_size)
|
|---|
| 1639 | {
|
|---|
| 1640 | memcpy (header->buffer, copy_ptr, bufsize);
|
|---|
| 1641 | copy_ptr += bufsize;
|
|---|
| 1642 | copy_size -= bufsize;
|
|---|
| 1643 | set_next_block_after (header + (bufsize - 1) / BLOCKSIZE);
|
|---|
| 1644 | header = find_next_block ();
|
|---|
| 1645 | bufsize = available_space_after (header);
|
|---|
| 1646 | }
|
|---|
| 1647 | memcpy (header->buffer, copy_ptr, copy_size);
|
|---|
| 1648 | memset (header->buffer + copy_size, 0, bufsize - copy_size);
|
|---|
| 1649 | set_next_block_after (header + (copy_size - 1) / BLOCKSIZE);
|
|---|
| 1650 | find_next_block ();
|
|---|
| 1651 | }
|
|---|
| 1652 |
|
|---|
| 1653 | static void
|
|---|
| 1654 | gnu_flush_write (size_t buffer_level)
|
|---|
| 1655 | {
|
|---|
| 1656 | flush_write_ptr = simple_flush_write; /* Avoid recursion */
|
|---|
| 1657 | _gnu_flush_write (buffer_level);
|
|---|
| 1658 | flush_write_ptr = gnu_flush_write;
|
|---|
| 1659 | }
|
|---|
| 1660 |
|
|---|
| 1661 | void
|
|---|
| 1662 | flush_read ()
|
|---|
| 1663 | {
|
|---|
| 1664 | flush_read_ptr ();
|
|---|
| 1665 | }
|
|---|
| 1666 |
|
|---|
| 1667 | void
|
|---|
| 1668 | flush_write ()
|
|---|
| 1669 | {
|
|---|
| 1670 | flush_write_ptr (record_size);
|
|---|
| 1671 | }
|
|---|
| 1672 |
|
|---|
| 1673 | void
|
|---|
| 1674 | open_archive (enum access_mode wanted_access)
|
|---|
| 1675 | {
|
|---|
| 1676 | flush_read_ptr = gnu_flush_read;
|
|---|
| 1677 | flush_write_ptr = gnu_flush_write;
|
|---|
| 1678 |
|
|---|
| 1679 | _open_archive (wanted_access);
|
|---|
| 1680 | switch (wanted_access)
|
|---|
| 1681 | {
|
|---|
| 1682 | case ACCESS_READ:
|
|---|
| 1683 | if (volume_label_option)
|
|---|
| 1684 | match_volume_label ();
|
|---|
| 1685 | break;
|
|---|
| 1686 |
|
|---|
| 1687 | case ACCESS_WRITE:
|
|---|
| 1688 | records_written = 0;
|
|---|
| 1689 | if (volume_label_option)
|
|---|
| 1690 | write_volume_label ();
|
|---|
| 1691 | break;
|
|---|
| 1692 |
|
|---|
| 1693 | default:
|
|---|
| 1694 | break;
|
|---|
| 1695 | }
|
|---|
| 1696 | set_volume_start_time ();
|
|---|
| 1697 | }
|
|---|