2 * Copyright (c) 2000, 2001, Red Hat, Inc.
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.
9 * A copy of the GNU General Public License can be found at
12 * Written by DJ Delorie <dj@cygnus.com>
16 /* Built-in tar functionality. See tar.h for usage. */
20 #include <sys/types.h>
21 #include <sys/fcntl.h>
24 //#include "zlib/zlib.h"
25 #include "io_stream.h"
26 //#include "compress.h"
29 #include "archive_tar.h"
32 #include "filemanip.h"
38 #define SYMLINK_COOKIE "!<symlink>"
46 archive_tar::archive_tar (io_stream
* original
)
51 LogBabblePrintf("tar: open `%p'\n", original
);
55 state
.lasterr
= EBADF
;
58 state
.parent
= original
;
60 if (sizeof (state
.tar_header
) != 512)
62 /* drastic, but important */
63 Log (LOG_TIMESTAMP
) << "compilation error: tar header struct not 512"
64 << " bytes (it's " << sizeof (state
.tar_header
)
71 archive_tar::read (void *buffer
, size_t len
)
77 archive_tar::write (const void *buffer
, size_t len
)
83 archive_tar::peek (void *buffer
, size_t len
)
97 return state
.file_offset
;
101 archive_tar::seek (long where
, io_stream_seek_t whence
)
103 /* seeking in the parent archive doesn't make sense. although we could
105 Also, seeking might make sense for rewing..??
111 archive_tar::skip_file ()
113 while (state
.file_length
> state
.file_offset
)
115 int len
= state
.parent
->read (buf
, 512);
116 state
.file_offset
+= 512;
120 state
.file_length
= 0;
121 state
.file_offset
= 0;
122 state
.header_read
= 0;
127 archive_tar::next_file_name ()
131 if (state
.header_read
)
133 if (strlen (state
.filename
))
134 return state
.filename
;
137 return std::string();
140 int r
= state
.parent
->read (&state
.tar_header
, 512);
142 /* See if we're at end of file */
144 return std::string();
146 /* See if the header is all zeros (i.e. last block) */
148 for (r
= 512 / sizeof (int); r
; r
--)
149 n
|= ((int *) &state
.tar_header
)[r
- 1];
151 return std::string();
153 if (!state
.have_longname
&& state
.tar_header
.typeflag
!= 'L')
155 memcpy (state
.filename
, state
.tar_header
.name
, 100);
156 state
.filename
[100] = 0;
158 else if (state
.have_longname
)
159 state
.have_longname
= 0;
161 sscanf (state
.tar_header
.size
, "%Io", &state
.file_length
);
162 state
.file_offset
= 0;
165 LogBabblePrintf ("%c %9d %s\n", state
.tar_header
.typeflag
,
166 state
.file_length
, state
.filename
);
168 switch (state
.tar_header
.typeflag
)
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..
174 if (state
.file_length
> CYG_PATH_MAX
)
177 LogPlainPrintf( "error: long file name exceeds %d characters\n",
180 state
.parent
->read (&state
.tar_header
, 512);
181 sscanf (state
.tar_header
.size
, "%Io", &state
.file_length
);
182 state
.file_offset
= 0;
184 return next_file_name ();
187 /* FIXME: this should be a single read() call */
188 while (state
.file_length
> state
.file_offset
)
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)
199 memcpy (c
, buf
, need
);
201 state
.file_offset
+= need
;
204 state
.have_longname
= 1;
205 return next_file_name ();
208 case '4': /* block */
210 LogPlainPrintf ("warning: not extracting special file %s\n",
213 return next_file_name ();
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
;
223 case '1': /* hard link, we just copy */
224 state
.header_read
= 1;
225 return state
.filename
;
228 LogPlainPrintf ("error: unknown (or unsupported) file type `%c'\n",
229 state
.tar_header
.typeflag
);
232 case 'g': /* POSIX.1-2001 global extended header */
233 case 'x': /* POSIX.1-2001 extended header */
235 return next_file_name ();
237 return std::string();
240 archive_tar::~archive_tar ()
248 fix_time_stamp (char *path
)
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
,
261 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
, 0);
264 SetFileTime (h
, 0, 0, &ftime
);
270 archive_tar::next_file_type ()
272 switch (state
.tar_header
.typeflag
)
278 return ARCHIVE_FILE_REGULAR
;
280 return ARCHIVE_FILE_HARDLINK
;
282 return ARCHIVE_FILE_DIRECTORY
;
284 return ARCHIVE_FILE_SYMLINK
;
286 return ARCHIVE_FILE_INVALID
;
291 archive_tar::linktarget ()
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();
301 archive_tar::extract_file ()
303 if (archive_children
)
305 archive_tar_file
*rv
= new archive_tar_file (state
);
310 archive_tar::get_mtime ()
313 return state
.parent
->get_mtime ();
318 archive_tar::get_mode ()
321 return state
.parent
->get_mode ();