Extract sparse files even if the output fd is not seekable.
[debian/tar] / src / sparse.c
1 /* Functions for dealing with sparse files
2
3    Copyright (C) 2003, 2004, 2005 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    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19 #include <system.h>
20 #include <quotearg.h>
21 #include "common.h"
22
23 struct tar_sparse_file;
24
25 enum sparse_scan_state
26   {
27     scan_begin,
28     scan_block,
29     scan_end
30   };
31
32 struct tar_sparse_optab
33 {
34   bool (*init) (struct tar_sparse_file *);
35   bool (*done) (struct tar_sparse_file *);
36   bool (*sparse_member_p) (struct tar_sparse_file *);
37   bool (*dump_header) (struct tar_sparse_file *);
38   bool (*fixup_header) (struct tar_sparse_file *);
39   bool (*decode_header) (struct tar_sparse_file *);
40   bool (*scan_block) (struct tar_sparse_file *, enum sparse_scan_state,
41                       void *);
42   bool (*dump_region) (struct tar_sparse_file *, size_t);
43   bool (*extract_region) (struct tar_sparse_file *, size_t);
44 };
45
46 struct tar_sparse_file
47 {
48   int fd;                           /* File descriptor */
49   bool seekable;                    /* Is fd seekable? */
50   size_t offset;                    /* Current offset in fd if seekable==false.
51                                        Otherwise unused */
52   size_t dumped_size;               /* Number of bytes actually written
53                                        to the archive */
54   struct tar_stat_info *stat_info;  /* Information about the file */
55   struct tar_sparse_optab *optab;
56   void *closure;                    /* Any additional data optab calls might
57                                        reqiure */
58 };
59
60 /* Dump zeros to file->fd until offset is reached. It is used instead of
61    lseek if the output file is not seekable */
62 static long
63 dump_zeros (struct tar_sparse_file *file, off_t offset)
64 {
65   char buf[BLOCKSIZE];
66   
67   if (offset - file->offset < 0)
68     {
69       errno = EINVAL;
70       return -1;
71     }
72
73   memset (buf, 0, sizeof buf);
74   while (file->offset < offset)
75     {
76       size_t size = offset - file->offset;
77       size_t wrbytes;
78       
79       if (size > sizeof buf)
80         size = sizeof buf;
81       wrbytes = write (file->fd, buf, size);
82       if (wrbytes <= 0)
83         {
84           if (wrbytes == 0)
85             errno = EINVAL;
86           return -1;
87         }
88       file->offset += wrbytes;
89     }
90   return file->offset;
91 }
92
93 static bool
94 tar_sparse_member_p (struct tar_sparse_file *file)
95 {
96   if (file->optab->sparse_member_p)
97     return file->optab->sparse_member_p (file);
98   return false;
99 }
100
101 static bool
102 tar_sparse_init (struct tar_sparse_file *file)
103 {
104   file->dumped_size = 0;
105   if (file->optab->init)
106     return file->optab->init (file);
107   return true;
108 }
109
110 static bool
111 tar_sparse_done (struct tar_sparse_file *file)
112 {
113   if (file->optab->done)
114     return file->optab->done (file);
115   return true;
116 }
117
118 static bool
119 tar_sparse_scan (struct tar_sparse_file *file, enum sparse_scan_state state,
120                  void *block)
121 {
122   if (file->optab->scan_block)
123     return file->optab->scan_block (file, state, block);
124   return true;
125 }
126
127 static bool
128 tar_sparse_dump_region (struct tar_sparse_file *file, size_t i)
129 {
130   if (file->optab->dump_region)
131     return file->optab->dump_region (file, i);
132   return false;
133 }
134
135 static bool
136 tar_sparse_extract_region (struct tar_sparse_file *file, size_t i)
137 {
138   if (file->optab->extract_region)
139     return file->optab->extract_region (file, i);
140   return false;
141 }
142
143 static bool
144 tar_sparse_dump_header (struct tar_sparse_file *file)
145 {
146   if (file->optab->dump_header)
147     return file->optab->dump_header (file);
148   return false;
149 }
150
151 static bool
152 tar_sparse_decode_header (struct tar_sparse_file *file)
153 {
154   if (file->optab->decode_header)
155     return file->optab->decode_header (file);
156   return true;
157 }
158
159 static bool
160 tar_sparse_fixup_header (struct tar_sparse_file *file)
161 {
162   if (file->optab->fixup_header)
163     return file->optab->fixup_header (file);
164   return true;
165 }
166
167 \f
168 static bool
169 lseek_or_error (struct tar_sparse_file *file, off_t offset)
170 {
171   off_t off;
172
173   if (file->seekable)
174     off = lseek (file->fd, offset, SEEK_SET);
175   else
176     off = dump_zeros (file, offset);
177   
178   if (off < 0)
179     {
180       seek_diag_details (file->stat_info->orig_file_name, offset);
181       return false;
182     }
183   return true;
184 }
185
186 /* Takes a blockful of data and basically cruises through it to see if
187    it's made *entirely* of zeros, returning a 0 the instant it finds
188    something that is a nonzero, i.e., useful data.  */
189 static bool
190 zero_block_p (char *buffer, size_t size)
191 {
192   while (size--)
193     if (*buffer++)
194       return false;
195   return true;
196 }
197
198 #define clear_block(p) memset (p, 0, BLOCKSIZE);
199
200 #define SPARSES_INIT_COUNT SPARSES_IN_SPARSE_HEADER
201
202 static void
203 sparse_add_map (struct tar_sparse_file *file, struct sp_array *sp)
204 {
205   if (file->stat_info->sparse_map == NULL)
206     {
207       file->stat_info->sparse_map =
208         xmalloc (SPARSES_INIT_COUNT * sizeof file->stat_info->sparse_map[0]);
209       file->stat_info->sparse_map_size = SPARSES_INIT_COUNT;
210     }
211   else if (file->stat_info->sparse_map_avail == file->stat_info->sparse_map_size)
212     {
213       file->stat_info->sparse_map_size *= 2;
214       file->stat_info->sparse_map =
215         xrealloc (file->stat_info->sparse_map,
216                   file->stat_info->sparse_map_size
217                   * sizeof file->stat_info->sparse_map[0]);
218     }
219   file->stat_info->sparse_map[file->stat_info->sparse_map_avail++] = *sp;
220 }
221
222 /* Scan the sparse file and create its map */
223 static bool
224 sparse_scan_file (struct tar_sparse_file *file)
225 {
226   static char buffer[BLOCKSIZE];
227   size_t count;
228   size_t offset = 0;
229   struct sp_array sp = {0, 0};
230
231   if (!lseek_or_error (file, 0))
232     return false;
233   clear_block (buffer);
234
235   file->stat_info->sparse_map_avail = 0;
236   file->stat_info->archive_file_size = 0;
237
238   if (!tar_sparse_scan (file, scan_begin, NULL))
239     return false;
240
241   while ((count = safe_read (file->fd, buffer, sizeof buffer)) != 0
242          && count != SAFE_READ_ERROR)
243     {
244       /* Analize the block */
245       if (zero_block_p (buffer, count))
246         {
247           if (sp.numbytes)
248             {
249               sparse_add_map (file, &sp);
250               sp.numbytes = 0;
251               if (!tar_sparse_scan (file, scan_block, NULL))
252                 return false;
253             }
254         }
255       else
256         {
257           if (sp.numbytes == 0)
258             sp.offset = offset;
259           sp.numbytes += count;
260           file->stat_info->archive_file_size += count;
261           if (!tar_sparse_scan (file, scan_block, buffer))
262             return false;
263         }
264
265       offset += count;
266       clear_block (buffer);
267     }
268
269   if (sp.numbytes == 0)
270     sp.offset = offset;
271
272   sparse_add_map (file, &sp);
273   file->stat_info->archive_file_size += count;
274   return tar_sparse_scan (file, scan_end, NULL);
275 }
276
277 static struct tar_sparse_optab oldgnu_optab;
278 static struct tar_sparse_optab star_optab;
279 static struct tar_sparse_optab pax_optab;
280
281 static bool
282 sparse_select_optab (struct tar_sparse_file *file)
283 {
284   switch (current_format == DEFAULT_FORMAT ? archive_format : current_format)
285     {
286     case V7_FORMAT:
287     case USTAR_FORMAT:
288       return false;
289
290     case OLDGNU_FORMAT:
291     case GNU_FORMAT: /*FIXME: This one should disappear? */
292       file->optab = &oldgnu_optab;
293       break;
294
295     case POSIX_FORMAT:
296       file->optab = &pax_optab;
297       break;
298
299     case STAR_FORMAT:
300       file->optab = &star_optab;
301       break;
302
303     default:
304       return false;
305     }
306   return true;
307 }
308
309 static bool
310 sparse_dump_region (struct tar_sparse_file *file, size_t i)
311 {
312   union block *blk;
313   off_t bytes_left = file->stat_info->sparse_map[i].numbytes;
314
315   if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
316     return false;
317
318   while (bytes_left > 0)
319     {
320       size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left;
321       size_t bytes_read;
322
323       blk = find_next_block ();
324       memset (blk->buffer, 0, BLOCKSIZE);
325       bytes_read = safe_read (file->fd, blk->buffer, bufsize);
326       if (bytes_read == SAFE_READ_ERROR)
327         {
328           read_diag_details (file->stat_info->orig_file_name,
329                              file->stat_info->sparse_map[i].offset
330                                  + file->stat_info->sparse_map[i].numbytes
331                                  - bytes_left,
332                      bufsize);
333           return false;
334         }
335
336       bytes_left -= bytes_read;
337       file->dumped_size += bytes_read;
338       set_next_block_after (blk);
339     }
340
341   return true;
342 }
343
344 static bool
345 sparse_extract_region (struct tar_sparse_file *file, size_t i)
346 {
347   size_t write_size;
348
349   if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
350     return false;
351
352   write_size = file->stat_info->sparse_map[i].numbytes;
353
354   if (write_size == 0)
355     {
356       /* Last block of the file is a hole */
357       if (file->seekable && sys_truncate (file->fd))
358         truncate_warn (file->stat_info->orig_file_name);
359     }
360   else while (write_size > 0)
361     {
362       size_t count;
363       size_t wrbytes = (write_size > BLOCKSIZE) ? BLOCKSIZE : write_size;
364       union block *blk = find_next_block ();
365       if (!blk)
366         {
367           ERROR ((0, 0, _("Unexpected EOF in archive")));
368           return false;
369         }
370       set_next_block_after (blk);
371       count = full_write (file->fd, blk->buffer, wrbytes);
372       write_size -= count;
373       file->dumped_size += count;
374       file->offset += count;
375       if (count != wrbytes)
376         {
377           write_error_details (file->stat_info->orig_file_name,
378                                count, wrbytes);
379           return false;
380         }
381     }
382   return true;
383 }
384
385 \f
386
387 /* Interface functions */
388 enum dump_status
389 sparse_dump_file (int fd, struct tar_stat_info *st)
390 {
391   bool rc;
392   struct tar_sparse_file file;
393
394   file.stat_info = st;
395   file.fd = fd;
396   file.seekable = true; /* File *must* be seekable for dump to work */
397   file.offset = 0;
398   
399   if (!sparse_select_optab (&file)
400       || !tar_sparse_init (&file))
401     return dump_status_not_implemented;
402
403   rc = sparse_scan_file (&file);
404   if (rc && file.optab->dump_region)
405     {
406       tar_sparse_dump_header (&file);
407
408       if (fd >= 0)
409         {
410           size_t i;
411
412           for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
413             rc = tar_sparse_dump_region (&file, i);
414         }
415     }
416
417   pad_archive(file.stat_info->archive_file_size - file.dumped_size);
418   return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
419 }
420
421 /* Returns true if the file represented by stat is a sparse one */
422 bool
423 sparse_file_p (struct tar_stat_info *st)
424 {
425   return (ST_NBLOCKS (st->stat)
426           < (st->stat.st_size / ST_NBLOCKSIZE
427              + (st->stat.st_size % ST_NBLOCKSIZE != 0)));
428 }
429
430 bool
431 sparse_member_p (struct tar_stat_info *st)
432 {
433   struct tar_sparse_file file;
434
435   if (!sparse_select_optab (&file))
436     return false;
437   file.stat_info = st;
438   return tar_sparse_member_p (&file);
439 }
440
441 bool
442 sparse_fixup_header (struct tar_stat_info *st)
443 {
444   struct tar_sparse_file file;
445
446   if (!sparse_select_optab (&file))
447     return false;
448   file.stat_info = st;
449   return tar_sparse_fixup_header (&file);
450 }
451
452 enum dump_status
453 sparse_extract_file (int fd, struct tar_stat_info *st, off_t *size)
454 {
455   bool rc = true;
456   struct tar_sparse_file file;
457   size_t i;
458
459   file.stat_info = st;
460   file.fd = fd;
461   file.seekable = lseek (fd, 0, SEEK_SET) == 0;
462   file.offset = 0;
463   
464   if (!sparse_select_optab (&file)
465       || !tar_sparse_init (&file))
466     return dump_status_not_implemented;
467
468   rc = tar_sparse_decode_header (&file);
469   for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
470     rc = tar_sparse_extract_region (&file, i);
471   *size = file.stat_info->archive_file_size - file.dumped_size;
472   return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
473 }
474
475 enum dump_status
476 sparse_skip_file (struct tar_stat_info *st)
477 {
478   bool rc = true;
479   struct tar_sparse_file file;
480
481   file.stat_info = st;
482   file.fd = -1;
483
484   if (!sparse_select_optab (&file)
485       || !tar_sparse_init (&file))
486     return dump_status_not_implemented;
487
488   rc = tar_sparse_decode_header (&file);
489   skip_file (file.stat_info->archive_file_size);
490   return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
491 }
492
493 \f
494 static char diff_buffer[BLOCKSIZE];
495
496 static bool
497 check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
498 {
499   if (!lseek_or_error (file, beg))
500     return false;
501
502   while (beg < end)
503     {
504       size_t bytes_read;
505       size_t rdsize = end - beg;
506
507       if (rdsize > BLOCKSIZE)
508         rdsize = BLOCKSIZE;
509       clear_block (diff_buffer);
510       bytes_read = safe_read (file->fd, diff_buffer, rdsize);
511       if (bytes_read == SAFE_READ_ERROR)
512         {
513           read_diag_details (file->stat_info->orig_file_name,
514                              beg,
515                              rdsize);
516           return false;
517         }
518       if (!zero_block_p (diff_buffer, bytes_read))
519         {
520           report_difference (file->stat_info,
521                              _("File fragment at %lu is not a hole"), beg);
522           return false;
523         }
524
525       beg += bytes_read;
526     }
527   return true;
528 }
529
530 static bool
531 check_data_region (struct tar_sparse_file *file, size_t i)
532 {
533   size_t size_left;
534
535   if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
536     return false;
537   size_left = file->stat_info->sparse_map[i].numbytes;
538   while (size_left > 0)
539     {
540       size_t bytes_read;
541       size_t rdsize = (size_left > BLOCKSIZE) ? BLOCKSIZE : size_left;
542
543       union block *blk = find_next_block ();
544       if (!blk)
545         {
546           ERROR ((0, 0, _("Unexpected EOF in archive")));
547           return false;
548         }
549       set_next_block_after (blk);
550       bytes_read = safe_read (file->fd, diff_buffer, rdsize);
551       if (bytes_read == SAFE_READ_ERROR)
552         {
553           read_diag_details (file->stat_info->orig_file_name,
554                              file->stat_info->sparse_map[i].offset
555                                  + file->stat_info->sparse_map[i].numbytes
556                                  - size_left,
557                              rdsize);
558           return false;
559         }
560       file->dumped_size += bytes_read;
561       size_left -= bytes_read;
562       if (memcmp (blk->buffer, diff_buffer, rdsize))
563         {
564           report_difference (file->stat_info, _("Contents differ"));
565           return false;
566         }
567     }
568   return true;
569 }
570
571 bool
572 sparse_diff_file (int fd, struct tar_stat_info *st)
573 {
574   bool rc = true;
575   struct tar_sparse_file file;
576   size_t i;
577   off_t offset = 0;
578
579   file.stat_info = st;
580   file.fd = fd;
581
582   if (!sparse_select_optab (&file)
583       || !tar_sparse_init (&file))
584     return dump_status_not_implemented;
585
586   rc = tar_sparse_decode_header (&file);
587   for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
588     {
589       rc = check_sparse_region (&file,
590                                 offset, file.stat_info->sparse_map[i].offset)
591         && check_data_region (&file, i);
592       offset = file.stat_info->sparse_map[i].offset
593                 + file.stat_info->sparse_map[i].numbytes;
594     }
595
596   if (!rc)
597     skip_file (file.stat_info->archive_file_size - file.dumped_size);
598
599   tar_sparse_done (&file);
600   return rc;
601 }
602
603 \f
604 /* Old GNU Format. The sparse file information is stored in the
605    oldgnu_header in the following manner:
606
607    The header is marked with type 'S'. Its `size' field contains
608    the cumulative size of all non-empty blocks of the file. The
609    actual file size is stored in `realsize' member of oldgnu_header.
610
611    The map of the file is stored in a list of `struct sparse'.
612    Each struct contains offset to the block of data and its
613    size (both as octal numbers). The first file header contains
614    at most 4 such structs (SPARSES_IN_OLDGNU_HEADER). If the map
615    contains more structs, then the field `isextended' of the main
616    header is set to 1 (binary) and the `struct sparse_header'
617    header follows, containing at most 21 following structs
618    (SPARSES_IN_SPARSE_HEADER). If more structs follow, `isextended'
619    field of the extended header is set and next  next extension header
620    follows, etc... */
621
622 enum oldgnu_add_status
623   {
624     add_ok,
625     add_finish,
626     add_fail
627   };
628
629 static bool
630 oldgnu_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
631 {
632   return current_header->header.typeflag == GNUTYPE_SPARSE;
633 }
634
635 /* Add a sparse item to the sparse file and its obstack */
636 static enum oldgnu_add_status
637 oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
638 {
639   struct sp_array sp;
640
641   if (s->numbytes[0] == '\0')
642     return add_finish;
643   sp.offset = OFF_FROM_HEADER (s->offset);
644   sp.numbytes = SIZE_FROM_HEADER (s->numbytes);
645   if (sp.offset < 0
646       || file->stat_info->stat.st_size < sp.offset + sp.numbytes
647       || file->stat_info->archive_file_size < 0)
648     return add_fail;
649
650   sparse_add_map (file, &sp);
651   return add_ok;
652 }
653
654 static bool
655 oldgnu_fixup_header (struct tar_sparse_file *file)
656 {
657   /* NOTE! st_size was initialized from the header
658      which actually contains archived size. The following fixes it */
659   file->stat_info->archive_file_size = file->stat_info->stat.st_size;
660   file->stat_info->stat.st_size =
661                 OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
662   return true;
663 }
664
665 /* Convert old GNU format sparse data to internal representation */
666 static bool
667 oldgnu_get_sparse_info (struct tar_sparse_file *file)
668 {
669   size_t i;
670   union block *h = current_header;
671   int ext_p;
672   static enum oldgnu_add_status rc;
673
674   file->stat_info->sparse_map_avail = 0;
675   for (i = 0; i < SPARSES_IN_OLDGNU_HEADER; i++)
676     {
677       rc = oldgnu_add_sparse (file, &h->oldgnu_header.sp[i]);
678       if (rc != add_ok)
679         break;
680     }
681
682   for (ext_p = h->oldgnu_header.isextended;
683        rc == add_ok && ext_p; ext_p = h->sparse_header.isextended)
684     {
685       h = find_next_block ();
686       if (!h)
687         {
688           ERROR ((0, 0, _("Unexpected EOF in archive")));
689           return false;
690         }
691       set_next_block_after (h);
692       for (i = 0; i < SPARSES_IN_SPARSE_HEADER && rc == add_ok; i++)
693         rc = oldgnu_add_sparse (file, &h->sparse_header.sp[i]);
694     }
695
696   if (rc == add_fail)
697     {
698       ERROR ((0, 0, _("%s: invalid sparse archive member"),
699               file->stat_info->orig_file_name));
700       return false;
701     }
702   return true;
703 }
704
705 static void
706 oldgnu_store_sparse_info (struct tar_sparse_file *file, size_t *pindex,
707                           struct sparse *sp, size_t sparse_size)
708 {
709   for (; *pindex < file->stat_info->sparse_map_avail
710          && sparse_size > 0; sparse_size--, sp++, ++*pindex)
711     {
712       OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].offset,
713                     sp->offset);
714       SIZE_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes,
715                      sp->numbytes);
716     }
717 }
718
719 static bool
720 oldgnu_dump_header (struct tar_sparse_file *file)
721 {
722   off_t block_ordinal = current_block_ordinal ();
723   union block *blk;
724   size_t i;
725
726   blk = start_header (file->stat_info);
727   blk->header.typeflag = GNUTYPE_SPARSE;
728   if (file->stat_info->sparse_map_avail > SPARSES_IN_OLDGNU_HEADER)
729     blk->oldgnu_header.isextended = 1;
730
731   /* Store the real file size */
732   OFF_TO_CHARS (file->stat_info->stat.st_size, blk->oldgnu_header.realsize);
733   /* Store the effective (shrunken) file size */
734   OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
735
736   i = 0;
737   oldgnu_store_sparse_info (file, &i,
738                             blk->oldgnu_header.sp,
739                             SPARSES_IN_OLDGNU_HEADER);
740   blk->oldgnu_header.isextended = i < file->stat_info->sparse_map_avail;
741   finish_header (file->stat_info, blk, block_ordinal);
742
743   while (i < file->stat_info->sparse_map_avail)
744     {
745       blk = find_next_block ();
746       memset (blk->buffer, 0, BLOCKSIZE);
747       oldgnu_store_sparse_info (file, &i,
748                                 blk->sparse_header.sp,
749                                 SPARSES_IN_SPARSE_HEADER);
750       set_next_block_after (blk);
751       if (i < file->stat_info->sparse_map_avail)
752         blk->sparse_header.isextended = 1;
753       else
754         break;
755     }
756   return true;
757 }
758
759 static struct tar_sparse_optab oldgnu_optab = {
760   NULL,  /* No init function */
761   NULL,  /* No done function */
762   oldgnu_sparse_member_p,
763   oldgnu_dump_header,
764   oldgnu_fixup_header,
765   oldgnu_get_sparse_info,
766   NULL,  /* No scan_block function */
767   sparse_dump_region,
768   sparse_extract_region,
769 };
770
771 \f
772 /* Star */
773
774 static bool
775 star_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
776 {
777   return current_header->header.typeflag == GNUTYPE_SPARSE;
778 }
779
780 static bool
781 star_fixup_header (struct tar_sparse_file *file)
782 {
783   /* NOTE! st_size was initialized from the header
784      which actually contains archived size. The following fixes it */
785   file->stat_info->archive_file_size = file->stat_info->stat.st_size;
786   file->stat_info->stat.st_size =
787             OFF_FROM_HEADER (current_header->star_in_header.realsize);
788   return true;
789 }
790
791 /* Convert STAR format sparse data to internal representation */
792 static bool
793 star_get_sparse_info (struct tar_sparse_file *file)
794 {
795   size_t i;
796   union block *h = current_header;
797   int ext_p;
798   static enum oldgnu_add_status rc;
799
800   file->stat_info->sparse_map_avail = 0;
801
802   if (h->star_in_header.prefix[0] == '\0'
803       && h->star_in_header.sp[0].offset[10] != '\0')
804     {
805       /* Old star format */
806       for (i = 0; i < SPARSES_IN_STAR_HEADER; i++)
807         {
808           rc = oldgnu_add_sparse (file, &h->star_in_header.sp[i]);
809           if (rc != add_ok)
810             break;
811         }
812       ext_p = h->star_in_header.isextended;
813     }
814   else
815     ext_p = 1;
816
817   for (; rc == add_ok && ext_p; ext_p = h->star_ext_header.isextended)
818     {
819       h = find_next_block ();
820       if (!h)
821         {
822           ERROR ((0, 0, _("Unexpected EOF in archive")));
823           return false;
824         }
825       set_next_block_after (h);
826       for (i = 0; i < SPARSES_IN_STAR_EXT_HEADER && rc == add_ok; i++)
827         rc = oldgnu_add_sparse (file, &h->star_ext_header.sp[i]);
828     }
829
830   if (rc == add_fail)
831     {
832       ERROR ((0, 0, _("%s: invalid sparse archive member"),
833               file->stat_info->orig_file_name));
834       return false;
835     }
836   return true;
837 }
838
839
840 static struct tar_sparse_optab star_optab = {
841   NULL,  /* No init function */
842   NULL,  /* No done function */
843   star_sparse_member_p,
844   NULL,
845   star_fixup_header,
846   star_get_sparse_info,
847   NULL,  /* No scan_block function */
848   NULL, /* No dump region function */
849   sparse_extract_region,
850 };
851
852 \f
853 /* GNU PAX sparse file format. The sparse file map is stored in
854    x header:
855
856    GNU.sparse.size      Real size of the stored file
857    GNU.sparse.numblocks Number of blocks in the sparse map
858    repeat numblocks time
859      GNU.sparse.offset    Offset of the next data block
860      GNU.sparse.numbytes  Size of the next data block
861    end repeat
862 */
863
864 static bool
865 pax_sparse_member_p (struct tar_sparse_file *file)
866 {
867   return file->stat_info->archive_file_size != file->stat_info->stat.st_size;
868 }
869
870 static bool
871 pax_dump_header (struct tar_sparse_file *file)
872 {
873   off_t block_ordinal = current_block_ordinal ();
874   union block *blk;
875   size_t i;
876
877   /* Store the real file size */
878   xheader_store ("GNU.sparse.size", file->stat_info, NULL);
879   xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
880   for (i = 0; i < file->stat_info->sparse_map_avail; i++)
881     {
882       xheader_store ("GNU.sparse.offset", file->stat_info, &i);
883       xheader_store ("GNU.sparse.numbytes", file->stat_info, &i);
884     }
885
886   blk = start_header (file->stat_info);
887   /* Store the effective (shrunken) file size */
888   OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
889   finish_header (file->stat_info, blk, block_ordinal);
890   return true;
891 }
892
893 static struct tar_sparse_optab pax_optab = {
894   NULL,  /* No init function */
895   NULL,  /* No done function */
896   pax_sparse_member_p,
897   pax_dump_header,
898   NULL,  /* No decode_header function */
899   NULL,  /* No fixup_header function */
900   NULL,  /* No scan_block function */
901   sparse_dump_region,
902   sparse_extract_region,
903 };
904