]> cygwin.com Git - cygwin-apps/setup.git/blame - archive_tar.cc
2002-02-19 Robert Collins <rbtcollins@hotmail.com>
[cygwin-apps/setup.git] / archive_tar.cc
CommitLineData
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
19static 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
49static int err;
50
51//static char file_name[_MAX_PATH+512];
52//static char have_longname = 0;
53//static int file_length;
54
55static char buf[512];
56
57int _tar_verbose = 0;
58FILE *_tar_vfile = 0;
59#define vp if (_tar_verbose) fprintf
60#define vp2 if (_tar_verbose>1) fprintf
61
62archive_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
86ssize_t
87archive_tar::read (void *buffer, size_t len)
88{
89 return -1;
90}
91
92ssize_t
ca9506cc 93archive_tar::write (const void *buffer, size_t len)
b24c88b3
RC
94{
95 return 0;
96}
97
98ssize_t
99archive_tar::peek (void *buffer, size_t len)
100{
101 return 0;
102}
103
104int
105archive_tar::error ()
106{
107 return state.lasterr;
108}
109
110long
111archive_tar::tell ()
112{
113 return state.file_offset;
114}
115
ca9506cc
RC
116int
117archive_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
126int
127archive_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 142String const
b24c88b3
RC
143archive_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
244archive_tar::~archive_tar ()
245{
246 if (state.parent)
247 delete state.parent;
e9440f0f 248 destroyed = 1;
b24c88b3
RC
249}
250
251# if 0
252static void
253fix_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
274archive_file_t
275archive_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 295String const
b24c88b3
RC
296archive_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
305io_stream *
306archive_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
314int
315archive_tar::get_mtime ()
316{
317 if (state.parent)
318 return state.parent->get_mtime ();
319 return 0;
320}
This page took 0.053675 seconds and 5 git commands to generate.