root/branches/3.00/src/archive_tar.cc

Revision 644, 6.9 kB (checked in by fujii, 4 years ago)

Add new netinstall source.

Line 
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: archive_tar.cc,v 2.11 2004/11/18 01:19:09 maxb Exp $\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 #if 0
39 #undef _WIN32
40 #include "bzlib.h"
41
42 #define FACTOR (0x19db1ded53ea710LL)
43 #define NSPERSEC 10000000LL
44 #define SYMLINK_COOKIE "!<symlink>"
45 #endif
46 static int err;
47
48 //static char file_name[_MAX_PATH+512];
49 //static char have_longname = 0;
50 //static int  file_length;
51
52 static char buf[512];
53
54 int _tar_verbose = 0;
55 FILE *_tar_vfile = 0;
56 #define vp if (_tar_verbose) fprintf
57 #define vp2 if (_tar_verbose>1) fprintf
58
59 archive_tar::archive_tar (io_stream * original)
60 {
61   archive_children = 0;
62   if (_tar_vfile == 0)
63     _tar_vfile = stderr;
64
65   vp2 (_tar_vfile, "tar: open `%p'\n", original);
66
67   if (!original)
68     {
69       state.lasterr = EBADF;
70       return;
71     }
72   state.parent = original;
73
74   if (sizeof (state.tar_header) != 512)
75     {
76       /* drastic, but important */
77       log (LOG_TIMESTAMP) << "compilation error: tar header struct not 512"
78                           << " bytes (it's " << sizeof (state.tar_header)
79                           << ")" << endLog;
80       LogSingleton::GetInstance().exit (1);
81     }
82 }
83
84 ssize_t
85 archive_tar::read (void *buffer, size_t len)
86 {
87   return -1;
88 }
89
90 ssize_t
91 archive_tar::write (const void *buffer, size_t len)
92 {
93   return 0;
94 }
95
96 ssize_t
97 archive_tar::peek (void *buffer, size_t len)
98 {
99   return 0;
100 }
101
102 int
103 archive_tar::error ()
104 {
105   return state.lasterr;
106 }
107
108 long
109 archive_tar::tell ()
110 {
111   return state.file_offset;
112 }
113
114 int
115 archive_tar::seek (long where, io_stream_seek_t whence)
116 {
117   /* seeking in the parent archive doesn't make sense. although we could
118      map to files ?
119      Also, seeking might make sense for rewing..??
120      */
121   return -1;
122 }
123
124 int
125 archive_tar::skip_file ()
126 {
127   while (state.file_length > state.file_offset)
128     {
129       int len = state.parent->read (buf, 512);
130       state.file_offset += 512;
131       if (len != 512)
132         return 1;
133     }
134   state.file_length = 0;
135   state.file_offset = 0;
136   state.header_read = 0;
137   return 0;
138 }
139
140 String const
141 archive_tar::next_file_name ()
142 {
143   char *c;
144
145   if (state.header_read)
146     if (strlen (state.filename))
147       return state.filename;
148     else
149       /* End of tar */
150       return String();
151
152   int r = state.parent->read (&state.tar_header, 512);
153
154   /* See if we're at end of file */
155   if (r != 512)
156     return String();
157
158   /* See if the header is all zeros (i.e. last block) */
159   int n = 0;
160   for (r = 512 / sizeof (int); r; r--)
161     n |= ((int *) &state.tar_header)[r - 1];
162   if (n == 0)
163     return String();
164
165   if (!state.have_longname && state.tar_header.typeflag != 'L')
166     {
167       memcpy (state.filename, state.tar_header.name, 100);
168       state.filename[100] = 0;
169     }
170   else if (state.have_longname)
171     state.have_longname = 0;
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 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 String const
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 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 int
314 archive_tar::get_mtime ()
315 {
316       if (state.parent)
317                     return state.parent->get_mtime ();
318             return 0;
319 }
Note: See TracBrowser for help on using the browser.