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