]> cygwin.com Git - cygwin-apps/setup.git/blob - archive_tar.cc
Cancel search timer after 'clear' button pressed
[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 /* seeking in the parent archive doesn't make sense. although we could
104 map to files ?
105 Also, seeking might make sense for rewing..??
106 */
107 return -1;
108 }
109
110 int
111 archive_tar::skip_file ()
112 {
113 while (state.file_length > state.file_offset)
114 {
115 int len = state.parent->read (buf, 512);
116 state.file_offset += 512;
117 if (len != 512)
118 return 1;
119 }
120 state.file_length = 0;
121 state.file_offset = 0;
122 state.header_read = 0;
123 return 0;
124 }
125
126 const std::string
127 archive_tar::next_file_name ()
128 {
129 char *c;
130
131 if (state.header_read)
132 {
133 if (strlen (state.filename))
134 return state.filename;
135 else
136 /* End of tar */
137 return std::string();
138 }
139
140 int r = state.parent->read (&state.tar_header, 512);
141
142 /* See if we're at end of file */
143 if (r != 512)
144 return std::string();
145
146 /* See if the header is all zeros (i.e. last block) */
147 int n = 0;
148 for (r = 512 / sizeof (int); r; r--)
149 n |= ((int *) &state.tar_header)[r - 1];
150 if (n == 0)
151 return std::string();
152
153 if (!state.have_longname && state.tar_header.typeflag != 'L')
154 {
155 memcpy (state.filename, state.tar_header.name, 100);
156 state.filename[100] = 0;
157 }
158 else if (state.have_longname)
159 state.have_longname = 0;
160
161 sscanf (state.tar_header.size, "%zo", &state.file_length);
162 state.file_offset = 0;
163
164 if (_tar_verbose)
165 LogBabblePrintf ("%c %9d %s\n", state.tar_header.typeflag,
166 state.file_length, state.filename);
167
168 switch (state.tar_header.typeflag)
169 {
170 case 'L': /* GNU tar long name extension */
171 /* we read the 'file' into the long filename, then call back into here
172 * to find out if the actual file is a real file, or a special file..
173 */
174 if (state.file_length > CYG_PATH_MAX)
175 {
176 skip_file ();
177 LogPlainPrintf( "error: long file name exceeds %d characters\n",
178 CYG_PATH_MAX);
179 err++;
180 state.parent->read (&state.tar_header, 512);
181 sscanf (state.tar_header.size, "%zo", &state.file_length);
182 state.file_offset = 0;
183 skip_file ();
184 return next_file_name ();
185 }
186 c = state.filename;
187 /* FIXME: this should be a single read() call */
188 while (state.file_length > state.file_offset)
189 {
190 int need =
191 state.file_length - state.file_offset >
192 512 ? 512 : state.file_length - state.file_offset;
193 if (state.parent->read (buf, 512) < 512)
194 // FIXME: What's up with the "0"? It's probably a mistake, and
195 // should be "". It used to be written as 0, and was subject to a
196 // bizarre implicit conversion by the unwise String(int)
197 // constructor.
198 return "0";
199 memcpy (c, buf, need);
200 c += need;
201 state.file_offset += need;
202 }
203 *c = 0;
204 state.have_longname = 1;
205 return next_file_name ();
206
207 case '3': /* char */
208 case '4': /* block */
209 case '6': /* fifo */
210 LogPlainPrintf ("warning: not extracting special file %s\n",
211 state.filename);
212 err++;
213 return next_file_name ();
214
215 case '0': /* regular file */
216 case 0: /* regular file also */
217 case '2': /* symbolic link */
218 case '5': /* directory */
219 case '7': /* contiguous file */
220 state.header_read = 1;
221 return state.filename;
222
223 case '1': /* hard link, we just copy */
224 state.header_read = 1;
225 return state.filename;
226
227 default:
228 LogPlainPrintf ("error: unknown (or unsupported) file type `%c'\n",
229 state.tar_header.typeflag);
230 err++;
231 /* fall through */
232 case 'g': /* POSIX.1-2001 global extended header */
233 case 'x': /* POSIX.1-2001 extended header */
234 skip_file ();
235 return next_file_name ();
236 }
237 return std::string();
238 }
239
240 archive_tar::~archive_tar ()
241 {
242 if (state.parent)
243 delete state.parent;
244 }
245
246 # if 0
247 static void
248 fix_time_stamp (char *path)
249 {
250 int mtime;
251 long long ftimev;
252 FILETIME ftime;
253 HANDLE h;
254
255 sscanf (tar_header.mtime, "%o", &mtime);
256 ftimev = mtime * NSPERSEC + FACTOR;
257 ftime.dwHighDateTime = ftimev >> 32;
258 ftime.dwLowDateTime = ftimev;
259 h = CreateFileA (path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
260 0, OPEN_EXISTING,
261 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
262 if (h)
263 {
264 SetFileTime (h, 0, 0, &ftime);
265 CloseHandle (h);
266 }
267 }
268 #endif
269 archive_file_t
270 archive_tar::next_file_type ()
271 {
272 switch (state.tar_header.typeflag)
273 {
274 /* regular files */
275 case '0':
276 case 0:
277 case '7':
278 return ARCHIVE_FILE_REGULAR;
279 case '1':
280 return ARCHIVE_FILE_HARDLINK;
281 case '5':
282 return ARCHIVE_FILE_DIRECTORY;
283 case '2':
284 return ARCHIVE_FILE_SYMLINK;
285 default:
286 return ARCHIVE_FILE_INVALID;
287 }
288 }
289
290 const std::string
291 archive_tar::linktarget ()
292 {
293 /* TODO: consider .. path traversal issues */
294 if (next_file_type () == ARCHIVE_FILE_SYMLINK ||
295 next_file_type () == ARCHIVE_FILE_HARDLINK)
296 return state.tar_header.linkname;
297 return std::string();
298 }
299
300 io_stream *
301 archive_tar::extract_file ()
302 {
303 if (archive_children)
304 return NULL;
305 archive_tar_file *rv = new archive_tar_file (state);
306 return rv;
307 }
308
309 time_t
310 archive_tar::get_mtime ()
311 {
312 if (state.parent)
313 return state.parent->get_mtime ();
314 return 0;
315 }
316
317 mode_t
318 archive_tar::get_mode ()
319 {
320 if (state.parent)
321 return state.parent->get_mode ();
322 return 0;
323 }
This page took 0.049481 seconds and 5 git commands to generate.