blob: 9d0061592efe298b212d060a1f31c7176030e40e [file] [log] [blame]
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001#!/usr/bin/env python
2# -*- coding: iso-8859-1 -*-
3#-------------------------------------------------------------------
4# tarfile.py
5#-------------------------------------------------------------------
6# Copyright (C) 2002 Lars Gustäbel <lars@gustaebel.de>
7# All rights reserved.
8#
9# Permission is hereby granted, free of charge, to any person
10# obtaining a copy of this software and associated documentation
11# files (the "Software"), to deal in the Software without
12# restriction, including without limitation the rights to use,
13# copy, modify, merge, publish, distribute, sublicense, and/or sell
14# copies of the Software, and to permit persons to whom the
15# Software is furnished to do so, subject to the following
16# conditions:
17#
18# The above copyright notice and this permission notice shall be
19# included in all copies or substantial portions of the Software.
20#
21# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28# OTHER DEALINGS IN THE SOFTWARE.
29#
30"""Read from and write to tar format archives.
31"""
32
33__version__ = "$Revision$"
34# $Source$
35
36version = "0.6.4"
37__author__ = "Lars Gustäbel (lars@gustaebel.de)"
38__date__ = "$Date$"
39__cvsid__ = "$Id$"
40__credits__ = "Gustavo Niemeyer, Niels Gustäbel, Richard Townsend."
41
42#---------
43# Imports
44#---------
45import sys
46import os
47import shutil
48import stat
49import errno
50import time
51import struct
52
Jack Jansencfc49022003-03-07 13:37:32 +000053if sys.platform == 'mac':
54 # This module needs work for MacOS9, especially in the area of pathname
55 # handling. In many places it is assumed a simple substitution of / by the
56 # local os.path.sep is good enough to convert pathnames, but this does not
57 # work with the mac rooted:path:name versus :nonrooted:path:name syntax
58 raise ImportError, "tarfile does not work for platform==mac"
59
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000060try:
61 import grp, pwd
62except ImportError:
63 grp = pwd = None
64
65# from tarfile import *
66__all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError"]
67
68#---------------------------------------------------------
69# tar constants
70#---------------------------------------------------------
71NUL = "\0" # the null character
72BLOCKSIZE = 512 # length of processing blocks
73RECORDSIZE = BLOCKSIZE * 20 # length of records
74MAGIC = "ustar" # magic tar string
75VERSION = "00" # version number
76
77LENGTH_NAME = 100 # maximum length of a filename
78LENGTH_LINK = 100 # maximum length of a linkname
79LENGTH_PREFIX = 155 # maximum length of the prefix field
80MAXSIZE_MEMBER = 077777777777L # maximum size of a file (11 octal digits)
81
82REGTYPE = "0" # regular file
83AREGTYPE = "\0" # regular file
84LNKTYPE = "1" # link (inside tarfile)
85SYMTYPE = "2" # symbolic link
86CHRTYPE = "3" # character special device
87BLKTYPE = "4" # block special device
88DIRTYPE = "5" # directory
89FIFOTYPE = "6" # fifo special device
90CONTTYPE = "7" # contiguous file
91
92GNUTYPE_LONGNAME = "L" # GNU tar extension for longnames
93GNUTYPE_LONGLINK = "K" # GNU tar extension for longlink
94GNUTYPE_SPARSE = "S" # GNU tar extension for sparse file
95
96#---------------------------------------------------------
97# tarfile constants
98#---------------------------------------------------------
99SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, # file types that tarfile
100 SYMTYPE, DIRTYPE, FIFOTYPE, # can cope with.
101 CONTTYPE, CHRTYPE, BLKTYPE,
102 GNUTYPE_LONGNAME, GNUTYPE_LONGLINK,
103 GNUTYPE_SPARSE)
104
105REGULAR_TYPES = (REGTYPE, AREGTYPE, # file types that somehow
106 CONTTYPE, GNUTYPE_SPARSE) # represent regular files
107
108#---------------------------------------------------------
109# Bits used in the mode field, values in octal.
110#---------------------------------------------------------
111S_IFLNK = 0120000 # symbolic link
112S_IFREG = 0100000 # regular file
113S_IFBLK = 0060000 # block device
114S_IFDIR = 0040000 # directory
115S_IFCHR = 0020000 # character device
116S_IFIFO = 0010000 # fifo
117
118TSUID = 04000 # set UID on execution
119TSGID = 02000 # set GID on execution
120TSVTX = 01000 # reserved
121
122TUREAD = 0400 # read by owner
123TUWRITE = 0200 # write by owner
124TUEXEC = 0100 # execute/search by owner
125TGREAD = 0040 # read by group
126TGWRITE = 0020 # write by group
127TGEXEC = 0010 # execute/search by group
128TOREAD = 0004 # read by other
129TOWRITE = 0002 # write by other
130TOEXEC = 0001 # execute/search by other
131
132#---------------------------------------------------------
133# Some useful functions
134#---------------------------------------------------------
135def nts(s):
136 """Convert a null-terminated string buffer to a python string.
137 """
Andrew M. Kuchling864bba12004-07-10 22:02:11 +0000138 return s.rstrip(NUL)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000139
140def calc_chksum(buf):
141 """Calculate the checksum for a member's header. It's a simple addition
142 of all bytes, treating the chksum field as if filled with spaces.
143 buf is a 512 byte long string buffer which holds the header.
144 """
145 chk = 256 # chksum field is treated as blanks,
146 # so the initial value is 8 * ord(" ")
147 for c in buf[:148]: chk += ord(c) # sum up all bytes before chksum
148 for c in buf[156:]: chk += ord(c) # sum up all bytes after chksum
149 return chk
150
151def copyfileobj(src, dst, length=None):
152 """Copy length bytes from fileobj src to fileobj dst.
153 If length is None, copy the entire content.
154 """
155 if length == 0:
156 return
157 if length is None:
158 shutil.copyfileobj(src, dst)
159 return
160
161 BUFSIZE = 16 * 1024
162 blocks, remainder = divmod(length, BUFSIZE)
163 for b in xrange(blocks):
164 buf = src.read(BUFSIZE)
165 if len(buf) < BUFSIZE:
166 raise IOError, "end of file reached"
167 dst.write(buf)
168
169 if remainder != 0:
170 buf = src.read(remainder)
171 if len(buf) < remainder:
172 raise IOError, "end of file reached"
173 dst.write(buf)
174 return
175
176filemode_table = (
Andrew M. Kuchling8bc462f2004-10-20 11:48:42 +0000177 ((S_IFLNK, "l"),
178 (S_IFREG, "-"),
179 (S_IFBLK, "b"),
180 (S_IFDIR, "d"),
181 (S_IFCHR, "c"),
182 (S_IFIFO, "p")),
183
184 ((TUREAD, "r"),),
185 ((TUWRITE, "w"),),
186 ((TUEXEC|TSUID, "s"),
187 (TSUID, "S"),
188 (TUEXEC, "x")),
189
190 ((TGREAD, "r"),),
191 ((TGWRITE, "w"),),
192 ((TGEXEC|TSGID, "s"),
193 (TSGID, "S"),
194 (TGEXEC, "x")),
195
196 ((TOREAD, "r"),),
197 ((TOWRITE, "w"),),
198 ((TOEXEC|TSVTX, "t"),
199 (TSVTX, "T"),
200 (TOEXEC, "x"))
201)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000202
203def filemode(mode):
204 """Convert a file's mode to a string of the form
205 -rwxrwxrwx.
206 Used by TarFile.list()
207 """
Andrew M. Kuchling8bc462f2004-10-20 11:48:42 +0000208 perm = []
209 for table in filemode_table:
210 for bit, char in table:
211 if mode & bit == bit:
212 perm.append(char)
213 break
214 else:
215 perm.append("-")
216 return "".join(perm)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000217
218if os.sep != "/":
219 normpath = lambda path: os.path.normpath(path).replace(os.sep, "/")
220else:
221 normpath = os.path.normpath
222
223class TarError(Exception):
224 """Base exception."""
225 pass
226class ExtractError(TarError):
227 """General exception for extract errors."""
228 pass
229class ReadError(TarError):
230 """Exception for unreadble tar archives."""
231 pass
232class CompressionError(TarError):
233 """Exception for unavailable compression methods."""
234 pass
235class StreamError(TarError):
236 """Exception for unsupported operations on stream-like TarFiles."""
237 pass
238
239#---------------------------
240# internal stream interface
241#---------------------------
242class _LowLevelFile:
243 """Low-level file object. Supports reading and writing.
244 It is used instead of a regular file object for streaming
245 access.
246 """
247
248 def __init__(self, name, mode):
249 mode = {
250 "r": os.O_RDONLY,
251 "w": os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
252 }[mode]
253 if hasattr(os, "O_BINARY"):
254 mode |= os.O_BINARY
255 self.fd = os.open(name, mode)
256
257 def close(self):
258 os.close(self.fd)
259
260 def read(self, size):
261 return os.read(self.fd, size)
262
263 def write(self, s):
264 os.write(self.fd, s)
265
266class _Stream:
267 """Class that serves as an adapter between TarFile and
268 a stream-like object. The stream-like object only
269 needs to have a read() or write() method and is accessed
270 blockwise. Use of gzip or bzip2 compression is possible.
271 A stream-like object could be for example: sys.stdin,
272 sys.stdout, a socket, a tape device etc.
273
274 _Stream is intended to be used only internally.
275 """
276
277 def __init__(self, name, mode, type, fileobj, bufsize):
278 """Construct a _Stream object.
279 """
280 self._extfileobj = True
281 if fileobj is None:
282 fileobj = _LowLevelFile(name, mode)
283 self._extfileobj = False
284
285 self.name = name or ""
286 self.mode = mode
287 self.type = type
288 self.fileobj = fileobj
289 self.bufsize = bufsize
290 self.buf = ""
291 self.pos = 0L
292 self.closed = False
293
294 if type == "gz":
295 try:
296 import zlib
297 except ImportError:
298 raise CompressionError, "zlib module is not available"
299 self.zlib = zlib
300 self.crc = zlib.crc32("")
301 if mode == "r":
302 self._init_read_gz()
303 else:
304 self._init_write_gz()
305
306 if type == "bz2":
307 try:
308 import bz2
309 except ImportError:
310 raise CompressionError, "bz2 module is not available"
311 if mode == "r":
312 self.dbuf = ""
313 self.cmp = bz2.BZ2Decompressor()
314 else:
315 self.cmp = bz2.BZ2Compressor()
316
317 def __del__(self):
318 if not self.closed:
319 self.close()
320
321 def _init_write_gz(self):
322 """Initialize for writing with gzip compression.
323 """
324 self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED,
325 -self.zlib.MAX_WBITS,
326 self.zlib.DEF_MEM_LEVEL,
327 0)
328 timestamp = struct.pack("<L", long(time.time()))
329 self.__write("\037\213\010\010%s\002\377" % timestamp)
330 if self.name.endswith(".gz"):
331 self.name = self.name[:-3]
332 self.__write(self.name + NUL)
333
334 def write(self, s):
335 """Write string s to the stream.
336 """
337 if self.type == "gz":
338 self.crc = self.zlib.crc32(s, self.crc)
339 self.pos += len(s)
340 if self.type != "tar":
341 s = self.cmp.compress(s)
342 self.__write(s)
343
344 def __write(self, s):
345 """Write string s to the stream if a whole new block
346 is ready to be written.
347 """
348 self.buf += s
349 while len(self.buf) > self.bufsize:
350 self.fileobj.write(self.buf[:self.bufsize])
351 self.buf = self.buf[self.bufsize:]
352
353 def close(self):
354 """Close the _Stream object. No operation should be
355 done on it afterwards.
356 """
357 if self.closed:
358 return
359
Martin v. Löwisc234a522004-08-22 21:28:33 +0000360 if self.mode == "w" and self.type != "tar":
361 self.buf += self.cmp.flush()
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000362 if self.mode == "w" and self.buf:
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000363 self.fileobj.write(self.buf)
364 self.buf = ""
365 if self.type == "gz":
366 self.fileobj.write(struct.pack("<l", self.crc))
Andrew M. Kuchling10a44492003-10-24 17:38:34 +0000367 self.fileobj.write(struct.pack("<L", self.pos & 0xffffFFFFL))
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000368
369 if not self._extfileobj:
370 self.fileobj.close()
371
372 self.closed = True
373
374 def _init_read_gz(self):
375 """Initialize for reading a gzip compressed fileobj.
376 """
377 self.cmp = self.zlib.decompressobj(-self.zlib.MAX_WBITS)
378 self.dbuf = ""
379
380 # taken from gzip.GzipFile with some alterations
381 if self.__read(2) != "\037\213":
382 raise ReadError, "not a gzip file"
383 if self.__read(1) != "\010":
384 raise CompressionError, "unsupported compression method"
385
386 flag = ord(self.__read(1))
387 self.__read(6)
388
389 if flag & 4:
390 xlen = ord(self.__read(1)) + 256 * ord(self.__read(1))
391 self.read(xlen)
392 if flag & 8:
393 while True:
394 s = self.__read(1)
395 if not s or s == NUL:
396 break
397 if flag & 16:
398 while True:
399 s = self.__read(1)
400 if not s or s == NUL:
401 break
402 if flag & 2:
403 self.__read(2)
404
405 def tell(self):
406 """Return the stream's file pointer position.
407 """
408 return self.pos
409
410 def seek(self, pos=0):
411 """Set the stream's file pointer to pos. Negative seeking
412 is forbidden.
413 """
414 if pos - self.pos >= 0:
415 blocks, remainder = divmod(pos - self.pos, self.bufsize)
416 for i in xrange(blocks):
417 self.read(self.bufsize)
418 self.read(remainder)
419 else:
420 raise StreamError, "seeking backwards is not allowed"
421 return self.pos
422
423 def read(self, size=None):
424 """Return the next size number of bytes from the stream.
425 If size is not defined, return all bytes of the stream
426 up to EOF.
427 """
428 if size is None:
429 t = []
430 while True:
431 buf = self._read(self.bufsize)
432 if not buf:
433 break
434 t.append(buf)
435 buf = "".join(t)
436 else:
437 buf = self._read(size)
438 self.pos += len(buf)
439 return buf
440
441 def _read(self, size):
442 """Return size bytes from the stream.
443 """
444 if self.type == "tar":
445 return self.__read(size)
446
447 c = len(self.dbuf)
448 t = [self.dbuf]
449 while c < size:
450 buf = self.__read(self.bufsize)
451 if not buf:
452 break
453 buf = self.cmp.decompress(buf)
454 t.append(buf)
455 c += len(buf)
456 t = "".join(t)
457 self.dbuf = t[size:]
458 return t[:size]
459
460 def __read(self, size):
461 """Return size bytes from stream. If internal buffer is empty,
462 read another block from the stream.
463 """
464 c = len(self.buf)
465 t = [self.buf]
466 while c < size:
467 buf = self.fileobj.read(self.bufsize)
468 if not buf:
469 break
470 t.append(buf)
471 c += len(buf)
472 t = "".join(t)
473 self.buf = t[size:]
474 return t[:size]
475# class _Stream
476
477#------------------------
478# Extraction file object
479#------------------------
480class ExFileObject(object):
481 """File-like object for reading an archive member.
482 Is returned by TarFile.extractfile(). Support for
483 sparse files included.
484 """
485
486 def __init__(self, tarfile, tarinfo):
487 self.fileobj = tarfile.fileobj
488 self.name = tarinfo.name
489 self.mode = "r"
490 self.closed = False
491 self.offset = tarinfo.offset_data
492 self.size = tarinfo.size
493 self.pos = 0L
494 self.linebuffer = ""
495 if tarinfo.issparse():
496 self.sparse = tarinfo.sparse
497 self.read = self._readsparse
498 else:
499 self.read = self._readnormal
500
501 def __read(self, size):
502 """Overloadable read method.
503 """
504 return self.fileobj.read(size)
505
506 def readline(self, size=-1):
507 """Read a line with approx. size. If size is negative,
508 read a whole line. readline() and read() must not
509 be mixed up (!).
510 """
511 if size < 0:
512 size = sys.maxint
513
514 nl = self.linebuffer.find("\n")
515 if nl >= 0:
516 nl = min(nl, size)
517 else:
518 size -= len(self.linebuffer)
Martin v. Löwisc11d6f12004-08-25 10:52:58 +0000519 while (nl < 0 and size > 0):
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000520 buf = self.read(min(size, 100))
521 if not buf:
522 break
523 self.linebuffer += buf
524 size -= len(buf)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000525 nl = self.linebuffer.find("\n")
526 if nl == -1:
527 s = self.linebuffer
528 self.linebuffer = ""
529 return s
530 buf = self.linebuffer[:nl]
531 self.linebuffer = self.linebuffer[nl + 1:]
532 while buf[-1:] == "\r":
533 buf = buf[:-1]
534 return buf + "\n"
535
536 def readlines(self):
537 """Return a list with all (following) lines.
538 """
539 result = []
540 while True:
541 line = self.readline()
542 if not line: break
543 result.append(line)
544 return result
545
546 def _readnormal(self, size=None):
547 """Read operation for regular files.
548 """
549 if self.closed:
550 raise ValueError, "file is closed"
551 self.fileobj.seek(self.offset + self.pos)
552 bytesleft = self.size - self.pos
553 if size is None:
554 bytestoread = bytesleft
555 else:
556 bytestoread = min(size, bytesleft)
557 self.pos += bytestoread
558 return self.__read(bytestoread)
559
560 def _readsparse(self, size=None):
561 """Read operation for sparse files.
562 """
563 if self.closed:
564 raise ValueError, "file is closed"
565
566 if size is None:
567 size = self.size - self.pos
568
569 data = []
570 while size > 0:
571 buf = self._readsparsesection(size)
572 if not buf:
573 break
574 size -= len(buf)
575 data.append(buf)
576 return "".join(data)
577
578 def _readsparsesection(self, size):
579 """Read a single section of a sparse file.
580 """
581 section = self.sparse.find(self.pos)
582
583 if section is None:
584 return ""
585
586 toread = min(size, section.offset + section.size - self.pos)
587 if isinstance(section, _data):
588 realpos = section.realpos + self.pos - section.offset
589 self.pos += toread
590 self.fileobj.seek(self.offset + realpos)
591 return self.__read(toread)
592 else:
593 self.pos += toread
594 return NUL * toread
595
596 def tell(self):
597 """Return the current file position.
598 """
599 return self.pos
600
601 def seek(self, pos, whence=0):
602 """Seek to a position in the file.
603 """
604 self.linebuffer = ""
605 if whence == 0:
606 self.pos = min(max(pos, 0), self.size)
607 if whence == 1:
608 if pos < 0:
609 self.pos = max(self.pos + pos, 0)
610 else:
611 self.pos = min(self.pos + pos, self.size)
612 if whence == 2:
613 self.pos = max(min(self.size + pos, self.size), 0)
614
615 def close(self):
616 """Close the file object.
617 """
618 self.closed = True
619#class ExFileObject
620
621#------------------
622# Exported Classes
623#------------------
624class TarInfo(object):
625 """Informational class which holds the details about an
626 archive member given by a tar header block.
627 TarInfo objects are returned by TarFile.getmember(),
628 TarFile.getmembers() and TarFile.gettarinfo() and are
629 usually created internally.
630 """
631
632 def __init__(self, name=""):
633 """Construct a TarInfo object. name is the optional name
634 of the member.
635 """
636
637 self.name = name # member name (dirnames must end with '/')
638 self.mode = 0666 # file permissions
639 self.uid = 0 # user id
640 self.gid = 0 # group id
641 self.size = 0 # file size
642 self.mtime = 0 # modification time
643 self.chksum = 0 # header checksum
644 self.type = REGTYPE # member type
645 self.linkname = "" # link name
646 self.uname = "user" # user name
647 self.gname = "group" # group name
648 self.devmajor = 0 #-
649 self.devminor = 0 #-for use with CHRTYPE and BLKTYPE
650 self.prefix = "" # prefix to filename or holding information
651 # about sparse files
652
653 self.offset = 0 # the tar header starts here
654 self.offset_data = 0 # the file's data starts here
655
656 def __repr__(self):
657 return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self))
658
Guido van Rossum75b64e62005-01-16 00:16:11 +0000659 @classmethod
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000660 def frombuf(cls, buf):
661 """Construct a TarInfo object from a 512 byte string buffer.
662 """
663 tarinfo = cls()
Neal Norwitzd96d1012004-07-20 22:23:02 +0000664 tarinfo.name = nts(buf[0:100])
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000665 tarinfo.mode = int(buf[100:108], 8)
666 tarinfo.uid = int(buf[108:116],8)
667 tarinfo.gid = int(buf[116:124],8)
Neal Norwitzd96d1012004-07-20 22:23:02 +0000668
669 # There are two possible codings for the size field we
670 # have to discriminate, see comment in tobuf() below.
671 if buf[124] != chr(0200):
672 tarinfo.size = long(buf[124:136], 8)
673 else:
674 tarinfo.size = 0L
675 for i in range(11):
676 tarinfo.size <<= 8
677 tarinfo.size += ord(buf[125 + i])
678
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000679 tarinfo.mtime = long(buf[136:148], 8)
680 tarinfo.chksum = int(buf[148:156], 8)
681 tarinfo.type = buf[156:157]
682 tarinfo.linkname = nts(buf[157:257])
683 tarinfo.uname = nts(buf[265:297])
684 tarinfo.gname = nts(buf[297:329])
685 try:
686 tarinfo.devmajor = int(buf[329:337], 8)
687 tarinfo.devminor = int(buf[337:345], 8)
688 except ValueError:
689 tarinfo.devmajor = tarinfo.devmajor = 0
Jack Jansen2b4b5a52003-04-22 22:03:11 +0000690 tarinfo.prefix = buf[345:500]
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000691
692 # The prefix field is used for filenames > 100 in
693 # the POSIX standard.
Jack Jansen2b4b5a52003-04-22 22:03:11 +0000694 # name = prefix + '/' + name
695 if tarinfo.type != GNUTYPE_SPARSE:
696 tarinfo.name = normpath(os.path.join(nts(tarinfo.prefix), tarinfo.name))
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000697
698 # Directory names should have a '/' at the end.
699 if tarinfo.isdir() and tarinfo.name[-1:] != "/":
700 tarinfo.name += "/"
701 return tarinfo
702
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000703 def tobuf(self):
704 """Return a tar header block as a 512 byte string.
705 """
Neal Norwitzd96d1012004-07-20 22:23:02 +0000706 # Prefer the size to be encoded as 11 octal ascii digits
707 # which is the most portable. If the size exceeds this
708 # limit (>= 8 GB), encode it as an 88-bit value which is
709 # a GNU tar feature.
710 if self.size <= MAXSIZE_MEMBER:
711 size = "%011o" % self.size
712 else:
713 s = self.size
714 size = ""
715 for i in range(11):
716 size = chr(s & 0377) + size
717 s >>= 8
718 size = chr(0200) + size
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000719
720 # The following code was contributed by Detlef Lannert.
721 parts = []
722 for value, fieldsize in (
Neal Norwitzd96d1012004-07-20 22:23:02 +0000723 (self.name, 100),
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000724 ("%07o" % (self.mode & 07777), 8),
725 ("%07o" % self.uid, 8),
726 ("%07o" % self.gid, 8),
Neal Norwitzd96d1012004-07-20 22:23:02 +0000727 (size, 12),
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000728 ("%011o" % self.mtime, 12),
729 (" ", 8),
730 (self.type, 1),
731 (self.linkname, 100),
732 (MAGIC, 6),
733 (VERSION, 2),
734 (self.uname, 32),
735 (self.gname, 32),
736 ("%07o" % self.devmajor, 8),
737 ("%07o" % self.devminor, 8),
738 (self.prefix, 155)
739 ):
740 l = len(value)
Andrew M. Kuchling864bba12004-07-10 22:02:11 +0000741 parts.append(value[:fieldsize] + (fieldsize - l) * NUL)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000742
743 buf = "".join(parts)
744 chksum = calc_chksum(buf)
745 buf = buf[:148] + "%06o\0" % chksum + buf[155:]
746 buf += (BLOCKSIZE - len(buf)) * NUL
747 self.buf = buf
748 return buf
749
750 def isreg(self):
751 return self.type in REGULAR_TYPES
752 def isfile(self):
753 return self.isreg()
754 def isdir(self):
755 return self.type == DIRTYPE
756 def issym(self):
757 return self.type == SYMTYPE
758 def islnk(self):
759 return self.type == LNKTYPE
760 def ischr(self):
761 return self.type == CHRTYPE
762 def isblk(self):
763 return self.type == BLKTYPE
764 def isfifo(self):
765 return self.type == FIFOTYPE
766 def issparse(self):
767 return self.type == GNUTYPE_SPARSE
768 def isdev(self):
769 return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE)
770# class TarInfo
771
772class TarFile(object):
773 """The TarFile Class provides an interface to tar archives.
774 """
775
776 debug = 0 # May be set from 0 (no msgs) to 3 (all msgs)
777
778 dereference = False # If true, add content of linked file to the
779 # tar file, else the link.
780
781 ignore_zeros = False # If true, skips empty or invalid blocks and
782 # continues processing.
783
784 errorlevel = 0 # If 0, fatal errors only appear in debug
785 # messages (if debug >= 0). If > 0, errors
786 # are passed to the caller as exceptions.
787
Martin v. Löwis75b9da42004-08-18 13:57:44 +0000788 posix = False # If True, generates POSIX.1-1990-compliant
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000789 # archives (no GNU extensions!)
790
791 fileobject = ExFileObject
792
793 def __init__(self, name=None, mode="r", fileobj=None):
794 """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
795 read from an existing archive, 'a' to append data to an existing
796 file or 'w' to create a new file overwriting an existing one. `mode'
797 defaults to 'r'.
798 If `fileobj' is given, it is used for reading or writing data. If it
799 can be determined, `mode' is overridden by `fileobj's mode.
800 `fileobj' is not closed, when TarFile is closed.
801 """
802 self.name = name
803
804 if len(mode) > 1 or mode not in "raw":
805 raise ValueError, "mode must be 'r', 'a' or 'w'"
806 self._mode = mode
807 self.mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode]
808
809 if not fileobj:
810 fileobj = file(self.name, self.mode)
811 self._extfileobj = False
812 else:
813 if self.name is None and hasattr(fileobj, "name"):
814 self.name = fileobj.name
815 if hasattr(fileobj, "mode"):
816 self.mode = fileobj.mode
817 self._extfileobj = True
818 self.fileobj = fileobj
819
820 # Init datastructures
821 self.closed = False
822 self.members = [] # list of members as TarInfo objects
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000823 self._loaded = False # flag if all members have been read
824 self.offset = 0L # current position in the archive file
825 self.inodes = {} # dictionary caching the inodes of
826 # archive members already added
827
828 if self._mode == "r":
829 self.firstmember = None
830 self.firstmember = self.next()
831
832 if self._mode == "a":
833 # Move to the end of the archive,
834 # before the first empty block.
835 self.firstmember = None
836 while True:
837 try:
838 tarinfo = self.next()
839 except ReadError:
840 self.fileobj.seek(0)
841 break
842 if tarinfo is None:
843 self.fileobj.seek(- BLOCKSIZE, 1)
844 break
845
846 if self._mode in "aw":
847 self._loaded = True
848
849 #--------------------------------------------------------------------------
850 # Below are the classmethods which act as alternate constructors to the
851 # TarFile class. The open() method is the only one that is needed for
852 # public use; it is the "super"-constructor and is able to select an
853 # adequate "sub"-constructor for a particular compression using the mapping
854 # from OPEN_METH.
855 #
856 # This concept allows one to subclass TarFile without losing the comfort of
857 # the super-constructor. A sub-constructor is registered and made available
858 # by adding it to the mapping in OPEN_METH.
859
Guido van Rossum75b64e62005-01-16 00:16:11 +0000860 @classmethod
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000861 def open(cls, name=None, mode="r", fileobj=None, bufsize=20*512):
862 """Open a tar archive for reading, writing or appending. Return
863 an appropriate TarFile class.
864
865 mode:
866 'r' open for reading with transparent compression
867 'r:' open for reading exclusively uncompressed
868 'r:gz' open for reading with gzip compression
869 'r:bz2' open for reading with bzip2 compression
870 'a' or 'a:' open for appending
871 'w' or 'w:' open for writing without compression
872 'w:gz' open for writing with gzip compression
873 'w:bz2' open for writing with bzip2 compression
874 'r|' open an uncompressed stream of tar blocks for reading
875 'r|gz' open a gzip compressed stream of tar blocks
876 'r|bz2' open a bzip2 compressed stream of tar blocks
877 'w|' open an uncompressed stream for writing
878 'w|gz' open a gzip compressed stream for writing
879 'w|bz2' open a bzip2 compressed stream for writing
880 """
881
882 if not name and not fileobj:
883 raise ValueError, "nothing to open"
884
885 if ":" in mode:
886 filemode, comptype = mode.split(":", 1)
887 filemode = filemode or "r"
888 comptype = comptype or "tar"
889
890 # Select the *open() function according to
891 # given compression.
892 if comptype in cls.OPEN_METH:
893 func = getattr(cls, cls.OPEN_METH[comptype])
894 else:
895 raise CompressionError, "unknown compression type %r" % comptype
896 return func(name, filemode, fileobj)
897
898 elif "|" in mode:
899 filemode, comptype = mode.split("|", 1)
900 filemode = filemode or "r"
901 comptype = comptype or "tar"
902
903 if filemode not in "rw":
904 raise ValueError, "mode must be 'r' or 'w'"
905
906 t = cls(name, filemode,
907 _Stream(name, filemode, comptype, fileobj, bufsize))
908 t._extfileobj = False
909 return t
910
911 elif mode == "r":
912 # Find out which *open() is appropriate for opening the file.
913 for comptype in cls.OPEN_METH:
914 func = getattr(cls, cls.OPEN_METH[comptype])
915 try:
916 return func(name, "r", fileobj)
917 except (ReadError, CompressionError):
918 continue
919 raise ReadError, "file could not be opened successfully"
920
921 elif mode in "aw":
922 return cls.taropen(name, mode, fileobj)
923
924 raise ValueError, "undiscernible mode"
925
Guido van Rossum75b64e62005-01-16 00:16:11 +0000926 @classmethod
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000927 def taropen(cls, name, mode="r", fileobj=None):
928 """Open uncompressed tar archive name for reading or writing.
929 """
930 if len(mode) > 1 or mode not in "raw":
931 raise ValueError, "mode must be 'r', 'a' or 'w'"
932 return cls(name, mode, fileobj)
933
Guido van Rossum75b64e62005-01-16 00:16:11 +0000934 @classmethod
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000935 def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9):
936 """Open gzip compressed tar archive name for reading or writing.
937 Appending is not allowed.
938 """
939 if len(mode) > 1 or mode not in "rw":
940 raise ValueError, "mode must be 'r' or 'w'"
941
942 try:
943 import gzip
Neal Norwitz4ec68242003-04-11 03:05:56 +0000944 gzip.GzipFile
945 except (ImportError, AttributeError):
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000946 raise CompressionError, "gzip module is not available"
947
948 pre, ext = os.path.splitext(name)
949 pre = os.path.basename(pre)
950 if ext == ".tgz":
951 ext = ".tar"
952 if ext == ".gz":
953 ext = ""
954 tarname = pre + ext
955
956 if fileobj is None:
957 fileobj = file(name, mode + "b")
958
959 if mode != "r":
960 name = tarname
961
962 try:
963 t = cls.taropen(tarname, mode,
964 gzip.GzipFile(name, mode, compresslevel, fileobj)
965 )
966 except IOError:
967 raise ReadError, "not a gzip file"
968 t._extfileobj = False
969 return t
970
Guido van Rossum75b64e62005-01-16 00:16:11 +0000971 @classmethod
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000972 def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9):
973 """Open bzip2 compressed tar archive name for reading or writing.
974 Appending is not allowed.
975 """
976 if len(mode) > 1 or mode not in "rw":
977 raise ValueError, "mode must be 'r' or 'w'."
978
979 try:
980 import bz2
981 except ImportError:
982 raise CompressionError, "bz2 module is not available"
983
984 pre, ext = os.path.splitext(name)
985 pre = os.path.basename(pre)
986 if ext == ".tbz2":
987 ext = ".tar"
988 if ext == ".bz2":
989 ext = ""
990 tarname = pre + ext
991
992 if fileobj is not None:
993 raise ValueError, "no support for external file objects"
994
995 try:
996 t = cls.taropen(tarname, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel))
997 except IOError:
998 raise ReadError, "not a bzip2 file"
999 t._extfileobj = False
1000 return t
1001
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001002 # All *open() methods are registered here.
1003 OPEN_METH = {
1004 "tar": "taropen", # uncompressed tar
1005 "gz": "gzopen", # gzip compressed tar
1006 "bz2": "bz2open" # bzip2 compressed tar
1007 }
1008
1009 #--------------------------------------------------------------------------
1010 # The public methods which TarFile provides:
1011
1012 def close(self):
1013 """Close the TarFile. In write-mode, two finishing zero blocks are
1014 appended to the archive.
1015 """
1016 if self.closed:
1017 return
1018
1019 if self._mode in "aw":
1020 self.fileobj.write(NUL * (BLOCKSIZE * 2))
1021 self.offset += (BLOCKSIZE * 2)
1022 # fill up the end with zero-blocks
1023 # (like option -b20 for tar does)
1024 blocks, remainder = divmod(self.offset, RECORDSIZE)
1025 if remainder > 0:
1026 self.fileobj.write(NUL * (RECORDSIZE - remainder))
1027
1028 if not self._extfileobj:
1029 self.fileobj.close()
1030 self.closed = True
1031
1032 def getmember(self, name):
1033 """Return a TarInfo object for member `name'. If `name' can not be
1034 found in the archive, KeyError is raised. If a member occurs more
1035 than once in the archive, its last occurence is assumed to be the
1036 most up-to-date version.
1037 """
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001038 tarinfo = self._getmember(name)
1039 if tarinfo is None:
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001040 raise KeyError, "filename %r not found" % name
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001041 return tarinfo
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001042
1043 def getmembers(self):
1044 """Return the members of the archive as a list of TarInfo objects. The
1045 list has the same order as the members in the archive.
1046 """
1047 self._check()
1048 if not self._loaded: # if we want to obtain a list of
1049 self._load() # all members, we first have to
1050 # scan the whole archive.
1051 return self.members
1052
1053 def getnames(self):
1054 """Return the members of the archive as a list of their names. It has
1055 the same order as the list returned by getmembers().
1056 """
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001057 return [tarinfo.name for tarinfo in self.getmembers()]
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001058
1059 def gettarinfo(self, name=None, arcname=None, fileobj=None):
1060 """Create a TarInfo object for either the file `name' or the file
1061 object `fileobj' (using os.fstat on its file descriptor). You can
1062 modify some of the TarInfo's attributes before you add it using
1063 addfile(). If given, `arcname' specifies an alternative name for the
1064 file in the archive.
1065 """
1066 self._check("aw")
1067
1068 # When fileobj is given, replace name by
1069 # fileobj's real name.
1070 if fileobj is not None:
1071 name = fileobj.name
1072
1073 # Building the name of the member in the archive.
1074 # Backward slashes are converted to forward slashes,
1075 # Absolute paths are turned to relative paths.
1076 if arcname is None:
1077 arcname = name
1078 arcname = normpath(arcname)
1079 drv, arcname = os.path.splitdrive(arcname)
1080 while arcname[0:1] == "/":
1081 arcname = arcname[1:]
1082
1083 # Now, fill the TarInfo object with
1084 # information specific for the file.
1085 tarinfo = TarInfo()
1086
1087 # Use os.stat or os.lstat, depending on platform
1088 # and if symlinks shall be resolved.
1089 if fileobj is None:
1090 if hasattr(os, "lstat") and not self.dereference:
1091 statres = os.lstat(name)
1092 else:
1093 statres = os.stat(name)
1094 else:
1095 statres = os.fstat(fileobj.fileno())
1096 linkname = ""
1097
1098 stmd = statres.st_mode
1099 if stat.S_ISREG(stmd):
1100 inode = (statres.st_ino, statres.st_dev)
1101 if inode in self.inodes and not self.dereference:
1102 # Is it a hardlink to an already
1103 # archived file?
1104 type = LNKTYPE
1105 linkname = self.inodes[inode]
1106 else:
1107 # The inode is added only if its valid.
1108 # For win32 it is always 0.
1109 type = REGTYPE
1110 if inode[0]:
1111 self.inodes[inode] = arcname
1112 elif stat.S_ISDIR(stmd):
1113 type = DIRTYPE
1114 if arcname[-1:] != "/":
1115 arcname += "/"
1116 elif stat.S_ISFIFO(stmd):
1117 type = FIFOTYPE
1118 elif stat.S_ISLNK(stmd):
1119 type = SYMTYPE
1120 linkname = os.readlink(name)
1121 elif stat.S_ISCHR(stmd):
1122 type = CHRTYPE
1123 elif stat.S_ISBLK(stmd):
1124 type = BLKTYPE
1125 else:
1126 return None
1127
1128 # Fill the TarInfo object with all
1129 # information we can get.
1130 tarinfo.name = arcname
1131 tarinfo.mode = stmd
1132 tarinfo.uid = statres.st_uid
1133 tarinfo.gid = statres.st_gid
Martin v. Löwis61d77e02004-08-20 06:35:46 +00001134 if stat.S_ISDIR(stmd):
1135 # For a directory, the size must be 0
1136 tarinfo.size = 0
1137 else:
1138 tarinfo.size = statres.st_size
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001139 tarinfo.mtime = statres.st_mtime
1140 tarinfo.type = type
1141 tarinfo.linkname = linkname
1142 if pwd:
1143 try:
1144 tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0]
1145 except KeyError:
1146 pass
1147 if grp:
1148 try:
1149 tarinfo.gname = grp.getgrgid(tarinfo.gid)[0]
1150 except KeyError:
1151 pass
1152
1153 if type in (CHRTYPE, BLKTYPE):
1154 if hasattr(os, "major") and hasattr(os, "minor"):
1155 tarinfo.devmajor = os.major(statres.st_rdev)
1156 tarinfo.devminor = os.minor(statres.st_rdev)
1157 return tarinfo
1158
1159 def list(self, verbose=True):
1160 """Print a table of contents to sys.stdout. If `verbose' is False, only
1161 the names of the members are printed. If it is True, an `ls -l'-like
1162 output is produced.
1163 """
1164 self._check()
1165
1166 for tarinfo in self:
1167 if verbose:
1168 print filemode(tarinfo.mode),
1169 print "%s/%s" % (tarinfo.uname or tarinfo.uid,
1170 tarinfo.gname or tarinfo.gid),
1171 if tarinfo.ischr() or tarinfo.isblk():
1172 print "%10s" % ("%d,%d" \
1173 % (tarinfo.devmajor, tarinfo.devminor)),
1174 else:
1175 print "%10d" % tarinfo.size,
1176 print "%d-%02d-%02d %02d:%02d:%02d" \
1177 % time.localtime(tarinfo.mtime)[:6],
1178
1179 print tarinfo.name,
1180
1181 if verbose:
1182 if tarinfo.issym():
1183 print "->", tarinfo.linkname,
1184 if tarinfo.islnk():
1185 print "link to", tarinfo.linkname,
1186 print
1187
1188 def add(self, name, arcname=None, recursive=True):
1189 """Add the file `name' to the archive. `name' may be any type of file
1190 (directory, fifo, symbolic link, etc.). If given, `arcname'
1191 specifies an alternative name for the file in the archive.
1192 Directories are added recursively by default. This can be avoided by
1193 setting `recursive' to False.
1194 """
1195 self._check("aw")
1196
1197 if arcname is None:
1198 arcname = name
1199
1200 # Skip if somebody tries to archive the archive...
1201 if self.name is not None \
1202 and os.path.abspath(name) == os.path.abspath(self.name):
1203 self._dbg(2, "tarfile: Skipped %r" % name)
1204 return
1205
1206 # Special case: The user wants to add the current
1207 # working directory.
1208 if name == ".":
1209 if recursive:
1210 if arcname == ".":
1211 arcname = ""
1212 for f in os.listdir("."):
1213 self.add(f, os.path.join(arcname, f))
1214 return
1215
1216 self._dbg(1, name)
1217
1218 # Create a TarInfo object from the file.
1219 tarinfo = self.gettarinfo(name, arcname)
1220
1221 if tarinfo is None:
1222 self._dbg(1, "tarfile: Unsupported type %r" % name)
1223 return
1224
1225 # Append the tar header and data to the archive.
1226 if tarinfo.isreg():
1227 f = file(name, "rb")
1228 self.addfile(tarinfo, f)
1229 f.close()
1230
1231 if tarinfo.type in (LNKTYPE, SYMTYPE, FIFOTYPE, CHRTYPE, BLKTYPE):
1232 tarinfo.size = 0L
1233 self.addfile(tarinfo)
1234
1235 if tarinfo.isdir():
1236 self.addfile(tarinfo)
1237 if recursive:
1238 for f in os.listdir(name):
1239 self.add(os.path.join(name, f), os.path.join(arcname, f))
1240
1241 def addfile(self, tarinfo, fileobj=None):
1242 """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
1243 given, tarinfo.size bytes are read from it and added to the archive.
1244 You can create TarInfo objects using gettarinfo().
1245 On Windows platforms, `fileobj' should always be opened with mode
1246 'rb' to avoid irritation about the file size.
1247 """
1248 self._check("aw")
1249
1250 tarinfo.name = normpath(tarinfo.name)
1251 if tarinfo.isdir():
1252 # directories should end with '/'
1253 tarinfo.name += "/"
1254
1255 if tarinfo.linkname:
1256 tarinfo.linkname = normpath(tarinfo.linkname)
1257
1258 if tarinfo.size > MAXSIZE_MEMBER:
Neal Norwitzd96d1012004-07-20 22:23:02 +00001259 if self.posix:
1260 raise ValueError, "file is too large (>= 8 GB)"
1261 else:
1262 self._dbg(2, "tarfile: Created GNU tar largefile header")
1263
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001264
1265 if len(tarinfo.linkname) > LENGTH_LINK:
1266 if self.posix:
1267 raise ValueError, "linkname is too long (>%d)" \
1268 % (LENGTH_LINK)
1269 else:
1270 self._create_gnulong(tarinfo.linkname, GNUTYPE_LONGLINK)
1271 tarinfo.linkname = tarinfo.linkname[:LENGTH_LINK -1]
1272 self._dbg(2, "tarfile: Created GNU tar extension LONGLINK")
1273
1274 if len(tarinfo.name) > LENGTH_NAME:
1275 if self.posix:
1276 prefix = tarinfo.name[:LENGTH_PREFIX + 1]
1277 while prefix and prefix[-1] != "/":
Tim Peters2c60f7a2003-01-29 03:49:43 +00001278 prefix = prefix[:-1]
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001279
1280 name = tarinfo.name[len(prefix):]
1281 prefix = prefix[:-1]
1282
1283 if not prefix or len(name) > LENGTH_NAME:
1284 raise ValueError, "name is too long (>%d)" \
1285 % (LENGTH_NAME)
1286
1287 tarinfo.name = name
1288 tarinfo.prefix = prefix
1289 else:
1290 self._create_gnulong(tarinfo.name, GNUTYPE_LONGNAME)
1291 tarinfo.name = tarinfo.name[:LENGTH_NAME - 1]
1292 self._dbg(2, "tarfile: Created GNU tar extension LONGNAME")
1293
1294 self.fileobj.write(tarinfo.tobuf())
1295 self.offset += BLOCKSIZE
1296
1297 # If there's data to follow, append it.
1298 if fileobj is not None:
1299 copyfileobj(fileobj, self.fileobj, tarinfo.size)
1300 blocks, remainder = divmod(tarinfo.size, BLOCKSIZE)
1301 if remainder > 0:
1302 self.fileobj.write(NUL * (BLOCKSIZE - remainder))
1303 blocks += 1
1304 self.offset += blocks * BLOCKSIZE
1305
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001306 self.members.append(tarinfo)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001307
1308 def extract(self, member, path=""):
1309 """Extract a member from the archive to the current working directory,
1310 using its full name. Its file information is extracted as accurately
1311 as possible. `member' may be a filename or a TarInfo object. You can
1312 specify a different directory using `path'.
1313 """
1314 self._check("r")
1315
1316 if isinstance(member, TarInfo):
1317 tarinfo = member
1318 else:
1319 tarinfo = self.getmember(member)
1320
Neal Norwitza4f651a2004-07-20 22:07:44 +00001321 # Prepare the link target for makelink().
1322 if tarinfo.islnk():
1323 tarinfo._link_target = os.path.join(path, tarinfo.linkname)
1324
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001325 try:
1326 self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
1327 except EnvironmentError, e:
1328 if self.errorlevel > 0:
1329 raise
1330 else:
1331 if e.filename is None:
1332 self._dbg(1, "tarfile: %s" % e.strerror)
1333 else:
1334 self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename))
1335 except ExtractError, e:
1336 if self.errorlevel > 1:
1337 raise
1338 else:
1339 self._dbg(1, "tarfile: %s" % e)
1340
1341 def extractfile(self, member):
1342 """Extract a member from the archive as a file object. `member' may be
1343 a filename or a TarInfo object. If `member' is a regular file, a
1344 file-like object is returned. If `member' is a link, a file-like
1345 object is constructed from the link's target. If `member' is none of
1346 the above, None is returned.
1347 The file-like object is read-only and provides the following
1348 methods: read(), readline(), readlines(), seek() and tell()
1349 """
1350 self._check("r")
1351
1352 if isinstance(member, TarInfo):
1353 tarinfo = member
1354 else:
1355 tarinfo = self.getmember(member)
1356
1357 if tarinfo.isreg():
1358 return self.fileobject(self, tarinfo)
1359
1360 elif tarinfo.type not in SUPPORTED_TYPES:
1361 # If a member's type is unknown, it is treated as a
1362 # regular file.
1363 return self.fileobject(self, tarinfo)
1364
1365 elif tarinfo.islnk() or tarinfo.issym():
1366 if isinstance(self.fileobj, _Stream):
1367 # A small but ugly workaround for the case that someone tries
1368 # to extract a (sym)link as a file-object from a non-seekable
1369 # stream of tar blocks.
1370 raise StreamError, "cannot extract (sym)link as file object"
1371 else:
1372 # A (sym)link's file object is it's target's file object.
1373 return self.extractfile(self._getmember(tarinfo.linkname,
1374 tarinfo))
1375 else:
1376 # If there's no data associated with the member (directory, chrdev,
1377 # blkdev, etc.), return None instead of a file object.
1378 return None
1379
1380 def _extract_member(self, tarinfo, targetpath):
1381 """Extract the TarInfo object tarinfo to a physical
1382 file called targetpath.
1383 """
1384 # Fetch the TarInfo object for the given name
1385 # and build the destination pathname, replacing
1386 # forward slashes to platform specific separators.
1387 if targetpath[-1:] == "/":
1388 targetpath = targetpath[:-1]
1389 targetpath = os.path.normpath(targetpath)
1390
1391 # Create all upper directories.
1392 upperdirs = os.path.dirname(targetpath)
1393 if upperdirs and not os.path.exists(upperdirs):
1394 ti = TarInfo()
1395 ti.name = upperdirs
1396 ti.type = DIRTYPE
1397 ti.mode = 0777
1398 ti.mtime = tarinfo.mtime
1399 ti.uid = tarinfo.uid
1400 ti.gid = tarinfo.gid
1401 ti.uname = tarinfo.uname
1402 ti.gname = tarinfo.gname
1403 try:
1404 self._extract_member(ti, ti.name)
1405 except:
1406 pass
1407
1408 if tarinfo.islnk() or tarinfo.issym():
1409 self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname))
1410 else:
1411 self._dbg(1, tarinfo.name)
1412
1413 if tarinfo.isreg():
1414 self.makefile(tarinfo, targetpath)
1415 elif tarinfo.isdir():
1416 self.makedir(tarinfo, targetpath)
1417 elif tarinfo.isfifo():
1418 self.makefifo(tarinfo, targetpath)
1419 elif tarinfo.ischr() or tarinfo.isblk():
1420 self.makedev(tarinfo, targetpath)
1421 elif tarinfo.islnk() or tarinfo.issym():
1422 self.makelink(tarinfo, targetpath)
1423 elif tarinfo.type not in SUPPORTED_TYPES:
1424 self.makeunknown(tarinfo, targetpath)
1425 else:
1426 self.makefile(tarinfo, targetpath)
1427
1428 self.chown(tarinfo, targetpath)
1429 if not tarinfo.issym():
1430 self.chmod(tarinfo, targetpath)
1431 self.utime(tarinfo, targetpath)
1432
1433 #--------------------------------------------------------------------------
1434 # Below are the different file methods. They are called via
1435 # _extract_member() when extract() is called. They can be replaced in a
1436 # subclass to implement other functionality.
1437
1438 def makedir(self, tarinfo, targetpath):
1439 """Make a directory called targetpath.
1440 """
1441 try:
1442 os.mkdir(targetpath)
1443 except EnvironmentError, e:
1444 if e.errno != errno.EEXIST:
1445 raise
1446
1447 def makefile(self, tarinfo, targetpath):
1448 """Make a file called targetpath.
1449 """
1450 source = self.extractfile(tarinfo)
1451 target = file(targetpath, "wb")
1452 copyfileobj(source, target)
1453 source.close()
1454 target.close()
1455
1456 def makeunknown(self, tarinfo, targetpath):
1457 """Make a file from a TarInfo object with an unknown type
1458 at targetpath.
1459 """
1460 self.makefile(tarinfo, targetpath)
1461 self._dbg(1, "tarfile: Unknown file type %r, " \
1462 "extracted as regular file." % tarinfo.type)
1463
1464 def makefifo(self, tarinfo, targetpath):
1465 """Make a fifo called targetpath.
1466 """
1467 if hasattr(os, "mkfifo"):
1468 os.mkfifo(targetpath)
1469 else:
1470 raise ExtractError, "fifo not supported by system"
1471
1472 def makedev(self, tarinfo, targetpath):
1473 """Make a character or block device called targetpath.
1474 """
1475 if not hasattr(os, "mknod") or not hasattr(os, "makedev"):
1476 raise ExtractError, "special devices not supported by system"
1477
1478 mode = tarinfo.mode
1479 if tarinfo.isblk():
1480 mode |= stat.S_IFBLK
1481 else:
1482 mode |= stat.S_IFCHR
1483
1484 os.mknod(targetpath, mode,
1485 os.makedev(tarinfo.devmajor, tarinfo.devminor))
1486
1487 def makelink(self, tarinfo, targetpath):
1488 """Make a (symbolic) link called targetpath. If it cannot be created
1489 (platform limitation), we try to make a copy of the referenced file
1490 instead of a link.
1491 """
1492 linkpath = tarinfo.linkname
1493 try:
1494 if tarinfo.issym():
1495 os.symlink(linkpath, targetpath)
1496 else:
Neal Norwitza4f651a2004-07-20 22:07:44 +00001497 # See extract().
1498 os.link(tarinfo._link_target, targetpath)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001499 except AttributeError:
1500 if tarinfo.issym():
1501 linkpath = os.path.join(os.path.dirname(tarinfo.name),
1502 linkpath)
1503 linkpath = normpath(linkpath)
1504
1505 try:
1506 self._extract_member(self.getmember(linkpath), targetpath)
1507 except (EnvironmentError, KeyError), e:
1508 linkpath = os.path.normpath(linkpath)
1509 try:
1510 shutil.copy2(linkpath, targetpath)
1511 except EnvironmentError, e:
1512 raise IOError, "link could not be created"
1513
1514 def chown(self, tarinfo, targetpath):
1515 """Set owner of targetpath according to tarinfo.
1516 """
1517 if pwd and hasattr(os, "geteuid") and os.geteuid() == 0:
1518 # We have to be root to do so.
1519 try:
1520 g = grp.getgrnam(tarinfo.gname)[2]
1521 except KeyError:
1522 try:
1523 g = grp.getgrgid(tarinfo.gid)[2]
1524 except KeyError:
1525 g = os.getgid()
1526 try:
1527 u = pwd.getpwnam(tarinfo.uname)[2]
1528 except KeyError:
1529 try:
1530 u = pwd.getpwuid(tarinfo.uid)[2]
1531 except KeyError:
1532 u = os.getuid()
1533 try:
1534 if tarinfo.issym() and hasattr(os, "lchown"):
1535 os.lchown(targetpath, u, g)
1536 else:
Andrew MacIntyre7970d202003-02-19 12:51:34 +00001537 if sys.platform != "os2emx":
1538 os.chown(targetpath, u, g)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001539 except EnvironmentError, e:
1540 raise ExtractError, "could not change owner"
1541
1542 def chmod(self, tarinfo, targetpath):
1543 """Set file permissions of targetpath according to tarinfo.
1544 """
Jack Jansen834eff62003-03-07 12:47:06 +00001545 if hasattr(os, 'chmod'):
1546 try:
1547 os.chmod(targetpath, tarinfo.mode)
1548 except EnvironmentError, e:
1549 raise ExtractError, "could not change mode"
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001550
1551 def utime(self, tarinfo, targetpath):
1552 """Set modification time of targetpath according to tarinfo.
1553 """
Jack Jansen834eff62003-03-07 12:47:06 +00001554 if not hasattr(os, 'utime'):
Tim Petersf9347782003-03-07 15:36:41 +00001555 return
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001556 if sys.platform == "win32" and tarinfo.isdir():
1557 # According to msdn.microsoft.com, it is an error (EACCES)
1558 # to use utime() on directories.
1559 return
1560 try:
1561 os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime))
1562 except EnvironmentError, e:
1563 raise ExtractError, "could not change modification time"
1564
1565 #--------------------------------------------------------------------------
1566
1567 def next(self):
1568 """Return the next member of the archive as a TarInfo object, when
1569 TarFile is opened for reading. Return None if there is no more
1570 available.
1571 """
1572 self._check("ra")
1573 if self.firstmember is not None:
1574 m = self.firstmember
1575 self.firstmember = None
1576 return m
1577
1578 # Read the next block.
Andrew M. Kuchling864bba12004-07-10 22:02:11 +00001579 self.fileobj.seek(self.offset)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001580 while True:
1581 buf = self.fileobj.read(BLOCKSIZE)
1582 if not buf:
1583 return None
1584 try:
1585 tarinfo = TarInfo.frombuf(buf)
1586 except ValueError:
1587 if self.ignore_zeros:
1588 if buf.count(NUL) == BLOCKSIZE:
1589 adj = "empty"
1590 else:
1591 adj = "invalid"
1592 self._dbg(2, "0x%X: %s block" % (self.offset, adj))
1593 self.offset += BLOCKSIZE
1594 continue
1595 else:
1596 # Block is empty or unreadable.
Andrew M. Kuchling864bba12004-07-10 22:02:11 +00001597 if self.offset == 0:
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001598 # If the first block is invalid. That does not
1599 # look like a tar archive we can handle.
1600 raise ReadError,"empty, unreadable or compressed file"
1601 return None
1602 break
1603
1604 # We shouldn't rely on this checksum, because some tar programs
1605 # calculate it differently and it is merely validating the
1606 # header block. We could just as well skip this part, which would
1607 # have a slight effect on performance...
1608 if tarinfo.chksum != calc_chksum(buf):
1609 self._dbg(1, "tarfile: Bad Checksum %r" % tarinfo.name)
1610
1611 # Set the TarInfo object's offset to the current position of the
1612 # TarFile and set self.offset to the position where the data blocks
1613 # should begin.
1614 tarinfo.offset = self.offset
1615 self.offset += BLOCKSIZE
1616
1617 # Check if the TarInfo object has a typeflag for which a callback
1618 # method is registered in the TYPE_METH. If so, then call it.
1619 if tarinfo.type in self.TYPE_METH:
Andrew M. Kuchling864bba12004-07-10 22:02:11 +00001620 return self.TYPE_METH[tarinfo.type](self, tarinfo)
1621
1622 tarinfo.offset_data = self.offset
1623 if tarinfo.isreg() or tarinfo.type not in SUPPORTED_TYPES:
1624 # Skip the following data blocks.
1625 self.offset += self._block(tarinfo.size)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001626
1627 if tarinfo.isreg() and tarinfo.name[:-1] == "/":
1628 # some old tar programs don't know DIRTYPE
1629 tarinfo.type = DIRTYPE
1630
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001631 self.members.append(tarinfo)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001632 return tarinfo
1633
1634 #--------------------------------------------------------------------------
1635 # Below are some methods which are called for special typeflags in the
1636 # next() method, e.g. for unwrapping GNU longname/longlink blocks. They
1637 # are registered in TYPE_METH below. You can register your own methods
1638 # with this mapping.
1639 # A registered method is called with a TarInfo object as only argument.
1640 #
1641 # During its execution the method MUST perform the following tasks:
1642 # 1. set tarinfo.offset_data to the position where the data blocks begin,
1643 # if there is data to follow.
1644 # 2. set self.offset to the position where the next member's header will
1645 # begin.
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001646 # 3. append the tarinfo object to self.members, if it is supposed to appear
1647 # as a member of the TarFile object.
Andrew M. Kuchling864bba12004-07-10 22:02:11 +00001648 # 4. return tarinfo or another valid TarInfo object.
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001649
1650 def proc_gnulong(self, tarinfo):
1651 """Evaluate the blocks that hold a GNU longname
1652 or longlink member.
1653 """
1654 buf = ""
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001655 count = tarinfo.size
1656 while count > 0:
1657 block = self.fileobj.read(BLOCKSIZE)
1658 buf += block
1659 self.offset += BLOCKSIZE
1660 count -= BLOCKSIZE
1661
Andrew M. Kuchling864bba12004-07-10 22:02:11 +00001662 # Fetch the next header
1663 next = self.next()
1664
1665 next.offset = tarinfo.offset
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001666 if tarinfo.type == GNUTYPE_LONGNAME:
Andrew M. Kuchling864bba12004-07-10 22:02:11 +00001667 next.name = nts(buf)
1668 elif tarinfo.type == GNUTYPE_LONGLINK:
1669 next.linkname = nts(buf)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001670
Andrew M. Kuchling864bba12004-07-10 22:02:11 +00001671 return next
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001672
1673 def proc_sparse(self, tarinfo):
1674 """Analyze a GNU sparse header plus extra headers.
1675 """
1676 buf = tarinfo.tobuf()
1677 sp = _ringbuffer()
1678 pos = 386
1679 lastpos = 0L
1680 realpos = 0L
1681 # There are 4 possible sparse structs in the
1682 # first header.
1683 for i in xrange(4):
1684 try:
1685 offset = int(buf[pos:pos + 12], 8)
1686 numbytes = int(buf[pos + 12:pos + 24], 8)
1687 except ValueError:
1688 break
1689 if offset > lastpos:
1690 sp.append(_hole(lastpos, offset - lastpos))
1691 sp.append(_data(offset, numbytes, realpos))
1692 realpos += numbytes
1693 lastpos = offset + numbytes
1694 pos += 24
1695
1696 isextended = ord(buf[482])
1697 origsize = int(buf[483:495], 8)
1698
1699 # If the isextended flag is given,
1700 # there are extra headers to process.
1701 while isextended == 1:
1702 buf = self.fileobj.read(BLOCKSIZE)
1703 self.offset += BLOCKSIZE
1704 pos = 0
1705 for i in xrange(21):
1706 try:
1707 offset = int(buf[pos:pos + 12], 8)
1708 numbytes = int(buf[pos + 12:pos + 24], 8)
1709 except ValueError:
1710 break
1711 if offset > lastpos:
1712 sp.append(_hole(lastpos, offset - lastpos))
1713 sp.append(_data(offset, numbytes, realpos))
1714 realpos += numbytes
1715 lastpos = offset + numbytes
1716 pos += 24
1717 isextended = ord(buf[504])
1718
1719 if lastpos < origsize:
1720 sp.append(_hole(lastpos, origsize - lastpos))
1721
1722 tarinfo.sparse = sp
1723
1724 tarinfo.offset_data = self.offset
1725 self.offset += self._block(tarinfo.size)
1726 tarinfo.size = origsize
Andrew M. Kuchling864bba12004-07-10 22:02:11 +00001727
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001728 self.members.append(tarinfo)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001729 return tarinfo
1730
1731 # The type mapping for the next() method. The keys are single character
1732 # strings, the typeflag. The values are methods which are called when
1733 # next() encounters such a typeflag.
1734 TYPE_METH = {
1735 GNUTYPE_LONGNAME: proc_gnulong,
1736 GNUTYPE_LONGLINK: proc_gnulong,
1737 GNUTYPE_SPARSE: proc_sparse
1738 }
1739
1740 #--------------------------------------------------------------------------
1741 # Little helper methods:
1742
1743 def _block(self, count):
1744 """Round up a byte count by BLOCKSIZE and return it,
1745 e.g. _block(834) => 1024.
1746 """
1747 blocks, remainder = divmod(count, BLOCKSIZE)
1748 if remainder:
1749 blocks += 1
1750 return blocks * BLOCKSIZE
1751
1752 def _getmember(self, name, tarinfo=None):
1753 """Find an archive member by name from bottom to top.
1754 If tarinfo is given, it is used as the starting point.
1755 """
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001756 # Ensure that all members have been loaded.
1757 members = self.getmembers()
1758
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001759 if tarinfo is None:
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001760 end = len(members)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001761 else:
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001762 end = members.index(tarinfo)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001763
1764 for i in xrange(end - 1, -1, -1):
Martin v. Löwisf3c56112004-09-18 09:08:52 +00001765 if name == members[i].name:
1766 return members[i]
Andrew M. Kuchling864bba12004-07-10 22:02:11 +00001767
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001768 def _load(self):
1769 """Read through the entire archive file and look for readable
1770 members.
1771 """
1772 while True:
1773 tarinfo = self.next()
1774 if tarinfo is None:
1775 break
1776 self._loaded = True
1777
1778 def _check(self, mode=None):
1779 """Check if TarFile is still open, and if the operation's mode
1780 corresponds to TarFile's mode.
1781 """
1782 if self.closed:
1783 raise IOError, "%s is closed" % self.__class__.__name__
1784 if mode is not None and self._mode not in mode:
1785 raise IOError, "bad operation for mode %r" % self._mode
1786
1787 def __iter__(self):
1788 """Provide an iterator object.
1789 """
1790 if self._loaded:
1791 return iter(self.members)
1792 else:
1793 return TarIter(self)
1794
1795 def _create_gnulong(self, name, type):
1796 """Write a GNU longname/longlink member to the TarFile.
1797 It consists of an extended tar header, with the length
1798 of the longname as size, followed by data blocks,
1799 which contain the longname as a null terminated string.
1800 """
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001801 name += NUL
1802
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001803 tarinfo = TarInfo()
1804 tarinfo.name = "././@LongLink"
1805 tarinfo.type = type
1806 tarinfo.mode = 0
1807 tarinfo.size = len(name)
1808
1809 # write extended header
1810 self.fileobj.write(tarinfo.tobuf())
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001811 self.offset += BLOCKSIZE
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001812 # write name blocks
1813 self.fileobj.write(name)
1814 blocks, remainder = divmod(tarinfo.size, BLOCKSIZE)
1815 if remainder > 0:
1816 self.fileobj.write(NUL * (BLOCKSIZE - remainder))
1817 blocks += 1
1818 self.offset += blocks * BLOCKSIZE
1819
1820 def _dbg(self, level, msg):
1821 """Write debugging output to sys.stderr.
1822 """
1823 if level <= self.debug:
1824 print >> sys.stderr, msg
1825# class TarFile
1826
1827class TarIter:
1828 """Iterator Class.
1829
1830 for tarinfo in TarFile(...):
1831 suite...
1832 """
1833
1834 def __init__(self, tarfile):
1835 """Construct a TarIter object.
1836 """
1837 self.tarfile = tarfile
1838 def __iter__(self):
1839 """Return iterator object.
1840 """
1841 return self
1842 def next(self):
1843 """Return the next item using TarFile's next() method.
1844 When all members have been read, set TarFile as _loaded.
1845 """
1846 tarinfo = self.tarfile.next()
1847 if not tarinfo:
1848 self.tarfile._loaded = True
1849 raise StopIteration
1850 return tarinfo
1851
1852# Helper classes for sparse file support
1853class _section:
1854 """Base class for _data and _hole.
1855 """
1856 def __init__(self, offset, size):
1857 self.offset = offset
1858 self.size = size
1859 def __contains__(self, offset):
1860 return self.offset <= offset < self.offset + self.size
1861
1862class _data(_section):
1863 """Represent a data section in a sparse file.
1864 """
1865 def __init__(self, offset, size, realpos):
1866 _section.__init__(self, offset, size)
1867 self.realpos = realpos
1868
1869class _hole(_section):
1870 """Represent a hole section in a sparse file.
1871 """
1872 pass
1873
1874class _ringbuffer(list):
1875 """Ringbuffer class which increases performance
1876 over a regular list.
1877 """
1878 def __init__(self):
1879 self.idx = 0
1880 def find(self, offset):
1881 idx = self.idx
1882 while True:
1883 item = self[idx]
1884 if offset in item:
1885 break
1886 idx += 1
1887 if idx == len(self):
1888 idx = 0
1889 if idx == self.idx:
1890 # End of File
1891 return None
1892 self.idx = idx
1893 return item
1894
1895#---------------------------------------------
1896# zipfile compatible TarFile class
1897#---------------------------------------------
1898TAR_PLAIN = 0 # zipfile.ZIP_STORED
1899TAR_GZIPPED = 8 # zipfile.ZIP_DEFLATED
1900class TarFileCompat:
1901 """TarFile class compatible with standard module zipfile's
1902 ZipFile class.
1903 """
1904 def __init__(self, file, mode="r", compression=TAR_PLAIN):
1905 if compression == TAR_PLAIN:
1906 self.tarfile = TarFile.taropen(file, mode)
1907 elif compression == TAR_GZIPPED:
1908 self.tarfile = TarFile.gzopen(file, mode)
1909 else:
1910 raise ValueError, "unknown compression constant"
1911 if mode[0:1] == "r":
1912 members = self.tarfile.getmembers()
1913 for i in xrange(len(members)):
1914 m = members[i]
1915 m.filename = m.name
1916 m.file_size = m.size
1917 m.date_time = time.gmtime(m.mtime)[:6]
1918 def namelist(self):
1919 return map(lambda m: m.name, self.infolist())
1920 def infolist(self):
1921 return filter(lambda m: m.type in REGULAR_TYPES,
1922 self.tarfile.getmembers())
1923 def printdir(self):
1924 self.tarfile.list()
1925 def testzip(self):
1926 return
1927 def getinfo(self, name):
1928 return self.tarfile.getmember(name)
1929 def read(self, name):
1930 return self.tarfile.extractfile(self.tarfile.getmember(name)).read()
1931 def write(self, filename, arcname=None, compress_type=None):
1932 self.tarfile.add(filename, arcname)
1933 def writestr(self, zinfo, bytes):
Raymond Hettingera6172712004-12-31 19:15:26 +00001934 try:
1935 from cStringIO import StringIO
1936 except ImportError:
1937 from StringIO import StringIO
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001938 import calendar
1939 zinfo.name = zinfo.filename
1940 zinfo.size = zinfo.file_size
1941 zinfo.mtime = calendar.timegm(zinfo.date_time)
Raymond Hettingera6172712004-12-31 19:15:26 +00001942 self.tarfile.addfile(zinfo, StringIO(bytes))
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001943 def close(self):
1944 self.tarfile.close()
1945#class TarFileCompat
1946
1947#--------------------
1948# exported functions
1949#--------------------
1950def is_tarfile(name):
1951 """Return True if name points to a tar archive that we
1952 are able to handle, else return False.
1953 """
1954 try:
1955 t = open(name)
1956 t.close()
1957 return True
1958 except TarError:
1959 return False
1960
1961open = TarFile.open