/* xsparse - expands compressed sparse file images extracted from GNU tar
archives.
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc.
Written by Sergey Poznyakoff
-
+
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
+ Free Software Foundation; either version 3, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <stdlib.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
+#include <string.h>
#include <unistd.h>
-#include <getopt.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <limits.h>
struct sp_array
{
off_t offset;
- size_t numbytes;
+ off_t numbytes;
};
char *progname;
static char *buffer;
static size_t bufsize = OFF_T_STRSIZE_BOUND;
char *p, *q;
-
+
buffer = emalloc (bufsize);
do
{
size_t len, s;
-
+
if (!fgets (buffer, bufsize, fp))
return 0;
len = strlen (buffer);
if (verbose)
printf ("Reading extended header file\n");
-
+
while (get_var (fp, &kw, &val))
{
if (verbose)
printf ("Found variable GNU.sparse.%s = %s\n", kw, val);
-
+
if (expect && strcmp (kw, expect))
die (1, "bad keyword sequence: expected `%s' but found `%s'",
expect, kw);
}
else if (strcmp (kw, "numbytes") == 0)
{
- sparse_map[i++].numbytes = string_to_size (val, NULL);
+ sparse_map[i++].numbytes = string_to_off (val, NULL);
}
else if (strcmp (kw, "map") == 0)
{
if (*val != ',')
die (1, "bad GNU.sparse.map: expected `,' but found `%c'",
*val);
- sparse_map[i].numbytes = string_to_size (val+1, &val);
+ sparse_map[i].numbytes = string_to_off (val+1, &val);
if (*val != ',')
{
if (!(*val == 0 && i == sparse_map_size-1))
if (verbose)
printf ("Reading v.1.0 sparse map\n");
-
+
get_line (nbuf, sizeof nbuf, ifp);
sparse_map_size = string_to_size (nbuf, NULL);
sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);
get_line (nbuf, sizeof nbuf, ifp);
sparse_map[i].offset = string_to_off (nbuf, NULL);
get_line (nbuf, sizeof nbuf, ifp);
- sparse_map[i].numbytes = string_to_size (nbuf, NULL);
+ sparse_map[i].numbytes = string_to_off (nbuf, NULL);
}
- fseek (ifp, ((ftell (ifp) + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE,
- SEEK_SET);
-}
+ fseeko (ifp, ((ftell (ifp) + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE,
+ SEEK_SET);
+}
void
expand_sparse (FILE *sfp, int ofd)
{
size_t i;
- size_t maxbytes = 0;
+ off_t max_numbytes = 0;
+ size_t maxbytes;
char *buffer;
for (i = 0; i < sparse_map_size; i++)
- if (maxbytes < sparse_map[i].numbytes)
- maxbytes = sparse_map[i].numbytes;
-
+ if (max_numbytes < sparse_map[i].numbytes)
+ max_numbytes = sparse_map[i].numbytes;
+
+ maxbytes = max_numbytes < SIZE_MAX ? max_numbytes : SIZE_MAX;
+
for (buffer = malloc (maxbytes); !buffer; maxbytes /= 2)
if (maxbytes == 0)
die (1, "not enough memory");
-
+
for (i = 0; i < sparse_map_size; i++)
{
- size_t size = sparse_map[i].numbytes;
+ off_t size = sparse_map[i].numbytes;
- lseek (ofd, sparse_map[i].offset, SEEK_SET);
- while (size)
+ if (size == 0)
+ ftruncate (ofd, sparse_map[i].offset);
+ else
{
- size_t rdsize = (size < maxbytes) ? size : maxbytes;
- if (rdsize != fread (buffer, 1, rdsize, sfp))
- die (1, "read error (%d)", errno);
- if (rdsize != write (ofd, buffer, rdsize))
- die (1, "write error (%d)", errno);
- size -= rdsize;
+ lseek (ofd, sparse_map[i].offset, SEEK_SET);
+ while (size)
+ {
+ size_t rdsize = (size < maxbytes) ? size : maxbytes;
+ if (rdsize != fread (buffer, 1, rdsize, sfp))
+ die (1, "read error (%d)", errno);
+ if (rdsize != write (ofd, buffer, rdsize))
+ die (1, "write error (%d)", errno);
+ size -= rdsize;
+ }
}
}
free (buffer);
{
char *p;
char *s;
-
+
if (name[0] == '.' && name[1] == '/')
name += 2;
p = name + strlen (name) - 1;
s = NULL;
-
+
for (; p > name && *p != '/'; p--)
;
if (*p == '/')
for (p--; p > name && *p != '/'; p--)
;
}
-
+
if (*p != '/')
{
if (s)
FILE *ifp;
struct stat st;
int ofd;
-
+
progname = argv[0];
while ((c = getopt (argc, argv, "hnvx:")) != EOF)
{
case 'v':
verbose++;
break;
-
+
default:
exit (1);
}
if (stat (inname, &st))
die (1, "cannot stat %s (%d)", inname, errno);
-
+
ifp = fopen (inname, "r");
if (ifp == NULL)
die (1, "cannot open file %s (%d)", inname, errno);
-
+
if (!xheader_file || version_major == 1)
read_map (ifp);
if (!outname)
guess_outname (inname);
-
+
ofd = open (outname, O_RDWR|O_CREAT|O_TRUNC, st.st_mode);
if (ofd == -1)
die (1, "cannot open file %s (%d)", outname, errno);
printf ("Finished dry run\n");
return 0;
}
-
+
expand_sparse (ifp, ofd);
fclose (ifp);
if (verbose)
printf ("Done\n");
-
+
if (outsize)
{
if (stat (outname, &st))
if (st.st_size != outsize)
die (1, "expanded file has wrong size");
}
-
+
return 0;
}
-