diff --git a/Doc/lib/libtarfile.tex b/Doc/lib/libtarfile.tex index 018e8b93afc..90884731893 100644 --- a/Doc/lib/libtarfile.tex +++ b/Doc/lib/libtarfile.tex @@ -32,7 +32,7 @@ Some facts and figures: it defaults to \code{'r'}. Here is a full list of mode combinations: \begin{tableii}{c|l}{code}{mode}{action} - \lineii{'r'}{Open for reading with transparent compression (recommended).} + \lineii{'r' or 'r:*'}{Open for reading with transparent compression (recommended).} \lineii{'r:'}{Open for reading exclusively without compression.} \lineii{'r:gz'}{Open for reading with gzip compression.} \lineii{'r:bz2'}{Open for reading with bzip2 compression.} @@ -65,6 +65,7 @@ Some facts and figures: (section~\ref{tar-examples}). The currently possible modes: \begin{tableii}{c|l}{code}{Mode}{Action} + \lineii{'r|*'}{Open a \emph{stream} of tar blocks for reading with transparent compression.} \lineii{'r|'}{Open a \emph{stream} of uncompressed tar blocks for reading.} \lineii{'r|gz'}{Open a gzip compressed \emph{stream} for reading.} \lineii{'r|bz2'}{Open a bzip2 compressed \emph{stream} for reading.} diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 8bce5d00754..56cce0331c8 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -274,7 +274,7 @@ class _Stream: _Stream is intended to be used only internally. """ - def __init__(self, name, mode, type, fileobj, bufsize): + def __init__(self, name, mode, comptype, fileobj, bufsize): """Construct a _Stream object. """ self._extfileobj = True @@ -282,16 +282,22 @@ class _Stream: fileobj = _LowLevelFile(name, mode) self._extfileobj = False - self.name = name or "" - self.mode = mode - self.type = type - self.fileobj = fileobj - self.bufsize = bufsize - self.buf = "" - self.pos = 0L - self.closed = False + if comptype == '*': + # Enable transparent compression detection for the + # stream interface + fileobj = _StreamProxy(fileobj) + comptype = fileobj.getcomptype() - if type == "gz": + self.name = name or "" + self.mode = mode + self.comptype = comptype + self.fileobj = fileobj + self.bufsize = bufsize + self.buf = "" + self.pos = 0L + self.closed = False + + if comptype == "gz": try: import zlib except ImportError: @@ -303,7 +309,7 @@ class _Stream: else: self._init_write_gz() - if type == "bz2": + if comptype == "bz2": try: import bz2 except ImportError: @@ -315,7 +321,7 @@ class _Stream: self.cmp = bz2.BZ2Compressor() def __del__(self): - if not self.closed: + if hasattr(self, "closed") and not self.closed: self.close() def _init_write_gz(self): @@ -334,10 +340,10 @@ class _Stream: def write(self, s): """Write string s to the stream. """ - if self.type == "gz": + if self.comptype == "gz": self.crc = self.zlib.crc32(s, self.crc) self.pos += len(s) - if self.type != "tar": + if self.comptype != "tar": s = self.cmp.compress(s) self.__write(s) @@ -357,12 +363,16 @@ class _Stream: if self.closed: return - if self.mode == "w" and self.type != "tar": + if self.mode == "w" and self.comptype != "tar": self.buf += self.cmp.flush() + if self.mode == "w" and self.buf: + blocks, remainder = divmod(len(self.buf), self.bufsize) + if remainder > 0: + self.buf += NUL * (self.bufsize - remainder) self.fileobj.write(self.buf) self.buf = "" - if self.type == "gz": + if self.comptype == "gz": self.fileobj.write(struct.pack("