]> cygwin.com Git - cygwin-apps/setup.git/blob - archive_tar.cc
Move hash checking progress message to string resources
[cygwin-apps/setup.git] / archive_tar.cc
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 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/types.h>
21 #include <sys/fcntl.h>
22 #include <errno.h>
23
24 //#include "zlib/zlib.h"
25 #include "io_stream.h"
26 //#include "compress.h"
27 #include "win32.h"
28 #include "archive.h"
29 #include "archive_tar.h"
30 #include "mkdir.h"
31 #include "LogFile.h"
32 #include "filemanip.h"
33
34 #if 0
35 #undef _WIN32
36 #include "bzlib.h"
37
38 #define SYMLINK_COOKIE "!<symlink>"
39 #endif
40 static int err;
41
42 static char buf[512];
43
44 int _tar_verbose = 0;
45
46 archive_tar::archive_tar (io_stream * original)
47 {
48 archive_children = 0;
49
50 if (_tar_verbose)
51 LogBabblePrintf("tar: open `%p'\n", original);
52
53 if (!original)
54 {
55 state.lasterr = EBADF;
56 return;
57 }
58 state.parent = original;
59
60 if (sizeof (state.tar_header) != 512)
61 {
62 /* drastic, but important */
63 Log (LOG_TIMESTAMP) << "compilation error: tar header struct not 512"
64 << " bytes (it's " << sizeof (state.tar_header)
65 << ")" << endLog;
66 Logger ().exit (1);
67 }
68 }
69
70 ssize_t
71 archive_tar::read (void *buffer, size_t len)
72 {
73 return -1;
74 }
75
76 ssize_t
77 archive_tar::write (const void *buffer, size_t len)
78 {
79 return 0;
80 }
81
82 ssize_t
83 archive_tar::peek (void *buffer, size_t len)
84 {
85 return 0;
86 }
87
88 int
89 archive_tar::error ()
90 {
91 return state.lasterr;
92 }
93
94 long
95 archive_tar::tell ()
96 {
97 return state.file_offset;
98 }
99
100 int
101 archive_tar::seek (long where, io_stream_seek_t whence)
102 {
103 /* Because the parent stream is compressed, we can only easily support
104 seek()-ing to rewind to the start */
105 if ((whence == IO_SEEK_SET) && (where == 0))
106 {
107 state.header_read = 0;
108 return state.parent->seek(where, whence);
109 }
110
111 return -1;
112 }
113
114 int
115 archive_tar::skip_file ()
116 {
117 while (state.file_length > state.file_offset)
118 {
119 int len = state.parent->read (buf, 512);
120 state.file_offset += 512;
121 if (len != 512)
122 return 1;
123 }
124 state.file_length = 0;
125 state.file_offset = 0;
126 state.header_read = 0;
127 return 0;
128 }
129
130 const std::string
131 archive_tar::next_file_name ()
132 {
133 char *c;
134
135 if (state.header_read)
136 {
137 if (strlen (state.filename))
138 return state.filename;
139 else
140 /* End of tar */
141 return std::string();
142 }
143
144 int r = state.parent->read (&state.tar_header, 512);
145
146 /* See if we're at end of file */
147 if (r != 512)
148 return std::string();
149
150 /* See if the header is all zeros (i.e. last block) */
151 int n = 0;
152 for (r = 512 / sizeof (int); r; r--)
153 n |= ((int *) &state.tar_header)[r - 1];
154 if (n == 0)
155 return std::string();
156
157 if (!state.have_longname && state.tar_header.typeflag != 'L')
158 {
159 memcpy (state.filename, state.tar_header.name, 100);
160 state.filename[100] = 0;
161 }
162 else if (state.have_longname)
163 state.have_longname = 0;
164
165 sscanf (state.tar_header.size, "%zo", &state.file_length);
166 state.file_offset = 0;
167
168 if (_tar_verbose)
169 LogBabblePrintf ("%c %9d %s\n", state.tar_header.typeflag,
170 state.file_length, state.filename);
171
172 switch (state.tar_header.typeflag)
173 {
174 case 'L': /* GNU tar long name extension */
175 /* we read the 'file' into the long filename, then call back into here
176 * to find out if the actual file is a real file, or a special file..
177 */
178 if (state.file_length > CYG_PATH_MAX)
179 {
180 skip_file ();
181 LogPlainPrintf( "error: long file name exceeds %d characters\n",
182 CYG_PATH_MAX);
183 err++;
184 state.parent->read (&state.tar_header, 512);
185 sscanf (state.tar_header.size, "%zo", &state.file_length);
186 state.file_offset = 0;
187 skip_file ();
188 return next_file_name ();
189 }
190 c = state.filename;
191 /* FIXME: this should be a single read() call */
192 while (state.file_length > state.file_offset)
193 {
194 int need =
195 state.file_length - state.file_offset >
196 512 ? 512 : state.file_length - state.file_offset;
197 if (state.parent->read (buf, 512) < 512)
198 // FIXME: What's up with the "0"? It's probably a mistake, and
199 // should be "". It used to be written as 0, and was subject to a
200 // bizarre implicit conversion by the unwise String(int)
201 // constructor.
202 return "0";
203 memcpy (c, buf, need);
204 c += need;
205 state.file_offset += need;
206 }
207 *c = 0;
208 state.have_longname = 1;
209 return next_file_name ();
210
211 case '3': /* char */
212 case '4': /* block */
213 case '6': /* fifo */
214 LogPlainPrintf ("warning: not extracting special file %s\n",
215 state.filename);
216 err++;
217 return next_file_name ();
218
219 case '0': /* regular file */
220 case 0: /* regular file also */
221 case '2': /* symbolic link */
222 case '5': /* directory */
223 case '7': /* contiguous file */
224 state.header_read = 1;
225 return state.filename;
226
227 case '1': /* hard link, we just copy */
228 state.header_read = 1;
229 return state.filename;
230
231 default:
232 LogPlainPrintf ("error: unknown (or unsupported) file type `%c'\n",
233 state.tar_header.typeflag);
234 err++;
235 /* fall through */
236 case 'g': /* POSIX.1-2001 global extended header */
237 case 'x': /* POSIX.1-2001 extended header */
238 skip_file ();
239 return next_file_name ();
240 }
241 return std::string();
242 }
243
244 archive_tar::~archive_tar ()
245 {
246 if (state.parent)
247 delete state.parent;
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
294 const std::string
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;
301 return std::string();
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 time_t
314 archive_tar::get_mtime ()
315 {
316 if (state.parent)
317 return state.parent->get_mtime ();
318 return 0;
319 }
320
321 mode_t
322 archive_tar::get_mode ()
323 {
324 if (state.parent)
325 return state.parent->get_mode ();
326 return 0;
327 }
This page took 0.060728 seconds and 5 git commands to generate.