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 "io_stream.h"
27 #include "archive_tar.h"
30 #include "filemanip.h"
37 archive_tar::archive_tar (io_stream
* original
)
42 LogBabblePrintf("tar: open `%p'\n", original
);
46 state
.lasterr
= EBADF
;
49 state
.parent
= original
;
51 if (sizeof (state
.tar_header
) != 512)
53 /* drastic, but important */
54 Log (LOG_TIMESTAMP
) << "compilation error: tar header struct not 512"
55 << " bytes (it's " << sizeof (state
.tar_header
)
62 archive_tar::read (void *buffer
, size_t len
)
68 archive_tar::write (const void *buffer
, size_t len
)
74 archive_tar::peek (void *buffer
, size_t len
)
88 return state
.file_offset
;
92 archive_tar::seek (off_t where
, io_stream_seek_t whence
)
94 /* Because the parent stream is compressed, we can only easily support
95 seek()-ing to rewind to the start */
96 if ((whence
== IO_SEEK_SET
) && (where
== 0))
98 state
.header_read
= 0;
99 return state
.parent
->seek(where
, whence
);
106 archive_tar::skip_file ()
108 while (state
.file_length
> state
.file_offset
)
110 int len
= state
.parent
->read (buf
, 512);
111 state
.file_offset
+= 512;
115 state
.file_length
= 0;
116 state
.file_offset
= 0;
117 state
.header_read
= 0;
122 archive_tar::next_file_name ()
126 if (state
.header_read
)
128 if (strlen (state
.filename
))
129 return state
.filename
;
132 return std::string();
135 int r
= state
.parent
->read (&state
.tar_header
, 512);
137 /* See if we're at end of file */
139 return std::string();
141 /* See if the header is all zeros (i.e. last block) */
143 for (r
= 512 / sizeof (int); r
; r
--)
144 n
|= ((int *) &state
.tar_header
)[r
- 1];
146 return std::string();
148 if (!state
.have_longname
)
150 memcpy (state
.filename
, state
.tar_header
.name
, 100);
151 state
.filename
[100] = 0;
154 if (!state
.have_longlink
)
156 memcpy (state
.linkname
, state
.tar_header
.linkname
, 100);
157 state
.linkname
[100] = 0;
160 /* typeflag for any 'real' file consumes the longname/longlink state from
162 if ((state
.tar_header
.typeflag
!= 'K') &&
163 (state
.tar_header
.typeflag
!= 'L'))
165 state
.have_longname
= 0;
166 state
.have_longlink
= 0;
169 state
.file_length
= strtoll (state
.tar_header
.size
, NULL
, 8);
170 state
.file_offset
= 0;
173 LogBabblePrintf ("%c %9d %s\n", state
.tar_header
.typeflag
,
174 state
.file_length
, state
.filename
);
176 switch (state
.tar_header
.typeflag
)
178 case 'K': /* GNU tar long link extension */
179 case 'L': /* GNU tar long name extension */
180 if (strcmp(state
.tar_header
.name
, "././@LongLink") != 0)
181 LogBabblePrintf("tar: unexpected filename %s in file type %c header\n", state
.tar_header
.name
, state
.tar_header
.typeflag
);
183 /* we read the 'file' into the long filename/linkname, then recursively
184 * call ourselves to handle the following block.
186 if (state
.file_length
> CYG_PATH_MAX
)
189 LogPlainPrintf( "error: long file name exceeds %d characters\n",
192 state
.parent
->read (&state
.tar_header
, 512);
193 state
.file_length
= strtoll (state
.tar_header
.size
, NULL
, 8);
194 state
.file_offset
= 0;
196 return next_file_name ();
199 if (state
.tar_header
.typeflag
== 'L')
202 state
.have_longname
= 1;
207 state
.have_longlink
= 1;
210 /* FIXME: this should be a single read() call */
211 while (state
.file_length
> state
.file_offset
)
214 state
.file_length
- state
.file_offset
>
215 512 ? 512 : state
.file_length
- state
.file_offset
;
216 if (state
.parent
->read (buf
, 512) < 512)
218 LogPlainPrintf( "error: error reading long name\n");
221 memcpy (c
, buf
, need
);
223 state
.file_offset
+= need
;
227 return next_file_name ();
230 case '4': /* block */
232 LogPlainPrintf ("warning: not extracting special file %s\n",
235 return next_file_name ();
237 case '0': /* regular file */
238 case 0: /* regular file also */
239 case '2': /* symbolic link */
240 case '5': /* directory */
241 case '7': /* contiguous file */
242 state
.header_read
= 1;
243 return state
.filename
;
245 case '1': /* hard link, we just copy */
246 state
.header_read
= 1;
247 return state
.filename
;
250 LogPlainPrintf ("error: unknown (or unsupported) file type `%c'\n",
251 state
.tar_header
.typeflag
);
254 case 'g': /* POSIX.1-2001 global extended header */
255 case 'x': /* POSIX.1-2001 extended header */
257 return next_file_name ();
259 return std::string();
262 archive_tar::~archive_tar ()
270 fix_time_stamp (char *path
)
277 sscanf (tar_header
.mtime
, "%o", &mtime
);
278 ftimev
= mtime
* NSPERSEC
+ FACTOR
;
279 ftime
.dwHighDateTime
= ftimev
>> 32;
280 ftime
.dwLowDateTime
= ftimev
;
281 h
= CreateFileA (path
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
283 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
, 0);
286 SetFileTime (h
, 0, 0, &ftime
);
292 archive_tar::next_file_type ()
294 switch (state
.tar_header
.typeflag
)
300 return ARCHIVE_FILE_REGULAR
;
302 return ARCHIVE_FILE_HARDLINK
;
304 return ARCHIVE_FILE_DIRECTORY
;
306 return ARCHIVE_FILE_SYMLINK
;
308 return ARCHIVE_FILE_INVALID
;
313 archive_tar::linktarget ()
315 /* TODO: consider .. path traversal issues */
316 if (next_file_type () == ARCHIVE_FILE_SYMLINK
||
317 next_file_type () == ARCHIVE_FILE_HARDLINK
)
318 return state
.linkname
;
319 return std::string();
323 archive_tar::extract_file ()
325 if (archive_children
)
327 archive_tar_file
*rv
= new archive_tar_file (state
);
332 archive_tar::get_mtime ()
335 return state
.parent
->get_mtime ();
340 archive_tar::get_mode ()
343 return state
.parent
->get_mode ();