]> cygwin.com Git - cygwin-apps/setup.git/blob - archive_tar.cc
2002-07-05 Robert Collins <rbtcollins@hotmail.com>
[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 #if 0
19 static const char *cvsid =
20 "\n%%% $Id$\n";
21 #endif
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/fcntl.h>
27 #include <errno.h>
28
29 //#include "zlib/zlib.h"
30 #include "io_stream.h"
31 //#include "compress.h"
32 #include "archive.h"
33 #include "archive_tar.h"
34 #include "mkdir.h"
35 #include "LogSingleton.h"
36 #include "filemanip.h"
37
38 #include "port.h"
39 #if 0
40 #undef _WIN32
41 #include "bzlib.h"
42
43 #define FACTOR (0x19db1ded53ea710LL)
44 #define NSPERSEC 10000000LL
45 #define SYMLINK_COOKIE "!<symlink>"
46 #endif
47 static int err;
48
49 //static char file_name[_MAX_PATH+512];
50 //static char have_longname = 0;
51 //static int file_length;
52
53 static char buf[512];
54
55 int _tar_verbose = 0;
56 FILE *_tar_vfile = 0;
57 #define vp if (_tar_verbose) fprintf
58 #define vp2 if (_tar_verbose>1) fprintf
59
60 archive_tar::archive_tar (io_stream * original)
61 {
62 archive_children = 0;
63 if (_tar_vfile == 0)
64 _tar_vfile = stderr;
65
66 vp2 (_tar_vfile, "tar: open `%p'\n", original);
67
68 if (!original)
69 {
70 state.lasterr = EBADF;
71 return;
72 }
73 state.parent = original;
74
75 if (sizeof (state.tar_header) != 512)
76 {
77 /* drastic, but important */
78 log (LOG_TIMESTAMP) << "compilation error: tar header struct not 512"
79 << " bytes (it's " << sizeof (state.tar_header)
80 << ")" << endLog;
81 LogSingleton::GetInstance().exit (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
92 archive_tar::write (const void *buffer, size_t len)
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
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
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
141 String const
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 */
151 return String();
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)
157 return String();
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)
164 return String();
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 else if (state.have_longname)
172 state.have_longname = 0;
173
174 sscanf (state.tar_header.size, "%o", &state.file_length);
175 state.file_offset = 0;
176
177 // vp2 (_tar_vfile, "%c %9d %s\n", state.tar_header.typeflag,
178 // state.file_length, state.filename);
179
180 switch (state.tar_header.typeflag)
181 {
182 case 'L': /* GNU tar long name extension */
183 /* we read the 'file' into the long filename, then call back into here
184 * to find out if the actual file is a real file, or a special file..
185 */
186 if (state.file_length > _MAX_PATH)
187 {
188 skip_file ();
189 fprintf (stderr, "error: long file name exceeds %d characters\n",
190 _MAX_PATH);
191 err++;
192 state.parent->read (&state.tar_header, 512);
193 sscanf (state.tar_header.size, "%o", &state.file_length);
194 state.file_offset = 0;
195 skip_file ();
196 return next_file_name ();
197 }
198 c = state.filename;
199 /* FIXME: this should be a single read() call */
200 while (state.file_length > state.file_offset)
201 {
202 int need =
203 state.file_length - state.file_offset >
204 512 ? 512 : state.file_length - state.file_offset;
205 if (state.parent->read (buf, 512) < 512)
206 return 0;
207 memcpy (c, buf, need);
208 c += need;
209 state.file_offset += need;
210 }
211 *c = 0;
212 state.have_longname = 1;
213 return next_file_name ();
214
215 case '3': /* char */
216 case '4': /* block */
217 case '6': /* fifo */
218 fprintf (stderr, "warning: not extracting special file %s\n",
219 state.filename);
220 err++;
221 return next_file_name ();
222
223 case '0': /* regular file */
224 case 0: /* regular file also */
225 case '2': /* symbolic link */
226 case '5': /* directory */
227 case '7': /* contiguous file */
228 state.header_read = 1;
229 return state.filename;
230
231 case '1': /* hard link, we just copy */
232 state.header_read = 1;
233 return state.filename;
234
235 default:
236 fprintf (stderr, "error: unknown (or unsupported) file type `%c'\n",
237 state.tar_header.typeflag);
238 err++;
239 skip_file ();
240 return next_file_name ();
241 }
242 return String();
243 }
244
245 archive_tar::~archive_tar ()
246 {
247 if (state.parent)
248 delete state.parent;
249 destroyed = 1;
250 }
251
252 # if 0
253 static void
254 fix_time_stamp (char *path)
255 {
256 int mtime;
257 long long ftimev;
258 FILETIME ftime;
259 HANDLE h;
260
261 sscanf (tar_header.mtime, "%o", &mtime);
262 ftimev = mtime * NSPERSEC + FACTOR;
263 ftime.dwHighDateTime = ftimev >> 32;
264 ftime.dwLowDateTime = ftimev;
265 h = CreateFileA (path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
266 0, OPEN_EXISTING,
267 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
268 if (h)
269 {
270 SetFileTime (h, 0, 0, &ftime);
271 CloseHandle (h);
272 }
273 }
274 #endif
275 archive_file_t
276 archive_tar::next_file_type ()
277 {
278 switch (state.tar_header.typeflag)
279 {
280 /* regular files */
281 case '0':
282 case 0:
283 case '7':
284 return ARCHIVE_FILE_REGULAR;
285 case '1':
286 return ARCHIVE_FILE_HARDLINK;
287 case '5':
288 return ARCHIVE_FILE_DIRECTORY;
289 case '2':
290 return ARCHIVE_FILE_SYMLINK;
291 default:
292 return ARCHIVE_FILE_INVALID;
293 }
294 }
295
296 String const
297 archive_tar::linktarget ()
298 {
299 /* TODO: consider .. path traversal issues */
300 if (next_file_type () == ARCHIVE_FILE_SYMLINK ||
301 next_file_type () == ARCHIVE_FILE_HARDLINK)
302 return state.tar_header.linkname;
303 return String();
304 }
305
306 io_stream *
307 archive_tar::extract_file ()
308 {
309 if (archive_children)
310 return NULL;
311 archive_tar_file *rv = new archive_tar_file (state);
312 return rv;
313 }
314
315 int
316 archive_tar::get_mtime ()
317 {
318 if (state.parent)
319 return state.parent->get_mtime ();
320 return 0;
321 }
This page took 0.046563 seconds and 5 git commands to generate.