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