~sergei.glushchenko/+junk/page-scan-hack

« back to all changes in this revision

Viewing changes to src/libarchive/contrib/untar.c

merge parallel compression branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * "untar" is an extremely simple tar extractor:
 
3
 *  * A single C source file, so it should be easy to compile
 
4
 *    and run on any system with a C compiler.
 
5
 *  * Extremely portable standard C.  The only non-ANSI function
 
6
 *    used is mkdir().
 
7
 *  * Reads basic ustar tar archives.
 
8
 *  * Does not require libarchive or any other special library.
 
9
 *
 
10
 * To compile: cc -o untar untar.c
 
11
 *
 
12
 * Usage:  untar <archive>
 
13
 *
 
14
 * In particular, this program should be sufficient to extract the
 
15
 * distribution for libarchive, allowing people to bootstrap
 
16
 * libarchive on systems that do not already have a tar program.
 
17
 *
 
18
 * To unpack libarchive-x.y.z.tar.gz:
 
19
 *    * gunzip libarchive-x.y.z.tar.gz
 
20
 *    * untar libarchive-x.y.z.tar
 
21
 *
 
22
 * Written by Tim Kientzle, March 2009.
 
23
 *
 
24
 * Released into the public domain.
 
25
 */
 
26
 
 
27
/* These are all highly standard and portable headers. */
 
28
#include <stdio.h>
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
 
 
32
/* This is for mkdir(); this may need to be changed for some platforms. */
 
33
#include <sys/stat.h>  /* For mkdir() */
 
34
 
 
35
/* Parse an octal number, ignoring leading and trailing nonsense. */
 
36
static int
 
37
parseoct(const char *p, size_t n)
 
38
{
 
39
        int i = 0;
 
40
 
 
41
        while (*p < '0' || *p > '7') {
 
42
                ++p;
 
43
                --n;
 
44
        }
 
45
        while (*p >= '0' && *p <= '7' && n > 0) {
 
46
                i *= 8;
 
47
                i += *p - '0';
 
48
                ++p;
 
49
                --n;
 
50
        }
 
51
        return (i);
 
52
}
 
53
 
 
54
/* Returns true if this is 512 zero bytes. */
 
55
static int
 
56
is_end_of_archive(const char *p)
 
57
{
 
58
        int n;
 
59
        for (n = 511; n >= 0; --n)
 
60
                if (p[n] != '\0')
 
61
                        return (0);
 
62
        return (1);
 
63
}
 
64
 
 
65
/* Create a directory, including parent directories as necessary. */
 
66
static void
 
67
create_dir(char *pathname, int mode)
 
68
{
 
69
        char *p;
 
70
        int r;
 
71
 
 
72
        /* Strip trailing '/' */
 
73
        if (pathname[strlen(pathname) - 1] == '/')
 
74
                pathname[strlen(pathname) - 1] = '\0';
 
75
 
 
76
        /* Try creating the directory. */
 
77
        r = mkdir(pathname, mode);
 
78
 
 
79
        if (r != 0) {
 
80
                /* On failure, try creating parent directory. */
 
81
                p = strrchr(pathname, '/');
 
82
                if (p != NULL) {
 
83
                        *p = '\0';
 
84
                        create_dir(pathname, 0755);
 
85
                        *p = '/';
 
86
                        r = mkdir(pathname, mode);
 
87
                }
 
88
        }
 
89
        if (r != 0)
 
90
                fprintf(stderr, "Could not create directory %s\n", pathname);
 
91
}
 
92
 
 
93
/* Create a file, including parent directory as necessary. */
 
94
static FILE *
 
95
create_file(char *pathname, int mode)
 
96
{
 
97
        FILE *f;
 
98
        f = fopen(pathname, "w+");
 
99
        if (f == NULL) {
 
100
                /* Try creating parent dir and then creating file. */
 
101
                char *p = strrchr(pathname, '/');
 
102
                if (p != NULL) {
 
103
                        *p = '\0';
 
104
                        create_dir(pathname, 0755);
 
105
                        *p = '/';
 
106
                        f = fopen(pathname, "w+");
 
107
                }
 
108
        }
 
109
        return (f);
 
110
}
 
111
 
 
112
/* Verify the tar checksum. */
 
113
static int
 
114
verify_checksum(const char *p)
 
115
{
 
116
        int n, u = 0;
 
117
        for (n = 0; n < 512; ++n) {
 
118
                if (n < 148 || n > 155)
 
119
                        /* Standard tar checksum adds unsigned bytes. */
 
120
                        u += ((unsigned char *)p)[n];
 
121
                else
 
122
                        u += 0x20;
 
123
 
 
124
        }
 
125
        return (u == parseoct(p + 148, 8));
 
126
}
 
127
 
 
128
/* Extract a tar archive. */
 
129
static void
 
130
untar(FILE *a, const char *path)
 
131
{
 
132
        char buff[512];
 
133
        FILE *f = NULL;
 
134
        size_t bytes_read;
 
135
        int filesize;
 
136
 
 
137
        printf("Extracting from %s\n", path);
 
138
        for (;;) {
 
139
                bytes_read = fread(buff, 1, 512, a);
 
140
                if (bytes_read < 512) {
 
141
                        fprintf(stderr,
 
142
                            "Short read on %s: expected 512, got %d\n",
 
143
                            path, bytes_read);
 
144
                        return;
 
145
                }
 
146
                if (is_end_of_archive(buff)) {
 
147
                        printf("End of %s\n", path);
 
148
                        return;
 
149
                }
 
150
                if (!verify_checksum(buff)) {
 
151
                        fprintf(stderr, "Checksum failure\n");
 
152
                        return;
 
153
                }
 
154
                filesize = parseoct(buff + 124, 12);
 
155
                switch (buff[156]) {
 
156
                case '1':
 
157
                        printf(" Ignoring hardlink %s\n", buff);
 
158
                        break;
 
159
                case '2':
 
160
                        printf(" Ignoring symlink %s\n", buff);
 
161
                        break;
 
162
                case '3':
 
163
                        printf(" Ignoring character device %s\n", buff);
 
164
                                break;
 
165
                case '4':
 
166
                        printf(" Ignoring block device %s\n", buff);
 
167
                        break;
 
168
                case '5':
 
169
                        printf(" Extracting dir %s\n", buff);
 
170
                        create_dir(buff, parseoct(buff + 100, 8));
 
171
                        filesize = 0;
 
172
                        break;
 
173
                case '6':
 
174
                        printf(" Ignoring FIFO %s\n", buff);
 
175
                        break;
 
176
                default:
 
177
                        printf(" Extracting file %s\n", buff);
 
178
                        f = create_file(buff, parseoct(buff + 100, 8));
 
179
                        break;
 
180
                }
 
181
                while (filesize > 0) {
 
182
                        bytes_read = fread(buff, 1, 512, a);
 
183
                        if (bytes_read < 512) {
 
184
                                fprintf(stderr,
 
185
                                    "Short read on %s: Expected 512, got %d\n",
 
186
                                    path, bytes_read);
 
187
                                return;
 
188
                        }
 
189
                        if (filesize < 512)
 
190
                                bytes_read = filesize;
 
191
                        if (f != NULL) {
 
192
                                if (fwrite(buff, 1, bytes_read, f)
 
193
                                    != bytes_read)
 
194
                                {
 
195
                                        fprintf(stderr, "Failed write\n");
 
196
                                        fclose(f);
 
197
                                        f = NULL;
 
198
                                }
 
199
                        }
 
200
                        filesize -= bytes_read;
 
201
                }
 
202
                if (f != NULL) {
 
203
                        fclose(f);
 
204
                        f = NULL;
 
205
                }
 
206
        }
 
207
}
 
208
 
 
209
int
 
210
main(int argc, char **argv)
 
211
{
 
212
        FILE *a;
 
213
 
 
214
        ++argv; /* Skip program name */
 
215
        for ( ;*argv != NULL; ++argv) {
 
216
                a = fopen(*argv, "r");
 
217
                if (a == NULL)
 
218
                        fprintf(stderr, "Unable to open %s\n", *argv);
 
219
                else {
 
220
                        untar(a, *argv);
 
221
                        fclose(a);
 
222
                }
 
223
        }
 
224
        return (0);
 
225
}