]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/python/tarfile.py
update colemak kbmap, simpler version with scroll working (thanks jeremy)
[plan9front.git] / sys / lib / python / tarfile.py
1 #!/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: 53162 $"
34 # $Source$
35
36 version     = "0.8.0"
37 __author__  = "Lars Gustäbel (lars@gustaebel.de)"
38 __date__    = "$Date: 2006-12-27 21:36:58 +1100 (Wed, 27 Dec 2006) $"
39 __cvsid__   = "$Id: tarfile.py 53162 2006-12-27 10:36:58Z lars.gustaebel $"
40 __credits__ = "Gustavo Niemeyer, Niels Gustäbel, Richard Townsend."
41
42 #---------
43 # Imports
44 #---------
45 import sys
46 import os
47 import shutil
48 import stat
49 import errno
50 import time
51 import struct
52 import copy
53
54 if sys.platform == 'mac':
55     # This module needs work for MacOS9, especially in the area of pathname
56     # handling. In many places it is assumed a simple substitution of / by the
57     # local os.path.sep is good enough to convert pathnames, but this does not
58     # work with the mac rooted:path:name versus :nonrooted:path:name syntax
59     raise ImportError, "tarfile does not work for platform==mac"
60
61 try:
62     import grp, pwd
63 except ImportError:
64     grp = pwd = None
65
66 # from tarfile import *
67 __all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError"]
68
69 #---------------------------------------------------------
70 # tar constants
71 #---------------------------------------------------------
72 NUL        = "\0"               # the null character
73 BLOCKSIZE  = 512                # length of processing blocks
74 RECORDSIZE = BLOCKSIZE * 20     # length of records
75 MAGIC      = "ustar"            # magic tar string
76 VERSION    = "00"               # version number
77
78 LENGTH_NAME    = 100            # maximum length of a filename
79 LENGTH_LINK    = 100            # maximum length of a linkname
80 LENGTH_PREFIX  = 155            # maximum length of the prefix field
81 MAXSIZE_MEMBER = 077777777777L  # maximum size of a file (11 octal digits)
82
83 REGTYPE  = "0"                  # regular file
84 AREGTYPE = "\0"                 # regular file
85 LNKTYPE  = "1"                  # link (inside tarfile)
86 SYMTYPE  = "2"                  # symbolic link
87 CHRTYPE  = "3"                  # character special device
88 BLKTYPE  = "4"                  # block special device
89 DIRTYPE  = "5"                  # directory
90 FIFOTYPE = "6"                  # fifo special device
91 CONTTYPE = "7"                  # contiguous file
92
93 GNUTYPE_LONGNAME = "L"          # GNU tar extension for longnames
94 GNUTYPE_LONGLINK = "K"          # GNU tar extension for longlink
95 GNUTYPE_SPARSE   = "S"          # GNU tar extension for sparse file
96
97 #---------------------------------------------------------
98 # tarfile constants
99 #---------------------------------------------------------
100 SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE,  # file types that tarfile
101                    SYMTYPE, DIRTYPE, FIFOTYPE,  # can cope with.
102                    CONTTYPE, CHRTYPE, BLKTYPE,
103                    GNUTYPE_LONGNAME, GNUTYPE_LONGLINK,
104                    GNUTYPE_SPARSE)
105
106 REGULAR_TYPES = (REGTYPE, AREGTYPE,             # file types that somehow
107                  CONTTYPE, GNUTYPE_SPARSE)      # represent regular files
108
109 #---------------------------------------------------------
110 # Bits used in the mode field, values in octal.
111 #---------------------------------------------------------
112 S_IFLNK = 0120000        # symbolic link
113 S_IFREG = 0100000        # regular file
114 S_IFBLK = 0060000        # block device
115 S_IFDIR = 0040000        # directory
116 S_IFCHR = 0020000        # character device
117 S_IFIFO = 0010000        # fifo
118
119 TSUID   = 04000          # set UID on execution
120 TSGID   = 02000          # set GID on execution
121 TSVTX   = 01000          # reserved
122
123 TUREAD  = 0400           # read by owner
124 TUWRITE = 0200           # write by owner
125 TUEXEC  = 0100           # execute/search by owner
126 TGREAD  = 0040           # read by group
127 TGWRITE = 0020           # write by group
128 TGEXEC  = 0010           # execute/search by group
129 TOREAD  = 0004           # read by other
130 TOWRITE = 0002           # write by other
131 TOEXEC  = 0001           # execute/search by other
132
133 #---------------------------------------------------------
134 # Some useful functions
135 #---------------------------------------------------------
136
137 def stn(s, length):
138     """Convert a python string to a null-terminated string buffer.
139     """
140     return s[:length] + (length - len(s)) * NUL
141
142 def nti(s):
143     """Convert a number field to a python number.
144     """
145     # There are two possible encodings for a number field, see
146     # itn() below.
147     if s[0] != chr(0200):
148         n = int(s.rstrip(NUL + " ") or "0", 8)
149     else:
150         n = 0L
151         for i in xrange(len(s) - 1):
152             n <<= 8
153             n += ord(s[i + 1])
154     return n
155
156 def itn(n, digits=8, posix=False):
157     """Convert a python number to a number field.
158     """
159     # POSIX 1003.1-1988 requires numbers to be encoded as a string of
160     # octal digits followed by a null-byte, this allows values up to
161     # (8**(digits-1))-1. GNU tar allows storing numbers greater than
162     # that if necessary. A leading 0200 byte indicates this particular
163     # encoding, the following digits-1 bytes are a big-endian
164     # representation. This allows values up to (256**(digits-1))-1.
165     if 0 <= n < 8 ** (digits - 1):
166         s = "%0*o" % (digits - 1, n) + NUL
167     else:
168         if posix:
169             raise ValueError("overflow in number field")
170
171         if n < 0:
172             # XXX We mimic GNU tar's behaviour with negative numbers,
173             # this could raise OverflowError.
174             n = struct.unpack("L", struct.pack("l", n))[0]
175
176         s = ""
177         for i in xrange(digits - 1):
178             s = chr(n & 0377) + s
179             n >>= 8
180         s = chr(0200) + s
181     return s
182
183 def calc_chksums(buf):
184     """Calculate the checksum for a member's header by summing up all
185        characters except for the chksum field which is treated as if
186        it was filled with spaces. According to the GNU tar sources,
187        some tars (Sun and NeXT) calculate chksum with signed char,
188        which will be different if there are chars in the buffer with
189        the high bit set. So we calculate two checksums, unsigned and
190        signed.
191     """
192     unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512]))
193     signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512]))
194     return unsigned_chksum, signed_chksum
195
196 def copyfileobj(src, dst, length=None):
197     """Copy length bytes from fileobj src to fileobj dst.
198        If length is None, copy the entire content.
199     """
200     if length == 0:
201         return
202     if length is None:
203         shutil.copyfileobj(src, dst)
204         return
205
206     BUFSIZE = 16 * 1024
207     blocks, remainder = divmod(length, BUFSIZE)
208     for b in xrange(blocks):
209         buf = src.read(BUFSIZE)
210         if len(buf) < BUFSIZE:
211             raise IOError("end of file reached")
212         dst.write(buf)
213
214     if remainder != 0:
215         buf = src.read(remainder)
216         if len(buf) < remainder:
217             raise IOError("end of file reached")
218         dst.write(buf)
219     return
220
221 filemode_table = (
222     ((S_IFLNK,      "l"),
223      (S_IFREG,      "-"),
224      (S_IFBLK,      "b"),
225      (S_IFDIR,      "d"),
226      (S_IFCHR,      "c"),
227      (S_IFIFO,      "p")),
228
229     ((TUREAD,       "r"),),
230     ((TUWRITE,      "w"),),
231     ((TUEXEC|TSUID, "s"),
232      (TSUID,        "S"),
233      (TUEXEC,       "x")),
234
235     ((TGREAD,       "r"),),
236     ((TGWRITE,      "w"),),
237     ((TGEXEC|TSGID, "s"),
238      (TSGID,        "S"),
239      (TGEXEC,       "x")),
240
241     ((TOREAD,       "r"),),
242     ((TOWRITE,      "w"),),
243     ((TOEXEC|TSVTX, "t"),
244      (TSVTX,        "T"),
245      (TOEXEC,       "x"))
246 )
247
248 def filemode(mode):
249     """Convert a file's mode to a string of the form
250        -rwxrwxrwx.
251        Used by TarFile.list()
252     """
253     perm = []
254     for table in filemode_table:
255         for bit, char in table:
256             if mode & bit == bit:
257                 perm.append(char)
258                 break
259         else:
260             perm.append("-")
261     return "".join(perm)
262
263 if os.sep != "/":
264     normpath = lambda path: os.path.normpath(path).replace(os.sep, "/")
265 else:
266     normpath = os.path.normpath
267
268 class TarError(Exception):
269     """Base exception."""
270     pass
271 class ExtractError(TarError):
272     """General exception for extract errors."""
273     pass
274 class ReadError(TarError):
275     """Exception for unreadble tar archives."""
276     pass
277 class CompressionError(TarError):
278     """Exception for unavailable compression methods."""
279     pass
280 class StreamError(TarError):
281     """Exception for unsupported operations on stream-like TarFiles."""
282     pass
283
284 #---------------------------
285 # internal stream interface
286 #---------------------------
287 class _LowLevelFile:
288     """Low-level file object. Supports reading and writing.
289        It is used instead of a regular file object for streaming
290        access.
291     """
292
293     def __init__(self, name, mode):
294         mode = {
295             "r": os.O_RDONLY,
296             "w": os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
297         }[mode]
298         if hasattr(os, "O_BINARY"):
299             mode |= os.O_BINARY
300         self.fd = os.open(name, mode)
301
302     def close(self):
303         os.close(self.fd)
304
305     def read(self, size):
306         return os.read(self.fd, size)
307
308     def write(self, s):
309         os.write(self.fd, s)
310
311 class _Stream:
312     """Class that serves as an adapter between TarFile and
313        a stream-like object.  The stream-like object only
314        needs to have a read() or write() method and is accessed
315        blockwise.  Use of gzip or bzip2 compression is possible.
316        A stream-like object could be for example: sys.stdin,
317        sys.stdout, a socket, a tape device etc.
318
319        _Stream is intended to be used only internally.
320     """
321
322     def __init__(self, name, mode, comptype, fileobj, bufsize):
323         """Construct a _Stream object.
324         """
325         self._extfileobj = True
326         if fileobj is None:
327             fileobj = _LowLevelFile(name, mode)
328             self._extfileobj = False
329
330         if comptype == '*':
331             # Enable transparent compression detection for the
332             # stream interface
333             fileobj = _StreamProxy(fileobj)
334             comptype = fileobj.getcomptype()
335
336         self.name     = name or ""
337         self.mode     = mode
338         self.comptype = comptype
339         self.fileobj  = fileobj
340         self.bufsize  = bufsize
341         self.buf      = ""
342         self.pos      = 0L
343         self.closed   = False
344
345         if comptype == "gz":
346             try:
347                 import zlib
348             except ImportError:
349                 raise CompressionError("zlib module is not available")
350             self.zlib = zlib
351             self.crc = zlib.crc32("")
352             if mode == "r":
353                 self._init_read_gz()
354             else:
355                 self._init_write_gz()
356
357         if comptype == "bz2":
358             try:
359                 import bz2
360             except ImportError:
361                 raise CompressionError("bz2 module is not available")
362             if mode == "r":
363                 self.dbuf = ""
364                 self.cmp = bz2.BZ2Decompressor()
365             else:
366                 self.cmp = bz2.BZ2Compressor()
367
368     def __del__(self):
369         if hasattr(self, "closed") and not self.closed:
370             self.close()
371
372     def _init_write_gz(self):
373         """Initialize for writing with gzip compression.
374         """
375         self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED,
376                                             -self.zlib.MAX_WBITS,
377                                             self.zlib.DEF_MEM_LEVEL,
378                                             0)
379         timestamp = struct.pack("<L", long(time.time()))
380         self.__write("\037\213\010\010%s\002\377" % timestamp)
381         if self.name.endswith(".gz"):
382             self.name = self.name[:-3]
383         self.__write(self.name + NUL)
384
385     def write(self, s):
386         """Write string s to the stream.
387         """
388         if self.comptype == "gz":
389             self.crc = self.zlib.crc32(s, self.crc)
390         self.pos += len(s)
391         if self.comptype != "tar":
392             s = self.cmp.compress(s)
393         self.__write(s)
394
395     def __write(self, s):
396         """Write string s to the stream if a whole new block
397            is ready to be written.
398         """
399         self.buf += s
400         while len(self.buf) > self.bufsize:
401             self.fileobj.write(self.buf[:self.bufsize])
402             self.buf = self.buf[self.bufsize:]
403
404     def close(self):
405         """Close the _Stream object. No operation should be
406            done on it afterwards.
407         """
408         if self.closed:
409             return
410
411         if self.mode == "w" and self.comptype != "tar":
412             self.buf += self.cmp.flush()
413
414         if self.mode == "w" and self.buf:
415             self.fileobj.write(self.buf)
416             self.buf = ""
417             if self.comptype == "gz":
418                 # The native zlib crc is an unsigned 32-bit integer, but
419                 # the Python wrapper implicitly casts that to a signed C
420                 # long.  So, on a 32-bit box self.crc may "look negative",
421                 # while the same crc on a 64-bit box may "look positive".
422                 # To avoid irksome warnings from the `struct` module, force
423                 # it to look positive on all boxes.
424                 self.fileobj.write(struct.pack("<L", self.crc & 0xffffffffL))
425                 self.fileobj.write(struct.pack("<L", self.pos & 0xffffFFFFL))
426
427         if not self._extfileobj:
428             self.fileobj.close()
429
430         self.closed = True
431
432     def _init_read_gz(self):
433         """Initialize for reading a gzip compressed fileobj.
434         """
435         self.cmp = self.zlib.decompressobj(-self.zlib.MAX_WBITS)
436         self.dbuf = ""
437
438         # taken from gzip.GzipFile with some alterations
439         if self.__read(2) != "\037\213":
440             raise ReadError("not a gzip file")
441         if self.__read(1) != "\010":
442             raise CompressionError("unsupported compression method")
443
444         flag = ord(self.__read(1))
445         self.__read(6)
446
447         if flag & 4:
448             xlen = ord(self.__read(1)) + 256 * ord(self.__read(1))
449             self.read(xlen)
450         if flag & 8:
451             while True:
452                 s = self.__read(1)
453                 if not s or s == NUL:
454                     break
455         if flag & 16:
456             while True:
457                 s = self.__read(1)
458                 if not s or s == NUL:
459                     break
460         if flag & 2:
461             self.__read(2)
462
463     def tell(self):
464         """Return the stream's file pointer position.
465         """
466         return self.pos
467
468     def seek(self, pos=0):
469         """Set the stream's file pointer to pos. Negative seeking
470            is forbidden.
471         """
472         if pos - self.pos >= 0:
473             blocks, remainder = divmod(pos - self.pos, self.bufsize)
474             for i in xrange(blocks):
475                 self.read(self.bufsize)
476             self.read(remainder)
477         else:
478             raise StreamError("seeking backwards is not allowed")
479         return self.pos
480
481     def read(self, size=None):
482         """Return the next size number of bytes from the stream.
483            If size is not defined, return all bytes of the stream
484            up to EOF.
485         """
486         if size is None:
487             t = []
488             while True:
489                 buf = self._read(self.bufsize)
490                 if not buf:
491                     break
492                 t.append(buf)
493             buf = "".join(t)
494         else:
495             buf = self._read(size)
496         self.pos += len(buf)
497         return buf
498
499     def _read(self, size):
500         """Return size bytes from the stream.
501         """
502         if self.comptype == "tar":
503             return self.__read(size)
504
505         c = len(self.dbuf)
506         t = [self.dbuf]
507         while c < size:
508             buf = self.__read(self.bufsize)
509             if not buf:
510                 break
511             buf = self.cmp.decompress(buf)
512             t.append(buf)
513             c += len(buf)
514         t = "".join(t)
515         self.dbuf = t[size:]
516         return t[:size]
517
518     def __read(self, size):
519         """Return size bytes from stream. If internal buffer is empty,
520            read another block from the stream.
521         """
522         c = len(self.buf)
523         t = [self.buf]
524         while c < size:
525             buf = self.fileobj.read(self.bufsize)
526             if not buf:
527                 break
528             t.append(buf)
529             c += len(buf)
530         t = "".join(t)
531         self.buf = t[size:]
532         return t[:size]
533 # class _Stream
534
535 class _StreamProxy(object):
536     """Small proxy class that enables transparent compression
537        detection for the Stream interface (mode 'r|*').
538     """
539
540     def __init__(self, fileobj):
541         self.fileobj = fileobj
542         self.buf = self.fileobj.read(BLOCKSIZE)
543
544     def read(self, size):
545         self.read = self.fileobj.read
546         return self.buf
547
548     def getcomptype(self):
549         if self.buf.startswith("\037\213\010"):
550             return "gz"
551         if self.buf.startswith("BZh91"):
552             return "bz2"
553         return "tar"
554
555     def close(self):
556         self.fileobj.close()
557 # class StreamProxy
558
559 class _BZ2Proxy(object):
560     """Small proxy class that enables external file object
561        support for "r:bz2" and "w:bz2" modes. This is actually
562        a workaround for a limitation in bz2 module's BZ2File
563        class which (unlike gzip.GzipFile) has no support for
564        a file object argument.
565     """
566
567     blocksize = 16 * 1024
568
569     def __init__(self, fileobj, mode):
570         self.fileobj = fileobj
571         self.mode = mode
572         self.init()
573
574     def init(self):
575         import bz2
576         self.pos = 0
577         if self.mode == "r":
578             self.bz2obj = bz2.BZ2Decompressor()
579             self.fileobj.seek(0)
580             self.buf = ""
581         else:
582             self.bz2obj = bz2.BZ2Compressor()
583
584     def read(self, size):
585         b = [self.buf]
586         x = len(self.buf)
587         while x < size:
588             try:
589                 raw = self.fileobj.read(self.blocksize)
590                 data = self.bz2obj.decompress(raw)
591                 b.append(data)
592             except EOFError:
593                 break
594             x += len(data)
595         self.buf = "".join(b)
596
597         buf = self.buf[:size]
598         self.buf = self.buf[size:]
599         self.pos += len(buf)
600         return buf
601
602     def seek(self, pos):
603         if pos < self.pos:
604             self.init()
605         self.read(pos - self.pos)
606
607     def tell(self):
608         return self.pos
609
610     def write(self, data):
611         self.pos += len(data)
612         raw = self.bz2obj.compress(data)
613         self.fileobj.write(raw)
614
615     def close(self):
616         if self.mode == "w":
617             raw = self.bz2obj.flush()
618             self.fileobj.write(raw)
619         self.fileobj.close()
620 # class _BZ2Proxy
621
622 #------------------------
623 # Extraction file object
624 #------------------------
625 class _FileInFile(object):
626     """A thin wrapper around an existing file object that
627        provides a part of its data as an individual file
628        object.
629     """
630
631     def __init__(self, fileobj, offset, size, sparse=None):
632         self.fileobj = fileobj
633         self.offset = offset
634         self.size = size
635         self.sparse = sparse
636         self.position = 0
637
638     def tell(self):
639         """Return the current file position.
640         """
641         return self.position
642
643     def seek(self, position):
644         """Seek to a position in the file.
645         """
646         self.position = position
647
648     def read(self, size=None):
649         """Read data from the file.
650         """
651         if size is None:
652             size = self.size - self.position
653         else:
654             size = min(size, self.size - self.position)
655
656         if self.sparse is None:
657             return self.readnormal(size)
658         else:
659             return self.readsparse(size)
660
661     def readnormal(self, size):
662         """Read operation for regular files.
663         """
664         self.fileobj.seek(self.offset + self.position)
665         self.position += size
666         return self.fileobj.read(size)
667
668     def readsparse(self, size):
669         """Read operation for sparse files.
670         """
671         data = []
672         while size > 0:
673             buf = self.readsparsesection(size)
674             if not buf:
675                 break
676             size -= len(buf)
677             data.append(buf)
678         return "".join(data)
679
680     def readsparsesection(self, size):
681         """Read a single section of a sparse file.
682         """
683         section = self.sparse.find(self.position)
684
685         if section is None:
686             return ""
687
688         size = min(size, section.offset + section.size - self.position)
689
690         if isinstance(section, _data):
691             realpos = section.realpos + self.position - section.offset
692             self.fileobj.seek(self.offset + realpos)
693             self.position += size
694             return self.fileobj.read(size)
695         else:
696             self.position += size
697             return NUL * size
698 #class _FileInFile
699
700
701 class ExFileObject(object):
702     """File-like object for reading an archive member.
703        Is returned by TarFile.extractfile().
704     """
705     blocksize = 1024
706
707     def __init__(self, tarfile, tarinfo):
708         self.fileobj = _FileInFile(tarfile.fileobj,
709                                    tarinfo.offset_data,
710                                    tarinfo.size,
711                                    getattr(tarinfo, "sparse", None))
712         self.name = tarinfo.name
713         self.mode = "r"
714         self.closed = False
715         self.size = tarinfo.size
716
717         self.position = 0
718         self.buffer = ""
719
720     def read(self, size=None):
721         """Read at most size bytes from the file. If size is not
722            present or None, read all data until EOF is reached.
723         """
724         if self.closed:
725             raise ValueError("I/O operation on closed file")
726
727         buf = ""
728         if self.buffer:
729             if size is None:
730                 buf = self.buffer
731                 self.buffer = ""
732             else:
733                 buf = self.buffer[:size]
734                 self.buffer = self.buffer[size:]
735
736         if size is None:
737             buf += self.fileobj.read()
738         else:
739             buf += self.fileobj.read(size - len(buf))
740
741         self.position += len(buf)
742         return buf
743
744     def readline(self, size=-1):
745         """Read one entire line from the file. If size is present
746            and non-negative, return a string with at most that
747            size, which may be an incomplete line.
748         """
749         if self.closed:
750             raise ValueError("I/O operation on closed file")
751
752         if "\n" in self.buffer:
753             pos = self.buffer.find("\n") + 1
754         else:
755             buffers = [self.buffer]
756             while True:
757                 buf = self.fileobj.read(self.blocksize)
758                 buffers.append(buf)
759                 if not buf or "\n" in buf:
760                     self.buffer = "".join(buffers)
761                     pos = self.buffer.find("\n") + 1
762                     if pos == 0:
763                         # no newline found.
764                         pos = len(self.buffer)
765                     break
766
767         if size != -1:
768             pos = min(size, pos)
769
770         buf = self.buffer[:pos]
771         self.buffer = self.buffer[pos:]
772         self.position += len(buf)
773         return buf
774
775     def readlines(self):
776         """Return a list with all remaining lines.
777         """
778         result = []
779         while True:
780             line = self.readline()
781             if not line: break
782             result.append(line)
783         return result
784
785     def tell(self):
786         """Return the current file position.
787         """
788         if self.closed:
789             raise ValueError("I/O operation on closed file")
790
791         return self.position
792
793     def seek(self, pos, whence=os.SEEK_SET):
794         """Seek to a position in the file.
795         """
796         if self.closed:
797             raise ValueError("I/O operation on closed file")
798
799         if whence == os.SEEK_SET:
800             self.position = min(max(pos, 0), self.size)
801         elif whence == os.SEEK_CUR:
802             if pos < 0:
803                 self.position = max(self.position + pos, 0)
804             else:
805                 self.position = min(self.position + pos, self.size)
806         elif whence == os.SEEK_END:
807             self.position = max(min(self.size + pos, self.size), 0)
808         else:
809             raise ValueError("Invalid argument")
810
811         self.buffer = ""
812         self.fileobj.seek(self.position)
813
814     def close(self):
815         """Close the file object.
816         """
817         self.closed = True
818
819     def __iter__(self):
820         """Get an iterator over the file's lines.
821         """
822         while True:
823             line = self.readline()
824             if not line:
825                 break
826             yield line
827 #class ExFileObject
828
829 #------------------
830 # Exported Classes
831 #------------------
832 class TarInfo(object):
833     """Informational class which holds the details about an
834        archive member given by a tar header block.
835        TarInfo objects are returned by TarFile.getmember(),
836        TarFile.getmembers() and TarFile.gettarinfo() and are
837        usually created internally.
838     """
839
840     def __init__(self, name=""):
841         """Construct a TarInfo object. name is the optional name
842            of the member.
843         """
844         self.name = name        # member name (dirnames must end with '/')
845         self.mode = 0666        # file permissions
846         self.uid = 0            # user id
847         self.gid = 0            # group id
848         self.size = 0           # file size
849         self.mtime = 0          # modification time
850         self.chksum = 0         # header checksum
851         self.type = REGTYPE     # member type
852         self.linkname = ""      # link name
853         self.uname = "user"     # user name
854         self.gname = "group"    # group name
855         self.devmajor = 0       # device major number
856         self.devminor = 0       # device minor number
857
858         self.offset = 0         # the tar header starts here
859         self.offset_data = 0    # the file's data starts here
860
861     def __repr__(self):
862         return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self))
863
864     @classmethod
865     def frombuf(cls, buf):
866         """Construct a TarInfo object from a 512 byte string buffer.
867         """
868         if len(buf) != BLOCKSIZE:
869             raise ValueError("truncated header")
870         if buf.count(NUL) == BLOCKSIZE:
871             raise ValueError("empty header")
872
873         tarinfo = cls()
874         tarinfo.buf = buf
875         tarinfo.name = buf[0:100].rstrip(NUL)
876         tarinfo.mode = nti(buf[100:108])
877         tarinfo.uid = nti(buf[108:116])
878         tarinfo.gid = nti(buf[116:124])
879         tarinfo.size = nti(buf[124:136])
880         tarinfo.mtime = nti(buf[136:148])
881         tarinfo.chksum = nti(buf[148:156])
882         tarinfo.type = buf[156:157]
883         tarinfo.linkname = buf[157:257].rstrip(NUL)
884         tarinfo.uname = buf[265:297].rstrip(NUL)
885         tarinfo.gname = buf[297:329].rstrip(NUL)
886         tarinfo.devmajor = nti(buf[329:337])
887         tarinfo.devminor = nti(buf[337:345])
888         prefix = buf[345:500].rstrip(NUL)
889
890         if prefix and not tarinfo.issparse():
891             tarinfo.name = prefix + "/" + tarinfo.name
892
893         if tarinfo.chksum not in calc_chksums(buf):
894             raise ValueError("invalid header")
895         return tarinfo
896
897     def tobuf(self, posix=False):
898         """Return a tar header as a string of 512 byte blocks.
899         """
900         buf = ""
901         type = self.type
902         prefix = ""
903
904         if self.name.endswith("/"):
905             type = DIRTYPE
906
907         if type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK):
908             # Prevent "././@LongLink" from being normalized.
909             name = self.name
910         else:
911             name = normpath(self.name)
912
913         if type == DIRTYPE:
914             # directories should end with '/'
915             name += "/"
916
917         linkname = self.linkname
918         if linkname:
919             # if linkname is empty we end up with a '.'
920             linkname = normpath(linkname)
921
922         if posix:
923             if self.size > MAXSIZE_MEMBER:
924                 raise ValueError("file is too large (>= 8 GB)")
925
926             if len(self.linkname) > LENGTH_LINK:
927                 raise ValueError("linkname is too long (>%d)" % (LENGTH_LINK))
928
929             if len(name) > LENGTH_NAME:
930                 prefix = name[:LENGTH_PREFIX + 1]
931                 while prefix and prefix[-1] != "/":
932                     prefix = prefix[:-1]
933
934                 name = name[len(prefix):]
935                 prefix = prefix[:-1]
936
937                 if not prefix or len(name) > LENGTH_NAME:
938                     raise ValueError("name is too long")
939
940         else:
941             if len(self.linkname) > LENGTH_LINK:
942                 buf += self._create_gnulong(self.linkname, GNUTYPE_LONGLINK)
943
944             if len(name) > LENGTH_NAME:
945                 buf += self._create_gnulong(name, GNUTYPE_LONGNAME)
946
947         parts = [
948             stn(name, 100),
949             itn(self.mode & 07777, 8, posix),
950             itn(self.uid, 8, posix),
951             itn(self.gid, 8, posix),
952             itn(self.size, 12, posix),
953             itn(self.mtime, 12, posix),
954             "        ", # checksum field
955             type,
956             stn(self.linkname, 100),
957             stn(MAGIC, 6),
958             stn(VERSION, 2),
959             stn(self.uname, 32),
960             stn(self.gname, 32),
961             itn(self.devmajor, 8, posix),
962             itn(self.devminor, 8, posix),
963             stn(prefix, 155)
964         ]
965
966         buf += struct.pack("%ds" % BLOCKSIZE, "".join(parts))
967         chksum = calc_chksums(buf[-BLOCKSIZE:])[0]
968         buf = buf[:-364] + "%06o\0" % chksum + buf[-357:]
969         self.buf = buf
970         return buf
971
972     def _create_gnulong(self, name, type):
973         """Create a GNU longname/longlink header from name.
974            It consists of an extended tar header, with the length
975            of the longname as size, followed by data blocks,
976            which contain the longname as a null terminated string.
977         """
978         name += NUL
979
980         tarinfo = self.__class__()
981         tarinfo.name = "././@LongLink"
982         tarinfo.type = type
983         tarinfo.mode = 0
984         tarinfo.size = len(name)
985
986         # create extended header
987         buf = tarinfo.tobuf()
988         # create name blocks
989         buf += name
990         blocks, remainder = divmod(len(name), BLOCKSIZE)
991         if remainder > 0:
992             buf += (BLOCKSIZE - remainder) * NUL
993         return buf
994
995     def isreg(self):
996         return self.type in REGULAR_TYPES
997     def isfile(self):
998         return self.isreg()
999     def isdir(self):
1000         return self.type == DIRTYPE
1001     def issym(self):
1002         return self.type == SYMTYPE
1003     def islnk(self):
1004         return self.type == LNKTYPE
1005     def ischr(self):
1006         return self.type == CHRTYPE
1007     def isblk(self):
1008         return self.type == BLKTYPE
1009     def isfifo(self):
1010         return self.type == FIFOTYPE
1011     def issparse(self):
1012         return self.type == GNUTYPE_SPARSE
1013     def isdev(self):
1014         return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE)
1015 # class TarInfo
1016
1017 class TarFile(object):
1018     """The TarFile Class provides an interface to tar archives.
1019     """
1020
1021     debug = 0                   # May be set from 0 (no msgs) to 3 (all msgs)
1022
1023     dereference = False         # If true, add content of linked file to the
1024                                 # tar file, else the link.
1025
1026     ignore_zeros = False        # If true, skips empty or invalid blocks and
1027                                 # continues processing.
1028
1029     errorlevel = 0              # If 0, fatal errors only appear in debug
1030                                 # messages (if debug >= 0). If > 0, errors
1031                                 # are passed to the caller as exceptions.
1032
1033     posix = False               # If True, generates POSIX.1-1990-compliant
1034                                 # archives (no GNU extensions!)
1035
1036     fileobject = ExFileObject
1037
1038     def __init__(self, name=None, mode="r", fileobj=None):
1039         """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
1040            read from an existing archive, 'a' to append data to an existing
1041            file or 'w' to create a new file overwriting an existing one. `mode'
1042            defaults to 'r'.
1043            If `fileobj' is given, it is used for reading or writing data. If it
1044            can be determined, `mode' is overridden by `fileobj's mode.
1045            `fileobj' is not closed, when TarFile is closed.
1046         """
1047         self.name = os.path.abspath(name)
1048
1049         if len(mode) > 1 or mode not in "raw":
1050             raise ValueError("mode must be 'r', 'a' or 'w'")
1051         self._mode = mode
1052         self.mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode]
1053
1054         if not fileobj:
1055             fileobj = file(self.name, self.mode)
1056             self._extfileobj = False
1057         else:
1058             if self.name is None and hasattr(fileobj, "name"):
1059                 self.name = os.path.abspath(fileobj.name)
1060             if hasattr(fileobj, "mode"):
1061                 self.mode = fileobj.mode
1062             self._extfileobj = True
1063         self.fileobj = fileobj
1064
1065         # Init datastructures
1066         self.closed = False
1067         self.members = []       # list of members as TarInfo objects
1068         self._loaded = False    # flag if all members have been read
1069         self.offset = 0L        # current position in the archive file
1070         self.inodes = {}        # dictionary caching the inodes of
1071                                 # archive members already added
1072
1073         if self._mode == "r":
1074             self.firstmember = None
1075             self.firstmember = self.next()
1076
1077         if self._mode == "a":
1078             # Move to the end of the archive,
1079             # before the first empty block.
1080             self.firstmember = None
1081             while True:
1082                 try:
1083                     tarinfo = self.next()
1084                 except ReadError:
1085                     self.fileobj.seek(0)
1086                     break
1087                 if tarinfo is None:
1088                     self.fileobj.seek(- BLOCKSIZE, 1)
1089                     break
1090
1091         if self._mode in "aw":
1092             self._loaded = True
1093
1094     #--------------------------------------------------------------------------
1095     # Below are the classmethods which act as alternate constructors to the
1096     # TarFile class. The open() method is the only one that is needed for
1097     # public use; it is the "super"-constructor and is able to select an
1098     # adequate "sub"-constructor for a particular compression using the mapping
1099     # from OPEN_METH.
1100     #
1101     # This concept allows one to subclass TarFile without losing the comfort of
1102     # the super-constructor. A sub-constructor is registered and made available
1103     # by adding it to the mapping in OPEN_METH.
1104
1105     @classmethod
1106     def open(cls, name=None, mode="r", fileobj=None, bufsize=20*512):
1107         """Open a tar archive for reading, writing or appending. Return
1108            an appropriate TarFile class.
1109
1110            mode:
1111            'r' or 'r:*' open for reading with transparent compression
1112            'r:'         open for reading exclusively uncompressed
1113            'r:gz'       open for reading with gzip compression
1114            'r:bz2'      open for reading with bzip2 compression
1115            'a' or 'a:'  open for appending
1116            'w' or 'w:'  open for writing without compression
1117            'w:gz'       open for writing with gzip compression
1118            'w:bz2'      open for writing with bzip2 compression
1119
1120            'r|*'        open a stream of tar blocks with transparent compression
1121            'r|'         open an uncompressed stream of tar blocks for reading
1122            'r|gz'       open a gzip compressed stream of tar blocks
1123            'r|bz2'      open a bzip2 compressed stream of tar blocks
1124            'w|'         open an uncompressed stream for writing
1125            'w|gz'       open a gzip compressed stream for writing
1126            'w|bz2'      open a bzip2 compressed stream for writing
1127         """
1128
1129         if not name and not fileobj:
1130             raise ValueError("nothing to open")
1131
1132         if mode in ("r", "r:*"):
1133             # Find out which *open() is appropriate for opening the file.
1134             for comptype in cls.OPEN_METH:
1135                 func = getattr(cls, cls.OPEN_METH[comptype])
1136                 if fileobj is not None:
1137                     saved_pos = fileobj.tell()
1138                 try:
1139                     return func(name, "r", fileobj)
1140                 except (ReadError, CompressionError):
1141                     if fileobj is not None:
1142                         fileobj.seek(saved_pos)
1143                     continue
1144             raise ReadError("file could not be opened successfully")
1145
1146         elif ":" in mode:
1147             filemode, comptype = mode.split(":", 1)
1148             filemode = filemode or "r"
1149             comptype = comptype or "tar"
1150
1151             # Select the *open() function according to
1152             # given compression.
1153             if comptype in cls.OPEN_METH:
1154                 func = getattr(cls, cls.OPEN_METH[comptype])
1155             else:
1156                 raise CompressionError("unknown compression type %r" % comptype)
1157             return func(name, filemode, fileobj)
1158
1159         elif "|" in mode:
1160             filemode, comptype = mode.split("|", 1)
1161             filemode = filemode or "r"
1162             comptype = comptype or "tar"
1163
1164             if filemode not in "rw":
1165                 raise ValueError("mode must be 'r' or 'w'")
1166
1167             t = cls(name, filemode,
1168                     _Stream(name, filemode, comptype, fileobj, bufsize))
1169             t._extfileobj = False
1170             return t
1171
1172         elif mode in "aw":
1173             return cls.taropen(name, mode, fileobj)
1174
1175         raise ValueError("undiscernible mode")
1176
1177     @classmethod
1178     def taropen(cls, name, mode="r", fileobj=None):
1179         """Open uncompressed tar archive name for reading or writing.
1180         """
1181         if len(mode) > 1 or mode not in "raw":
1182             raise ValueError("mode must be 'r', 'a' or 'w'")
1183         return cls(name, mode, fileobj)
1184
1185     @classmethod
1186     def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9):
1187         """Open gzip compressed tar archive name for reading or writing.
1188            Appending is not allowed.
1189         """
1190         if len(mode) > 1 or mode not in "rw":
1191             raise ValueError("mode must be 'r' or 'w'")
1192
1193         try:
1194             import gzip
1195             gzip.GzipFile
1196         except (ImportError, AttributeError):
1197             raise CompressionError("gzip module is not available")
1198
1199         if fileobj is None:
1200             fileobj = file(name, mode + "b")
1201
1202         try:
1203             t = cls.taropen(name, mode,
1204                 gzip.GzipFile(name, mode, compresslevel, fileobj))
1205         except IOError:
1206             raise ReadError("not a gzip file")
1207         t._extfileobj = False
1208         return t
1209
1210     @classmethod
1211     def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9):
1212         """Open bzip2 compressed tar archive name for reading or writing.
1213            Appending is not allowed.
1214         """
1215         if len(mode) > 1 or mode not in "rw":
1216             raise ValueError("mode must be 'r' or 'w'.")
1217
1218         try:
1219             import bz2
1220         except ImportError:
1221             raise CompressionError("bz2 module is not available")
1222
1223         if fileobj is not None:
1224             fileobj = _BZ2Proxy(fileobj, mode)
1225         else:
1226             fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel)
1227
1228         try:
1229             t = cls.taropen(name, mode, fileobj)
1230         except IOError:
1231             raise ReadError("not a bzip2 file")
1232         t._extfileobj = False
1233         return t
1234
1235     # All *open() methods are registered here.
1236     OPEN_METH = {
1237         "tar": "taropen",   # uncompressed tar
1238         "gz":  "gzopen",    # gzip compressed tar
1239         "bz2": "bz2open"    # bzip2 compressed tar
1240     }
1241
1242     #--------------------------------------------------------------------------
1243     # The public methods which TarFile provides:
1244
1245     def close(self):
1246         """Close the TarFile. In write-mode, two finishing zero blocks are
1247            appended to the archive.
1248         """
1249         if self.closed:
1250             return
1251
1252         if self._mode in "aw":
1253             self.fileobj.write(NUL * (BLOCKSIZE * 2))
1254             self.offset += (BLOCKSIZE * 2)
1255             # fill up the end with zero-blocks
1256             # (like option -b20 for tar does)
1257             blocks, remainder = divmod(self.offset, RECORDSIZE)
1258             if remainder > 0:
1259                 self.fileobj.write(NUL * (RECORDSIZE - remainder))
1260
1261         if not self._extfileobj:
1262             self.fileobj.close()
1263         self.closed = True
1264
1265     def getmember(self, name):
1266         """Return a TarInfo object for member `name'. If `name' can not be
1267            found in the archive, KeyError is raised. If a member occurs more
1268            than once in the archive, its last occurence is assumed to be the
1269            most up-to-date version.
1270         """
1271         tarinfo = self._getmember(name)
1272         if tarinfo is None:
1273             raise KeyError("filename %r not found" % name)
1274         return tarinfo
1275
1276     def getmembers(self):
1277         """Return the members of the archive as a list of TarInfo objects. The
1278            list has the same order as the members in the archive.
1279         """
1280         self._check()
1281         if not self._loaded:    # if we want to obtain a list of
1282             self._load()        # all members, we first have to
1283                                 # scan the whole archive.
1284         return self.members
1285
1286     def getnames(self):
1287         """Return the members of the archive as a list of their names. It has
1288            the same order as the list returned by getmembers().
1289         """
1290         return [tarinfo.name for tarinfo in self.getmembers()]
1291
1292     def gettarinfo(self, name=None, arcname=None, fileobj=None):
1293         """Create a TarInfo object for either the file `name' or the file
1294            object `fileobj' (using os.fstat on its file descriptor). You can
1295            modify some of the TarInfo's attributes before you add it using
1296            addfile(). If given, `arcname' specifies an alternative name for the
1297            file in the archive.
1298         """
1299         self._check("aw")
1300
1301         # When fileobj is given, replace name by
1302         # fileobj's real name.
1303         if fileobj is not None:
1304             name = fileobj.name
1305
1306         # Building the name of the member in the archive.
1307         # Backward slashes are converted to forward slashes,
1308         # Absolute paths are turned to relative paths.
1309         if arcname is None:
1310             arcname = name
1311         arcname = normpath(arcname)
1312         drv, arcname = os.path.splitdrive(arcname)
1313         while arcname[0:1] == "/":
1314             arcname = arcname[1:]
1315
1316         # Now, fill the TarInfo object with
1317         # information specific for the file.
1318         tarinfo = TarInfo()
1319
1320         # Use os.stat or os.lstat, depending on platform
1321         # and if symlinks shall be resolved.
1322         if fileobj is None:
1323             if hasattr(os, "lstat") and not self.dereference:
1324                 statres = os.lstat(name)
1325             else:
1326                 statres = os.stat(name)
1327         else:
1328             statres = os.fstat(fileobj.fileno())
1329         linkname = ""
1330
1331         stmd = statres.st_mode
1332         if stat.S_ISREG(stmd):
1333             inode = (statres.st_ino, statres.st_dev)
1334             if not self.dereference and \
1335                     statres.st_nlink > 1 and inode in self.inodes:
1336                 # Is it a hardlink to an already
1337                 # archived file?
1338                 type = LNKTYPE
1339                 linkname = self.inodes[inode]
1340             else:
1341                 # The inode is added only if its valid.
1342                 # For win32 it is always 0.
1343                 type = REGTYPE
1344                 if inode[0]:
1345                     self.inodes[inode] = arcname
1346         elif stat.S_ISDIR(stmd):
1347             type = DIRTYPE
1348             if arcname[-1:] != "/":
1349                 arcname += "/"
1350         elif stat.S_ISFIFO(stmd):
1351             type = FIFOTYPE
1352         elif stat.S_ISLNK(stmd):
1353             type = SYMTYPE
1354             linkname = os.readlink(name)
1355         elif stat.S_ISCHR(stmd):
1356             type = CHRTYPE
1357         elif stat.S_ISBLK(stmd):
1358             type = BLKTYPE
1359         else:
1360             return None
1361
1362         # Fill the TarInfo object with all
1363         # information we can get.
1364         tarinfo.name = arcname
1365         tarinfo.mode = stmd
1366         tarinfo.uid = statres.st_uid
1367         tarinfo.gid = statres.st_gid
1368         if stat.S_ISREG(stmd):
1369             tarinfo.size = statres.st_size
1370         else:
1371             tarinfo.size = 0L
1372         tarinfo.mtime = statres.st_mtime
1373         tarinfo.type = type
1374         tarinfo.linkname = linkname
1375         if pwd:
1376             try:
1377                 tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0]
1378             except KeyError:
1379                 pass
1380         if grp:
1381             try:
1382                 tarinfo.gname = grp.getgrgid(tarinfo.gid)[0]
1383             except KeyError:
1384                 pass
1385
1386         if type in (CHRTYPE, BLKTYPE):
1387             if hasattr(os, "major") and hasattr(os, "minor"):
1388                 tarinfo.devmajor = os.major(statres.st_rdev)
1389                 tarinfo.devminor = os.minor(statres.st_rdev)
1390         return tarinfo
1391
1392     def list(self, verbose=True):
1393         """Print a table of contents to sys.stdout. If `verbose' is False, only
1394            the names of the members are printed. If it is True, an `ls -l'-like
1395            output is produced.
1396         """
1397         self._check()
1398
1399         for tarinfo in self:
1400             if verbose:
1401                 print filemode(tarinfo.mode),
1402                 print "%s/%s" % (tarinfo.uname or tarinfo.uid,
1403                                  tarinfo.gname or tarinfo.gid),
1404                 if tarinfo.ischr() or tarinfo.isblk():
1405                     print "%10s" % ("%d,%d" \
1406                                     % (tarinfo.devmajor, tarinfo.devminor)),
1407                 else:
1408                     print "%10d" % tarinfo.size,
1409                 print "%d-%02d-%02d %02d:%02d:%02d" \
1410                       % time.localtime(tarinfo.mtime)[:6],
1411
1412             print tarinfo.name,
1413
1414             if verbose:
1415                 if tarinfo.issym():
1416                     print "->", tarinfo.linkname,
1417                 if tarinfo.islnk():
1418                     print "link to", tarinfo.linkname,
1419             print
1420
1421     def add(self, name, arcname=None, recursive=True):
1422         """Add the file `name' to the archive. `name' may be any type of file
1423            (directory, fifo, symbolic link, etc.). If given, `arcname'
1424            specifies an alternative name for the file in the archive.
1425            Directories are added recursively by default. This can be avoided by
1426            setting `recursive' to False.
1427         """
1428         self._check("aw")
1429
1430         if arcname is None:
1431             arcname = name
1432
1433         # Skip if somebody tries to archive the archive...
1434         if self.name is not None and os.path.abspath(name) == self.name:
1435             self._dbg(2, "tarfile: Skipped %r" % name)
1436             return
1437
1438         # Special case: The user wants to add the current
1439         # working directory.
1440         if name == ".":
1441             if recursive:
1442                 if arcname == ".":
1443                     arcname = ""
1444                 for f in os.listdir("."):
1445                     self.add(f, os.path.join(arcname, f))
1446             return
1447
1448         self._dbg(1, name)
1449
1450         # Create a TarInfo object from the file.
1451         tarinfo = self.gettarinfo(name, arcname)
1452
1453         if tarinfo is None:
1454             self._dbg(1, "tarfile: Unsupported type %r" % name)
1455             return
1456
1457         # Append the tar header and data to the archive.
1458         if tarinfo.isreg():
1459             f = file(name, "rb")
1460             self.addfile(tarinfo, f)
1461             f.close()
1462
1463         elif tarinfo.isdir():
1464             self.addfile(tarinfo)
1465             if recursive:
1466                 for f in os.listdir(name):
1467                     self.add(os.path.join(name, f), os.path.join(arcname, f))
1468
1469         else:
1470             self.addfile(tarinfo)
1471
1472     def addfile(self, tarinfo, fileobj=None):
1473         """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
1474            given, tarinfo.size bytes are read from it and added to the archive.
1475            You can create TarInfo objects using gettarinfo().
1476            On Windows platforms, `fileobj' should always be opened with mode
1477            'rb' to avoid irritation about the file size.
1478         """
1479         self._check("aw")
1480
1481         tarinfo = copy.copy(tarinfo)
1482
1483         buf = tarinfo.tobuf(self.posix)
1484         self.fileobj.write(buf)
1485         self.offset += len(buf)
1486
1487         # If there's data to follow, append it.
1488         if fileobj is not None:
1489             copyfileobj(fileobj, self.fileobj, tarinfo.size)
1490             blocks, remainder = divmod(tarinfo.size, BLOCKSIZE)
1491             if remainder > 0:
1492                 self.fileobj.write(NUL * (BLOCKSIZE - remainder))
1493                 blocks += 1
1494             self.offset += blocks * BLOCKSIZE
1495
1496         self.members.append(tarinfo)
1497
1498     def extractall(self, path=".", members=None):
1499         """Extract all members from the archive to the current working
1500            directory and set owner, modification time and permissions on
1501            directories afterwards. `path' specifies a different directory
1502            to extract to. `members' is optional and must be a subset of the
1503            list returned by getmembers().
1504         """
1505         directories = []
1506
1507         if members is None:
1508             members = self
1509
1510         for tarinfo in members:
1511             if tarinfo.isdir():
1512                 # Extract directory with a safe mode, so that
1513                 # all files below can be extracted as well.
1514                 try:
1515                     os.makedirs(os.path.join(path, tarinfo.name), 0777)
1516                 except EnvironmentError:
1517                     pass
1518                 directories.append(tarinfo)
1519             else:
1520                 self.extract(tarinfo, path)
1521
1522         # Reverse sort directories.
1523         directories.sort(lambda a, b: cmp(a.name, b.name))
1524         directories.reverse()
1525
1526         # Set correct owner, mtime and filemode on directories.
1527         for tarinfo in directories:
1528             path = os.path.join(path, tarinfo.name)
1529             try:
1530                 self.chown(tarinfo, path)
1531                 self.utime(tarinfo, path)
1532                 self.chmod(tarinfo, path)
1533             except ExtractError, e:
1534                 if self.errorlevel > 1:
1535                     raise
1536                 else:
1537                     self._dbg(1, "tarfile: %s" % e)
1538
1539     def extract(self, member, path=""):
1540         """Extract a member from the archive to the current working directory,
1541            using its full name. Its file information is extracted as accurately
1542            as possible. `member' may be a filename or a TarInfo object. You can
1543            specify a different directory using `path'.
1544         """
1545         self._check("r")
1546
1547         if isinstance(member, TarInfo):
1548             tarinfo = member
1549         else:
1550             tarinfo = self.getmember(member)
1551
1552         # Prepare the link target for makelink().
1553         if tarinfo.islnk():
1554             tarinfo._link_target = os.path.join(path, tarinfo.linkname)
1555
1556         try:
1557             self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
1558         except EnvironmentError, e:
1559             if self.errorlevel > 0:
1560                 raise
1561             else:
1562                 if e.filename is None:
1563                     self._dbg(1, "tarfile: %s" % e.strerror)
1564                 else:
1565                     self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename))
1566         except ExtractError, e:
1567             if self.errorlevel > 1:
1568                 raise
1569             else:
1570                 self._dbg(1, "tarfile: %s" % e)
1571
1572     def extractfile(self, member):
1573         """Extract a member from the archive as a file object. `member' may be
1574            a filename or a TarInfo object. If `member' is a regular file, a
1575            file-like object is returned. If `member' is a link, a file-like
1576            object is constructed from the link's target. If `member' is none of
1577            the above, None is returned.
1578            The file-like object is read-only and provides the following
1579            methods: read(), readline(), readlines(), seek() and tell()
1580         """
1581         self._check("r")
1582
1583         if isinstance(member, TarInfo):
1584             tarinfo = member
1585         else:
1586             tarinfo = self.getmember(member)
1587
1588         if tarinfo.isreg():
1589             return self.fileobject(self, tarinfo)
1590
1591         elif tarinfo.type not in SUPPORTED_TYPES:
1592             # If a member's type is unknown, it is treated as a
1593             # regular file.
1594             return self.fileobject(self, tarinfo)
1595
1596         elif tarinfo.islnk() or tarinfo.issym():
1597             if isinstance(self.fileobj, _Stream):
1598                 # A small but ugly workaround for the case that someone tries
1599                 # to extract a (sym)link as a file-object from a non-seekable
1600                 # stream of tar blocks.
1601                 raise StreamError("cannot extract (sym)link as file object")
1602             else:
1603                 # A (sym)link's file object is its target's file object.
1604                 return self.extractfile(self._getmember(tarinfo.linkname,
1605                                                         tarinfo))
1606         else:
1607             # If there's no data associated with the member (directory, chrdev,
1608             # blkdev, etc.), return None instead of a file object.
1609             return None
1610
1611     def _extract_member(self, tarinfo, targetpath):
1612         """Extract the TarInfo object tarinfo to a physical
1613            file called targetpath.
1614         """
1615         # Fetch the TarInfo object for the given name
1616         # and build the destination pathname, replacing
1617         # forward slashes to platform specific separators.
1618         if targetpath[-1:] == "/":
1619             targetpath = targetpath[:-1]
1620         targetpath = os.path.normpath(targetpath)
1621
1622         # Create all upper directories.
1623         upperdirs = os.path.dirname(targetpath)
1624         if upperdirs and not os.path.exists(upperdirs):
1625             ti = TarInfo()
1626             ti.name  = upperdirs
1627             ti.type  = DIRTYPE
1628             ti.mode  = 0777
1629             ti.mtime = tarinfo.mtime
1630             ti.uid   = tarinfo.uid
1631             ti.gid   = tarinfo.gid
1632             ti.uname = tarinfo.uname
1633             ti.gname = tarinfo.gname
1634             try:
1635                 self._extract_member(ti, ti.name)
1636             except:
1637                 pass
1638
1639         if tarinfo.islnk() or tarinfo.issym():
1640             self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname))
1641         else:
1642             self._dbg(1, tarinfo.name)
1643
1644         if tarinfo.isreg():
1645             self.makefile(tarinfo, targetpath)
1646         elif tarinfo.isdir():
1647             self.makedir(tarinfo, targetpath)
1648         elif tarinfo.isfifo():
1649             self.makefifo(tarinfo, targetpath)
1650         elif tarinfo.ischr() or tarinfo.isblk():
1651             self.makedev(tarinfo, targetpath)
1652         elif tarinfo.islnk() or tarinfo.issym():
1653             self.makelink(tarinfo, targetpath)
1654         elif tarinfo.type not in SUPPORTED_TYPES:
1655             self.makeunknown(tarinfo, targetpath)
1656         else:
1657             self.makefile(tarinfo, targetpath)
1658
1659         self.chown(tarinfo, targetpath)
1660         if not tarinfo.issym():
1661             self.chmod(tarinfo, targetpath)
1662             self.utime(tarinfo, targetpath)
1663
1664     #--------------------------------------------------------------------------
1665     # Below are the different file methods. They are called via
1666     # _extract_member() when extract() is called. They can be replaced in a
1667     # subclass to implement other functionality.
1668
1669     def makedir(self, tarinfo, targetpath):
1670         """Make a directory called targetpath.
1671         """
1672         try:
1673             os.mkdir(targetpath)
1674         except EnvironmentError, e:
1675             if e.errno != errno.EEXIST:
1676                 raise
1677
1678     def makefile(self, tarinfo, targetpath):
1679         """Make a file called targetpath.
1680         """
1681         source = self.extractfile(tarinfo)
1682         target = file(targetpath, "wb")
1683         copyfileobj(source, target)
1684         source.close()
1685         target.close()
1686
1687     def makeunknown(self, tarinfo, targetpath):
1688         """Make a file from a TarInfo object with an unknown type
1689            at targetpath.
1690         """
1691         self.makefile(tarinfo, targetpath)
1692         self._dbg(1, "tarfile: Unknown file type %r, " \
1693                      "extracted as regular file." % tarinfo.type)
1694
1695     def makefifo(self, tarinfo, targetpath):
1696         """Make a fifo called targetpath.
1697         """
1698         if hasattr(os, "mkfifo"):
1699             os.mkfifo(targetpath)
1700         else:
1701             raise ExtractError("fifo not supported by system")
1702
1703     def makedev(self, tarinfo, targetpath):
1704         """Make a character or block device called targetpath.
1705         """
1706         if not hasattr(os, "mknod") or not hasattr(os, "makedev"):
1707             raise ExtractError("special devices not supported by system")
1708
1709         mode = tarinfo.mode
1710         if tarinfo.isblk():
1711             mode |= stat.S_IFBLK
1712         else:
1713             mode |= stat.S_IFCHR
1714
1715         os.mknod(targetpath, mode,
1716                  os.makedev(tarinfo.devmajor, tarinfo.devminor))
1717
1718     def makelink(self, tarinfo, targetpath):
1719         """Make a (symbolic) link called targetpath. If it cannot be created
1720           (platform limitation), we try to make a copy of the referenced file
1721           instead of a link.
1722         """
1723         linkpath = tarinfo.linkname
1724         try:
1725             if tarinfo.issym():
1726                 os.symlink(linkpath, targetpath)
1727             else:
1728                 # See extract().
1729                 os.link(tarinfo._link_target, targetpath)
1730         except AttributeError:
1731             if tarinfo.issym():
1732                 linkpath = os.path.join(os.path.dirname(tarinfo.name),
1733                                         linkpath)
1734                 linkpath = normpath(linkpath)
1735
1736             try:
1737                 self._extract_member(self.getmember(linkpath), targetpath)
1738             except (EnvironmentError, KeyError), e:
1739                 linkpath = os.path.normpath(linkpath)
1740                 try:
1741                     shutil.copy2(linkpath, targetpath)
1742                 except EnvironmentError, e:
1743                     raise IOError("link could not be created")
1744
1745     def chown(self, tarinfo, targetpath):
1746         """Set owner of targetpath according to tarinfo.
1747         """
1748         if pwd and hasattr(os, "geteuid") and os.geteuid() == 0:
1749             # We have to be root to do so.
1750             try:
1751                 g = grp.getgrnam(tarinfo.gname)[2]
1752             except KeyError:
1753                 try:
1754                     g = grp.getgrgid(tarinfo.gid)[2]
1755                 except KeyError:
1756                     g = os.getgid()
1757             try:
1758                 u = pwd.getpwnam(tarinfo.uname)[2]
1759             except KeyError:
1760                 try:
1761                     u = pwd.getpwuid(tarinfo.uid)[2]
1762                 except KeyError:
1763                     u = os.getuid()
1764             try:
1765                 if tarinfo.issym() and hasattr(os, "lchown"):
1766                     os.lchown(targetpath, u, g)
1767                 else:
1768                     if sys.platform != "os2emx":
1769                         os.chown(targetpath, u, g)
1770             except EnvironmentError, e:
1771                 raise ExtractError("could not change owner")
1772
1773     def chmod(self, tarinfo, targetpath):
1774         """Set file permissions of targetpath according to tarinfo.
1775         """
1776         if hasattr(os, 'chmod'):
1777             try:
1778                 os.chmod(targetpath, tarinfo.mode)
1779             except EnvironmentError, e:
1780                 raise ExtractError("could not change mode")
1781
1782     def utime(self, tarinfo, targetpath):
1783         """Set modification time of targetpath according to tarinfo.
1784         """
1785         if not hasattr(os, 'utime'):
1786             return
1787         if sys.platform == "win32" and tarinfo.isdir():
1788             # According to msdn.microsoft.com, it is an error (EACCES)
1789             # to use utime() on directories.
1790             return
1791         try:
1792             os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime))
1793         except EnvironmentError, e:
1794             raise ExtractError("could not change modification time")
1795
1796     #--------------------------------------------------------------------------
1797     def next(self):
1798         """Return the next member of the archive as a TarInfo object, when
1799            TarFile is opened for reading. Return None if there is no more
1800            available.
1801         """
1802         self._check("ra")
1803         if self.firstmember is not None:
1804             m = self.firstmember
1805             self.firstmember = None
1806             return m
1807
1808         # Read the next block.
1809         self.fileobj.seek(self.offset)
1810         while True:
1811             buf = self.fileobj.read(BLOCKSIZE)
1812             if not buf:
1813                 return None
1814
1815             try:
1816                 tarinfo = TarInfo.frombuf(buf)
1817
1818                 # Set the TarInfo object's offset to the current position of the
1819                 # TarFile and set self.offset to the position where the data blocks
1820                 # should begin.
1821                 tarinfo.offset = self.offset
1822                 self.offset += BLOCKSIZE
1823
1824                 tarinfo = self.proc_member(tarinfo)
1825
1826             except ValueError, e:
1827                 if self.ignore_zeros:
1828                     self._dbg(2, "0x%X: empty or invalid block: %s" %
1829                               (self.offset, e))
1830                     self.offset += BLOCKSIZE
1831                     continue
1832                 else:
1833                     if self.offset == 0:
1834                         raise ReadError("empty, unreadable or compressed "
1835                                         "file: %s" % e)
1836                     return None
1837             break
1838
1839         # Some old tar programs represent a directory as a regular
1840         # file with a trailing slash.
1841         if tarinfo.isreg() and tarinfo.name.endswith("/"):
1842             tarinfo.type = DIRTYPE
1843
1844         # Directory names should have a '/' at the end.
1845         if tarinfo.isdir():
1846             tarinfo.name += "/"
1847
1848         self.members.append(tarinfo)
1849         return tarinfo
1850
1851     #--------------------------------------------------------------------------
1852     # The following are methods that are called depending on the type of a
1853     # member. The entry point is proc_member() which is called with a TarInfo
1854     # object created from the header block from the current offset. The
1855     # proc_member() method can be overridden in a subclass to add custom
1856     # proc_*() methods. A proc_*() method MUST implement the following
1857     # operations:
1858     # 1. Set tarinfo.offset_data to the position where the data blocks begin,
1859     #    if there is data that follows.
1860     # 2. Set self.offset to the position where the next member's header will
1861     #    begin.
1862     # 3. Return tarinfo or another valid TarInfo object.
1863     def proc_member(self, tarinfo):
1864         """Choose the right processing method for tarinfo depending
1865            on its type and call it.
1866         """
1867         if tarinfo.type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK):
1868             return self.proc_gnulong(tarinfo)
1869         elif tarinfo.type == GNUTYPE_SPARSE:
1870             return self.proc_sparse(tarinfo)
1871         else:
1872             return self.proc_builtin(tarinfo)
1873
1874     def proc_builtin(self, tarinfo):
1875         """Process a builtin type member or an unknown member
1876            which will be treated as a regular file.
1877         """
1878         tarinfo.offset_data = self.offset
1879         if tarinfo.isreg() or tarinfo.type not in SUPPORTED_TYPES:
1880             # Skip the following data blocks.
1881             self.offset += self._block(tarinfo.size)
1882         return tarinfo
1883
1884     def proc_gnulong(self, tarinfo):
1885         """Process the blocks that hold a GNU longname
1886            or longlink member.
1887         """
1888         buf = ""
1889         count = tarinfo.size
1890         while count > 0:
1891             block = self.fileobj.read(BLOCKSIZE)
1892             buf += block
1893             self.offset += BLOCKSIZE
1894             count -= BLOCKSIZE
1895
1896         # Fetch the next header and process it.
1897         b = self.fileobj.read(BLOCKSIZE)
1898         t = TarInfo.frombuf(b)
1899         t.offset = self.offset
1900         self.offset += BLOCKSIZE
1901         next = self.proc_member(t)
1902
1903         # Patch the TarInfo object from the next header with
1904         # the longname information.
1905         next.offset = tarinfo.offset
1906         if tarinfo.type == GNUTYPE_LONGNAME:
1907             next.name = buf.rstrip(NUL)
1908         elif tarinfo.type == GNUTYPE_LONGLINK:
1909             next.linkname = buf.rstrip(NUL)
1910
1911         return next
1912
1913     def proc_sparse(self, tarinfo):
1914         """Process a GNU sparse header plus extra headers.
1915         """
1916         buf = tarinfo.buf
1917         sp = _ringbuffer()
1918         pos = 386
1919         lastpos = 0L
1920         realpos = 0L
1921         # There are 4 possible sparse structs in the
1922         # first header.
1923         for i in xrange(4):
1924             try:
1925                 offset = nti(buf[pos:pos + 12])
1926                 numbytes = nti(buf[pos + 12:pos + 24])
1927             except ValueError:
1928                 break
1929             if offset > lastpos:
1930                 sp.append(_hole(lastpos, offset - lastpos))
1931             sp.append(_data(offset, numbytes, realpos))
1932             realpos += numbytes
1933             lastpos = offset + numbytes
1934             pos += 24
1935
1936         isextended = ord(buf[482])
1937         origsize = nti(buf[483:495])
1938
1939         # If the isextended flag is given,
1940         # there are extra headers to process.
1941         while isextended == 1:
1942             buf = self.fileobj.read(BLOCKSIZE)
1943             self.offset += BLOCKSIZE
1944             pos = 0
1945             for i in xrange(21):
1946                 try:
1947                     offset = nti(buf[pos:pos + 12])
1948                     numbytes = nti(buf[pos + 12:pos + 24])
1949                 except ValueError:
1950                     break
1951                 if offset > lastpos:
1952                     sp.append(_hole(lastpos, offset - lastpos))
1953                 sp.append(_data(offset, numbytes, realpos))
1954                 realpos += numbytes
1955                 lastpos = offset + numbytes
1956                 pos += 24
1957             isextended = ord(buf[504])
1958
1959         if lastpos < origsize:
1960             sp.append(_hole(lastpos, origsize - lastpos))
1961
1962         tarinfo.sparse = sp
1963
1964         tarinfo.offset_data = self.offset
1965         self.offset += self._block(tarinfo.size)
1966         tarinfo.size = origsize
1967
1968         return tarinfo
1969
1970     #--------------------------------------------------------------------------
1971     # Little helper methods:
1972
1973     def _block(self, count):
1974         """Round up a byte count by BLOCKSIZE and return it,
1975            e.g. _block(834) => 1024.
1976         """
1977         blocks, remainder = divmod(count, BLOCKSIZE)
1978         if remainder:
1979             blocks += 1
1980         return blocks * BLOCKSIZE
1981
1982     def _getmember(self, name, tarinfo=None):
1983         """Find an archive member by name from bottom to top.
1984            If tarinfo is given, it is used as the starting point.
1985         """
1986         # Ensure that all members have been loaded.
1987         members = self.getmembers()
1988
1989         if tarinfo is None:
1990             end = len(members)
1991         else:
1992             end = members.index(tarinfo)
1993
1994         for i in xrange(end - 1, -1, -1):
1995             if name == members[i].name:
1996                 return members[i]
1997
1998     def _load(self):
1999         """Read through the entire archive file and look for readable
2000            members.
2001         """
2002         while True:
2003             tarinfo = self.next()
2004             if tarinfo is None:
2005                 break
2006         self._loaded = True
2007
2008     def _check(self, mode=None):
2009         """Check if TarFile is still open, and if the operation's mode
2010            corresponds to TarFile's mode.
2011         """
2012         if self.closed:
2013             raise IOError("%s is closed" % self.__class__.__name__)
2014         if mode is not None and self._mode not in mode:
2015             raise IOError("bad operation for mode %r" % self._mode)
2016
2017     def __iter__(self):
2018         """Provide an iterator object.
2019         """
2020         if self._loaded:
2021             return iter(self.members)
2022         else:
2023             return TarIter(self)
2024
2025     def _dbg(self, level, msg):
2026         """Write debugging output to sys.stderr.
2027         """
2028         if level <= self.debug:
2029             print >> sys.stderr, msg
2030 # class TarFile
2031
2032 class TarIter:
2033     """Iterator Class.
2034
2035        for tarinfo in TarFile(...):
2036            suite...
2037     """
2038
2039     def __init__(self, tarfile):
2040         """Construct a TarIter object.
2041         """
2042         self.tarfile = tarfile
2043         self.index = 0
2044     def __iter__(self):
2045         """Return iterator object.
2046         """
2047         return self
2048     def next(self):
2049         """Return the next item using TarFile's next() method.
2050            When all members have been read, set TarFile as _loaded.
2051         """
2052         # Fix for SF #1100429: Under rare circumstances it can
2053         # happen that getmembers() is called during iteration,
2054         # which will cause TarIter to stop prematurely.
2055         if not self.tarfile._loaded:
2056             tarinfo = self.tarfile.next()
2057             if not tarinfo:
2058                 self.tarfile._loaded = True
2059                 raise StopIteration
2060         else:
2061             try:
2062                 tarinfo = self.tarfile.members[self.index]
2063             except IndexError:
2064                 raise StopIteration
2065         self.index += 1
2066         return tarinfo
2067
2068 # Helper classes for sparse file support
2069 class _section:
2070     """Base class for _data and _hole.
2071     """
2072     def __init__(self, offset, size):
2073         self.offset = offset
2074         self.size = size
2075     def __contains__(self, offset):
2076         return self.offset <= offset < self.offset + self.size
2077
2078 class _data(_section):
2079     """Represent a data section in a sparse file.
2080     """
2081     def __init__(self, offset, size, realpos):
2082         _section.__init__(self, offset, size)
2083         self.realpos = realpos
2084
2085 class _hole(_section):
2086     """Represent a hole section in a sparse file.
2087     """
2088     pass
2089
2090 class _ringbuffer(list):
2091     """Ringbuffer class which increases performance
2092        over a regular list.
2093     """
2094     def __init__(self):
2095         self.idx = 0
2096     def find(self, offset):
2097         idx = self.idx
2098         while True:
2099             item = self[idx]
2100             if offset in item:
2101                 break
2102             idx += 1
2103             if idx == len(self):
2104                 idx = 0
2105             if idx == self.idx:
2106                 # End of File
2107                 return None
2108         self.idx = idx
2109         return item
2110
2111 #---------------------------------------------
2112 # zipfile compatible TarFile class
2113 #---------------------------------------------
2114 TAR_PLAIN = 0           # zipfile.ZIP_STORED
2115 TAR_GZIPPED = 8         # zipfile.ZIP_DEFLATED
2116 class TarFileCompat:
2117     """TarFile class compatible with standard module zipfile's
2118        ZipFile class.
2119     """
2120     def __init__(self, file, mode="r", compression=TAR_PLAIN):
2121         if compression == TAR_PLAIN:
2122             self.tarfile = TarFile.taropen(file, mode)
2123         elif compression == TAR_GZIPPED:
2124             self.tarfile = TarFile.gzopen(file, mode)
2125         else:
2126             raise ValueError("unknown compression constant")
2127         if mode[0:1] == "r":
2128             members = self.tarfile.getmembers()
2129             for m in members:
2130                 m.filename = m.name
2131                 m.file_size = m.size
2132                 m.date_time = time.gmtime(m.mtime)[:6]
2133     def namelist(self):
2134         return map(lambda m: m.name, self.infolist())
2135     def infolist(self):
2136         return filter(lambda m: m.type in REGULAR_TYPES,
2137                       self.tarfile.getmembers())
2138     def printdir(self):
2139         self.tarfile.list()
2140     def testzip(self):
2141         return
2142     def getinfo(self, name):
2143         return self.tarfile.getmember(name)
2144     def read(self, name):
2145         return self.tarfile.extractfile(self.tarfile.getmember(name)).read()
2146     def write(self, filename, arcname=None, compress_type=None):
2147         self.tarfile.add(filename, arcname)
2148     def writestr(self, zinfo, bytes):
2149         try:
2150             from cStringIO import StringIO
2151         except ImportError:
2152             from StringIO import StringIO
2153         import calendar
2154         zinfo.name = zinfo.filename
2155         zinfo.size = zinfo.file_size
2156         zinfo.mtime = calendar.timegm(zinfo.date_time)
2157         self.tarfile.addfile(zinfo, StringIO(bytes))
2158     def close(self):
2159         self.tarfile.close()
2160 #class TarFileCompat
2161
2162 #--------------------
2163 # exported functions
2164 #--------------------
2165 def is_tarfile(name):
2166     """Return True if name points to a tar archive that we
2167        are able to handle, else return False.
2168     """
2169     try:
2170         t = open(name)
2171         t.close()
2172         return True
2173     except TarError:
2174         return False
2175
2176 open = TarFile.open