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