File: | src/buffer.c |
Warning: | line 1655, column 7 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Buffer management for tar. | |||
2 | ||||
3 | Copyright 1988, 1992-1994, 1996-1997, 1999-2010, 2013-2014 Free | |||
4 | Software Foundation, Inc. | |||
5 | ||||
6 | This file is part of GNU tar. | |||
7 | ||||
8 | GNU tar is free software; you can redistribute it and/or modify | |||
9 | it under the terms of the GNU General Public License as published by | |||
10 | the Free Software Foundation; either version 3 of the License, or | |||
11 | (at your option) any later version. | |||
12 | ||||
13 | GNU tar is distributed in the hope that it will be useful, | |||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
16 | GNU General Public License for more details. | |||
17 | ||||
18 | You should have received a copy of the GNU General Public License | |||
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
20 | ||||
21 | Written by John Gilmore, on 1985-08-25. */ | |||
22 | ||||
23 | #include <system.h> | |||
24 | #include <system-ioctl.h> | |||
25 | ||||
26 | #include <signal.h> | |||
27 | ||||
28 | #include <closeout.h> | |||
29 | #include <fnmatch.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_MAX10 10 | |||
38 | ||||
39 | /* Variables. */ | |||
40 | ||||
41 | static tarlong prev_written; /* bytes written on previous volumes */ | |||
42 | static tarlong bytes_written; /* bytes written on this volume */ | |||
43 | static void *record_buffer[2]; /* allocated memory */ | |||
44 | static union block *record_buffer_aligned[2]; | |||
45 | static int record_index; | |||
46 | ||||
47 | /* FIXME: The following variables should ideally be static to this | |||
48 | module. However, this cannot be done yet. The cleanup continues! */ | |||
49 | ||||
50 | union block *record_start; /* start of record of archive */ | |||
51 | union block *record_end; /* last+1 block of archive record */ | |||
52 | union block *current_block; /* current block of archive */ | |||
53 | enum access_mode access_mode; /* how do we handle the archive */ | |||
54 | off_t records_read; /* number of records read from this archive */ | |||
55 | off_t records_written; /* likewise, for records written */ | |||
56 | extern off_t records_skipped; /* number of records skipped at the start | |||
57 | of the archive, defined in delete.c */ | |||
58 | ||||
59 | static off_t record_start_block; /* block ordinal at record_start */ | |||
60 | ||||
61 | /* Where we write list messages (not errors, not interactions) to. */ | |||
62 | FILE *stdlis; | |||
63 | ||||
64 | static void backspace_output (void); | |||
65 | ||||
66 | /* PID of child program, if compress_option or remote archive access. */ | |||
67 | static pid_t child_pid; | |||
68 | ||||
69 | /* Error recovery stuff */ | |||
70 | static int read_error_count; | |||
71 | ||||
72 | /* Have we hit EOF yet? */ | |||
73 | static bool_Bool hit_eof; | |||
74 | ||||
75 | static bool_Bool read_full_records = false0; | |||
76 | ||||
77 | /* We're reading, but we just read the last block and it's time to update. | |||
78 | Declared in update.c | |||
79 | ||||
80 | FIXME: Either eliminate it or move it to common.h. | |||
81 | */ | |||
82 | extern bool_Bool time_to_start_writing; | |||
83 | ||||
84 | bool_Bool write_archive_to_stdout; | |||
85 | ||||
86 | static void (*flush_write_ptr) (size_t); | |||
87 | static void (*flush_read_ptr) (void); | |||
88 | ||||
89 | ||||
90 | char *volume_label; | |||
91 | char *continued_file_name; | |||
92 | uintmax_t continued_file_size; | |||
93 | uintmax_t continued_file_offset; | |||
94 | ||||
95 | ||||
96 | static int volno = 1; /* which volume of a multi-volume tape we're | |||
97 | on */ | |||
98 | static int global_volno = 1; /* volume number to print in external | |||
99 | messages */ | |||
100 | ||||
101 | bool_Bool write_archive_to_stdout; | |||
102 | ||||
103 | ||||
104 | /* Multi-volume tracking support */ | |||
105 | ||||
106 | /* When creating a multi-volume archive, each 'bufmap' represents | |||
107 | a member stored (perhaps partly) in the current record buffer. | |||
108 | After flushing the record to the output media, all bufmaps that | |||
109 | represent fully written members are removed from the list, then | |||
110 | the sizeleft and start numbers in the remaining bufmaps are updated. | |||
111 | ||||
112 | When reading from a multi-volume archive, the list degrades to a | |||
113 | single element, which keeps information about the member currently | |||
114 | being read. | |||
115 | */ | |||
116 | ||||
117 | struct bufmap | |||
118 | { | |||
119 | struct bufmap *next; /* Pointer to the next map entry */ | |||
120 | size_t start; /* Offset of the first data block */ | |||
121 | char *file_name; /* Name of the stored file */ | |||
122 | off_t sizetotal; /* Size of the stored file */ | |||
123 | off_t sizeleft; /* Size left to read/write */ | |||
124 | }; | |||
125 | static struct bufmap *bufmap_head, *bufmap_tail; | |||
126 | ||||
127 | /* This variable, when set, inhibits updating the bufmap chain after | |||
128 | a write. This is necessary when writing extended POSIX headers. */ | |||
129 | static int inhibit_map; | |||
130 | ||||
131 | void | |||
132 | mv_begin_write (const char *file_name, off_t totsize, off_t sizeleft) | |||
133 | { | |||
134 | if (multi_volume_option) | |||
135 | { | |||
136 | struct bufmap *bp = xmalloc (sizeof bp[0]); | |||
137 | if (bufmap_tail) | |||
138 | bufmap_tail->next = bp; | |||
139 | else | |||
140 | bufmap_head = bp; | |||
141 | bufmap_tail = bp; | |||
142 | ||||
143 | bp->next = NULL((void*)0); | |||
144 | bp->start = current_block - record_start; | |||
145 | bp->file_name = xstrdup (file_name); | |||
146 | bp->sizetotal = totsize; | |||
147 | bp->sizeleft = sizeleft; | |||
148 | } | |||
149 | } | |||
150 | ||||
151 | static struct bufmap * | |||
152 | bufmap_locate (size_t off) | |||
153 | { | |||
154 | struct bufmap *map; | |||
155 | ||||
156 | for (map = bufmap_head; map; map = map->next) | |||
157 | { | |||
158 | if (!map->next | |||
159 | || off < map->next->start * BLOCKSIZE512) | |||
160 | break; | |||
161 | } | |||
162 | return map; | |||
163 | } | |||
164 | ||||
165 | static void | |||
166 | bufmap_free (struct bufmap *mark) | |||
167 | { | |||
168 | struct bufmap *map; | |||
169 | for (map = bufmap_head; map && map != mark; ) | |||
170 | { | |||
171 | struct bufmap *next = map->next; | |||
172 | free (map->file_name); | |||
173 | free (map); | |||
174 | map = next; | |||
175 | } | |||
176 | bufmap_head = map; | |||
177 | if (!bufmap_head) | |||
178 | bufmap_tail = bufmap_head; | |||
179 | } | |||
180 | ||||
181 | static void | |||
182 | bufmap_reset (struct bufmap *map, ssize_t fixup) | |||
183 | { | |||
184 | bufmap_free (map); | |||
185 | if (map) | |||
186 | { | |||
187 | for (; map; map = map->next) | |||
188 | map->start += fixup; | |||
189 | } | |||
190 | } | |||
191 | ||||
192 | ||||
193 | static struct tar_stat_info dummy; | |||
194 | ||||
195 | void | |||
196 | buffer_write_global_xheader (void) | |||
197 | { | |||
198 | xheader_write_global (&dummy.xhdr); | |||
199 | } | |||
200 | ||||
201 | void | |||
202 | mv_begin_read (struct tar_stat_info *st) | |||
203 | { | |||
204 | mv_begin_write (st->orig_file_name, st->stat.st_size, st->stat.st_size); | |||
205 | } | |||
206 | ||||
207 | void | |||
208 | mv_end (void) | |||
209 | { | |||
210 | if (multi_volume_option) | |||
211 | bufmap_free (NULL((void*)0)); | |||
212 | } | |||
213 | ||||
214 | void | |||
215 | mv_size_left (off_t size) | |||
216 | { | |||
217 | if (bufmap_head) | |||
218 | bufmap_head->sizeleft = size; | |||
219 | } | |||
220 | ||||
221 | ||||
222 | /* Functions. */ | |||
223 | ||||
224 | void | |||
225 | clear_read_error_count (void) | |||
226 | { | |||
227 | read_error_count = 0; | |||
228 | } | |||
229 | ||||
230 | ||||
231 | /* Time-related functions */ | |||
232 | ||||
233 | static double duration; | |||
234 | ||||
235 | void | |||
236 | set_start_time (void) | |||
237 | { | |||
238 | gettime (&start_time); | |||
239 | volume_start_time = start_time; | |||
240 | last_stat_time = start_time; | |||
241 | } | |||
242 | ||||
243 | static void | |||
244 | set_volume_start_time (void) | |||
245 | { | |||
246 | gettime (&volume_start_time); | |||
247 | last_stat_time = volume_start_time; | |||
248 | } | |||
249 | ||||
250 | double | |||
251 | compute_duration (void) | |||
252 | { | |||
253 | struct timespec now; | |||
254 | gettime (&now); | |||
255 | duration += ((now.tv_sec - last_stat_time.tv_sec) | |||
256 | + (now.tv_nsec - last_stat_time.tv_nsec) / 1e9); | |||
257 | gettime (&last_stat_time); | |||
258 | return duration; | |||
259 | } | |||
260 | ||||
261 | ||||
262 | /* Compression detection */ | |||
263 | ||||
264 | enum compress_type { | |||
265 | ct_none, /* Unknown compression type */ | |||
266 | ct_tar, /* Plain tar file */ | |||
267 | ct_compress, | |||
268 | ct_gzip, | |||
269 | ct_bzip2, | |||
270 | ct_lzip, | |||
271 | ct_lzma, | |||
272 | ct_lzop, | |||
273 | ct_xz | |||
274 | }; | |||
275 | ||||
276 | static enum compress_type archive_compression_type = ct_none; | |||
277 | ||||
278 | struct zip_magic | |||
279 | { | |||
280 | enum compress_type type; | |||
281 | size_t length; | |||
282 | char const *magic; | |||
283 | }; | |||
284 | ||||
285 | struct zip_program | |||
286 | { | |||
287 | enum compress_type type; | |||
288 | char const *program; | |||
289 | char const *optionrpl_option; | |||
290 | }; | |||
291 | ||||
292 | static struct zip_magic const magic[] = { | |||
293 | { ct_none, 0, 0 }, | |||
294 | { ct_tar, 0, 0 }, | |||
295 | { ct_compress, 2, "\037\235" }, | |||
296 | { ct_gzip, 2, "\037\213" }, | |||
297 | { ct_bzip2, 3, "BZh" }, | |||
298 | { ct_lzip, 4, "LZIP" }, | |||
299 | { ct_lzma, 6, "\xFFLZMA" }, | |||
300 | { ct_lzop, 4, "\211LZO" }, | |||
301 | { ct_xz, 6, "\xFD" "7zXZ" }, | |||
302 | }; | |||
303 | ||||
304 | #define NMAGIC(sizeof(magic)/sizeof(magic[0])) (sizeof(magic)/sizeof(magic[0])) | |||
305 | ||||
306 | static struct zip_program zip_program[] = { | |||
307 | { ct_compress, COMPRESS_PROGRAM"compress", "-Z" }, | |||
308 | { ct_compress, GZIP_PROGRAM"gzip", "-z" }, | |||
309 | { ct_gzip, GZIP_PROGRAM"gzip", "-z" }, | |||
310 | { ct_bzip2, BZIP2_PROGRAM"bzip2", "-j" }, | |||
311 | { ct_bzip2, "lbzip2", "-j" }, | |||
312 | { ct_lzip, LZIP_PROGRAM"lzip", "--lzip" }, | |||
313 | { ct_lzma, LZMA_PROGRAM"lzma", "--lzma" }, | |||
314 | { ct_lzma, XZ_PROGRAM"xz", "-J" }, | |||
315 | { ct_lzop, LZOP_PROGRAM"lzop", "--lzop" }, | |||
316 | { ct_xz, XZ_PROGRAM"xz", "-J" }, | |||
317 | { ct_none } | |||
318 | }; | |||
319 | ||||
320 | static struct zip_program const * | |||
321 | find_zip_program (enum compress_type type, int *pstate) | |||
322 | { | |||
323 | int i; | |||
324 | ||||
325 | for (i = *pstate; zip_program[i].type != ct_none; i++) | |||
326 | { | |||
327 | if (zip_program[i].type == type) | |||
328 | { | |||
329 | *pstate = i + 1; | |||
330 | return zip_program + i; | |||
331 | } | |||
332 | } | |||
333 | *pstate = i; | |||
334 | return NULL((void*)0); | |||
335 | } | |||
336 | ||||
337 | const char * | |||
338 | first_decompress_program (int *pstate) | |||
339 | { | |||
340 | struct zip_program const *zp; | |||
341 | ||||
342 | if (use_compress_program_option) | |||
343 | return use_compress_program_option; | |||
344 | ||||
345 | if (archive_compression_type == ct_none) | |||
346 | return NULL((void*)0); | |||
347 | ||||
348 | *pstate = 0; | |||
349 | zp = find_zip_program (archive_compression_type, pstate); | |||
350 | return zp ? zp->program : NULL((void*)0); | |||
351 | } | |||
352 | ||||
353 | const char * | |||
354 | next_decompress_program (int *pstate) | |||
355 | { | |||
356 | struct zip_program const *zp; | |||
357 | ||||
358 | if (use_compress_program_option) | |||
359 | return NULL((void*)0); | |||
360 | zp = find_zip_program (archive_compression_type, pstate); | |||
361 | return zp ? zp->program : NULL((void*)0); | |||
362 | } | |||
363 | ||||
364 | static const char * | |||
365 | compress_option (enum compress_type type) | |||
366 | { | |||
367 | struct zip_program const *zp; | |||
368 | int i = 0; | |||
369 | zp = find_zip_program (type, &i); | |||
370 | return zp ? zp->optionrpl_option : NULL((void*)0); | |||
371 | } | |||
372 | ||||
373 | /* Check if the file ARCHIVE is a compressed archive. */ | |||
374 | static enum compress_type | |||
375 | check_compressed_archive (bool_Bool *pshort) | |||
376 | { | |||
377 | struct zip_magic const *p; | |||
378 | bool_Bool sfr; | |||
379 | bool_Bool temp; | |||
380 | ||||
381 | if (!pshort) | |||
382 | pshort = &temp; | |||
383 | ||||
384 | /* Prepare global data needed for find_next_block: */ | |||
385 | record_end = record_start; /* set up for 1st record = # 0 */ | |||
386 | sfr = read_full_records; | |||
387 | read_full_records = true1; /* Suppress fatal error on reading a partial | |||
388 | record */ | |||
389 | *pshort = find_next_block () == 0; | |||
390 | ||||
391 | /* Restore global values */ | |||
392 | read_full_records = sfr; | |||
393 | ||||
394 | if (tar_checksum (record_start, true1) == HEADER_SUCCESS) | |||
395 | /* Probably a valid header */ | |||
396 | return ct_tar; | |||
397 | ||||
398 | for (p = magic + 2; p < magic + NMAGIC(sizeof(magic)/sizeof(magic[0])); p++) | |||
399 | if (memcmp (record_start->buffer, p->magic, p->length) == 0) | |||
400 | return p->type; | |||
401 | ||||
402 | return ct_none; | |||
403 | } | |||
404 | ||||
405 | /* Guess if the archive is seekable. */ | |||
406 | static void | |||
407 | guess_seekable_archive (void) | |||
408 | { | |||
409 | struct stat st; | |||
410 | ||||
411 | if (subcommand_option == DELETE_SUBCOMMAND) | |||
412 | { | |||
413 | /* The current code in delete.c is based on the assumption that | |||
414 | skip_member() reads all data from the archive. So, we should | |||
415 | make sure it won't use seeks. On the other hand, the same code | |||
416 | depends on the ability to backspace a record in the archive, | |||
417 | so setting seekable_archive to false is technically incorrect. | |||
418 | However, it is tested only in skip_member(), so it's not a | |||
419 | problem. */ | |||
420 | seekable_archive = false0; | |||
421 | } | |||
422 | ||||
423 | if (seek_option != -1) | |||
424 | { | |||
425 | seekable_archive = !!seek_option; | |||
426 | return; | |||
427 | } | |||
428 | ||||
429 | if (!multi_volume_option && !use_compress_program_option | |||
430 | && fstat (archive, &st) == 0) | |||
431 | seekable_archive = S_ISREG (st.st_mode)((((st.st_mode)) & 0170000) == (0100000)); | |||
432 | else | |||
433 | seekable_archive = false0; | |||
434 | } | |||
435 | ||||
436 | /* Open an archive named archive_name_array[0]. Detect if it is | |||
437 | a compressed archive of known type and use corresponding decompression | |||
438 | program if so */ | |||
439 | static int | |||
440 | open_compressed_archive (void) | |||
441 | { | |||
442 | archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,((!force_local_option && (rmt_dev_name__ = strchr (archive_name_array [0], ':')) && rmt_dev_name__ > (archive_name_array [0]) && ! memchr (archive_name_array[0], '/', rmt_dev_name__ - (archive_name_array[0]))) ? rmt_open__ (archive_name_array [0], 00 | 0, (1 << 30), rsh_command_option) : open (archive_name_array [0], 00 | 0, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))) | |||
443 | MODE_RW, rsh_command_option)((!force_local_option && (rmt_dev_name__ = strchr (archive_name_array [0], ':')) && rmt_dev_name__ > (archive_name_array [0]) && ! memchr (archive_name_array[0], '/', rmt_dev_name__ - (archive_name_array[0]))) ? rmt_open__ (archive_name_array [0], 00 | 0, (1 << 30), rsh_command_option) : open (archive_name_array [0], 00 | 0, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))); | |||
444 | if (archive == -1) | |||
445 | return archive; | |||
446 | ||||
447 | if (!multi_volume_option) | |||
448 | { | |||
449 | if (!use_compress_program_option) | |||
450 | { | |||
451 | bool_Bool shortfile; | |||
452 | enum compress_type type = check_compressed_archive (&shortfile); | |||
453 | ||||
454 | switch (type) | |||
455 | { | |||
456 | case ct_tar: | |||
457 | if (shortfile) | |||
458 | ERROR ((0, 0, _("This does not look like a tar archive")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This does not look like a tar archive", 5)); exit_status = 2; } while (0); | |||
459 | return archive; | |||
460 | ||||
461 | case ct_none: | |||
462 | if (shortfile) | |||
463 | ERROR ((0, 0, _("This does not look like a tar archive")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This does not look like a tar archive", 5)); exit_status = 2; } while (0); | |||
464 | set_compression_program_by_suffix (archive_name_array[0], NULL((void*)0)); | |||
465 | if (!use_compress_program_option) | |||
466 | return archive; | |||
467 | break; | |||
468 | ||||
469 | default: | |||
470 | archive_compression_type = type; | |||
471 | break; | |||
472 | } | |||
473 | } | |||
474 | ||||
475 | /* FD is not needed any more */ | |||
476 | rmtclose (archive)(((archive) >= (1 << 30)) ? rmt_close__ (archive - ( 1 << 30)) : close (archive)); | |||
477 | ||||
478 | hit_eof = false0; /* It might have been set by find_next_block in | |||
479 | check_compressed_archive */ | |||
480 | ||||
481 | /* Open compressed archive */ | |||
482 | child_pid = sys_child_open_for_uncompress (); | |||
483 | read_full_records = true1; | |||
484 | } | |||
485 | ||||
486 | records_read = 0; | |||
487 | record_end = record_start; /* set up for 1st record = # 0 */ | |||
488 | ||||
489 | return archive; | |||
490 | } | |||
491 | ||||
492 | static int | |||
493 | print_stats (FILE *fp, const char *text, tarlong numbytes) | |||
494 | { | |||
495 | char abbr[LONGEST_HUMAN_READABLE((2 * sizeof (uintmax_t) * 8 * 146 / 485 + 1) * (16 + 1) - 16 + 1 + 3) + 1]; | |||
496 | char rate[LONGEST_HUMAN_READABLE((2 * sizeof (uintmax_t) * 8 * 146 / 485 + 1) * (16 + 1) - 16 + 1 + 3) + 1]; | |||
497 | int n = 0; | |||
498 | ||||
499 | int human_opts = human_autoscale | human_base_1024 | human_SI | human_B; | |||
500 | ||||
501 | if (text && text[0]) | |||
502 | n += fprintf (fp, "%s: ", gettext (text))__fprintf_chk (fp, 2 - 1, "%s: ", dcgettext (((void*)0), text , 5)); | |||
503 | return n + fprintf (fp, TARLONG_FORMAT " (%s, %s/s)",__fprintf_chk (fp, 2 - 1, "%.0f" " (%s, %s/s)", numbytes, human_readable (numbytes, abbr, human_opts, 1, 1), (0 < duration && numbytes / duration < (uintmax_t) -1 ? human_readable (numbytes / duration, rate, human_opts, 1, 1) : "?")) | |||
504 | numbytes,__fprintf_chk (fp, 2 - 1, "%.0f" " (%s, %s/s)", numbytes, human_readable (numbytes, abbr, human_opts, 1, 1), (0 < duration && numbytes / duration < (uintmax_t) -1 ? human_readable (numbytes / duration, rate, human_opts, 1, 1) : "?")) | |||
505 | human_readable (numbytes, abbr, human_opts, 1, 1),__fprintf_chk (fp, 2 - 1, "%.0f" " (%s, %s/s)", numbytes, human_readable (numbytes, abbr, human_opts, 1, 1), (0 < duration && numbytes / duration < (uintmax_t) -1 ? human_readable (numbytes / duration, rate, human_opts, 1, 1) : "?")) | |||
506 | (0 < duration && numbytes / duration < (uintmax_t) -1__fprintf_chk (fp, 2 - 1, "%.0f" " (%s, %s/s)", numbytes, human_readable (numbytes, abbr, human_opts, 1, 1), (0 < duration && numbytes / duration < (uintmax_t) -1 ? human_readable (numbytes / duration, rate, human_opts, 1, 1) : "?")) | |||
507 | ? human_readable (numbytes / duration, rate, human_opts, 1, 1)__fprintf_chk (fp, 2 - 1, "%.0f" " (%s, %s/s)", numbytes, human_readable (numbytes, abbr, human_opts, 1, 1), (0 < duration && numbytes / duration < (uintmax_t) -1 ? human_readable (numbytes / duration, rate, human_opts, 1, 1) : "?")) | |||
508 | : "?"))__fprintf_chk (fp, 2 - 1, "%.0f" " (%s, %s/s)", numbytes, human_readable (numbytes, abbr, human_opts, 1, 1), (0 < duration && numbytes / duration < (uintmax_t) -1 ? human_readable (numbytes / duration, rate, human_opts, 1, 1) : "?")); | |||
509 | } | |||
510 | ||||
511 | /* Format totals to file FP. FORMATS is an array of strings to output | |||
512 | before each data item (bytes read, written, deleted, in that order). | |||
513 | EOR is a delimiter to output after each item (used only if deleting | |||
514 | from the archive), EOL is a delimiter to add at the end of the output | |||
515 | line. */ | |||
516 | int | |||
517 | format_total_stats (FILE *fp, const char **formats, int eor, int eol) | |||
518 | { | |||
519 | int n; | |||
520 | ||||
521 | switch (subcommand_option) | |||
522 | { | |||
523 | case CREATE_SUBCOMMAND: | |||
524 | case CAT_SUBCOMMAND: | |||
525 | case UPDATE_SUBCOMMAND: | |||
526 | case APPEND_SUBCOMMAND: | |||
527 | n = print_stats (fp, formats[TF_WRITE1], | |||
528 | prev_written + bytes_written); | |||
529 | break; | |||
530 | ||||
531 | case DELETE_SUBCOMMAND: | |||
532 | { | |||
533 | char buf[UINTMAX_STRSIZE_BOUND(((((sizeof (uintmax_t) * 8 - (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) * 146 + 484) / 485) + (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) + 1)]; | |||
534 | n = print_stats (fp, formats[TF_READ0], | |||
535 | records_read * record_size); | |||
536 | ||||
537 | fputc (eor, fp)fputc_unlocked (eor,fp); | |||
538 | n++; | |||
539 | ||||
540 | n += print_stats (fp, formats[TF_WRITE1], | |||
541 | prev_written + bytes_written); | |||
542 | ||||
543 | fputc (eor, fp)fputc_unlocked (eor,fp); | |||
544 | n++; | |||
545 | ||||
546 | if (formats[TF_DELETED2] && formats[TF_DELETED2][0]) | |||
547 | n += fprintf (fp, "%s: ", gettext (formats[TF_DELETED]))__fprintf_chk (fp, 2 - 1, "%s: ", dcgettext (((void*)0), formats [2], 5)); | |||
548 | n += fprintf (fp, "%s",__fprintf_chk (fp, 2 - 1, "%s", umaxtostr ((records_read - records_skipped ) * record_size - (prev_written + bytes_written), buf)) | |||
549 | STRINGIFY_BIGINT ((records_read - records_skipped)__fprintf_chk (fp, 2 - 1, "%s", umaxtostr ((records_read - records_skipped ) * record_size - (prev_written + bytes_written), buf)) | |||
550 | * record_size__fprintf_chk (fp, 2 - 1, "%s", umaxtostr ((records_read - records_skipped ) * record_size - (prev_written + bytes_written), buf)) | |||
551 | - (prev_written + bytes_written), buf))__fprintf_chk (fp, 2 - 1, "%s", umaxtostr ((records_read - records_skipped ) * record_size - (prev_written + bytes_written), buf)); | |||
552 | } | |||
553 | break; | |||
554 | ||||
555 | case EXTRACT_SUBCOMMAND: | |||
556 | case LIST_SUBCOMMAND: | |||
557 | case DIFF_SUBCOMMAND: | |||
558 | n = print_stats (fp, _(formats[TF_READ])dcgettext (((void*)0), formats[0], 5), | |||
559 | records_read * record_size); | |||
560 | break; | |||
561 | ||||
562 | default: | |||
563 | abort (); | |||
564 | } | |||
565 | if (eol) | |||
566 | { | |||
567 | fputc (eol, fp)fputc_unlocked (eol,fp); | |||
568 | n++; | |||
569 | } | |||
570 | return n; | |||
571 | } | |||
572 | ||||
573 | const char *default_total_format[] = { | |||
574 | N_("Total bytes read")"Total bytes read", | |||
575 | /* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*". */ | |||
576 | N_("Total bytes written")"Total bytes written", | |||
577 | N_("Total bytes deleted")"Total bytes deleted" | |||
578 | }; | |||
579 | ||||
580 | void | |||
581 | print_total_stats (void) | |||
582 | { | |||
583 | format_total_stats (stderrstderr, default_total_format, '\n', '\n'); | |||
584 | } | |||
585 | ||||
586 | /* Compute and return the block ordinal at current_block. */ | |||
587 | off_t | |||
588 | current_block_ordinal (void) | |||
589 | { | |||
590 | return record_start_block + (current_block - record_start); | |||
591 | } | |||
592 | ||||
593 | /* If the EOF flag is set, reset it, as well as current_block, etc. */ | |||
594 | void | |||
595 | reset_eof (void) | |||
596 | { | |||
597 | if (hit_eof) | |||
598 | { | |||
599 | hit_eof = false0; | |||
600 | current_block = record_start; | |||
601 | record_end = record_start + blocking_factor; | |||
602 | access_mode = ACCESS_WRITE; | |||
603 | } | |||
604 | } | |||
605 | ||||
606 | /* Return the location of the next available input or output block. | |||
607 | Return zero for EOF. Once we have returned zero, we just keep returning | |||
608 | it, to avoid accidentally going on to the next file on the tape. */ | |||
609 | union block * | |||
610 | find_next_block (void) | |||
611 | { | |||
612 | if (current_block == record_end) | |||
613 | { | |||
614 | if (hit_eof) | |||
615 | return 0; | |||
616 | flush_archive (); | |||
617 | if (current_block == record_end) | |||
618 | { | |||
619 | hit_eof = true1; | |||
620 | return 0; | |||
621 | } | |||
622 | } | |||
623 | return current_block; | |||
624 | } | |||
625 | ||||
626 | /* Indicate that we have used all blocks up thru BLOCK. */ | |||
627 | void | |||
628 | set_next_block_after (union block *block) | |||
629 | { | |||
630 | while (block >= current_block) | |||
631 | current_block++; | |||
632 | ||||
633 | /* Do *not* flush the archive here. If we do, the same argument to | |||
634 | set_next_block_after could mean the next block (if the input record | |||
635 | is exactly one block long), which is not what is intended. */ | |||
636 | ||||
637 | if (current_block > record_end) | |||
638 | abort (); | |||
639 | } | |||
640 | ||||
641 | /* Return the number of bytes comprising the space between POINTER | |||
642 | through the end of the current buffer of blocks. This space is | |||
643 | available for filling with data, or taking data from. POINTER is | |||
644 | usually (but not always) the result of previous find_next_block call. */ | |||
645 | size_t | |||
646 | available_space_after (union block *pointer) | |||
647 | { | |||
648 | return record_end->buffer - pointer->buffer; | |||
649 | } | |||
650 | ||||
651 | /* Close file having descriptor FD, and abort if close unsuccessful. */ | |||
652 | void | |||
653 | xclose (int fd) | |||
654 | { | |||
655 | if (close (fd) != 0) | |||
656 | close_error (_("(pipe)")dcgettext (((void*)0), "(pipe)", 5)); | |||
657 | } | |||
658 | ||||
659 | static void | |||
660 | init_buffer (void) | |||
661 | { | |||
662 | if (! record_buffer_aligned[record_index]) | |||
663 | record_buffer_aligned[record_index] = | |||
664 | page_aligned_alloc (&record_buffer[record_index], record_size); | |||
665 | ||||
666 | record_start = record_buffer_aligned[record_index]; | |||
667 | current_block = record_start; | |||
668 | record_end = record_start + blocking_factor; | |||
669 | } | |||
670 | ||||
671 | static void | |||
672 | check_tty (enum access_mode mode) | |||
673 | { | |||
674 | /* Refuse to read archive from and write it to a tty. */ | |||
675 | if (strcmp (archive_name_array[0], "-") == 0 | |||
676 | && isatty (mode == ACCESS_READ ? STDIN_FILENO0 : STDOUT_FILENO1)) | |||
677 | { | |||
678 | FATAL_ERROR ((0, 0,do { if (error_hook) error_hook (); error (0, 0, mode == ACCESS_READ ? dcgettext (((void*)0), "Refusing to read archive contents from terminal " "(missing -f option?)", 5) : dcgettext (((void*)0), "Refusing to write archive contents to terminal " "(missing -f option?)", 5)); fatal_exit (); } while (0) | |||
679 | mode == ACCESS_READdo { if (error_hook) error_hook (); error (0, 0, mode == ACCESS_READ ? dcgettext (((void*)0), "Refusing to read archive contents from terminal " "(missing -f option?)", 5) : dcgettext (((void*)0), "Refusing to write archive contents to terminal " "(missing -f option?)", 5)); fatal_exit (); } while (0) | |||
680 | ? _("Refusing to read archive contents from terminal "do { if (error_hook) error_hook (); error (0, 0, mode == ACCESS_READ ? dcgettext (((void*)0), "Refusing to read archive contents from terminal " "(missing -f option?)", 5) : dcgettext (((void*)0), "Refusing to write archive contents to terminal " "(missing -f option?)", 5)); fatal_exit (); } while (0) | |||
681 | "(missing -f option?)")do { if (error_hook) error_hook (); error (0, 0, mode == ACCESS_READ ? dcgettext (((void*)0), "Refusing to read archive contents from terminal " "(missing -f option?)", 5) : dcgettext (((void*)0), "Refusing to write archive contents to terminal " "(missing -f option?)", 5)); fatal_exit (); } while (0) | |||
682 | : _("Refusing to write archive contents to terminal "do { if (error_hook) error_hook (); error (0, 0, mode == ACCESS_READ ? dcgettext (((void*)0), "Refusing to read archive contents from terminal " "(missing -f option?)", 5) : dcgettext (((void*)0), "Refusing to write archive contents to terminal " "(missing -f option?)", 5)); fatal_exit (); } while (0) | |||
683 | "(missing -f option?)")))do { if (error_hook) error_hook (); error (0, 0, mode == ACCESS_READ ? dcgettext (((void*)0), "Refusing to read archive contents from terminal " "(missing -f option?)", 5) : dcgettext (((void*)0), "Refusing to write archive contents to terminal " "(missing -f option?)", 5)); fatal_exit (); } while (0); | |||
684 | } | |||
685 | } | |||
686 | ||||
687 | /* Open an archive file. The argument specifies whether we are | |||
688 | reading or writing, or both. */ | |||
689 | static void | |||
690 | _open_archive (enum access_mode wanted_access) | |||
691 | { | |||
692 | int backed_up_flag = 0; | |||
693 | ||||
694 | if (record_size == 0) | |||
695 | FATAL_ERROR ((0, 0, _("Invalid value for record_size")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Invalid value for record_size", 5)); fatal_exit ( ); } while (0); | |||
696 | ||||
697 | if (archive_names == 0) | |||
698 | FATAL_ERROR ((0, 0, _("No archive name given")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "No archive name given", 5)); fatal_exit (); } while (0); | |||
699 | ||||
700 | tar_stat_destroy (¤t_stat_info); | |||
701 | ||||
702 | record_index = 0; | |||
703 | init_buffer (); | |||
704 | ||||
705 | /* When updating the archive, we start with reading. */ | |||
706 | access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access; | |||
707 | check_tty (access_mode); | |||
708 | ||||
709 | read_full_records = read_full_records_option; | |||
710 | ||||
711 | records_read = 0; | |||
712 | ||||
713 | if (use_compress_program_option) | |||
714 | { | |||
715 | switch (wanted_access) | |||
716 | { | |||
717 | case ACCESS_READ: | |||
718 | child_pid = sys_child_open_for_uncompress (); | |||
719 | read_full_records = true1; | |||
720 | record_end = record_start; /* set up for 1st record = # 0 */ | |||
721 | break; | |||
722 | ||||
723 | case ACCESS_WRITE: | |||
724 | child_pid = sys_child_open_for_compress (); | |||
725 | break; | |||
726 | ||||
727 | case ACCESS_UPDATE: | |||
728 | abort (); /* Should not happen */ | |||
729 | break; | |||
730 | } | |||
731 | ||||
732 | if (!index_file_name | |||
733 | && wanted_access == ACCESS_WRITE | |||
734 | && strcmp (archive_name_array[0], "-") == 0) | |||
735 | stdlis = stderrstderr; | |||
736 | } | |||
737 | else if (strcmp (archive_name_array[0], "-") == 0) | |||
738 | { | |||
739 | read_full_records = true1; /* could be a pipe, be safe */ | |||
740 | if (verify_option) | |||
741 | FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Cannot verify stdin/stdout archive", 5)); fatal_exit (); } while (0); | |||
742 | ||||
743 | switch (wanted_access) | |||
744 | { | |||
745 | case ACCESS_READ: | |||
746 | { | |||
747 | bool_Bool shortfile; | |||
748 | enum compress_type type; | |||
749 | ||||
750 | archive = STDIN_FILENO0; | |||
751 | type = check_compressed_archive (&shortfile); | |||
752 | if (type != ct_tar && type != ct_none) | |||
753 | FATAL_ERROR ((0, 0,do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Archive is compressed. Use %s option", 5), compress_option (type)); fatal_exit (); } while (0) | |||
754 | _("Archive is compressed. Use %s option"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Archive is compressed. Use %s option", 5), compress_option (type)); fatal_exit (); } while (0) | |||
755 | compress_option (type)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Archive is compressed. Use %s option", 5), compress_option (type)); fatal_exit (); } while (0); | |||
756 | if (shortfile) | |||
757 | ERROR ((0, 0, _("This does not look like a tar archive")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This does not look like a tar archive", 5)); exit_status = 2; } while (0); | |||
758 | } | |||
759 | break; | |||
760 | ||||
761 | case ACCESS_WRITE: | |||
762 | archive = STDOUT_FILENO1; | |||
763 | if (!index_file_name) | |||
764 | stdlis = stderrstderr; | |||
765 | break; | |||
766 | ||||
767 | case ACCESS_UPDATE: | |||
768 | archive = STDIN_FILENO0; | |||
769 | write_archive_to_stdout = true1; | |||
770 | record_end = record_start; /* set up for 1st record = # 0 */ | |||
771 | if (!index_file_name) | |||
772 | stdlis = stderrstderr; | |||
773 | break; | |||
774 | } | |||
775 | } | |||
776 | else | |||
777 | switch (wanted_access) | |||
778 | { | |||
779 | case ACCESS_READ: | |||
780 | archive = open_compressed_archive (); | |||
781 | if (archive >= 0) | |||
782 | guess_seekable_archive (); | |||
783 | break; | |||
784 | ||||
785 | case ACCESS_WRITE: | |||
786 | if (backup_option) | |||
787 | { | |||
788 | maybe_backup_file (archive_name_array[0], 1); | |||
789 | backed_up_flag = 1; | |||
790 | } | |||
791 | if (verify_option) | |||
792 | archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,((!force_local_option && (rmt_dev_name__ = strchr (archive_name_array [0], ':')) && rmt_dev_name__ > (archive_name_array [0]) && ! memchr (archive_name_array[0], '/', rmt_dev_name__ - (archive_name_array[0]))) ? rmt_open__ (archive_name_array [0], 02 | 0100 | 0, (1 << 30), rsh_command_option) : open (archive_name_array[0], 02 | 0100 | 0, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))) | |||
793 | MODE_RW, rsh_command_option)((!force_local_option && (rmt_dev_name__ = strchr (archive_name_array [0], ':')) && rmt_dev_name__ > (archive_name_array [0]) && ! memchr (archive_name_array[0], '/', rmt_dev_name__ - (archive_name_array[0]))) ? rmt_open__ (archive_name_array [0], 02 | 0100 | 0, (1 << 30), rsh_command_option) : open (archive_name_array[0], 02 | 0100 | 0, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))); | |||
794 | else | |||
795 | archive = rmtcreat (archive_name_array[0], MODE_RW,((!force_local_option && (rmt_dev_name__ = strchr (archive_name_array [0], ':')) && rmt_dev_name__ > (archive_name_array [0]) && ! memchr (archive_name_array[0], '/', rmt_dev_name__ - (archive_name_array[0]))) ? rmt_open__ (archive_name_array [0], 0100 | 01, (1 << 30), rsh_command_option) : creat ( archive_name_array[0], (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))) | |||
796 | rsh_command_option)((!force_local_option && (rmt_dev_name__ = strchr (archive_name_array [0], ':')) && rmt_dev_name__ > (archive_name_array [0]) && ! memchr (archive_name_array[0], '/', rmt_dev_name__ - (archive_name_array[0]))) ? rmt_open__ (archive_name_array [0], 0100 | 01, (1 << 30), rsh_command_option) : creat ( archive_name_array[0], (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))); | |||
797 | break; | |||
798 | ||||
799 | case ACCESS_UPDATE: | |||
800 | archive = rmtopen (archive_name_array[0],((!force_local_option && (rmt_dev_name__ = strchr (archive_name_array [0], ':')) && rmt_dev_name__ > (archive_name_array [0]) && ! memchr (archive_name_array[0], '/', rmt_dev_name__ - (archive_name_array[0]))) ? rmt_open__ (archive_name_array [0], 02 | 0100 | 0, (1 << 30), rsh_command_option) : open (archive_name_array[0], 02 | 0100 | 0, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))) | |||
801 | O_RDWR | O_CREAT | O_BINARY,((!force_local_option && (rmt_dev_name__ = strchr (archive_name_array [0], ':')) && rmt_dev_name__ > (archive_name_array [0]) && ! memchr (archive_name_array[0], '/', rmt_dev_name__ - (archive_name_array[0]))) ? rmt_open__ (archive_name_array [0], 02 | 0100 | 0, (1 << 30), rsh_command_option) : open (archive_name_array[0], 02 | 0100 | 0, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))) | |||
802 | MODE_RW, rsh_command_option)((!force_local_option && (rmt_dev_name__ = strchr (archive_name_array [0], ':')) && rmt_dev_name__ > (archive_name_array [0]) && ! memchr (archive_name_array[0], '/', rmt_dev_name__ - (archive_name_array[0]))) ? rmt_open__ (archive_name_array [0], 02 | 0100 | 0, (1 << 30), rsh_command_option) : open (archive_name_array[0], 02 | 0100 | 0, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))); | |||
803 | ||||
804 | switch (check_compressed_archive (NULL((void*)0))) | |||
805 | { | |||
806 | case ct_none: | |||
807 | case ct_tar: | |||
808 | break; | |||
809 | ||||
810 | default: | |||
811 | FATAL_ERROR ((0, 0,do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Cannot update compressed archives", 5)); fatal_exit (); } while (0) | |||
812 | _("Cannot update compressed archives")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Cannot update compressed archives", 5)); fatal_exit (); } while (0); | |||
813 | } | |||
814 | break; | |||
815 | } | |||
816 | ||||
817 | if (archive < 0 | |||
818 | || (! _isrmt (archive)((archive) >= (1 << 30)) && !sys_get_archive_stat ())) | |||
819 | { | |||
820 | int saved_errno = errno(*__errno_location ()); | |||
821 | ||||
822 | if (backed_up_flag) | |||
823 | undo_last_backup (); | |||
824 | errno(*__errno_location ()) = saved_errno; | |||
825 | open_fatal (archive_name_array[0]); | |||
826 | } | |||
827 | ||||
828 | sys_detect_dev_null_output (); | |||
829 | sys_save_archive_dev_ino (); | |||
830 | SET_BINARY_MODE (archive); | |||
831 | ||||
832 | switch (wanted_access) | |||
833 | { | |||
834 | case ACCESS_READ: | |||
835 | find_next_block (); /* read it in, check for EOF */ | |||
836 | break; | |||
837 | ||||
838 | case ACCESS_UPDATE: | |||
839 | case ACCESS_WRITE: | |||
840 | records_written = 0; | |||
841 | break; | |||
842 | } | |||
843 | } | |||
844 | ||||
845 | /* Perform a write to flush the buffer. */ | |||
846 | static ssize_t | |||
847 | _flush_write (void) | |||
848 | { | |||
849 | ssize_t status; | |||
850 | ||||
851 | checkpoint_run (true1); | |||
852 | if (tape_length_option && tape_length_option <= bytes_written) | |||
853 | { | |||
854 | errno(*__errno_location ()) = ENOSPC28; | |||
855 | status = 0; | |||
856 | } | |||
857 | else if (dev_null_output) | |||
858 | status = record_size; | |||
859 | else | |||
860 | status = sys_write_archive_buffer (); | |||
861 | ||||
862 | if (status && multi_volume_option && !inhibit_map) | |||
863 | { | |||
864 | struct bufmap *map = bufmap_locate (status); | |||
865 | if (map) | |||
866 | { | |||
867 | size_t delta = status - map->start * BLOCKSIZE512; | |||
868 | if (delta > map->sizeleft) | |||
869 | delta = map->sizeleft; | |||
870 | map->sizeleft -= delta; | |||
871 | if (map->sizeleft == 0) | |||
872 | map = map->next; | |||
873 | bufmap_reset (map, map ? (- map->start) : 0); | |||
874 | } | |||
875 | } | |||
876 | return status; | |||
877 | } | |||
878 | ||||
879 | /* Handle write errors on the archive. Write errors are always fatal. | |||
880 | Hitting the end of a volume does not cause a write error unless the | |||
881 | write was the first record of the volume. */ | |||
882 | void | |||
883 | archive_write_error (ssize_t status) | |||
884 | { | |||
885 | /* It might be useful to know how much was written before the error | |||
886 | occurred. */ | |||
887 | if (totals_option) | |||
888 | { | |||
889 | int e = errno(*__errno_location ()); | |||
890 | print_total_stats (); | |||
891 | errno(*__errno_location ()) = e; | |||
892 | } | |||
893 | ||||
894 | write_fatal_details (*archive_name_cursor, status, record_size); | |||
895 | } | |||
896 | ||||
897 | /* Handle read errors on the archive. If the read should be retried, | |||
898 | return to the caller. */ | |||
899 | void | |||
900 | archive_read_error (void) | |||
901 | { | |||
902 | read_error (*archive_name_cursor); | |||
903 | ||||
904 | if (record_start_block == 0) | |||
905 | FATAL_ERROR ((0, 0, _("At beginning of tape, quitting now")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "At beginning of tape, quitting now", 5)); fatal_exit (); } while (0); | |||
906 | ||||
907 | /* Read error in mid archive. We retry up to READ_ERROR_MAX times and | |||
908 | then give up on reading the archive. */ | |||
909 | ||||
910 | if (read_error_count++ > READ_ERROR_MAX10) | |||
911 | FATAL_ERROR ((0, 0, _("Too many errors, quitting")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Too many errors, quitting", 5)); fatal_exit (); } while (0); | |||
912 | return; | |||
913 | } | |||
914 | ||||
915 | static bool_Bool | |||
916 | archive_is_dev (void) | |||
917 | { | |||
918 | struct stat st; | |||
919 | ||||
920 | if (fstat (archive, &st)) | |||
921 | { | |||
922 | stat_diag (*archive_name_cursor); | |||
923 | return false0; | |||
924 | } | |||
925 | return S_ISBLK (st.st_mode)((((st.st_mode)) & 0170000) == (0060000)) || S_ISCHR (st.st_mode)((((st.st_mode)) & 0170000) == (0020000)); | |||
926 | } | |||
927 | ||||
928 | static void | |||
929 | short_read (size_t status) | |||
930 | { | |||
931 | size_t left; /* bytes left */ | |||
932 | char *more; /* pointer to next byte to read */ | |||
933 | ||||
934 | more = record_start->buffer + status; | |||
935 | left = record_size - status; | |||
936 | ||||
937 | if (left && left % BLOCKSIZE512 == 0 | |||
938 | && (warning_option & WARN_RECORD_SIZE0x00400000) | |||
939 | && record_start_block == 0 && status != 0 | |||
940 | && archive_is_dev ()) | |||
941 | { | |||
942 | unsigned long rsize = status / BLOCKSIZE512; | |||
943 | WARN ((0, 0,do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Record size = %lu block", "Record size = %lu blocks" , rsize, 5), rsize); } while (0) | |||
944 | ngettext ("Record size = %lu block",do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Record size = %lu block", "Record size = %lu blocks" , rsize, 5), rsize); } while (0) | |||
945 | "Record size = %lu blocks",do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Record size = %lu block", "Record size = %lu blocks" , rsize, 5), rsize); } while (0) | |||
946 | rsize),do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Record size = %lu block", "Record size = %lu blocks" , rsize, 5), rsize); } while (0) | |||
947 | rsize))do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Record size = %lu block", "Record size = %lu blocks" , rsize, 5), rsize); } while (0); | |||
948 | } | |||
949 | ||||
950 | while (left % BLOCKSIZE512 != 0 | |||
951 | || (left && status && read_full_records)) | |||
952 | { | |||
953 | if (status) | |||
954 | while ((status = rmtread (archive, more, left)(((archive) >= (1 << 30)) ? rmt_read__ (archive - (1 << 30), more, left) : safe_read (archive, more, left))) == SAFE_READ_ERROR((size_t) -1)) | |||
955 | archive_read_error (); | |||
956 | ||||
957 | if (status == 0) | |||
958 | break; | |||
959 | ||||
960 | if (! read_full_records) | |||
961 | { | |||
962 | unsigned long rest = record_size - left; | |||
963 | ||||
964 | FATAL_ERROR ((0, 0,do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Unaligned block (%lu byte) in archive", "Unaligned block (%lu bytes) in archive" , rest, 5), rest); fatal_exit (); } while (0) | |||
965 | ngettext ("Unaligned block (%lu byte) in archive",do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Unaligned block (%lu byte) in archive", "Unaligned block (%lu bytes) in archive" , rest, 5), rest); fatal_exit (); } while (0) | |||
966 | "Unaligned block (%lu bytes) in archive",do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Unaligned block (%lu byte) in archive", "Unaligned block (%lu bytes) in archive" , rest, 5), rest); fatal_exit (); } while (0) | |||
967 | rest),do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Unaligned block (%lu byte) in archive", "Unaligned block (%lu bytes) in archive" , rest, 5), rest); fatal_exit (); } while (0) | |||
968 | rest))do { if (error_hook) error_hook (); error (0, 0, dcngettext ( ((void*)0), "Unaligned block (%lu byte) in archive", "Unaligned block (%lu bytes) in archive" , rest, 5), rest); fatal_exit (); } while (0); | |||
969 | } | |||
970 | ||||
971 | left -= status; | |||
972 | more += status; | |||
973 | } | |||
974 | ||||
975 | record_end = record_start + (record_size - left) / BLOCKSIZE512; | |||
976 | records_read++; | |||
977 | } | |||
978 | ||||
979 | /* Flush the current buffer to/from the archive. */ | |||
980 | void | |||
981 | flush_archive (void) | |||
982 | { | |||
983 | size_t buffer_level = current_block->buffer - record_start->buffer; | |||
984 | record_start_block += record_end - record_start; | |||
985 | current_block = record_start; | |||
986 | record_end = record_start + blocking_factor; | |||
987 | ||||
988 | if (access_mode == ACCESS_READ && time_to_start_writing) | |||
989 | { | |||
990 | access_mode = ACCESS_WRITE; | |||
991 | time_to_start_writing = false0; | |||
992 | backspace_output (); | |||
993 | } | |||
994 | ||||
995 | switch (access_mode) | |||
996 | { | |||
997 | case ACCESS_READ: | |||
998 | flush_read (); | |||
999 | break; | |||
1000 | ||||
1001 | case ACCESS_WRITE: | |||
1002 | flush_write_ptr (buffer_level); | |||
1003 | break; | |||
1004 | ||||
1005 | case ACCESS_UPDATE: | |||
1006 | abort (); | |||
1007 | } | |||
1008 | } | |||
1009 | ||||
1010 | /* Backspace the archive descriptor by one record worth. If it's a | |||
1011 | tape, MTIOCTOP will work. If it's something else, try to seek on | |||
1012 | it. If we can't seek, we lose! */ | |||
1013 | static void | |||
1014 | backspace_output (void) | |||
1015 | { | |||
1016 | #ifdef MTIOCTOP(((1U) << (((0 +8)+8)+14)) | ((('m')) << (0 +8)) | (((1)) << 0) | ((((sizeof(struct mtop)))) << ((0 +8)+8))) | |||
1017 | { | |||
1018 | struct mtop operation; | |||
1019 | ||||
1020 | operation.mt_op = MTBSR4; | |||
1021 | operation.mt_count = 1; | |||
1022 | if (rmtioctl (archive, MTIOCTOP, (char *) &operation)(((archive) >= (1 << 30)) ? rmt_ioctl__ (archive - ( 1 << 30), (((1U) << (((0 +8)+8)+14)) | ((('m')) << (0 +8)) | (((1)) << 0) | ((((sizeof(struct mtop)))) << ((0 +8)+8))), (char *) &operation) : ioctl (archive, ((( 1U) << (((0 +8)+8)+14)) | ((('m')) << (0 +8)) | ( ((1)) << 0) | ((((sizeof(struct mtop)))) << ((0 + 8)+8))), (char *) &operation)) >= 0) | |||
1023 | return; | |||
1024 | if (errno(*__errno_location ()) == EIO5 && rmtioctl (archive, MTIOCTOP, (char *) &operation)(((archive) >= (1 << 30)) ? rmt_ioctl__ (archive - ( 1 << 30), (((1U) << (((0 +8)+8)+14)) | ((('m')) << (0 +8)) | (((1)) << 0) | ((((sizeof(struct mtop)))) << ((0 +8)+8))), (char *) &operation) : ioctl (archive, ((( 1U) << (((0 +8)+8)+14)) | ((('m')) << (0 +8)) | ( ((1)) << 0) | ((((sizeof(struct mtop)))) << ((0 + 8)+8))), (char *) &operation)) >= 0) | |||
1025 | return; | |||
1026 | } | |||
1027 | #endif | |||
1028 | ||||
1029 | { | |||
1030 | off_t position = rmtlseek (archive, (off_t) 0, SEEK_CUR)(((archive) >= (1 << 30)) ? rmt_lseek__ (archive - ( 1 << 30), (off_t) 0, 1) : lseek (archive, (off_t) 0, 1) ); | |||
1031 | ||||
1032 | /* Seek back to the beginning of this record and start writing there. */ | |||
1033 | ||||
1034 | position -= record_size; | |||
1035 | if (position < 0) | |||
1036 | position = 0; | |||
1037 | if (rmtlseek (archive, position, SEEK_SET)(((archive) >= (1 << 30)) ? rmt_lseek__ (archive - ( 1 << 30), position, 0) : lseek (archive, position, 0)) != position) | |||
1038 | { | |||
1039 | /* Lseek failed. Try a different method. */ | |||
1040 | ||||
1041 | WARN ((0, 0,do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Cannot backspace archive file; it may be unreadable without -i" , 5)); } while (0) | |||
1042 | _("Cannot backspace archive file; it may be unreadable without -i")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Cannot backspace archive file; it may be unreadable without -i" , 5)); } while (0); | |||
1043 | ||||
1044 | /* Replace the first part of the record with NULs. */ | |||
1045 | ||||
1046 | if (record_start->buffer != output_start) | |||
1047 | memset (record_start->buffer, 0, | |||
1048 | output_start - record_start->buffer); | |||
1049 | } | |||
1050 | } | |||
1051 | } | |||
1052 | ||||
1053 | off_t | |||
1054 | seek_archive (off_t size) | |||
1055 | { | |||
1056 | off_t start = current_block_ordinal (); | |||
1057 | off_t offset; | |||
1058 | off_t nrec, nblk; | |||
1059 | off_t skipped = (blocking_factor - (current_block - record_start)) | |||
1060 | * BLOCKSIZE512; | |||
1061 | ||||
1062 | if (size <= skipped) | |||
1063 | return 0; | |||
1064 | ||||
1065 | /* Compute number of records to skip */ | |||
1066 | nrec = (size - skipped) / record_size; | |||
1067 | if (nrec == 0) | |||
1068 | return 0; | |||
1069 | offset = rmtlseek (archive, nrec * record_size, SEEK_CUR)(((archive) >= (1 << 30)) ? rmt_lseek__ (archive - ( 1 << 30), nrec * record_size, 1) : lseek (archive, nrec * record_size, 1)); | |||
1070 | if (offset < 0) | |||
1071 | return offset; | |||
1072 | ||||
1073 | if (offset % record_size) | |||
1074 | FATAL_ERROR ((0, 0, _("rmtlseek not stopped at a record boundary")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "rmtlseek not stopped at a record boundary", 5)); fatal_exit (); } while (0); | |||
1075 | ||||
1076 | /* Convert to number of records */ | |||
1077 | offset /= BLOCKSIZE512; | |||
1078 | /* Compute number of skipped blocks */ | |||
1079 | nblk = offset - start; | |||
1080 | ||||
1081 | /* Update buffering info */ | |||
1082 | records_read += nblk / blocking_factor; | |||
1083 | record_start_block = offset - blocking_factor; | |||
1084 | current_block = record_end; | |||
1085 | ||||
1086 | return nblk; | |||
1087 | } | |||
1088 | ||||
1089 | /* Close the archive file. */ | |||
1090 | void | |||
1091 | close_archive (void) | |||
1092 | { | |||
1093 | if (time_to_start_writing || access_mode == ACCESS_WRITE) | |||
1094 | { | |||
1095 | flush_archive (); | |||
1096 | if (current_block > record_start) | |||
1097 | flush_archive (); | |||
1098 | } | |||
1099 | ||||
1100 | compute_duration (); | |||
1101 | if (verify_option) | |||
1102 | verify_volume (); | |||
1103 | ||||
1104 | if (rmtclose (archive)(((archive) >= (1 << 30)) ? rmt_close__ (archive - ( 1 << 30)) : close (archive)) != 0) | |||
1105 | close_error (*archive_name_cursor); | |||
1106 | ||||
1107 | sys_wait_for_child (child_pid, hit_eof); | |||
1108 | ||||
1109 | tar_stat_destroy (¤t_stat_info); | |||
1110 | free (record_buffer[0]); | |||
1111 | free (record_buffer[1]); | |||
1112 | bufmap_free (NULL((void*)0)); | |||
1113 | } | |||
1114 | ||||
1115 | /* Called to initialize the global volume number. */ | |||
1116 | void | |||
1117 | init_volume_number (void) | |||
1118 | { | |||
1119 | FILE *file = fopen (volno_file_option, "r"); | |||
1120 | ||||
1121 | if (file) | |||
1122 | { | |||
1123 | if (fscanf (file, "%d", &global_volno) != 1 | |||
1124 | || global_volno < 0) | |||
1125 | FATAL_ERROR ((0, 0, _("%s: contains invalid volume number"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s: contains invalid volume number", 5), quotearg_colon (volno_file_option)); fatal_exit (); } while (0) | |||
1126 | quotearg_colon (volno_file_option)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s: contains invalid volume number", 5), quotearg_colon (volno_file_option)); fatal_exit (); } while (0); | |||
1127 | if (ferror (file)ferror_unlocked (file)) | |||
1128 | read_error (volno_file_option); | |||
1129 | if (fclose (file) != 0) | |||
1130 | close_error (volno_file_option); | |||
1131 | } | |||
1132 | else if (errno(*__errno_location ()) != ENOENT2) | |||
1133 | open_error (volno_file_option); | |||
1134 | } | |||
1135 | ||||
1136 | /* Called to write out the closing global volume number. */ | |||
1137 | void | |||
1138 | closeout_volume_number (void) | |||
1139 | { | |||
1140 | FILE *file = fopen (volno_file_option, "w"); | |||
1141 | ||||
1142 | if (file) | |||
1143 | { | |||
1144 | fprintf (file, "%d\n", global_volno)__fprintf_chk (file, 2 - 1, "%d\n", global_volno); | |||
1145 | if (ferror (file)ferror_unlocked (file)) | |||
1146 | write_error (volno_file_option); | |||
1147 | if (fclose (file) != 0) | |||
1148 | close_error (volno_file_option); | |||
1149 | } | |||
1150 | else | |||
1151 | open_error (volno_file_option); | |||
1152 | } | |||
1153 | ||||
1154 | ||||
1155 | static void | |||
1156 | increase_volume_number (void) | |||
1157 | { | |||
1158 | global_volno++; | |||
1159 | if (global_volno < 0) | |||
1160 | FATAL_ERROR ((0, 0, _("Volume number overflow")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Volume number overflow", 5)); fatal_exit (); } while (0); | |||
1161 | volno++; | |||
1162 | } | |||
1163 | ||||
1164 | static void | |||
1165 | change_tape_menu (FILE *read_file) | |||
1166 | { | |||
1167 | char *input_buffer = NULL((void*)0); | |||
1168 | size_t size = 0; | |||
1169 | bool_Bool stop = false0; | |||
1170 | ||||
1171 | while (!stop) | |||
1172 | { | |||
1173 | fputc ('\007', stderr)fputc_unlocked ('\007',stderr); | |||
1174 | fprintf (stderr,__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), "Prepare volume #%d for %s and hit return: " , 5), global_volno + 1, quote (*archive_name_cursor)) | |||
1175 | _("Prepare volume #%d for %s and hit return: "),__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), "Prepare volume #%d for %s and hit return: " , 5), global_volno + 1, quote (*archive_name_cursor)) | |||
1176 | global_volno + 1, quote (*archive_name_cursor))__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), "Prepare volume #%d for %s and hit return: " , 5), global_volno + 1, quote (*archive_name_cursor)); | |||
1177 | fflush (stderr)fflush_unlocked (stderr); | |||
1178 | ||||
1179 | if (getline (&input_buffer, &size, read_file) <= 0) | |||
1180 | { | |||
1181 | WARN ((0, 0, _("EOF where user reply was expected")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "EOF where user reply was expected", 5)); } while ( 0); | |||
1182 | ||||
1183 | if (subcommand_option != EXTRACT_SUBCOMMAND | |||
1184 | && subcommand_option != LIST_SUBCOMMAND | |||
1185 | && subcommand_option != DIFF_SUBCOMMAND) | |||
1186 | WARN ((0, 0, _("WARNING: Archive is incomplete")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "WARNING: Archive is incomplete", 5)); } while (0); | |||
1187 | ||||
1188 | fatal_exit (); | |||
1189 | } | |||
1190 | ||||
1191 | if (input_buffer[0] == '\n' | |||
1192 | || input_buffer[0] == 'y' | |||
1193 | || input_buffer[0] == 'Y') | |||
1194 | break; | |||
1195 | ||||
1196 | switch (input_buffer[0]) | |||
1197 | { | |||
1198 | case '?': | |||
1199 | { | |||
1200 | fprintf (stderr, _("\__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), " 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" , 5)) | |||
1201 | n name Give a new file name for the next (and subsequent) volume(s)\n\__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), " 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" , 5)) | |||
1202 | q Abort tar\n\__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), " 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" , 5)) | |||
1203 | y or newline Continue operation\n"))__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), " 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" , 5)); | |||
1204 | if (!restrict_option) | |||
1205 | fprintf (stderr, _(" ! Spawn a subshell\n"))__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), " ! Spawn a subshell\n" , 5)); | |||
1206 | fprintf (stderr, _(" ? Print this list\n"))__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), " ? Print this list\n" , 5)); | |||
1207 | } | |||
1208 | break; | |||
1209 | ||||
1210 | case 'q': | |||
1211 | /* Quit. */ | |||
1212 | ||||
1213 | WARN ((0, 0, _("No new volume; exiting.\n")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "No new volume; exiting.\n", 5)); } while (0); | |||
1214 | ||||
1215 | if (subcommand_option != EXTRACT_SUBCOMMAND | |||
1216 | && subcommand_option != LIST_SUBCOMMAND | |||
1217 | && subcommand_option != DIFF_SUBCOMMAND) | |||
1218 | WARN ((0, 0, _("WARNING: Archive is incomplete")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "WARNING: Archive is incomplete", 5)); } while (0); | |||
1219 | ||||
1220 | fatal_exit (); | |||
1221 | ||||
1222 | case 'n': | |||
1223 | /* Get new file name. */ | |||
1224 | ||||
1225 | { | |||
1226 | char *name; | |||
1227 | char *cursor; | |||
1228 | ||||
1229 | for (name = input_buffer + 1; | |||
1230 | *name == ' ' || *name == '\t'; | |||
1231 | name++) | |||
1232 | ; | |||
1233 | ||||
1234 | for (cursor = name; *cursor && *cursor != '\n'; cursor++) | |||
1235 | ; | |||
1236 | *cursor = '\0'; | |||
1237 | ||||
1238 | if (name[0]) | |||
1239 | { | |||
1240 | /* FIXME: the following allocation is never reclaimed. */ | |||
1241 | *archive_name_cursor = xstrdup (name); | |||
1242 | stop = true1; | |||
1243 | } | |||
1244 | else | |||
1245 | fprintf (stderr, "%s",__fprintf_chk (stderr, 2 - 1, "%s", dcgettext (((void*)0), "File name not specified. Try again.\n" , 5)) | |||
1246 | _("File name not specified. Try again.\n"))__fprintf_chk (stderr, 2 - 1, "%s", dcgettext (((void*)0), "File name not specified. Try again.\n" , 5)); | |||
1247 | } | |||
1248 | break; | |||
1249 | ||||
1250 | case '!': | |||
1251 | if (!restrict_option) | |||
1252 | { | |||
1253 | sys_spawn_shell (); | |||
1254 | break; | |||
1255 | } | |||
1256 | /* FALL THROUGH */ | |||
1257 | ||||
1258 | default: | |||
1259 | fprintf (stderr, _("Invalid input. Type ? for help.\n"))__fprintf_chk (stderr, 2 - 1, dcgettext (((void*)0), "Invalid input. Type ? for help.\n" , 5)); | |||
1260 | } | |||
1261 | } | |||
1262 | free (input_buffer); | |||
1263 | } | |||
1264 | ||||
1265 | /* We've hit the end of the old volume. Close it and open the next one. | |||
1266 | Return nonzero on success. | |||
1267 | */ | |||
1268 | static bool_Bool | |||
1269 | new_volume (enum access_mode mode) | |||
1270 | { | |||
1271 | static FILE *read_file; | |||
1272 | static int looped; | |||
1273 | int prompt; | |||
1274 | ||||
1275 | if (!read_file && !info_script_option) | |||
1276 | /* FIXME: if fopen is used, it will never be closed. */ | |||
1277 | read_file = archive == STDIN_FILENO0 ? fopen (TTY_NAME"/dev/tty", "r") : stdinstdin; | |||
1278 | ||||
1279 | if (now_verifying) | |||
1280 | return false0; | |||
1281 | if (verify_option) | |||
1282 | verify_volume (); | |||
1283 | ||||
1284 | assign_string (&volume_label, NULL((void*)0)); | |||
1285 | assign_string (&continued_file_name, NULL((void*)0)); | |||
1286 | continued_file_size = continued_file_offset = 0; | |||
1287 | current_block = record_start; | |||
1288 | ||||
1289 | if (rmtclose (archive)(((archive) >= (1 << 30)) ? rmt_close__ (archive - ( 1 << 30)) : close (archive)) != 0) | |||
1290 | close_error (*archive_name_cursor); | |||
1291 | ||||
1292 | archive_name_cursor++; | |||
1293 | if (archive_name_cursor == archive_name_array + archive_names) | |||
1294 | { | |||
1295 | archive_name_cursor = archive_name_array; | |||
1296 | looped = 1; | |||
1297 | } | |||
1298 | prompt = looped; | |||
1299 | ||||
1300 | tryagain: | |||
1301 | if (prompt) | |||
1302 | { | |||
1303 | /* We have to prompt from now on. */ | |||
1304 | ||||
1305 | if (info_script_option) | |||
1306 | { | |||
1307 | if (volno_file_option) | |||
1308 | closeout_volume_number (); | |||
1309 | if (sys_exec_info_script (archive_name_cursor, global_volno+1)) | |||
1310 | FATAL_ERROR ((0, 0, _("%s command failed"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s command failed", 5), quote (info_script_option )); fatal_exit (); } while (0) | |||
1311 | quote (info_script_option)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s command failed", 5), quote (info_script_option )); fatal_exit (); } while (0); | |||
1312 | } | |||
1313 | else | |||
1314 | change_tape_menu (read_file); | |||
1315 | } | |||
1316 | ||||
1317 | if (strcmp (archive_name_cursor[0], "-") == 0) | |||
1318 | { | |||
1319 | read_full_records = true1; | |||
1320 | archive = STDIN_FILENO0; | |||
1321 | } | |||
1322 | else if (verify_option) | |||
1323 | archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,((!force_local_option && (rmt_dev_name__ = strchr (*archive_name_cursor , ':')) && rmt_dev_name__ > (*archive_name_cursor) && ! memchr (*archive_name_cursor, '/', rmt_dev_name__ - (*archive_name_cursor))) ? rmt_open__ (*archive_name_cursor , 02 | 0100, (1 << 30), rsh_command_option) : open (*archive_name_cursor , 02 | 0100, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))) | |||
1324 | rsh_command_option)((!force_local_option && (rmt_dev_name__ = strchr (*archive_name_cursor , ':')) && rmt_dev_name__ > (*archive_name_cursor) && ! memchr (*archive_name_cursor, '/', rmt_dev_name__ - (*archive_name_cursor))) ? rmt_open__ (*archive_name_cursor , 02 | 0100, (1 << 30), rsh_command_option) : open (*archive_name_cursor , 02 | 0100, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))); | |||
1325 | else | |||
1326 | switch (mode) | |||
1327 | { | |||
1328 | case ACCESS_READ: | |||
1329 | archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,((!force_local_option && (rmt_dev_name__ = strchr (*archive_name_cursor , ':')) && rmt_dev_name__ > (*archive_name_cursor) && ! memchr (*archive_name_cursor, '/', rmt_dev_name__ - (*archive_name_cursor))) ? rmt_open__ (*archive_name_cursor , 00, (1 << 30), rsh_command_option) : open (*archive_name_cursor , 00, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))) | |||
1330 | rsh_command_option)((!force_local_option && (rmt_dev_name__ = strchr (*archive_name_cursor , ':')) && rmt_dev_name__ > (*archive_name_cursor) && ! memchr (*archive_name_cursor, '/', rmt_dev_name__ - (*archive_name_cursor))) ? rmt_open__ (*archive_name_cursor , 00, (1 << 30), rsh_command_option) : open (*archive_name_cursor , 00, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))); | |||
1331 | guess_seekable_archive (); | |||
1332 | break; | |||
1333 | ||||
1334 | case ACCESS_WRITE: | |||
1335 | if (backup_option) | |||
1336 | maybe_backup_file (*archive_name_cursor, 1); | |||
1337 | archive = rmtcreat (*archive_name_cursor, MODE_RW,((!force_local_option && (rmt_dev_name__ = strchr (*archive_name_cursor , ':')) && rmt_dev_name__ > (*archive_name_cursor) && ! memchr (*archive_name_cursor, '/', rmt_dev_name__ - (*archive_name_cursor))) ? rmt_open__ (*archive_name_cursor , 0100 | 01, (1 << 30), rsh_command_option) : creat (*archive_name_cursor , (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))) )) | |||
1338 | rsh_command_option)((!force_local_option && (rmt_dev_name__ = strchr (*archive_name_cursor , ':')) && rmt_dev_name__ > (*archive_name_cursor) && ! memchr (*archive_name_cursor, '/', rmt_dev_name__ - (*archive_name_cursor))) ? rmt_open__ (*archive_name_cursor , 0100 | 01, (1 << 30), rsh_command_option) : creat (*archive_name_cursor , (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))) )); | |||
1339 | break; | |||
1340 | ||||
1341 | case ACCESS_UPDATE: | |||
1342 | archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,((!force_local_option && (rmt_dev_name__ = strchr (*archive_name_cursor , ':')) && rmt_dev_name__ > (*archive_name_cursor) && ! memchr (*archive_name_cursor, '/', rmt_dev_name__ - (*archive_name_cursor))) ? rmt_open__ (*archive_name_cursor , 02 | 0100, (1 << 30), rsh_command_option) : open (*archive_name_cursor , 02 | 0100, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))) | |||
1343 | rsh_command_option)((!force_local_option && (rmt_dev_name__ = strchr (*archive_name_cursor , ':')) && rmt_dev_name__ > (*archive_name_cursor) && ! memchr (*archive_name_cursor, '/', rmt_dev_name__ - (*archive_name_cursor))) ? rmt_open__ (*archive_name_cursor , 02 | 0100, (1 << 30), rsh_command_option) : open (*archive_name_cursor , 02 | 0100, (0200 | (0200 >> 3) | ((0200 >> 3) >> 3) | (0400 | (0400 >> 3) | ((0400 >> 3) >> 3))))); | |||
1344 | break; | |||
1345 | } | |||
1346 | ||||
1347 | if (archive < 0) | |||
1348 | { | |||
1349 | open_warn (*archive_name_cursor); | |||
1350 | if (!verify_option && mode == ACCESS_WRITE && backup_option) | |||
1351 | undo_last_backup (); | |||
1352 | prompt = 1; | |||
1353 | goto tryagain; | |||
1354 | } | |||
1355 | ||||
1356 | SET_BINARY_MODE (archive); | |||
1357 | ||||
1358 | return true1; | |||
1359 | } | |||
1360 | ||||
1361 | static bool_Bool | |||
1362 | read_header0 (struct tar_stat_info *info) | |||
1363 | { | |||
1364 | enum read_header rc; | |||
1365 | ||||
1366 | tar_stat_init (info); | |||
1367 | rc = read_header (¤t_header, info, read_header_auto); | |||
1368 | if (rc == HEADER_SUCCESS) | |||
1369 | { | |||
1370 | set_next_block_after (current_header); | |||
1371 | return true1; | |||
1372 | } | |||
1373 | ERROR ((0, 0, _("This does not look like a tar archive")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This does not look like a tar archive", 5)); exit_status = 2; } while (0); | |||
1374 | return false0; | |||
1375 | } | |||
1376 | ||||
1377 | static bool_Bool | |||
1378 | try_new_volume (void) | |||
1379 | { | |||
1380 | size_t status; | |||
1381 | union block *header; | |||
1382 | enum access_mode acc; | |||
1383 | ||||
1384 | switch (subcommand_option) | |||
1385 | { | |||
1386 | case APPEND_SUBCOMMAND: | |||
1387 | case CAT_SUBCOMMAND: | |||
1388 | case UPDATE_SUBCOMMAND: | |||
1389 | acc = ACCESS_UPDATE; | |||
1390 | break; | |||
1391 | ||||
1392 | default: | |||
1393 | acc = ACCESS_READ; | |||
1394 | break; | |||
1395 | } | |||
1396 | ||||
1397 | if (!new_volume (acc)) | |||
1398 | return true1; | |||
1399 | ||||
1400 | while ((status = rmtread (archive, record_start->buffer, record_size)(((archive) >= (1 << 30)) ? rmt_read__ (archive - (1 << 30), record_start->buffer, record_size) : safe_read (archive, record_start->buffer, record_size))) | |||
1401 | == SAFE_READ_ERROR((size_t) -1)) | |||
1402 | archive_read_error (); | |||
1403 | ||||
1404 | if (status != record_size) | |||
1405 | short_read (status); | |||
1406 | ||||
1407 | header = find_next_block (); | |||
1408 | if (!header) | |||
1409 | return false0; | |||
1410 | ||||
1411 | switch (header->header.typeflag) | |||
1412 | { | |||
1413 | case XGLTYPE'g': | |||
1414 | { | |||
1415 | tar_stat_init (&dummy); | |||
1416 | if (read_header (&header, &dummy, read_header_x_global) | |||
1417 | != HEADER_SUCCESS_EXTENDED) | |||
1418 | { | |||
1419 | ERROR ((0, 0, _("This does not look like a tar archive")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This does not look like a tar archive", 5)); exit_status = 2; } while (0); | |||
1420 | return false0; | |||
1421 | } | |||
1422 | ||||
1423 | xheader_decode (&dummy); /* decodes values from the global header */ | |||
1424 | tar_stat_destroy (&dummy); | |||
1425 | ||||
1426 | /* The initial global header must be immediately followed by | |||
1427 | an extended PAX header for the first member in this volume. | |||
1428 | However, in some cases tar may split volumes in the middle | |||
1429 | of a PAX header. This is incorrect, and should be fixed | |||
1430 | in the future versions. In the meantime we must be | |||
1431 | prepared to correctly list and extract such archives. | |||
1432 | ||||
1433 | If this happens, the following call to read_header returns | |||
1434 | HEADER_FAILURE, which is ignored. | |||
1435 | ||||
1436 | See also tests/multiv07.at */ | |||
1437 | ||||
1438 | switch (read_header (&header, &dummy, read_header_auto)) | |||
1439 | { | |||
1440 | case HEADER_SUCCESS: | |||
1441 | set_next_block_after (header); | |||
1442 | break; | |||
1443 | ||||
1444 | case HEADER_FAILURE: | |||
1445 | break; | |||
1446 | ||||
1447 | default: | |||
1448 | ERROR ((0, 0, _("This does not look like a tar archive")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This does not look like a tar archive", 5)); exit_status = 2; } while (0); | |||
1449 | return false0; | |||
1450 | } | |||
1451 | break; | |||
1452 | } | |||
1453 | ||||
1454 | case GNUTYPE_VOLHDR'V': | |||
1455 | if (!read_header0 (&dummy)) | |||
1456 | return false0; | |||
1457 | tar_stat_destroy (&dummy); | |||
1458 | assign_string (&volume_label, current_header->header.name); | |||
1459 | set_next_block_after (header); | |||
1460 | header = find_next_block (); | |||
1461 | if (header->header.typeflag != GNUTYPE_MULTIVOL'M') | |||
1462 | break; | |||
1463 | /* FALL THROUGH */ | |||
1464 | ||||
1465 | case GNUTYPE_MULTIVOL'M': | |||
1466 | if (!read_header0 (&dummy)) | |||
1467 | return false0; | |||
1468 | tar_stat_destroy (&dummy); | |||
1469 | assign_string (&continued_file_name, current_header->header.name); | |||
1470 | continued_file_size = | |||
1471 | UINTMAX_FROM_HEADER (current_header->header.size)uintmax_from_header (current_header->header.size, sizeof ( current_header->header.size)); | |||
1472 | continued_file_offset = | |||
1473 | UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset)uintmax_from_header (current_header->oldgnu_header.offset, sizeof (current_header->oldgnu_header.offset)); | |||
1474 | break; | |||
1475 | ||||
1476 | default: | |||
1477 | break; | |||
1478 | } | |||
1479 | ||||
1480 | if (bufmap_head) | |||
1481 | { | |||
1482 | uintmax_t s; | |||
1483 | if (!continued_file_name | |||
1484 | || strcmp (continued_file_name, bufmap_head->file_name)) | |||
1485 | { | |||
1486 | if ((archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT) | |||
1487 | && strlen (bufmap_head->file_name) >= NAME_FIELD_SIZE100 | |||
1488 | && strncmp (continued_file_name, bufmap_head->file_name, | |||
1489 | NAME_FIELD_SIZE100) == 0) | |||
1490 | WARN ((0, 0,do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is possibly continued on this volume: header contains truncated name" , 5), quote (bufmap_head->file_name)); } while (0) | |||
1491 | _("%s is possibly continued on this volume: header contains truncated name"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is possibly continued on this volume: header contains truncated name" , 5), quote (bufmap_head->file_name)); } while (0) | |||
1492 | quote (bufmap_head->file_name)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is possibly continued on this volume: header contains truncated name" , 5), quote (bufmap_head->file_name)); } while (0); | |||
1493 | else | |||
1494 | { | |||
1495 | WARN ((0, 0, _("%s is not continued on this volume"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is not continued on this volume", 5), quote (bufmap_head ->file_name)); } while (0) | |||
1496 | quote (bufmap_head->file_name)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is not continued on this volume", 5), quote (bufmap_head ->file_name)); } while (0); | |||
1497 | return false0; | |||
1498 | } | |||
1499 | } | |||
1500 | ||||
1501 | s = continued_file_size + continued_file_offset; | |||
1502 | ||||
1503 | if (bufmap_head->sizetotal != s || s < continued_file_offset) | |||
1504 | { | |||
1505 | char totsizebuf[UINTMAX_STRSIZE_BOUND(((((sizeof (uintmax_t) * 8 - (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) * 146 + 484) / 485) + (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) + 1)]; | |||
1506 | char s1buf[UINTMAX_STRSIZE_BOUND(((((sizeof (uintmax_t) * 8 - (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) * 146 + 484) / 485) + (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) + 1)]; | |||
1507 | char s2buf[UINTMAX_STRSIZE_BOUND(((((sizeof (uintmax_t) * 8 - (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) * 146 + 484) / 485) + (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) + 1)]; | |||
1508 | ||||
1509 | WARN ((0, 0, _("%s is the wrong size (%s != %s + %s)"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is the wrong size (%s != %s + %s)", 5), quote ( continued_file_name), umaxtostr (bufmap_head->sizetotal, totsizebuf ), umaxtostr (continued_file_size, s1buf), umaxtostr (continued_file_offset , s2buf)); } while (0) | |||
1510 | quote (continued_file_name),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is the wrong size (%s != %s + %s)", 5), quote ( continued_file_name), umaxtostr (bufmap_head->sizetotal, totsizebuf ), umaxtostr (continued_file_size, s1buf), umaxtostr (continued_file_offset , s2buf)); } while (0) | |||
1511 | STRINGIFY_BIGINT (bufmap_head->sizetotal, totsizebuf),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is the wrong size (%s != %s + %s)", 5), quote ( continued_file_name), umaxtostr (bufmap_head->sizetotal, totsizebuf ), umaxtostr (continued_file_size, s1buf), umaxtostr (continued_file_offset , s2buf)); } while (0) | |||
1512 | STRINGIFY_BIGINT (continued_file_size, s1buf),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is the wrong size (%s != %s + %s)", 5), quote ( continued_file_name), umaxtostr (bufmap_head->sizetotal, totsizebuf ), umaxtostr (continued_file_size, s1buf), umaxtostr (continued_file_offset , s2buf)); } while (0) | |||
1513 | STRINGIFY_BIGINT (continued_file_offset, s2buf)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s is the wrong size (%s != %s + %s)", 5), quote ( continued_file_name), umaxtostr (bufmap_head->sizetotal, totsizebuf ), umaxtostr (continued_file_size, s1buf), umaxtostr (continued_file_offset , s2buf)); } while (0); | |||
1514 | return false0; | |||
1515 | } | |||
1516 | ||||
1517 | if (bufmap_head->sizetotal - bufmap_head->sizeleft != | |||
1518 | continued_file_offset) | |||
1519 | { | |||
1520 | char totsizebuf[UINTMAX_STRSIZE_BOUND(((((sizeof (uintmax_t) * 8 - (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) * 146 + 484) / 485) + (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) + 1)]; | |||
1521 | char s1buf[UINTMAX_STRSIZE_BOUND(((((sizeof (uintmax_t) * 8 - (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) * 146 + 484) / 485) + (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) + 1)]; | |||
1522 | char s2buf[UINTMAX_STRSIZE_BOUND(((((sizeof (uintmax_t) * 8 - (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) * 146 + 484) / 485) + (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) + 1)]; | |||
1523 | ||||
1524 | WARN ((0, 0, _("This volume is out of sequence (%s - %s != %s)"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This volume is out of sequence (%s - %s != %s)", 5 ), umaxtostr (bufmap_head->sizetotal, totsizebuf), umaxtostr (bufmap_head->sizeleft, s1buf), umaxtostr (continued_file_offset , s2buf)); } while (0) | |||
1525 | STRINGIFY_BIGINT (bufmap_head->sizetotal, totsizebuf),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This volume is out of sequence (%s - %s != %s)", 5 ), umaxtostr (bufmap_head->sizetotal, totsizebuf), umaxtostr (bufmap_head->sizeleft, s1buf), umaxtostr (continued_file_offset , s2buf)); } while (0) | |||
1526 | STRINGIFY_BIGINT (bufmap_head->sizeleft, s1buf),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This volume is out of sequence (%s - %s != %s)", 5 ), umaxtostr (bufmap_head->sizetotal, totsizebuf), umaxtostr (bufmap_head->sizeleft, s1buf), umaxtostr (continued_file_offset , s2buf)); } while (0) | |||
1527 | STRINGIFY_BIGINT (continued_file_offset, s2buf)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "This volume is out of sequence (%s - %s != %s)", 5 ), umaxtostr (bufmap_head->sizetotal, totsizebuf), umaxtostr (bufmap_head->sizeleft, s1buf), umaxtostr (continued_file_offset , s2buf)); } while (0); | |||
1528 | ||||
1529 | return false0; | |||
1530 | } | |||
1531 | } | |||
1532 | ||||
1533 | increase_volume_number (); | |||
1534 | return true1; | |||
1535 | } | |||
1536 | ||||
1537 | ||||
1538 | #define VOLUME_TEXT" Volume " " Volume " | |||
1539 | #define VOLUME_TEXT_LEN(sizeof " Volume " - 1) (sizeof VOLUME_TEXT" Volume " - 1) | |||
1540 | ||||
1541 | char * | |||
1542 | drop_volume_label_suffix (const char *label) | |||
1543 | { | |||
1544 | const char *p; | |||
1545 | size_t len = strlen (label); | |||
1546 | ||||
1547 | if (len < 1) | |||
1548 | return NULL((void*)0); | |||
1549 | ||||
1550 | for (p = label + len - 1; p > label && isdigit ((unsigned char) *p)((*__ctype_b_loc ())[(int) (((unsigned char) *p))] & (unsigned short int) _ISdigit); p--) | |||
1551 | ; | |||
1552 | if (p > label && p - (VOLUME_TEXT_LEN(sizeof " Volume " - 1) - 1) > label) | |||
1553 | { | |||
1554 | p -= VOLUME_TEXT_LEN(sizeof " Volume " - 1) - 1; | |||
1555 | if (memcmp (p, VOLUME_TEXT" Volume ", VOLUME_TEXT_LEN(sizeof " Volume " - 1)) == 0) | |||
1556 | { | |||
1557 | char *s = xmalloc ((len = p - label) + 1); | |||
1558 | memcpy (s, label, len); | |||
1559 | s[len] = 0; | |||
1560 | return s; | |||
1561 | } | |||
1562 | } | |||
1563 | ||||
1564 | return NULL((void*)0); | |||
1565 | } | |||
1566 | ||||
1567 | /* Check LABEL against the volume label, seen as a globbing | |||
1568 | pattern. Return true if the pattern matches. In case of failure, | |||
1569 | retry matching a volume sequence number before giving up in | |||
1570 | multi-volume mode. */ | |||
1571 | static bool_Bool | |||
1572 | check_label_pattern (const char *label) | |||
1573 | { | |||
1574 | char *string; | |||
1575 | bool_Bool result = false0; | |||
1576 | ||||
1577 | if (fnmatch (volume_label_option, label, 0) == 0) | |||
1578 | return true1; | |||
1579 | ||||
1580 | if (!multi_volume_option) | |||
1581 | return false0; | |||
1582 | ||||
1583 | string = drop_volume_label_suffix (label); | |||
1584 | if (string) | |||
1585 | { | |||
1586 | result = fnmatch (string, volume_label_option, 0) == 0; | |||
1587 | free (string); | |||
1588 | } | |||
1589 | return result; | |||
1590 | } | |||
1591 | ||||
1592 | /* Check if the next block contains a volume label and if this matches | |||
1593 | the one given in the command line */ | |||
1594 | static void | |||
1595 | match_volume_label (void) | |||
1596 | { | |||
1597 | if (!volume_label) | |||
1598 | { | |||
1599 | union block *label = find_next_block (); | |||
1600 | ||||
1601 | if (!label) | |||
1602 | FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Archive not labeled to match %s", 5), quote (volume_label_option )); fatal_exit (); } while (0) | |||
1603 | quote (volume_label_option)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Archive not labeled to match %s", 5), quote (volume_label_option )); fatal_exit (); } while (0); | |||
1604 | if (label->header.typeflag == GNUTYPE_VOLHDR'V') | |||
1605 | { | |||
1606 | if (memchr (label->header.name, '\0', sizeof label->header.name)) | |||
1607 | assign_string (&volume_label, label->header.name); | |||
1608 | else | |||
1609 | { | |||
1610 | volume_label = xmalloc (sizeof (label->header.name) + 1); | |||
1611 | memcpy (volume_label, label->header.name, | |||
1612 | sizeof (label->header.name)); | |||
1613 | volume_label[sizeof (label->header.name)] = 0; | |||
1614 | } | |||
1615 | } | |||
1616 | else if (label->header.typeflag == XGLTYPE'g') | |||
1617 | { | |||
1618 | struct tar_stat_info st; | |||
1619 | tar_stat_init (&st); | |||
1620 | xheader_read (&st.xhdr, label, | |||
1621 | OFF_FROM_HEADER (label->header.size)off_from_header (label->header.size, sizeof (label->header .size))); | |||
1622 | xheader_decode (&st); | |||
1623 | tar_stat_destroy (&st); | |||
1624 | } | |||
1625 | } | |||
1626 | ||||
1627 | if (!volume_label) | |||
1628 | FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Archive not labeled to match %s", 5), quote (volume_label_option )); fatal_exit (); } while (0) | |||
1629 | quote (volume_label_option)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Archive not labeled to match %s", 5), quote (volume_label_option )); fatal_exit (); } while (0); | |||
1630 | ||||
1631 | if (!check_label_pattern (volume_label)) | |||
1632 | FATAL_ERROR ((0, 0, _("Volume %s does not match %s"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Volume %s does not match %s", 5), quote_n (0, volume_label ), quote_n (1, volume_label_option)); fatal_exit (); } while ( 0) | |||
1633 | quote_n (0, volume_label),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Volume %s does not match %s", 5), quote_n (0, volume_label ), quote_n (1, volume_label_option)); fatal_exit (); } while ( 0) | |||
1634 | quote_n (1, volume_label_option)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "Volume %s does not match %s", 5), quote_n (0, volume_label ), quote_n (1, volume_label_option)); fatal_exit (); } while ( 0); | |||
1635 | } | |||
1636 | ||||
1637 | /* Mark the archive with volume label STR. */ | |||
1638 | static void | |||
1639 | _write_volume_label (const char *str) | |||
1640 | { | |||
1641 | if (archive_format == POSIX_FORMAT) | |||
1642 | xheader_store ("GNU.volume.label", &dummy, str); | |||
1643 | else | |||
1644 | { | |||
1645 | union block *label = find_next_block (); | |||
1646 | ||||
1647 | memset (label, 0, BLOCKSIZE512); | |||
1648 | ||||
1649 | strcpy (label->header.name, str); | |||
1650 | assign_string (¤t_stat_info.file_name, | |||
1651 | label->header.name); | |||
1652 | current_stat_info.had_trailing_slash = | |||
1653 | strip_trailing_slashes (current_stat_info.file_name); | |||
1654 | ||||
1655 | label->header.typeflag = GNUTYPE_VOLHDR'V'; | |||
| ||||
1656 | TIME_TO_CHARS (start_time.tv_sec, label->header.mtime)time_to_chars (start_time.tv_sec, label->header.mtime, sizeof (label->header.mtime)); | |||
1657 | finish_header (¤t_stat_info, label, -1); | |||
1658 | set_next_block_after (label); | |||
1659 | } | |||
1660 | } | |||
1661 | ||||
1662 | #define VOL_SUFFIX"Volume" "Volume" | |||
1663 | ||||
1664 | /* Add a volume label to a part of multi-volume archive */ | |||
1665 | static void | |||
1666 | add_volume_label (void) | |||
1667 | { | |||
1668 | char buf[UINTMAX_STRSIZE_BOUND(((((sizeof (uintmax_t) * 8 - (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) * 146 + 484) / 485) + (! ((__typeof__ (uintmax_t)) 0 < (__typeof__ (uintmax_t)) -1))) + 1)]; | |||
1669 | char *p = STRINGIFY_BIGINT (volno, buf)umaxtostr (volno, buf); | |||
1670 | char *s = xmalloc (strlen (volume_label_option) + sizeof VOL_SUFFIX"Volume" | |||
1671 | + strlen (p) + 2); | |||
1672 | sprintf (s, "%s %s %s", volume_label_option, VOL_SUFFIX, p)__builtin___sprintf_chk (s, 2 - 1, __builtin_object_size (s, 2 > 1), "%s %s %s", volume_label_option, "Volume", p); | |||
1673 | _write_volume_label (s); | |||
1674 | free (s); | |||
1675 | } | |||
1676 | ||||
1677 | static void | |||
1678 | add_chunk_header (struct bufmap *map) | |||
1679 | { | |||
1680 | if (archive_format == POSIX_FORMAT) | |||
1681 | { | |||
1682 | off_t block_ordinal; | |||
1683 | union block *blk; | |||
1684 | struct tar_stat_info st; | |||
1685 | ||||
1686 | memset (&st, 0, sizeof st); | |||
1687 | st.orig_file_name = st.file_name = map->file_name; | |||
1688 | st.stat.st_mode = S_IFREG0100000|S_IRUSR0400|S_IWUSR0200|S_IRGRP(0400 >> 3)|S_IROTH((0400 >> 3) >> 3); | |||
1689 | st.stat.st_uid = getuid (); | |||
1690 | st.stat.st_gid = getgid (); | |||
1691 | st.orig_file_name = xheader_format_name (&st, | |||
1692 | "%d/GNUFileParts.%p/%f.%n", | |||
1693 | volno); | |||
1694 | st.file_name = st.orig_file_name; | |||
1695 | st.archive_file_size = st.stat.st_size = map->sizeleft; | |||
1696 | ||||
1697 | block_ordinal = current_block_ordinal (); | |||
1698 | blk = start_header (&st); | |||
1699 | if (!blk) | |||
1700 | abort (); /* FIXME */ | |||
1701 | finish_header (&st, blk, block_ordinal); | |||
1702 | free (st.orig_file_name); | |||
1703 | } | |||
1704 | } | |||
1705 | ||||
1706 | ||||
1707 | /* Add a volume label to the current archive */ | |||
1708 | static void | |||
1709 | write_volume_label (void) | |||
1710 | { | |||
1711 | if (multi_volume_option) | |||
1712 | add_volume_label (); | |||
1713 | else | |||
1714 | _write_volume_label (volume_label_option); | |||
1715 | } | |||
1716 | ||||
1717 | /* Write GNU multi-volume header */ | |||
1718 | static void | |||
1719 | gnu_add_multi_volume_header (struct bufmap *map) | |||
1720 | { | |||
1721 | int tmp; | |||
1722 | union block *block = find_next_block (); | |||
1723 | ||||
1724 | if (strlen (map->file_name) > NAME_FIELD_SIZE100) | |||
1725 | WARN ((0, 0,do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s: file name too long to be stored in a GNU multivolume header, truncated" , 5), quotearg_colon (map->file_name)); } while (0) | |||
1726 | _("%s: file name too long to be stored in a GNU multivolume header, truncated"),do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s: file name too long to be stored in a GNU multivolume header, truncated" , 5), quotearg_colon (map->file_name)); } while (0) | |||
1727 | quotearg_colon (map->file_name)))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "%s: file name too long to be stored in a GNU multivolume header, truncated" , 5), quotearg_colon (map->file_name)); } while (0); | |||
1728 | ||||
1729 | memset (block, 0, BLOCKSIZE512); | |||
1730 | ||||
1731 | strncpy (block->header.name, map->file_name, NAME_FIELD_SIZE100); | |||
1732 | block->header.typeflag = GNUTYPE_MULTIVOL'M'; | |||
1733 | ||||
1734 | OFF_TO_CHARS (map->sizeleft, block->header.size)off_to_chars (map->sizeleft, block->header.size, sizeof (block->header.size)); | |||
1735 | OFF_TO_CHARS (map->sizetotal - map->sizeleft,off_to_chars (map->sizetotal - map->sizeleft, block-> oldgnu_header.offset, sizeof (block->oldgnu_header.offset) ) | |||
1736 | block->oldgnu_header.offset)off_to_chars (map->sizetotal - map->sizeleft, block-> oldgnu_header.offset, sizeof (block->oldgnu_header.offset) ); | |||
1737 | ||||
1738 | tmp = verbose_option; | |||
1739 | verbose_option = 0; | |||
1740 | finish_header (¤t_stat_info, block, -1); | |||
1741 | verbose_option = tmp; | |||
1742 | set_next_block_after (block); | |||
1743 | } | |||
1744 | ||||
1745 | /* Add a multi volume header to the current archive. The exact header format | |||
1746 | depends on the archive format. */ | |||
1747 | static void | |||
1748 | add_multi_volume_header (struct bufmap *map) | |||
1749 | { | |||
1750 | if (archive_format == POSIX_FORMAT) | |||
1751 | { | |||
1752 | off_t d = map->sizetotal - map->sizeleft; | |||
1753 | xheader_store ("GNU.volume.filename", &dummy, map->file_name); | |||
1754 | xheader_store ("GNU.volume.size", &dummy, &map->sizeleft); | |||
1755 | xheader_store ("GNU.volume.offset", &dummy, &d); | |||
1756 | } | |||
1757 | else | |||
1758 | gnu_add_multi_volume_header (map); | |||
1759 | } | |||
1760 | ||||
1761 | ||||
1762 | /* Low-level flush functions */ | |||
1763 | ||||
1764 | /* Simple flush read (no multi-volume or label extensions) */ | |||
1765 | static void | |||
1766 | simple_flush_read (void) | |||
1767 | { | |||
1768 | size_t status; /* result from system call */ | |||
1769 | ||||
1770 | checkpoint_run (false0); | |||
1771 | ||||
1772 | /* Clear the count of errors. This only applies to a single call to | |||
1773 | flush_read. */ | |||
1774 | ||||
1775 | read_error_count = 0; /* clear error count */ | |||
1776 | ||||
1777 | if (write_archive_to_stdout && record_start_block != 0) | |||
1778 | { | |||
1779 | archive = STDOUT_FILENO1; | |||
1780 | status = sys_write_archive_buffer (); | |||
1781 | archive = STDIN_FILENO0; | |||
1782 | if (status != record_size) | |||
1783 | archive_write_error (status); | |||
1784 | } | |||
1785 | ||||
1786 | for (;;) | |||
1787 | { | |||
1788 | status = rmtread (archive, record_start->buffer, record_size)(((archive) >= (1 << 30)) ? rmt_read__ (archive - (1 << 30), record_start->buffer, record_size) : safe_read (archive, record_start->buffer, record_size)); | |||
1789 | if (status == record_size) | |||
1790 | { | |||
1791 | records_read++; | |||
1792 | return; | |||
1793 | } | |||
1794 | if (status == SAFE_READ_ERROR((size_t) -1)) | |||
1795 | { | |||
1796 | archive_read_error (); | |||
1797 | continue; /* try again */ | |||
1798 | } | |||
1799 | break; | |||
1800 | } | |||
1801 | short_read (status); | |||
1802 | } | |||
1803 | ||||
1804 | /* Simple flush write (no multi-volume or label extensions) */ | |||
1805 | static void | |||
1806 | simple_flush_write (size_t level __attribute__((unused))) | |||
1807 | { | |||
1808 | ssize_t status; | |||
1809 | ||||
1810 | status = _flush_write (); | |||
1811 | if (status != record_size) | |||
1812 | archive_write_error (status); | |||
1813 | else | |||
1814 | { | |||
1815 | records_written++; | |||
1816 | bytes_written += status; | |||
1817 | } | |||
1818 | } | |||
1819 | ||||
1820 | ||||
1821 | /* GNU flush functions. These support multi-volume and archive labels in | |||
1822 | GNU and PAX archive formats. */ | |||
1823 | ||||
1824 | static void | |||
1825 | _gnu_flush_read (void) | |||
1826 | { | |||
1827 | size_t status; /* result from system call */ | |||
1828 | ||||
1829 | checkpoint_run (false0); | |||
1830 | ||||
1831 | /* Clear the count of errors. This only applies to a single call to | |||
1832 | flush_read. */ | |||
1833 | ||||
1834 | read_error_count = 0; /* clear error count */ | |||
1835 | ||||
1836 | if (write_archive_to_stdout && record_start_block != 0) | |||
1837 | { | |||
1838 | archive = STDOUT_FILENO1; | |||
1839 | status = sys_write_archive_buffer (); | |||
1840 | archive = STDIN_FILENO0; | |||
1841 | if (status != record_size) | |||
1842 | archive_write_error (status); | |||
1843 | } | |||
1844 | ||||
1845 | for (;;) | |||
1846 | { | |||
1847 | status = rmtread (archive, record_start->buffer, record_size)(((archive) >= (1 << 30)) ? rmt_read__ (archive - (1 << 30), record_start->buffer, record_size) : safe_read (archive, record_start->buffer, record_size)); | |||
1848 | if (status == record_size) | |||
1849 | { | |||
1850 | records_read++; | |||
1851 | return; | |||
1852 | } | |||
1853 | ||||
1854 | /* The condition below used to include | |||
1855 | || (status > 0 && !read_full_records) | |||
1856 | This is incorrect since even if new_volume() succeeds, the | |||
1857 | subsequent call to rmtread will overwrite the chunk of data | |||
1858 | already read in the buffer, so the processing will fail */ | |||
1859 | if ((status == 0 | |||
1860 | || (status == SAFE_READ_ERROR((size_t) -1) && errno(*__errno_location ()) == ENOSPC28)) | |||
1861 | && multi_volume_option) | |||
1862 | { | |||
1863 | while (!try_new_volume ()) | |||
1864 | ; | |||
1865 | if (current_block == record_end) | |||
1866 | /* Necessary for blocking_factor == 1 */ | |||
1867 | flush_archive(); | |||
1868 | return; | |||
1869 | } | |||
1870 | else if (status == SAFE_READ_ERROR((size_t) -1)) | |||
1871 | { | |||
1872 | archive_read_error (); | |||
1873 | continue; | |||
1874 | } | |||
1875 | break; | |||
1876 | } | |||
1877 | short_read (status); | |||
1878 | } | |||
1879 | ||||
1880 | static void | |||
1881 | gnu_flush_read (void) | |||
1882 | { | |||
1883 | flush_read_ptr = simple_flush_read; /* Avoid recursion */ | |||
1884 | _gnu_flush_read (); | |||
1885 | flush_read_ptr = gnu_flush_read; | |||
1886 | } | |||
1887 | ||||
1888 | static void | |||
1889 | _gnu_flush_write (size_t buffer_level) | |||
1890 | { | |||
1891 | ssize_t status; | |||
1892 | union block *header; | |||
1893 | char *copy_ptr; | |||
1894 | size_t copy_size; | |||
1895 | size_t bufsize; | |||
1896 | struct bufmap *map; | |||
1897 | ||||
1898 | status = _flush_write (); | |||
1899 | if (status != record_size && !multi_volume_option) | |||
1900 | archive_write_error (status); | |||
1901 | else | |||
1902 | { | |||
1903 | if (status) | |||
1904 | records_written++; | |||
1905 | bytes_written += status; | |||
1906 | } | |||
1907 | ||||
1908 | if (status == record_size) | |||
1909 | { | |||
1910 | return; | |||
1911 | } | |||
1912 | ||||
1913 | map = bufmap_locate (status); | |||
1914 | ||||
1915 | if (status % BLOCKSIZE512) | |||
1916 | { | |||
1917 | ERROR ((0, 0, _("write did not end on a block boundary")))do { if (error_hook) error_hook (); error (0, 0, dcgettext (( (void*)0), "write did not end on a block boundary", 5)); exit_status = 2; } while (0); | |||
1918 | archive_write_error (status); | |||
1919 | } | |||
1920 | ||||
1921 | /* In multi-volume mode. */ | |||
1922 | /* ENXIO is for the UNIX PC. */ | |||
1923 | if (status < 0 && errno(*__errno_location ()) != ENOSPC28 && errno(*__errno_location ()) != EIO5 && errno(*__errno_location ()) != ENXIO6) | |||
1924 | archive_write_error (status); | |||
1925 | ||||
1926 | if (!new_volume (ACCESS_WRITE)) | |||
1927 | return; | |||
1928 | ||||
1929 | tar_stat_destroy (&dummy); | |||
1930 | ||||
1931 | increase_volume_number (); | |||
1932 | prev_written += bytes_written; | |||
1933 | bytes_written = 0; | |||
1934 | ||||
1935 | copy_ptr = record_start->buffer + status; | |||
1936 | copy_size = buffer_level - status; | |||
1937 | ||||
1938 | /* Switch to the next buffer */ | |||
1939 | record_index = !record_index; | |||
1940 | init_buffer (); | |||
1941 | ||||
1942 | inhibit_map = 1; | |||
1943 | ||||
1944 | if (volume_label_option) | |||
1945 | add_volume_label (); | |||
1946 | ||||
1947 | if (map) | |||
1948 | add_multi_volume_header (map); | |||
1949 | ||||
1950 | write_extended (true1, &dummy, find_next_block ()); | |||
1951 | tar_stat_destroy (&dummy); | |||
1952 | ||||
1953 | if (map) | |||
1954 | add_chunk_header (map); | |||
1955 | header = find_next_block (); | |||
1956 | bufmap_reset (map, header - record_start); | |||
1957 | bufsize = available_space_after (header); | |||
1958 | inhibit_map = 0; | |||
1959 | while (bufsize < copy_size) | |||
1960 | { | |||
1961 | memcpy (header->buffer, copy_ptr, bufsize); | |||
1962 | copy_ptr += bufsize; | |||
1963 | copy_size -= bufsize; | |||
1964 | set_next_block_after (header + (bufsize - 1) / BLOCKSIZE512); | |||
1965 | header = find_next_block (); | |||
1966 | bufsize = available_space_after (header); | |||
1967 | } | |||
1968 | memcpy (header->buffer, copy_ptr, copy_size); | |||
1969 | memset (header->buffer + copy_size, 0, bufsize - copy_size); | |||
1970 | set_next_block_after (header + (copy_size - 1) / BLOCKSIZE512); | |||
1971 | find_next_block (); | |||
1972 | } | |||
1973 | ||||
1974 | static void | |||
1975 | gnu_flush_write (size_t buffer_level) | |||
1976 | { | |||
1977 | flush_write_ptr = simple_flush_write; /* Avoid recursion */ | |||
1978 | _gnu_flush_write (buffer_level); | |||
1979 | flush_write_ptr = gnu_flush_write; | |||
1980 | } | |||
1981 | ||||
1982 | void | |||
1983 | flush_read (void) | |||
1984 | { | |||
1985 | flush_read_ptr (); | |||
1986 | } | |||
1987 | ||||
1988 | void | |||
1989 | flush_write (void) | |||
1990 | { | |||
1991 | flush_write_ptr (record_size); | |||
1992 | } | |||
1993 | ||||
1994 | void | |||
1995 | open_archive (enum access_mode wanted_access) | |||
1996 | { | |||
1997 | flush_read_ptr = gnu_flush_read; | |||
1998 | flush_write_ptr = gnu_flush_write; | |||
1999 | ||||
2000 | _open_archive (wanted_access); | |||
2001 | switch (wanted_access) | |||
| ||||
2002 | { | |||
2003 | case ACCESS_READ: | |||
2004 | case ACCESS_UPDATE: | |||
2005 | if (volume_label_option) | |||
2006 | match_volume_label (); | |||
2007 | break; | |||
2008 | ||||
2009 | case ACCESS_WRITE: | |||
2010 | records_written = 0; | |||
2011 | if (volume_label_option) | |||
2012 | write_volume_label (); | |||
2013 | break; | |||
2014 | } | |||
2015 | set_volume_start_time (); | |||
2016 | } |