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