]> Dogcows Code - chaz/tar/blob - src/sparse.c
tar: don't assume size of a sparse file chunk fits in size_t
[chaz/tar] / src / sparse.c
1 /* Functions for dealing with sparse files
2
3 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Free Software
4 Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any later
9 version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20 #include <system.h>
21 #include <inttostr.h>
22 #include <quotearg.h>
23 #include "common.h"
24
25 struct tar_sparse_file;
26 static bool sparse_select_optab (struct tar_sparse_file *file);
27
28 enum sparse_scan_state
29 {
30 scan_begin,
31 scan_block,
32 scan_end
33 };
34
35 struct tar_sparse_optab
36 {
37 bool (*init) (struct tar_sparse_file *);
38 bool (*done) (struct tar_sparse_file *);
39 bool (*sparse_member_p) (struct tar_sparse_file *);
40 bool (*dump_header) (struct tar_sparse_file *);
41 bool (*fixup_header) (struct tar_sparse_file *);
42 bool (*decode_header) (struct tar_sparse_file *);
43 bool (*scan_block) (struct tar_sparse_file *, enum sparse_scan_state,
44 void *);
45 bool (*dump_region) (struct tar_sparse_file *, size_t);
46 bool (*extract_region) (struct tar_sparse_file *, size_t);
47 };
48
49 struct tar_sparse_file
50 {
51 int fd; /* File descriptor */
52 bool seekable; /* Is fd seekable? */
53 off_t offset; /* Current offset in fd if seekable==false.
54 Otherwise unused */
55 off_t dumped_size; /* Number of bytes actually written
56 to the archive */
57 struct tar_stat_info *stat_info; /* Information about the file */
58 struct tar_sparse_optab const *optab; /* Operation table */
59 void *closure; /* Any additional data optab calls might
60 require */
61 };
62
63 /* Dump zeros to file->fd until offset is reached. It is used instead of
64 lseek if the output file is not seekable */
65 static bool
66 dump_zeros (struct tar_sparse_file *file, off_t offset)
67 {
68 static char const zero_buf[BLOCKSIZE];
69
70 if (offset < file->offset)
71 {
72 errno = EINVAL;
73 return false;
74 }
75
76 while (file->offset < offset)
77 {
78 size_t size = (BLOCKSIZE < offset - file->offset
79 ? BLOCKSIZE
80 : offset - file->offset);
81 ssize_t wrbytes;
82
83 wrbytes = write (file->fd, zero_buf, size);
84 if (wrbytes <= 0)
85 {
86 if (wrbytes == 0)
87 errno = EINVAL;
88 return false;
89 }
90 file->offset += wrbytes;
91 }
92
93 return true;
94 }
95
96 static bool
97 tar_sparse_member_p (struct tar_sparse_file *file)
98 {
99 if (file->optab->sparse_member_p)
100 return file->optab->sparse_member_p (file);
101 return false;
102 }
103
104 static bool
105 tar_sparse_init (struct tar_sparse_file *file)
106 {
107 memset (file, 0, sizeof *file);
108
109 if (!sparse_select_optab (file))
110 return false;
111
112 if (file->optab->init)
113 return file->optab->init (file);
114
115 return true;
116 }
117
118 static bool
119 tar_sparse_done (struct tar_sparse_file *file)
120 {
121 if (file->optab->done)
122 return file->optab->done (file);
123 return true;
124 }
125
126 static bool
127 tar_sparse_scan (struct tar_sparse_file *file, enum sparse_scan_state state,
128 void *block)
129 {
130 if (file->optab->scan_block)
131 return file->optab->scan_block (file, state, block);
132 return true;
133 }
134
135 static bool
136 tar_sparse_dump_region (struct tar_sparse_file *file, size_t i)
137 {
138 if (file->optab->dump_region)
139 return file->optab->dump_region (file, i);
140 return false;
141 }
142
143 static bool
144 tar_sparse_extract_region (struct tar_sparse_file *file, size_t i)
145 {
146 if (file->optab->extract_region)
147 return file->optab->extract_region (file, i);
148 return false;
149 }
150
151 static bool
152 tar_sparse_dump_header (struct tar_sparse_file *file)
153 {
154 if (file->optab->dump_header)
155 return file->optab->dump_header (file);
156 return false;
157 }
158
159 static bool
160 tar_sparse_decode_header (struct tar_sparse_file *file)
161 {
162 if (file->optab->decode_header)
163 return file->optab->decode_header (file);
164 return true;
165 }
166
167 static bool
168 tar_sparse_fixup_header (struct tar_sparse_file *file)
169 {
170 if (file->optab->fixup_header)
171 return file->optab->fixup_header (file);
172 return true;
173 }
174
175 \f
176 static bool
177 lseek_or_error (struct tar_sparse_file *file, off_t offset)
178 {
179 if (file->seekable
180 ? lseek (file->fd, offset, SEEK_SET) < 0
181 : ! dump_zeros (file, offset))
182 {
183 seek_diag_details (file->stat_info->orig_file_name, offset);
184 return false;
185 }
186 return true;
187 }
188
189 /* Takes a blockful of data and basically cruises through it to see if
190 it's made *entirely* of zeros, returning a 0 the instant it finds
191 something that is a nonzero, i.e., useful data. */
192 static bool
193 zero_block_p (char const *buffer, size_t size)
194 {
195 while (size--)
196 if (*buffer++)
197 return false;
198 return true;
199 }
200
201 static void
202 sparse_add_map (struct tar_stat_info *st, struct sp_array const *sp)
203 {
204 struct sp_array *sparse_map = st->sparse_map;
205 size_t avail = st->sparse_map_avail;
206 if (avail == st->sparse_map_size)
207 st->sparse_map = sparse_map =
208 x2nrealloc (sparse_map, &st->sparse_map_size, sizeof *sparse_map);
209 sparse_map[avail] = *sp;
210 st->sparse_map_avail = avail + 1;
211 }
212
213 /* Scan the sparse file and create its map */
214 static bool
215 sparse_scan_file (struct tar_sparse_file *file)
216 {
217 struct tar_stat_info *st = file->stat_info;
218 int fd = file->fd;
219 char buffer[BLOCKSIZE];
220 size_t count;
221 off_t offset = 0;
222 struct sp_array sp = {0, 0};
223
224 if (!lseek_or_error (file, 0))
225 return false;
226
227 st->archive_file_size = 0;
228
229 if (!tar_sparse_scan (file, scan_begin, NULL))
230 return false;
231
232 while ((count = safe_read (fd, buffer, sizeof buffer)) != 0
233 && count != SAFE_READ_ERROR)
234 {
235 /* Analyze the block. */
236 if (zero_block_p (buffer, count))
237 {
238 if (sp.numbytes)
239 {
240 sparse_add_map (st, &sp);
241 sp.numbytes = 0;
242 if (!tar_sparse_scan (file, scan_block, NULL))
243 return false;
244 }
245 }
246 else
247 {
248 if (sp.numbytes == 0)
249 sp.offset = offset;
250 sp.numbytes += count;
251 st->archive_file_size += count;
252 if (!tar_sparse_scan (file, scan_block, buffer))
253 return false;
254 }
255
256 offset += count;
257 }
258
259 if (sp.numbytes == 0)
260 sp.offset = offset;
261
262 sparse_add_map (st, &sp);
263 st->archive_file_size += count;
264 return tar_sparse_scan (file, scan_end, NULL);
265 }
266
267 static struct tar_sparse_optab const oldgnu_optab;
268 static struct tar_sparse_optab const star_optab;
269 static struct tar_sparse_optab const pax_optab;
270
271 static bool
272 sparse_select_optab (struct tar_sparse_file *file)
273 {
274 switch (current_format == DEFAULT_FORMAT ? archive_format : current_format)
275 {
276 case V7_FORMAT:
277 case USTAR_FORMAT:
278 return false;
279
280 case OLDGNU_FORMAT:
281 case GNU_FORMAT: /*FIXME: This one should disappear? */
282 file->optab = &oldgnu_optab;
283 break;
284
285 case POSIX_FORMAT:
286 file->optab = &pax_optab;
287 break;
288
289 case STAR_FORMAT:
290 file->optab = &star_optab;
291 break;
292
293 default:
294 return false;
295 }
296 return true;
297 }
298
299 static bool
300 sparse_dump_region (struct tar_sparse_file *file, size_t i)
301 {
302 union block *blk;
303 off_t bytes_left = file->stat_info->sparse_map[i].numbytes;
304
305 if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
306 return false;
307
308 while (bytes_left > 0)
309 {
310 size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left;
311 size_t bytes_read;
312
313 blk = find_next_block ();
314 bytes_read = safe_read (file->fd, blk->buffer, bufsize);
315 if (bytes_read == SAFE_READ_ERROR)
316 {
317 read_diag_details (file->stat_info->orig_file_name,
318 (file->stat_info->sparse_map[i].offset
319 + file->stat_info->sparse_map[i].numbytes
320 - bytes_left),
321 bufsize);
322 return false;
323 }
324
325 memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read);
326 bytes_left -= bytes_read;
327 file->dumped_size += bytes_read;
328 set_next_block_after (blk);
329 }
330
331 return true;
332 }
333
334 static bool
335 sparse_extract_region (struct tar_sparse_file *file, size_t i)
336 {
337 off_t write_size;
338
339 if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
340 return false;
341
342 write_size = file->stat_info->sparse_map[i].numbytes;
343
344 if (write_size == 0)
345 {
346 /* Last block of the file is a hole */
347 if (file->seekable && sys_truncate (file->fd))
348 truncate_warn (file->stat_info->orig_file_name);
349 }
350 else while (write_size > 0)
351 {
352 size_t count;
353 size_t wrbytes = (write_size > BLOCKSIZE) ? BLOCKSIZE : write_size;
354 union block *blk = find_next_block ();
355 if (!blk)
356 {
357 ERROR ((0, 0, _("Unexpected EOF in archive")));
358 return false;
359 }
360 set_next_block_after (blk);
361 count = full_write (file->fd, blk->buffer, wrbytes);
362 write_size -= count;
363 file->dumped_size += count;
364 mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
365 file->offset += count;
366 if (count != wrbytes)
367 {
368 write_error_details (file->stat_info->orig_file_name,
369 count, wrbytes);
370 return false;
371 }
372 }
373 return true;
374 }
375
376 \f
377
378 /* Interface functions */
379 enum dump_status
380 sparse_dump_file (int fd, struct tar_stat_info *st)
381 {
382 bool rc;
383 struct tar_sparse_file file;
384
385 if (!tar_sparse_init (&file))
386 return dump_status_not_implemented;
387
388 file.stat_info = st;
389 file.fd = fd;
390 file.seekable = true; /* File *must* be seekable for dump to work */
391
392 rc = sparse_scan_file (&file);
393 if (rc && file.optab->dump_region)
394 {
395 tar_sparse_dump_header (&file);
396
397 if (fd >= 0)
398 {
399 size_t i;
400
401 mv_begin_write (file.stat_info->file_name,
402 file.stat_info->stat.st_size,
403 file.stat_info->archive_file_size - file.dumped_size);
404 for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
405 rc = tar_sparse_dump_region (&file, i);
406 }
407 }
408
409 pad_archive (file.stat_info->archive_file_size - file.dumped_size);
410 return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
411 }
412
413 bool
414 sparse_member_p (struct tar_stat_info *st)
415 {
416 struct tar_sparse_file file;
417
418 if (!tar_sparse_init (&file))
419 return false;
420 file.stat_info = st;
421 return tar_sparse_member_p (&file);
422 }
423
424 bool
425 sparse_fixup_header (struct tar_stat_info *st)
426 {
427 struct tar_sparse_file file;
428
429 if (!tar_sparse_init (&file))
430 return false;
431 file.stat_info = st;
432 return tar_sparse_fixup_header (&file);
433 }
434
435 enum dump_status
436 sparse_extract_file (int fd, struct tar_stat_info *st, off_t *size)
437 {
438 bool rc = true;
439 struct tar_sparse_file file;
440 size_t i;
441
442 if (!tar_sparse_init (&file))
443 return dump_status_not_implemented;
444
445 file.stat_info = st;
446 file.fd = fd;
447 file.seekable = lseek (fd, 0, SEEK_SET) == 0;
448 file.offset = 0;
449
450 rc = tar_sparse_decode_header (&file);
451 for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
452 rc = tar_sparse_extract_region (&file, i);
453 *size = file.stat_info->archive_file_size - file.dumped_size;
454 return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
455 }
456
457 enum dump_status
458 sparse_skip_file (struct tar_stat_info *st)
459 {
460 bool rc = true;
461 struct tar_sparse_file file;
462
463 if (!tar_sparse_init (&file))
464 return dump_status_not_implemented;
465
466 file.stat_info = st;
467 file.fd = -1;
468
469 rc = tar_sparse_decode_header (&file);
470 skip_file (file.stat_info->archive_file_size - file.dumped_size);
471 return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
472 }
473
474 \f
475 static bool
476 check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
477 {
478 if (!lseek_or_error (file, beg))
479 return false;
480
481 while (beg < end)
482 {
483 size_t bytes_read;
484 size_t rdsize = BLOCKSIZE < end - beg ? BLOCKSIZE : end - beg;
485 char diff_buffer[BLOCKSIZE];
486
487 bytes_read = safe_read (file->fd, diff_buffer, rdsize);
488 if (bytes_read == SAFE_READ_ERROR)
489 {
490 read_diag_details (file->stat_info->orig_file_name,
491 beg,
492 rdsize);
493 return false;
494 }
495 if (!zero_block_p (diff_buffer, bytes_read))
496 {
497 char begbuf[INT_BUFSIZE_BOUND (off_t)];
498 report_difference (file->stat_info,
499 _("File fragment at %s is not a hole"),
500 offtostr (beg, begbuf));
501 return false;
502 }
503
504 beg += bytes_read;
505 }
506 return true;
507 }
508
509 static bool
510 check_data_region (struct tar_sparse_file *file, size_t i)
511 {
512 off_t size_left;
513
514 if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
515 return false;
516 size_left = file->stat_info->sparse_map[i].numbytes;
517 mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
518
519 while (size_left > 0)
520 {
521 size_t bytes_read;
522 size_t rdsize = (size_left > BLOCKSIZE) ? BLOCKSIZE : size_left;
523 char diff_buffer[BLOCKSIZE];
524
525 union block *blk = find_next_block ();
526 if (!blk)
527 {
528 ERROR ((0, 0, _("Unexpected EOF in archive")));
529 return false;
530 }
531 set_next_block_after (blk);
532 bytes_read = safe_read (file->fd, diff_buffer, rdsize);
533 if (bytes_read == SAFE_READ_ERROR)
534 {
535 read_diag_details (file->stat_info->orig_file_name,
536 (file->stat_info->sparse_map[i].offset
537 + file->stat_info->sparse_map[i].numbytes
538 - size_left),
539 rdsize);
540 return false;
541 }
542 file->dumped_size += bytes_read;
543 size_left -= bytes_read;
544 mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
545 if (memcmp (blk->buffer, diff_buffer, rdsize))
546 {
547 report_difference (file->stat_info, _("Contents differ"));
548 return false;
549 }
550 }
551 return true;
552 }
553
554 bool
555 sparse_diff_file (int fd, struct tar_stat_info *st)
556 {
557 bool rc = true;
558 struct tar_sparse_file file;
559 size_t i;
560 off_t offset = 0;
561
562 if (!tar_sparse_init (&file))
563 return dump_status_not_implemented;
564
565 file.stat_info = st;
566 file.fd = fd;
567 file.seekable = true; /* File *must* be seekable for compare to work */
568
569 rc = tar_sparse_decode_header (&file);
570 mv_begin_read (st);
571 for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
572 {
573 rc = check_sparse_region (&file,
574 offset, file.stat_info->sparse_map[i].offset)
575 && check_data_region (&file, i);
576 offset = file.stat_info->sparse_map[i].offset
577 + file.stat_info->sparse_map[i].numbytes;
578 }
579
580 if (!rc)
581 skip_file (file.stat_info->archive_file_size - file.dumped_size);
582 mv_end ();
583
584 tar_sparse_done (&file);
585 return rc;
586 }
587
588 \f
589 /* Old GNU Format. The sparse file information is stored in the
590 oldgnu_header in the following manner:
591
592 The header is marked with type 'S'. Its `size' field contains
593 the cumulative size of all non-empty blocks of the file. The
594 actual file size is stored in `realsize' member of oldgnu_header.
595
596 The map of the file is stored in a list of `struct sparse'.
597 Each struct contains offset to the block of data and its
598 size (both as octal numbers). The first file header contains
599 at most 4 such structs (SPARSES_IN_OLDGNU_HEADER). If the map
600 contains more structs, then the field `isextended' of the main
601 header is set to 1 (binary) and the `struct sparse_header'
602 header follows, containing at most 21 following structs
603 (SPARSES_IN_SPARSE_HEADER). If more structs follow, `isextended'
604 field of the extended header is set and next next extension header
605 follows, etc... */
606
607 enum oldgnu_add_status
608 {
609 add_ok,
610 add_finish,
611 add_fail
612 };
613
614 static bool
615 oldgnu_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
616 {
617 return current_header->header.typeflag == GNUTYPE_SPARSE;
618 }
619
620 /* Add a sparse item to the sparse file and its obstack */
621 static enum oldgnu_add_status
622 oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
623 {
624 struct sp_array sp;
625
626 if (s->numbytes[0] == '\0')
627 return add_finish;
628 sp.offset = OFF_FROM_HEADER (s->offset);
629 sp.numbytes = OFF_FROM_HEADER (s->numbytes);
630 if (sp.offset < 0
631 || sp.offset + sp.numbytes < 0
632 || file->stat_info->stat.st_size < sp.offset + sp.numbytes
633 || file->stat_info->archive_file_size < 0)
634 return add_fail;
635
636 sparse_add_map (file->stat_info, &sp);
637 return add_ok;
638 }
639
640 static bool
641 oldgnu_fixup_header (struct tar_sparse_file *file)
642 {
643 /* NOTE! st_size was initialized from the header
644 which actually contains archived size. The following fixes it */
645 file->stat_info->archive_file_size = file->stat_info->stat.st_size;
646 file->stat_info->stat.st_size =
647 OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
648 return true;
649 }
650
651 /* Convert old GNU format sparse data to internal representation */
652 static bool
653 oldgnu_get_sparse_info (struct tar_sparse_file *file)
654 {
655 size_t i;
656 union block *h = current_header;
657 int ext_p;
658 enum oldgnu_add_status rc;
659
660 file->stat_info->sparse_map_avail = 0;
661 for (i = 0; i < SPARSES_IN_OLDGNU_HEADER; i++)
662 {
663 rc = oldgnu_add_sparse (file, &h->oldgnu_header.sp[i]);
664 if (rc != add_ok)
665 break;
666 }
667
668 for (ext_p = h->oldgnu_header.isextended;
669 rc == add_ok && ext_p; ext_p = h->sparse_header.isextended)
670 {
671 h = find_next_block ();
672 if (!h)
673 {
674 ERROR ((0, 0, _("Unexpected EOF in archive")));
675 return false;
676 }
677 set_next_block_after (h);
678 for (i = 0; i < SPARSES_IN_SPARSE_HEADER && rc == add_ok; i++)
679 rc = oldgnu_add_sparse (file, &h->sparse_header.sp[i]);
680 }
681
682 if (rc == add_fail)
683 {
684 ERROR ((0, 0, _("%s: invalid sparse archive member"),
685 file->stat_info->orig_file_name));
686 return false;
687 }
688 return true;
689 }
690
691 static void
692 oldgnu_store_sparse_info (struct tar_sparse_file *file, size_t *pindex,
693 struct sparse *sp, size_t sparse_size)
694 {
695 for (; *pindex < file->stat_info->sparse_map_avail
696 && sparse_size > 0; sparse_size--, sp++, ++*pindex)
697 {
698 OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].offset,
699 sp->offset);
700 OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes,
701 sp->numbytes);
702 }
703 }
704
705 static bool
706 oldgnu_dump_header (struct tar_sparse_file *file)
707 {
708 off_t block_ordinal = current_block_ordinal ();
709 union block *blk;
710 size_t i;
711
712 blk = start_header (file->stat_info);
713 blk->header.typeflag = GNUTYPE_SPARSE;
714 if (file->stat_info->sparse_map_avail > SPARSES_IN_OLDGNU_HEADER)
715 blk->oldgnu_header.isextended = 1;
716
717 /* Store the real file size */
718 OFF_TO_CHARS (file->stat_info->stat.st_size, blk->oldgnu_header.realsize);
719 /* Store the effective (shrunken) file size */
720 OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
721
722 i = 0;
723 oldgnu_store_sparse_info (file, &i,
724 blk->oldgnu_header.sp,
725 SPARSES_IN_OLDGNU_HEADER);
726 blk->oldgnu_header.isextended = i < file->stat_info->sparse_map_avail;
727 finish_header (file->stat_info, blk, block_ordinal);
728
729 while (i < file->stat_info->sparse_map_avail)
730 {
731 blk = find_next_block ();
732 memset (blk->buffer, 0, BLOCKSIZE);
733 oldgnu_store_sparse_info (file, &i,
734 blk->sparse_header.sp,
735 SPARSES_IN_SPARSE_HEADER);
736 if (i < file->stat_info->sparse_map_avail)
737 blk->sparse_header.isextended = 1;
738 set_next_block_after (blk);
739 }
740 return true;
741 }
742
743 static struct tar_sparse_optab const oldgnu_optab = {
744 NULL, /* No init function */
745 NULL, /* No done function */
746 oldgnu_sparse_member_p,
747 oldgnu_dump_header,
748 oldgnu_fixup_header,
749 oldgnu_get_sparse_info,
750 NULL, /* No scan_block function */
751 sparse_dump_region,
752 sparse_extract_region,
753 };
754
755 \f
756 /* Star */
757
758 static bool
759 star_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
760 {
761 return current_header->header.typeflag == GNUTYPE_SPARSE;
762 }
763
764 static bool
765 star_fixup_header (struct tar_sparse_file *file)
766 {
767 /* NOTE! st_size was initialized from the header
768 which actually contains archived size. The following fixes it */
769 file->stat_info->archive_file_size = file->stat_info->stat.st_size;
770 file->stat_info->stat.st_size =
771 OFF_FROM_HEADER (current_header->star_in_header.realsize);
772 return true;
773 }
774
775 /* Convert STAR format sparse data to internal representation */
776 static bool
777 star_get_sparse_info (struct tar_sparse_file *file)
778 {
779 size_t i;
780 union block *h = current_header;
781 int ext_p;
782 enum oldgnu_add_status rc = add_ok;
783
784 file->stat_info->sparse_map_avail = 0;
785
786 if (h->star_in_header.prefix[0] == '\0'
787 && h->star_in_header.sp[0].offset[10] != '\0')
788 {
789 /* Old star format */
790 for (i = 0; i < SPARSES_IN_STAR_HEADER; i++)
791 {
792 rc = oldgnu_add_sparse (file, &h->star_in_header.sp[i]);
793 if (rc != add_ok)
794 break;
795 }
796 ext_p = h->star_in_header.isextended;
797 }
798 else
799 ext_p = 1;
800
801 for (; rc == add_ok && ext_p; ext_p = h->star_ext_header.isextended)
802 {
803 h = find_next_block ();
804 if (!h)
805 {
806 ERROR ((0, 0, _("Unexpected EOF in archive")));
807 return false;
808 }
809 set_next_block_after (h);
810 for (i = 0; i < SPARSES_IN_STAR_EXT_HEADER && rc == add_ok; i++)
811 rc = oldgnu_add_sparse (file, &h->star_ext_header.sp[i]);
812 }
813
814 if (rc == add_fail)
815 {
816 ERROR ((0, 0, _("%s: invalid sparse archive member"),
817 file->stat_info->orig_file_name));
818 return false;
819 }
820 return true;
821 }
822
823
824 static struct tar_sparse_optab const star_optab = {
825 NULL, /* No init function */
826 NULL, /* No done function */
827 star_sparse_member_p,
828 NULL,
829 star_fixup_header,
830 star_get_sparse_info,
831 NULL, /* No scan_block function */
832 NULL, /* No dump region function */
833 sparse_extract_region,
834 };
835
836 \f
837 /* GNU PAX sparse file format. There are several versions:
838
839 * 0.0
840
841 The initial version of sparse format used by tar 1.14-1.15.1.
842 The sparse file map is stored in x header:
843
844 GNU.sparse.size Real size of the stored file
845 GNU.sparse.numblocks Number of blocks in the sparse map
846 repeat numblocks time
847 GNU.sparse.offset Offset of the next data block
848 GNU.sparse.numbytes Size of the next data block
849 end repeat
850
851 This has been reported as conflicting with the POSIX specs. The reason is
852 that offsets and sizes of non-zero data blocks were stored in multiple
853 instances of GNU.sparse.offset/GNU.sparse.numbytes variables, whereas
854 POSIX requires the latest occurrence of the variable to override all
855 previous occurrences.
856
857 To avoid this incompatibility two following versions were introduced.
858
859 * 0.1
860
861 Used by tar 1.15.2 -- 1.15.91 (alpha releases).
862
863 The sparse file map is stored in
864 x header:
865
866 GNU.sparse.size Real size of the stored file
867 GNU.sparse.numblocks Number of blocks in the sparse map
868 GNU.sparse.map Map of non-null data chunks. A string consisting
869 of comma-separated values "offset,size[,offset,size]..."
870
871 The resulting GNU.sparse.map string can be *very* long. While POSIX does not
872 impose any limit on the length of a x header variable, this can confuse some
873 tars.
874
875 * 1.0
876
877 Starting from this version, the exact sparse format version is specified
878 explicitely in the header using the following variables:
879
880 GNU.sparse.major Major version
881 GNU.sparse.minor Minor version
882
883 X header keeps the following variables:
884
885 GNU.sparse.name Real file name of the sparse file
886 GNU.sparse.realsize Real size of the stored file (corresponds to the old
887 GNU.sparse.size variable)
888
889 The name field of the ustar header is constructed using the pattern
890 "%d/GNUSparseFile.%p/%f".
891
892 The sparse map itself is stored in the file data block, preceding the actual
893 file data. It consists of a series of octal numbers of arbitrary length,
894 delimited by newlines. The map is padded with nulls to the nearest block
895 boundary.
896
897 The first number gives the number of entries in the map. Following are map
898 entries, each one consisting of two numbers giving the offset and size of
899 the data block it describes.
900
901 The format is designed in such a way that non-posix aware tars and tars not
902 supporting GNU.sparse.* keywords will extract each sparse file in its
903 condensed form with the file map attached and will place it into a separate
904 directory. Then, using a simple program it would be possible to expand the
905 file to its original form even without GNU tar.
906
907 Bu default, v.1.0 archives are created. To use other formats,
908 --sparse-version option is provided. Additionally, v.0.0 can be obtained
909 by deleting GNU.sparse.map from 0.1 format: --sparse-version 0.1
910 --pax-option delete=GNU.sparse.map
911 */
912
913 static bool
914 pax_sparse_member_p (struct tar_sparse_file *file)
915 {
916 return file->stat_info->sparse_map_avail > 0
917 || file->stat_info->sparse_major > 0;
918 }
919
920 static bool
921 pax_dump_header_0 (struct tar_sparse_file *file)
922 {
923 off_t block_ordinal = current_block_ordinal ();
924 union block *blk;
925 size_t i;
926 char nbuf[UINTMAX_STRSIZE_BOUND];
927 struct sp_array *map = file->stat_info->sparse_map;
928 char *save_file_name = NULL;
929
930 /* Store the real file size */
931 xheader_store ("GNU.sparse.size", file->stat_info, NULL);
932 xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
933
934 if (xheader_keyword_deleted_p ("GNU.sparse.map")
935 || tar_sparse_minor == 0)
936 {
937 for (i = 0; i < file->stat_info->sparse_map_avail; i++)
938 {
939 xheader_store ("GNU.sparse.offset", file->stat_info, &i);
940 xheader_store ("GNU.sparse.numbytes", file->stat_info, &i);
941 }
942 }
943 else
944 {
945 xheader_store ("GNU.sparse.name", file->stat_info, NULL);
946 save_file_name = file->stat_info->file_name;
947 file->stat_info->file_name = xheader_format_name (file->stat_info,
948 "%d/GNUSparseFile.%p/%f", 0);
949
950 xheader_string_begin (&file->stat_info->xhdr);
951 for (i = 0; i < file->stat_info->sparse_map_avail; i++)
952 {
953 if (i)
954 xheader_string_add (&file->stat_info->xhdr, ",");
955 xheader_string_add (&file->stat_info->xhdr,
956 umaxtostr (map[i].offset, nbuf));
957 xheader_string_add (&file->stat_info->xhdr, ",");
958 xheader_string_add (&file->stat_info->xhdr,
959 umaxtostr (map[i].numbytes, nbuf));
960 }
961 if (!xheader_string_end (&file->stat_info->xhdr,
962 "GNU.sparse.map"))
963 {
964 free (file->stat_info->file_name);
965 file->stat_info->file_name = save_file_name;
966 return false;
967 }
968 }
969 blk = start_header (file->stat_info);
970 /* Store the effective (shrunken) file size */
971 OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
972 finish_header (file->stat_info, blk, block_ordinal);
973 if (save_file_name)
974 {
975 free (file->stat_info->file_name);
976 file->stat_info->file_name = save_file_name;
977 }
978 return true;
979 }
980
981 static bool
982 pax_dump_header_1 (struct tar_sparse_file *file)
983 {
984 off_t block_ordinal = current_block_ordinal ();
985 union block *blk;
986 char *p, *q;
987 size_t i;
988 char nbuf[UINTMAX_STRSIZE_BOUND];
989 off_t size = 0;
990 struct sp_array *map = file->stat_info->sparse_map;
991 char *save_file_name = file->stat_info->file_name;
992
993 #define COPY_STRING(b,dst,src) do \
994 { \
995 char *endp = b->buffer + BLOCKSIZE; \
996 char const *srcp = src; \
997 while (*srcp) \
998 { \
999 if (dst == endp) \
1000 { \
1001 set_next_block_after (b); \
1002 b = find_next_block (); \
1003 dst = b->buffer; \
1004 endp = b->buffer + BLOCKSIZE; \
1005 } \
1006 *dst++ = *srcp++; \
1007 } \
1008 } while (0)
1009
1010 /* Compute stored file size */
1011 p = umaxtostr (file->stat_info->sparse_map_avail, nbuf);
1012 size += strlen (p) + 1;
1013 for (i = 0; i < file->stat_info->sparse_map_avail; i++)
1014 {
1015 p = umaxtostr (map[i].offset, nbuf);
1016 size += strlen (p) + 1;
1017 p = umaxtostr (map[i].numbytes, nbuf);
1018 size += strlen (p) + 1;
1019 }
1020 size = (size + BLOCKSIZE - 1) / BLOCKSIZE;
1021 file->stat_info->archive_file_size += size * BLOCKSIZE;
1022 file->dumped_size += size * BLOCKSIZE;
1023
1024 /* Store sparse file identification */
1025 xheader_store ("GNU.sparse.major", file->stat_info, NULL);
1026 xheader_store ("GNU.sparse.minor", file->stat_info, NULL);
1027 xheader_store ("GNU.sparse.name", file->stat_info, NULL);
1028 xheader_store ("GNU.sparse.realsize", file->stat_info, NULL);
1029
1030 file->stat_info->file_name = xheader_format_name (file->stat_info,
1031 "%d/GNUSparseFile.%p/%f", 0);
1032
1033 blk = start_header (file->stat_info);
1034 /* Store the effective (shrunken) file size */
1035 OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
1036 finish_header (file->stat_info, blk, block_ordinal);
1037 free (file->stat_info->file_name);
1038 file->stat_info->file_name = save_file_name;
1039
1040 blk = find_next_block ();
1041 q = blk->buffer;
1042 p = umaxtostr (file->stat_info->sparse_map_avail, nbuf);
1043 COPY_STRING (blk, q, p);
1044 COPY_STRING (blk, q, "\n");
1045 for (i = 0; i < file->stat_info->sparse_map_avail; i++)
1046 {
1047 p = umaxtostr (map[i].offset, nbuf);
1048 COPY_STRING (blk, q, p);
1049 COPY_STRING (blk, q, "\n");
1050 p = umaxtostr (map[i].numbytes, nbuf);
1051 COPY_STRING (blk, q, p);
1052 COPY_STRING (blk, q, "\n");
1053 }
1054 memset (q, 0, BLOCKSIZE - (q - blk->buffer));
1055 set_next_block_after (blk);
1056 return true;
1057 }
1058
1059 static bool
1060 pax_dump_header (struct tar_sparse_file *file)
1061 {
1062 file->stat_info->sparse_major = tar_sparse_major;
1063 file->stat_info->sparse_minor = tar_sparse_minor;
1064
1065 return (file->stat_info->sparse_major == 0) ?
1066 pax_dump_header_0 (file) : pax_dump_header_1 (file);
1067 }
1068
1069 static bool
1070 decode_num (uintmax_t *num, char const *arg, uintmax_t maxval)
1071 {
1072 uintmax_t u;
1073 char *arg_lim;
1074
1075 if (!ISDIGIT (*arg))
1076 return false;
1077
1078 u = strtoumax (arg, &arg_lim, 10);
1079
1080 if (! (u <= maxval && errno != ERANGE) || *arg_lim)
1081 return false;
1082
1083 *num = u;
1084 return true;
1085 }
1086
1087 static bool
1088 pax_decode_header (struct tar_sparse_file *file)
1089 {
1090 if (file->stat_info->sparse_major > 0)
1091 {
1092 uintmax_t u;
1093 char nbuf[UINTMAX_STRSIZE_BOUND];
1094 union block *blk;
1095 char *p;
1096 size_t i;
1097
1098 #define COPY_BUF(b,buf,src) do \
1099 { \
1100 char *endp = b->buffer + BLOCKSIZE; \
1101 char *dst = buf; \
1102 do \
1103 { \
1104 if (dst == buf + UINTMAX_STRSIZE_BOUND -1) \
1105 { \
1106 ERROR ((0, 0, _("%s: numeric overflow in sparse archive member"), \
1107 file->stat_info->orig_file_name)); \
1108 return false; \
1109 } \
1110 if (src == endp) \
1111 { \
1112 set_next_block_after (b); \
1113 file->dumped_size += BLOCKSIZE; \
1114 b = find_next_block (); \
1115 src = b->buffer; \
1116 endp = b->buffer + BLOCKSIZE; \
1117 } \
1118 *dst = *src++; \
1119 } \
1120 while (*dst++ != '\n'); \
1121 dst[-1] = 0; \
1122 } while (0)
1123
1124 set_next_block_after (current_header);
1125 file->dumped_size += BLOCKSIZE;
1126 blk = find_next_block ();
1127 p = blk->buffer;
1128 COPY_BUF (blk,nbuf,p);
1129 if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)))
1130 {
1131 ERROR ((0, 0, _("%s: malformed sparse archive member"),
1132 file->stat_info->orig_file_name));
1133 return false;
1134 }
1135 file->stat_info->sparse_map_size = u;
1136 file->stat_info->sparse_map = xcalloc (file->stat_info->sparse_map_size,
1137 sizeof (*file->stat_info->sparse_map));
1138 file->stat_info->sparse_map_avail = 0;
1139 for (i = 0; i < file->stat_info->sparse_map_size; i++)
1140 {
1141 struct sp_array sp;
1142
1143 COPY_BUF (blk,nbuf,p);
1144 if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t)))
1145 {
1146 ERROR ((0, 0, _("%s: malformed sparse archive member"),
1147 file->stat_info->orig_file_name));
1148 return false;
1149 }
1150 sp.offset = u;
1151 COPY_BUF (blk,nbuf,p);
1152 if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t)))
1153 {
1154 ERROR ((0, 0, _("%s: malformed sparse archive member"),
1155 file->stat_info->orig_file_name));
1156 return false;
1157 }
1158 sp.numbytes = u;
1159 sparse_add_map (file->stat_info, &sp);
1160 }
1161 set_next_block_after (blk);
1162 }
1163
1164 return true;
1165 }
1166
1167 static struct tar_sparse_optab const pax_optab = {
1168 NULL, /* No init function */
1169 NULL, /* No done function */
1170 pax_sparse_member_p,
1171 pax_dump_header,
1172 NULL,
1173 pax_decode_header,
1174 NULL, /* No scan_block function */
1175 sparse_dump_region,
1176 sparse_extract_region,
1177 };
This page took 0.080944 seconds and 5 git commands to generate.