tarfile.py

来自「python s60 1.4.5版本的源代码」· Python 代码 · 共 1,815 行 · 第 1/4 页

PY
1,815
字号

    def __read(self, size):
        
        c = len(self.buf)
        t = [self.buf]
        while c < size:
            buf = self.fileobj.read(self.bufsize)
            if not buf:
                break
            t.append(buf)
            c += len(buf)
        t = "".join(t)
        self.buf = t[size:]
        return t[:size]
# class _Stream

class _StreamProxy(object):
    

    def __init__(self, fileobj):
        self.fileobj = fileobj
        self.buf = self.fileobj.read(BLOCKSIZE)

    def read(self, size):
        self.read = self.fileobj.read
        return self.buf

    def getcomptype(self):
        if self.buf.startswith("\037\213\010"):
            return "gz"
        if self.buf.startswith("BZh91"):
            return "bz2"
        return "tar"

    def close(self):
        self.fileobj.close()
# class StreamProxy

#------------------------
# Extraction file object
#------------------------
class ExFileObject(object):
    

    def __init__(self, tarfile, tarinfo):
        self.fileobj = tarfile.fileobj
        self.name    = tarinfo.name
        self.mode    = "r"
        self.closed  = False
        self.offset  = tarinfo.offset_data
        self.size    = tarinfo.size
        self.pos     = 0L
        self.linebuffer = ""
        if tarinfo.issparse():
            self.sparse = tarinfo.sparse
            self.read = self._readsparse
        else:
            self.read = self._readnormal

    def __read(self, size):
        
        return self.fileobj.read(size)

    def readline(self, size=-1):
        
        if size < 0:
            size = sys.maxint

        nl = self.linebuffer.find("\n")
        if nl >= 0:
            nl = min(nl, size)
        else:
            size -= len(self.linebuffer)
            while nl < 0:
                buf = self.read(min(size, 100))
                if not buf:
                    break
                self.linebuffer += buf
                size -= len(buf)
                if size <= 0:
                    break
                nl = self.linebuffer.find("\n")
            if nl == -1:
                s = self.linebuffer
                self.linebuffer = ""
                return s
        buf = self.linebuffer[:nl]
        self.linebuffer = self.linebuffer[nl + 1:]
        while buf[-1:] == "\r":
            buf = buf[:-1]
        return buf + "\n"

    def readlines(self):
        
        result = []
        while True:
            line = self.readline()
            if not line: break
            result.append(line)
        return result

    def _readnormal(self, size=None):
        
        if self.closed:
            raise ValueError, "file is closed"
        self.fileobj.seek(self.offset + self.pos)
        bytesleft = self.size - self.pos
        if size is None:
            bytestoread = bytesleft
        else:
            bytestoread = min(size, bytesleft)
        self.pos += bytestoread
        return self.__read(bytestoread)

    def _readsparse(self, size=None):
        
        if self.closed:
            raise ValueError, "file is closed"

        if size is None:
            size = self.size - self.pos

        data = []
        while size > 0:
            buf = self._readsparsesection(size)
            if not buf:
                break
            size -= len(buf)
            data.append(buf)
        return "".join(data)

    def _readsparsesection(self, size):
        
        section = self.sparse.find(self.pos)

        if section is None:
            return ""

        toread = min(size, section.offset + section.size - self.pos)
        if isinstance(section, _data):
            realpos = section.realpos + self.pos - section.offset
            self.pos += toread
            self.fileobj.seek(self.offset + realpos)
            return self.__read(toread)
        else:
            self.pos += toread
            return NUL * toread

    def tell(self):
        
        return self.pos

    def seek(self, pos, whence=0):
        
        self.linebuffer = ""
        if whence == 0:
            self.pos = min(max(pos, 0), self.size)
        if whence == 1:
            if pos < 0:
                self.pos = max(self.pos + pos, 0)
            else:
                self.pos = min(self.pos + pos, self.size)
        if whence == 2:
            self.pos = max(min(self.size + pos, self.size), 0)

    def close(self):
        
        self.closed = True
#class ExFileObject

#------------------
# Exported Classes
#------------------
class TarInfo(object):
    

    def __init__(self, name=""):
        

        self.name     = name       # member name (dirnames must end with '/')
        self.mode     = 0666       # file permissions
        self.uid      = 0          # user id
        self.gid      = 0          # group id
        self.size     = 0          # file size
        self.mtime    = 0          # modification time
        self.chksum   = 0          # header checksum
        self.type     = REGTYPE    # member type
        self.linkname = ""         # link name
        self.uname    = "user"     # user name
        self.gname    = "group"    # group name
        self.devmajor = 0          #-
        self.devminor = 0          #-for use with CHRTYPE and BLKTYPE
        self.prefix   = ""         # prefix to filename or holding information
                                   # about sparse files

        self.offset   = 0          # the tar header starts here
        self.offset_data = 0       # the file's data starts here

    def __repr__(self):
        return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self))

    def frombuf(cls, buf):
        
        tarinfo = cls()
        tarinfo.name   =  nts(buf[0:100])
        tarinfo.mode   = int(buf[100:108], 8)
        tarinfo.uid    = int(buf[108:116],8)
        tarinfo.gid    = int(buf[116:124],8)
        tarinfo.size   = long(buf[124:136], 8)
        tarinfo.mtime  = long(buf[136:148], 8)
        tarinfo.chksum = int(buf[148:156], 8)
        tarinfo.type   = buf[156:157]
        tarinfo.linkname = nts(buf[157:257])
        tarinfo.uname  = nts(buf[265:297])
        tarinfo.gname  = nts(buf[297:329])
        try:
            tarinfo.devmajor = int(buf[329:337], 8)
            tarinfo.devminor = int(buf[337:345], 8)
        except ValueError:
            tarinfo.devmajor = tarinfo.devmajor = 0
        tarinfo.prefix = buf[345:500]

        # The prefix field is used for filenames > 100 in
        # the POSIX standard.
        # name = prefix + '/' + name
        if tarinfo.type != GNUTYPE_SPARSE:
            tarinfo.name = normpath(os.path.join(nts(tarinfo.prefix), tarinfo.name))

        # Directory names should have a '/' at the end.
        if tarinfo.isdir() and tarinfo.name[-1:] != "/":
            tarinfo.name += "/"
        return tarinfo

    frombuf = classmethod(frombuf)

    def tobuf(self):
        
        name = self.name

        # The following code was contributed by Detlef Lannert.
        parts = []
        for value, fieldsize in (
                (name, 100),
                ("%07o" % (self.mode & 07777), 8),
                ("%07o" % self.uid, 8),
                ("%07o" % self.gid, 8),
                ("%011o" % self.size, 12),
                ("%011o" % self.mtime, 12),
                ("        ", 8),
                (self.type, 1),
                (self.linkname, 100),
                (MAGIC, 6),
                (VERSION, 2),
                (self.uname, 32),
                (self.gname, 32),
                ("%07o" % self.devmajor, 8),
                ("%07o" % self.devminor, 8),
                (self.prefix, 155)
            ):
            l = len(value)
            parts.append(value + (fieldsize - l) * NUL)

        buf = "".join(parts)
        chksum = calc_chksum(buf)
        buf = buf[:148] + "%06o\0" % chksum + buf[155:]
        buf += (BLOCKSIZE - len(buf)) * NUL
        self.buf = buf
        return buf

    def isreg(self):
        return self.type in REGULAR_TYPES
    def isfile(self):
        return self.isreg()
    def isdir(self):
        return self.type == DIRTYPE
    def issym(self):
        return self.type == SYMTYPE
    def islnk(self):
        return self.type == LNKTYPE
    def ischr(self):
        return self.type == CHRTYPE
    def isblk(self):
        return self.type == BLKTYPE
    def isfifo(self):
        return self.type == FIFOTYPE
    def issparse(self):
        return self.type == GNUTYPE_SPARSE
    def isdev(self):
        return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE)
# class TarInfo

class TarFile(object):
    

    debug = 0                   # May be set from 0 (no msgs) to 3 (all msgs)

    dereference = False         # If true, add content of linked file to the
                                # tar file, else the link.

    ignore_zeros = False        # If true, skips empty or invalid blocks and
                                # continues processing.

    errorlevel = 0              # If 0, fatal errors only appear in debug
                                # messages (if debug >= 0). If > 0, errors
                                # are passed to the caller as exceptions.

    posix = True                # If True, generates POSIX.1-1990-compliant
                                # archives (no GNU extensions!)

    fileobject = ExFileObject

    def __init__(self, name=None, mode="r", fileobj=None):
        
        self.name = name

        if len(mode) > 1 or mode not in "raw":
            raise ValueError, "mode must be 'r', 'a' or 'w'"
        self._mode = mode
        self.mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode]

        if not fileobj:
            fileobj = file(self.name, self.mode)
            self._extfileobj = False
        else:
            if self.name is None and hasattr(fileobj, "name"):
                self.name = fileobj.name
            if hasattr(fileobj, "mode"):
                self.mode = fileobj.mode
            self._extfileobj = True
        self.fileobj = fileobj

        # Init datastructures
        self.closed      = False
        self.members     = []       # list of members as TarInfo objects
        self.membernames = []       # names of members
        self.chunks      = [0]      # chunk cache
        self._loaded     = False    # flag if all members have been read
        self.offset      = 0L       # current position in the archive file
        self.inodes      = {}       # dictionary caching the inodes of
                                    # archive members already added

        if self._mode == "r":
            self.firstmember = None
            self.firstmember = self.next()

        if self._mode == "a":
            # Move to the end of the archive,
            # before the first empty block.
            self.firstmember = None
            while True:
                try:
                    tarinfo = self.next()
                except ReadError:
                    self.fileobj.seek(0)
                    break
                if tarinfo is None:
                    self.fileobj.seek(- BLOCKSIZE, 1)
                    break

        if self._mode in "aw":
            self._loaded = True

    #--------------------------------------------------------------------------
    # Below are the classmethods which act as alternate constructors to the
    # TarFile class. The open() method is the only one that is needed for
    # public use; it is the "super"-constructor and is able to select an
    # adequate "sub"-constructor for a particular compression using the mapping
    # from OPEN_METH.
    #
    # This concept allows one to subclass TarFile without losing the comfort of
    # the super-constructor. A sub-constructor is registered and made available
    # by adding it to the mapping in OPEN_METH.

    def open(cls, name=None, mode="r", fileobj=None, bufsize=20*512):
        

        if not name and not fileobj:
            raise ValueError, "nothing to open"

        if mode in ("r", "r:*"):
            # Find out which *open() is appropriate for opening the file.
            for comptype in cls.OPEN_METH:
                func = getattr(cls, cls.OPEN_METH[comptype])
                try:
                    return func(name, "r", fileobj)
                except (ReadError, CompressionError):
                    continue
            raise ReadError, "file could not be opened successfully"

        elif ":" in mode:
            filemode, comptype = mode.split(":", 1)
            filemode = filemode or "r"
            comptype = comptype or "tar"

            # Select the *open() function according to
            # given compression.
            if comptype in cls.OPEN_METH:
                func = getattr(cls, cls.OPEN_METH[comptype])
            else:
                raise CompressionError, "unknown compression type %r" % comptype
            return func(name, filemode, fileobj)

        elif "|" in mode:
            filemode, comptype = mode.split("|", 1)
            filemode = filemode or "r"
            comptype = comptype or "tar"

            if filemode not in "rw":
                raise ValueError, "mode must be 'r' or 'w'"

            t = cls(name, filemode,
                    _Stream(name, filemode, comptype, fileobj, bufsize))
            t._extfileobj = False
            return t

        elif mode in "aw":
            return cls.taropen(name, mode, fileobj)

        raise ValueError, "undiscernible mode"

    open = classmethod(open)

    def taropen(cls, name, mode="r", fileobj=None):
        
        if len(mode) > 1 or mode not in "raw":
            raise ValueError, "mode must be 'r', 'a' or 'w'"
        return cls(name, mode, fileobj)

    taropen = classmethod(taropen)

    def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9):
        
        if len(mode) > 1 or mode not in "rw":
            raise ValueError, "mode must be 'r' or 'w'"

        try:
            import gzip
        except ImportError:
            raise CompressionError, "gzip module is not available"

        pre, ext = os.path.splitext(name)
        pre = os.path.basename(pre)
        if ext == ".tgz":
            ext = ".tar"
        if ext == ".gz":
            ext = ""
        tarname = pre + ext

        if fileobj is None:
            fileobj = file(name, mode + "b")

        if mode != "r":
            name = tarname

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?