]>
Dogcows Code - chaz/tar/blob - scripts/xsparse.c
1 /* xsparse - expands compressed sparse file images extracted from GNU tar
4 Copyright 2006, 2007, 2010, 2013 Free Software Foundation, Inc.
6 This file is part of GNU tar.
8 GNU tar is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 GNU tar is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 Written by Sergey Poznyakoff */
34 /* Bound on length of the string representing an off_t.
35 See INT_STRLEN_BOUND in intprops.h for explanation */
36 #define OFF_T_STRLEN_BOUND ((sizeof (off_t) * CHAR_BIT) * 146 / 485 + 1)
37 #define OFF_T_STRSIZE_BOUND (OFF_T_STRLEN_BOUND+1)
51 die (int code
, char *fmt
, ...)
55 fprintf (stderr
, "%s: ", progname
);
57 vfprintf (stderr
, fmt
, ap
);
59 fprintf (stderr
, "\n");
66 char *p
= malloc (size
);
68 die (1, "not enough memory");
73 string_to_off (char *p
, char **endp
)
81 if (9 < (unsigned) digit
)
88 die (1, "number parse error near %s", p
);
91 die (1, "number out of allowed range, near %s", p
);
94 die (1, "negative number");
102 string_to_size (char *p
, char **endp
)
104 off_t v
= string_to_off (p
, endp
);
107 die (1, "number too big");
111 size_t sparse_map_size
;
112 struct sp_array
*sparse_map
;
115 get_line (char *s
, int size
, FILE *stream
)
117 char *p
= fgets (s
, size
, stream
);
121 die (1, "unexpected end of file");
123 if (s
[len
- 1] != '\n')
124 die (1, "buffer overflow");
129 get_var (FILE *fp
, char **name
, char **value
)
132 static size_t bufsize
= OFF_T_STRSIZE_BOUND
;
135 buffer
= emalloc (bufsize
);
140 if (!fgets (buffer
, bufsize
, fp
))
142 len
= strlen (buffer
);
146 s
= string_to_size (buffer
, &p
);
148 die (1, "malformed header: expected space but found %s", p
);
149 if (buffer
[len
-1] != '\n')
154 buffer
= realloc (buffer
, bufsize
);
156 die (1, "not enough memory");
158 if (!fgets (buffer
+ len
, s
- len
+ 1, fp
))
159 die (1, "unexpected end of file or read error");
163 while (memcmp (p
, "GNU.sparse.", 11));
168 die (1, "malformed header: expected '=' not found");
170 q
[strlen (q
) - 1] = 0;
178 unsigned version_major
;
179 unsigned version_minor
;
182 read_xheader (char *name
)
185 FILE *fp
= fopen (name
, "r");
190 printf ("Reading extended header file\n");
192 while (get_var (fp
, &kw
, &val
))
195 printf ("Found variable GNU.sparse.%s = %s\n", kw
, val
);
197 if (expect
&& strcmp (kw
, expect
))
198 die (1, "bad keyword sequence: expected '%s' but found '%s'",
201 if (strcmp (kw
, "name") == 0)
203 outname
= emalloc (strlen (val
) + 1);
204 strcpy (outname
, val
);
206 else if (strcmp (kw
, "major") == 0)
208 version_major
= string_to_size (val
, NULL
);
210 else if (strcmp (kw
, "minor") == 0)
212 version_minor
= string_to_size (val
, NULL
);
214 else if (strcmp (kw
, "realsize") == 0
215 || strcmp (kw
, "size") == 0)
217 outsize
= string_to_off (val
, NULL
);
219 else if (strcmp (kw
, "numblocks") == 0)
221 sparse_map_size
= string_to_size (val
, NULL
);
222 sparse_map
= emalloc (sparse_map_size
* sizeof *sparse_map
);
224 else if (strcmp (kw
, "offset") == 0)
226 sparse_map
[i
].offset
= string_to_off (val
, NULL
);
229 else if (strcmp (kw
, "numbytes") == 0)
231 sparse_map
[i
++].numbytes
= string_to_off (val
, NULL
);
233 else if (strcmp (kw
, "map") == 0)
235 for (i
= 0; i
< sparse_map_size
; i
++)
237 sparse_map
[i
].offset
= string_to_off (val
, &val
);
239 die (1, "bad GNU.sparse.map: expected ',' but found '%c'",
241 sparse_map
[i
].numbytes
= string_to_off (val
+1, &val
);
244 if (!(*val
== 0 && i
== sparse_map_size
-1))
245 die (1, "bad GNU.sparse.map: expected ',' but found '%c'",
252 die (1, "bad GNU.sparse.map: garbage at the end");
256 die (1, "bad keyword sequence: expected '%s' not found", expect
);
257 if (version_major
== 0 && sparse_map_size
== 0)
258 die (1, "size of the sparse map unknown");
259 if (i
!= sparse_map_size
)
260 die (1, "not all sparse entries supplied");
268 char nbuf
[OFF_T_STRSIZE_BOUND
];
271 printf ("Reading v.1.0 sparse map\n");
273 get_line (nbuf
, sizeof nbuf
, ifp
);
274 sparse_map_size
= string_to_size (nbuf
, NULL
);
275 sparse_map
= emalloc (sparse_map_size
* sizeof *sparse_map
);
277 for (i
= 0; i
< sparse_map_size
; i
++)
279 get_line (nbuf
, sizeof nbuf
, ifp
);
280 sparse_map
[i
].offset
= string_to_off (nbuf
, NULL
);
281 get_line (nbuf
, sizeof nbuf
, ifp
);
282 sparse_map
[i
].numbytes
= string_to_off (nbuf
, NULL
);
285 fseeko (ifp
, ((ftell (ifp
) + BLOCKSIZE
- 1) / BLOCKSIZE
) * BLOCKSIZE
,
290 expand_sparse (FILE *sfp
, int ofd
)
293 off_t max_numbytes
= 0;
297 for (i
= 0; i
< sparse_map_size
; i
++)
298 if (max_numbytes
< sparse_map
[i
].numbytes
)
299 max_numbytes
= sparse_map
[i
].numbytes
;
301 maxbytes
= max_numbytes
< SIZE_MAX
? max_numbytes
: SIZE_MAX
;
303 for (buffer
= malloc (maxbytes
); !buffer
; maxbytes
/= 2)
305 die (1, "not enough memory");
307 for (i
= 0; i
< sparse_map_size
; i
++)
309 off_t size
= sparse_map
[i
].numbytes
;
312 ftruncate (ofd
, sparse_map
[i
].offset
);
315 lseek (ofd
, sparse_map
[i
].offset
, SEEK_SET
);
318 size_t rdsize
= (size
< maxbytes
) ? size
: maxbytes
;
319 if (rdsize
!= fread (buffer
, 1, rdsize
, sfp
))
320 die (1, "read error (%d)", errno
);
321 if (rdsize
!= write (ofd
, buffer
, rdsize
))
322 die (1, "write error (%d)", errno
);
333 printf ("Usage: %s [OPTIONS] infile [outfile]\n", progname
);
334 printf ("%s: expand sparse files extracted from GNU archives\n",
336 printf ("\nOPTIONS are:\n\n");
337 printf (" -h Display this help list\n");
338 printf (" -n Dry run: do nothing, print what would have been done\n");
339 printf (" -v Increase verbosity level\n");
340 printf (" -x FILE Parse extended header FILE\n\n");
346 guess_outname (char *name
)
351 if (name
[0] == '.' && name
[1] == '/')
354 p
= name
+ strlen (name
) - 1;
357 for (; p
> name
&& *p
!= '/'; p
--)
363 for (p
--; p
> name
&& *p
!= '/'; p
--)
373 outname
= emalloc (4 + strlen (name
));
374 strcpy (outname
, "../");
375 strcpy (outname
+ 3, name
);
380 size_t len
= p
- name
+ 1;
381 outname
= emalloc (len
+ strlen (s
) + 1);
382 memcpy (outname
, name
, len
);
383 strcpy (outname
+ len
, s
);
388 main (int argc
, char **argv
)
392 char *xheader_file
= NULL
;
399 while ((c
= getopt (argc
, argv
, "hnvx:")) != EOF
)
408 xheader_file
= optarg
;
425 if (argc
== 0 || argc
> 2)
429 read_xheader (xheader_file
);
435 if (stat (inname
, &st
))
436 die (1, "cannot stat %s (%d)", inname
, errno
);
438 ifp
= fopen (inname
, "r");
440 die (1, "cannot open file %s (%d)", inname
, errno
);
442 if (!xheader_file
|| version_major
== 1)
446 guess_outname (inname
);
448 ofd
= open (outname
, O_RDWR
|O_CREAT
|O_TRUNC
, st
.st_mode
);
450 die (1, "cannot open file %s (%d)", outname
, errno
);
453 printf ("Expanding file '%s' to '%s'\n", inname
, outname
);
457 printf ("Finished dry run\n");
461 expand_sparse (ifp
, ofd
);
471 if (stat (outname
, &st
))
472 die (1, "cannot stat output file %s (%d)", outname
, errno
);
473 if (st
.st_size
!= outsize
)
474 die (1, "expanded file has wrong size");
This page took 0.05654 seconds and 5 git commands to generate.