]>
Commit | Line | Data |
---|---|---|
b24c88b3 RC |
1 | /* |
2 | * Copyright (c) 2000, 2001, Red Hat, Inc. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by DJ Delorie <dj@cygnus.com> | |
13 | * | |
14 | */ | |
15 | ||
16 | /* Built-in tar functionality. See tar.h for usage. */ | |
17 | ||
18 | #if 0 | |
19 | static const char *cvsid = | |
20 | "\n%%% $Id$\n"; | |
21 | #endif | |
22 | ||
23 | #include "win32.h" | |
24 | #include <stdio.h> | |
25 | #include <stdlib.h> | |
26 | #include <sys/types.h> | |
27 | #include <sys/fcntl.h> | |
28 | #include <errno.h> | |
29 | ||
30 | //#include "zlib/zlib.h" | |
31 | #include "io_stream.h" | |
32 | //#include "compress.h" | |
33 | #include "archive.h" | |
34 | #include "archive_tar.h" | |
35 | #include "mkdir.h" | |
36 | #include "log.h" | |
37 | #include "filemanip.h" | |
38 | #include "concat.h" | |
39 | ||
40 | #include "port.h" | |
41 | #if 0 | |
42 | #undef _WIN32 | |
43 | #include "bzlib.h" | |
44 | ||
45 | #define FACTOR (0x19db1ded53ea710LL) | |
46 | #define NSPERSEC 10000000LL | |
47 | #define SYMLINK_COOKIE "!<symlink>" | |
48 | #endif | |
49 | static int err; | |
50 | ||
51 | //static char file_name[_MAX_PATH+512]; | |
52 | //static char have_longname = 0; | |
53 | //static int file_length; | |
54 | ||
55 | static char buf[512]; | |
56 | ||
57 | int _tar_verbose = 0; | |
58 | FILE *_tar_vfile = 0; | |
59 | #define vp if (_tar_verbose) fprintf | |
60 | #define vp2 if (_tar_verbose>1) fprintf | |
61 | ||
62 | archive_tar::archive_tar (io_stream * original) | |
63 | { | |
64 | archive_children = 0; | |
65 | if (_tar_vfile == 0) | |
66 | _tar_vfile = stderr; | |
67 | ||
68 | vp2 (_tar_vfile, "tar: open `%p'\n", original); | |
69 | ||
70 | if (!original) | |
71 | { | |
72 | state.lasterr = EBADF; | |
73 | return; | |
74 | } | |
75 | state.parent = original; | |
76 | ||
77 | if (sizeof (state.tar_header) != 512) | |
78 | { | |
79 | /* drastic, but important */ | |
80 | fprintf (stderr, "compilation error: tar header struct not 512" | |
81 | " bytes (it's %d)\n", sizeof (state.tar_header)); | |
82 | exit_setup (1); | |
83 | } | |
84 | } | |
85 | ||
86 | ssize_t | |
87 | archive_tar::read (void *buffer, size_t len) | |
88 | { | |
89 | return -1; | |
90 | } | |
91 | ||
92 | ssize_t | |
ca9506cc | 93 | archive_tar::write (const void *buffer, size_t len) |
b24c88b3 RC |
94 | { |
95 | return 0; | |
96 | } | |
97 | ||
98 | ssize_t | |
99 | archive_tar::peek (void *buffer, size_t len) | |
100 | { | |
101 | return 0; | |
102 | } | |
103 | ||
104 | int | |
105 | archive_tar::error () | |
106 | { | |
107 | return state.lasterr; | |
108 | } | |
109 | ||
110 | long | |
111 | archive_tar::tell () | |
112 | { | |
113 | return state.file_offset; | |
114 | } | |
115 | ||
ca9506cc RC |
116 | int |
117 | archive_tar::seek (long where, io_stream_seek_t whence) | |
118 | { | |
119 | /* seeking in the parent archive doesn't make sense. although we could | |
120 | map to files ? | |
121 | Also, seeking might make sense for rewing..?? | |
122 | */ | |
123 | return -1; | |
124 | } | |
125 | ||
b24c88b3 RC |
126 | int |
127 | archive_tar::skip_file () | |
128 | { | |
129 | while (state.file_length > state.file_offset) | |
130 | { | |
131 | int len = state.parent->read (buf, 512); | |
132 | state.file_offset += 512; | |
133 | if (len != 512) | |
134 | return 1; | |
135 | } | |
136 | state.file_length = 0; | |
137 | state.file_offset = 0; | |
138 | state.header_read = 0; | |
139 | return 0; | |
140 | } | |
141 | ||
3c054baf | 142 | String const |
b24c88b3 RC |
143 | archive_tar::next_file_name () |
144 | { | |
145 | char *c; | |
146 | ||
147 | if (state.header_read) | |
148 | if (strlen (state.filename)) | |
149 | return state.filename; | |
150 | else | |
151 | /* End of tar */ | |
3c054baf | 152 | return String(); |
b24c88b3 RC |
153 | |
154 | int r = state.parent->read (&state.tar_header, 512); | |
155 | ||
156 | /* See if we're at end of file */ | |
157 | if (r != 512) | |
158 | return NULL; | |
159 | ||
160 | /* See if the header is all zeros (i.e. last block) */ | |
161 | int n = 0; | |
162 | for (r = 512 / sizeof (int); r; r--) | |
163 | n |= ((int *) &state.tar_header)[r - 1]; | |
164 | if (n == 0) | |
165 | return NULL; | |
166 | ||
167 | if (!state.have_longname && state.tar_header.typeflag != 'L') | |
168 | { | |
169 | memcpy (state.filename, state.tar_header.name, 100); | |
170 | state.filename[100] = 0; | |
171 | } | |
172 | ||
173 | sscanf (state.tar_header.size, "%o", &state.file_length); | |
174 | state.file_offset = 0; | |
175 | ||
176 | // vp2 (_tar_vfile, "%c %9d %s\n", state.tar_header.typeflag, | |
177 | // state.file_length, state.filename); | |
178 | ||
179 | switch (state.tar_header.typeflag) | |
180 | { | |
181 | case 'L': /* GNU tar long name extension */ | |
182 | /* we read the 'file' into the long filename, then call back into here | |
183 | * to find out if the actual file is a real file, or a special file.. | |
184 | */ | |
185 | if (state.file_length > _MAX_PATH) | |
186 | { | |
187 | skip_file (); | |
188 | fprintf (stderr, "error: long file name exceeds %d characters\n", | |
189 | _MAX_PATH); | |
190 | err++; | |
191 | state.parent->read (&state.tar_header, 512); | |
192 | sscanf (state.tar_header.size, "%o", &state.file_length); | |
193 | state.file_offset = 0; | |
194 | skip_file (); | |
195 | return next_file_name (); | |
196 | } | |
197 | c = state.filename; | |
198 | /* FIXME: this should be a single read() call */ | |
199 | while (state.file_length > state.file_offset) | |
200 | { | |
201 | int need = | |
202 | state.file_length - state.file_offset > | |
203 | 512 ? 512 : state.file_length - state.file_offset; | |
204 | if (state.parent->read (buf, 512) < 512) | |
205 | return 0; | |
206 | memcpy (c, buf, need); | |
207 | c += need; | |
208 | state.file_offset += need; | |
209 | } | |
210 | *c = 0; | |
211 | state.have_longname = 1; | |
212 | return next_file_name (); | |
213 | ||
214 | case '3': /* char */ | |
215 | case '4': /* block */ | |
216 | case '6': /* fifo */ | |
217 | fprintf (stderr, "warning: not extracting special file %s\n", | |
218 | state.filename); | |
219 | err++; | |
220 | return next_file_name (); | |
221 | ||
222 | case '0': /* regular file */ | |
223 | case 0: /* regular file also */ | |
224 | case '2': /* symbolic link */ | |
225 | case '5': /* directory */ | |
226 | case '7': /* contiguous file */ | |
227 | state.header_read = 1; | |
228 | return state.filename; | |
229 | ||
230 | case '1': /* hard link, we just copy */ | |
231 | state.header_read = 1; | |
232 | return state.filename; | |
233 | ||
234 | default: | |
235 | fprintf (stderr, "error: unknown (or unsupported) file type `%c'\n", | |
236 | state.tar_header.typeflag); | |
237 | err++; | |
238 | skip_file (); | |
239 | return next_file_name (); | |
240 | } | |
241 | return NULL; | |
242 | } | |
243 | ||
244 | archive_tar::~archive_tar () | |
245 | { | |
246 | if (state.parent) | |
247 | delete state.parent; | |
e9440f0f | 248 | destroyed = 1; |
b24c88b3 RC |
249 | } |
250 | ||
251 | # if 0 | |
252 | static void | |
253 | fix_time_stamp (char *path) | |
254 | { | |
255 | int mtime; | |
256 | long long ftimev; | |
257 | FILETIME ftime; | |
258 | HANDLE h; | |
259 | ||
260 | sscanf (tar_header.mtime, "%o", &mtime); | |
261 | ftimev = mtime * NSPERSEC + FACTOR; | |
262 | ftime.dwHighDateTime = ftimev >> 32; | |
263 | ftime.dwLowDateTime = ftimev; | |
264 | h = CreateFileA (path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | |
265 | 0, OPEN_EXISTING, | |
266 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0); | |
267 | if (h) | |
268 | { | |
269 | SetFileTime (h, 0, 0, &ftime); | |
270 | CloseHandle (h); | |
271 | } | |
272 | } | |
273 | #endif | |
274 | archive_file_t | |
275 | archive_tar::next_file_type () | |
276 | { | |
277 | switch (state.tar_header.typeflag) | |
278 | { | |
279 | /* regular files */ | |
280 | case '0': | |
281 | case 0: | |
282 | case '7': | |
283 | return ARCHIVE_FILE_REGULAR; | |
284 | case '1': | |
285 | return ARCHIVE_FILE_HARDLINK; | |
286 | case '5': | |
287 | return ARCHIVE_FILE_DIRECTORY; | |
288 | case '2': | |
289 | return ARCHIVE_FILE_SYMLINK; | |
290 | default: | |
291 | return ARCHIVE_FILE_INVALID; | |
292 | } | |
293 | } | |
294 | ||
3c054baf | 295 | String const |
b24c88b3 RC |
296 | archive_tar::linktarget () |
297 | { | |
298 | /* TODO: consider .. path traversal issues */ | |
299 | if (next_file_type () == ARCHIVE_FILE_SYMLINK || | |
300 | next_file_type () == ARCHIVE_FILE_HARDLINK) | |
301 | return state.tar_header.linkname; | |
3c054baf | 302 | return String(); |
b24c88b3 RC |
303 | } |
304 | ||
305 | io_stream * | |
306 | archive_tar::extract_file () | |
307 | { | |
308 | if (archive_children) | |
309 | return NULL; | |
310 | archive_tar_file *rv = new archive_tar_file (state); | |
311 | return rv; | |
312 | } | |
313 | ||
314 | int | |
315 | archive_tar::get_mtime () | |
316 | { | |
317 | if (state.parent) | |
318 | return state.parent->get_mtime (); | |
319 | return 0; | |
320 | } |