예제 #1
0
def _collect_infos(dirname):
    """ Utility function used by ExplodedZipFile to generate ZipInfo
    entries for all of the files and directories under dirname """

    for r, _ds, fs in walk(dirname):
        if not islink(r) and r != dirname:
            i = ZipInfo()
            i.filename = join(relpath(r, dirname), "")
            i.file_size = 0
            i.compress_size = 0
            i.CRC = 0
            yield i.filename, i

        for f in fs:
            df = join(r, f)
            relfn = relpath(join(r, f), dirname)

            if islink(df):
                pass

            elif isfile(df):
                i = ZipInfo()
                i.filename = relfn
                i.file_size = getsize(df)
                i.compress_size = i.file_size
                i.CRC = file_crc32(df)
                yield i.filename, i

            else:
                # TODO: is there any more special treatment?
                pass
예제 #2
0
def _collect_infos(dirname):

    """ Utility function used by ExplodedZipFile to generate ZipInfo
    entries for all of the files and directories under dirname """

    for r, _ds, fs in walk(dirname):
        if not islink(r) and r != dirname:
            i = ZipInfo()
            i.filename = join(relpath(r, dirname), "")
            i.file_size = 0
            i.compress_size = 0
            i.CRC = 0
            yield i.filename, i

        for f in fs:
            df = join(r, f)
            relfn = relpath(join(r, f), dirname)

            if islink(df):
                pass

            elif isfile(df):
                i = ZipInfo()
                i.filename = relfn
                i.file_size = getsize(df)
                i.compress_size = i.file_size
                i.CRC = file_crc32(df)
                yield i.filename, i

            else:
                # TODO: is there any more special treatment?
                pass
예제 #3
0
def create_zipinfo(filename, mtime=None, dir=False, executable=False, symlink=False,
                   comment=None):
    """Create a instance of `ZipInfo`.

    :param filename: file name of the entry
    :param mtime: modified time of the entry
    :param dir: if `True`, the entry is a directory
    :param executable: if `True`, the entry is a executable file
    :param symlink: if `True`, the entry is a symbolic link
    :param comment: comment of the entry
    """
    from zipfile import ZipInfo, ZIP_DEFLATED, ZIP_STORED
    zipinfo = ZipInfo()

    # The general purpose bit flag 11 is used to denote
    # UTF-8 encoding for path and comment. Only set it for
    # non-ascii files for increased portability.
    # See http://www.pkware.com/documents/casestudies/APPNOTE.TXT
    if any(ord(c) >= 128 for c in filename):
        zipinfo.flag_bits |= 0x0800
    zipinfo.filename = filename.encode('utf-8')

    if mtime is not None:
        mtime = to_datetime(mtime, utc)
        zipinfo.date_time = mtime.utctimetuple()[:6]
        # The "extended-timestamp" extra field is used for the
        # modified time of the entry in unix time. It avoids
        # extracting wrong modified time if non-GMT timezone.
        # See http://www.opensource.apple.com/source/zip/zip-6/unzip/unzip
        #     /proginfo/extra.fld
        zipinfo.extra += struct.pack(
            '<hhBl',
            0x5455,                 # extended-timestamp extra block type
            1 + 4,                  # size of this block
            1,                      # modification time is present
            to_timestamp(mtime))    # time of last modification

    # external_attr is 4 bytes in size. The high order two
    # bytes represent UNIX permission and file type bits,
    # while the low order two contain MS-DOS FAT file
    # attributes, most notably bit 4 marking directories.
    if dir:
        if not zipinfo.filename.endswith('/'):
            zipinfo.filename += '/'
        zipinfo.compress_type = ZIP_STORED
        zipinfo.external_attr = 040755 << 16L        # permissions drwxr-xr-x
        zipinfo.external_attr |= 0x10                # MS-DOS directory flag
    else:
        zipinfo.compress_type = ZIP_DEFLATED
        zipinfo.external_attr = 0644 << 16L          # permissions -r-wr--r--
        if executable:
            zipinfo.external_attr |= 0755 << 16L     # -rwxr-xr-x
        if symlink:
            zipinfo.compress_type = ZIP_STORED
            zipinfo.external_attr |= 0120000 << 16L  # symlink file type

    if comment:
        zipinfo.comment = comment.encode('utf-8')

    return zipinfo
예제 #4
0
def create_zipinfo(filename, mtime=None, dir=False, executable=False, symlink=False,
                   comment=None):
    """Create a instance of `ZipInfo`.

    :param filename: file name of the entry
    :param mtime: modified time of the entry
    :param dir: if `True`, the entry is a directory
    :param executable: if `True`, the entry is a executable file
    :param symlink: if `True`, the entry is a symbolic link
    :param comment: comment of the entry
    """
    from zipfile import ZipInfo, ZIP_DEFLATED, ZIP_STORED
    zipinfo = ZipInfo()

    # The general purpose bit flag 11 is used to denote
    # UTF-8 encoding for path and comment. Only set it for
    # non-ascii files for increased portability.
    # See http://www.pkware.com/documents/casestudies/APPNOTE.TXT
    if any(ord(c) >= 128 for c in filename):
        zipinfo.flag_bits |= 0x0800
    zipinfo.filename = filename.encode('utf-8')

    if mtime is not None:
        mtime = to_datetime(mtime, utc)
        zipinfo.date_time = mtime.utctimetuple()[:6]
        # The "extended-timestamp" extra field is used for the
        # modified time of the entry in unix time. It avoids
        # extracting wrong modified time if non-GMT timezone.
        # See http://www.opensource.apple.com/source/zip/zip-6/unzip/unzip
        #     /proginfo/extra.fld
        zipinfo.extra += struct.pack(
            '<hhBl',
            0x5455,                 # extended-timestamp extra block type
            1 + 4,                  # size of this block
            1,                      # modification time is present
            to_timestamp(mtime))    # time of last modification

    # external_attr is 4 bytes in size. The high order two
    # bytes represent UNIX permission and file type bits,
    # while the low order two contain MS-DOS FAT file
    # attributes, most notably bit 4 marking directories.
    if dir:
        if not zipinfo.filename.endswith('/'):
            zipinfo.filename += '/'
        zipinfo.compress_type = ZIP_STORED
        zipinfo.external_attr = 040755 << 16L       # permissions drwxr-xr-x
        zipinfo.external_attr |= 0x10               # MS-DOS directory flag
    else:
        zipinfo.compress_type = ZIP_DEFLATED
        zipinfo.external_attr = 0644 << 16L         # permissions -r-wr--r--
        if executable:
            zipinfo.external_attr |= 0755 << 16L    # -rwxr-xr-x
        if symlink:
            zipinfo.compress_type = ZIP_STORED
            zipinfo.external_attr |= 0120000 << 16L # symlink file type

    if comment:
        zipinfo.comment = comment.encode('utf-8')

    return zipinfo
예제 #5
0
    def _render_zip(self, req, filename, repos, data):
        """ZIP archive with all the added and/or modified files."""
        new_rev = data['new_rev']
        req.send_response(200)
        req.send_header('Content-Type', 'application/zip')
        req.send_header('Content-Disposition',
                        content_disposition('inline', filename + '.zip'))

        from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED

        buf = StringIO()
        zipfile = ZipFile(buf, 'w', ZIP_DEFLATED)
        for old_node, new_node, kind, change in repos.get_changes(
            new_path=data['new_path'], new_rev=data['new_rev'],
            old_path=data['old_path'], old_rev=data['old_rev']):
            if kind == Node.FILE and change != Changeset.DELETE:
                assert new_node
                zipinfo = ZipInfo()
                zipinfo.filename = new_node.path.strip('/').encode('utf-8')
                # Note: unicode filenames are not supported by zipfile.
                # UTF-8 is not supported by all Zip tools either,
                # but as some do, I think UTF-8 is the best option here.
                zipinfo.date_time = new_node.last_modified.utctimetuple()[:6]
                zipinfo.external_attr = 0644 << 16L # needed since Python 2.5
                zipinfo.compress_type = ZIP_DEFLATED
                zipfile.writestr(zipinfo, new_node.get_content().read())
        zipfile.close()

        zip_str = buf.getvalue()
        req.send_header("Content-Length", len(zip_str))
        req.end_headers()
        req.write(zip_str)
        raise RequestDone
예제 #6
0
 def _add_path(self, path, version, myzip):
     mtime = os.path.getmtime(path)
     info = ZipInfo("versions/%d/%s" % (version, path),
                    Archive.unixtime_to_utcziptime(mtime))
     info.create_system = 3
     info.extra += struct.pack('<HHBl', 0x5455, 5, 1, int(mtime))
     # http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute
     # make mode without file type, which may be system-specific
     clean_mode = os.stat(path).st_mode & 0o007777
     if (os.path.islink(path)):
         # set zip file type to link
         info.external_attr = (Archive.ZIP_EXT_ATTR_LINK | clean_mode) << 16
         myzip.writestr(info, os.readlink(path))
     elif (os.path.isdir(path)):
         # set zip file type to dir
         info.external_attr = (Archive.ZIP_EXT_ATTR_DIR | clean_mode) << 16
         # dos directory flag
         info.external_attr |= 0x10
         # it seems we should have a trailing slash for dirs
         if not (info.filename.endswith('/')):
             info.filename = "%s/" % (info.filename)
         myzip.writestr(info, '')
         for name in os.listdir(path):
             self._add_path(os.path.join(path, name), version, myzip)
     elif (os.path.isfile(path)):
         info.external_attr = (Archive.ZIP_EXT_ATTR_FILE | clean_mode) << 16
         myzip.writestr(info, open(path, 'rb').read())
     else:
         raise Exception()
예제 #7
0
    def _render_zip(self, req, repos, chgset):
        """ZIP archive with all the added and/or modified files."""
        req.send_response(200)
        req.send_header('Content-Type', 'application/zip')
        req.send_header('Content-Disposition', 'attachment;'
                        'filename=Changeset%s.zip' % chgset.rev)
        req.end_headers()

        try:
            from cStringIO import StringIO
        except ImportError:
            from StringIO import StringIO
        from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED

        buf = StringIO()
        zipfile = ZipFile(buf, 'w', ZIP_DEFLATED)
        for path, kind, change, base_path, base_rev in chgset.get_changes():
            if kind == Node.FILE and change != Changeset.DELETE:
                node = repos.get_node(path, chgset.rev)
                zipinfo = ZipInfo()
                zipinfo.filename = node.path
                zipinfo.date_time = time.gmtime(node.last_modified)[:6]
                zipinfo.compress_type = ZIP_DEFLATED
                zipfile.writestr(zipinfo, node.get_content().read())
        zipfile.close()
        req.write(buf.getvalue())
예제 #8
0
 def _add_path(self, path, version, myzip):
     mtime = os.path.getmtime(path)
     info = ZipInfo("versions/%d/%s"%(version, path), Archive.unixtime_to_utcziptime(mtime))
     info.create_system = 3
     info.extra += struct.pack('<HHBl', 0x5455, 5, 1, mtime)
     # http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute
     # make mode without file type, which may be system-specific
     clean_mode = os.stat(path).st_mode & 0007777
     if (os.path.islink(path)):
         # set zip file type to link
         info.external_attr = (Archive.ZIP_EXT_ATTR_LINK | clean_mode) << 16L
         myzip.writestr(info, os.readlink(path))
     elif (os.path.isdir(path)):
         # set zip file type to dir 
         info.external_attr = (Archive.ZIP_EXT_ATTR_DIR | clean_mode) << 16L
         # dos directory flag
         info.external_attr |= 0x10
         # it seems we should have a trailing slash for dirs
         if not(info.filename.endswith('/')): info.filename = "%s/"%(info.filename)
         myzip.writestr(info, '')
         for name in os.listdir(path):
             self._add_path(os.path.join(path, name), version, myzip)
     elif (os.path.isfile(path)):
         info.external_attr = (Archive.ZIP_EXT_ATTR_FILE | clean_mode) << 16L
         myzip.writestr(info, open(path).read())
     else:
         raise Exception()
예제 #9
0
    def _render_zip(self, req, repos, chgset):
        """ZIP archive with all the added and/or modified files."""
        req.send_response(200)
        req.send_header('Content-Type', 'application/zip')
        req.send_header('Content-Disposition',
                        'filename=Changeset%s.zip' % chgset.rev)
        req.end_headers()

        try:
            from cStringIO import StringIO
        except ImportError:
            from StringIO import StringIO
        from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED

        buf = StringIO()
        zipfile = ZipFile(buf, 'w', ZIP_DEFLATED)
        for path, kind, change, base_path, base_rev in chgset.get_changes():
            if kind == Node.FILE and change != Changeset.DELETE:
                node = repos.get_node(path, chgset.rev)
                zipinfo = ZipInfo()
                zipinfo.filename = node.path
                zipinfo.date_time = time.gmtime(node.last_modified)[:6]
                zipinfo.compress_type = ZIP_DEFLATED
                zipfile.writestr(zipinfo, node.get_content().read())
        zipfile.close()
        req.write(buf.getvalue())
예제 #10
0
파일: changeset.py 프로젝트: yeoupooh/tow
    def _render_zip(self, req, filename, repos, diff):
        """ZIP archive with all the added and/or modified files."""
        new_rev = diff.new_rev
        req.send_response(200)
        req.send_header('Content-Type', 'application/zip')
        req.send_header('Content-Disposition', 'attachment;'
                        'filename=%s.zip' % filename)

        from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED

        buf = StringIO()
        zipfile = ZipFile(buf, 'w', ZIP_DEFLATED)
        for old_node, new_node, kind, change in repos.get_changes(**diff):
            if kind == Node.FILE and change != Changeset.DELETE:
                assert new_node
                zipinfo = ZipInfo()
                zipinfo.filename = new_node.path.encode('utf-8')
                # Note: unicode filenames are not supported by zipfile.
                # UTF-8 is not supported by all Zip tools either,
                # but as some does, I think UTF-8 is the best option here.
                zipinfo.date_time = time.gmtime(new_node.last_modified)[:6]
                zipinfo.compress_type = ZIP_DEFLATED
                zipfile.writestr(zipinfo, new_node.get_content().read())
        zipfile.close()

        buf.seek(0, 2) # be sure to be at the end
        req.send_header("Content-Length", buf.tell())
        req.end_headers()

        req.write(buf.getvalue())
예제 #11
0
    def _render_zip(self, req, filename, repos, diff):
        """ZIP archive with all the added and/or modified files."""
        new_rev = diff.new_rev
        req.send_response(200)
        req.send_header('Content-Type', 'application/zip')
        req.send_header('Content-Disposition', 'attachment;'
                        'filename=%s.zip' % filename)

        from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED

        buf = StringIO()
        zipfile = ZipFile(buf, 'w', ZIP_DEFLATED)
        for old_node, new_node, kind, change in repos.get_changes(**diff):
            if kind == Node.FILE and change != Changeset.DELETE:
                assert new_node
                zipinfo = ZipInfo()
                zipinfo.filename = new_node.path.encode('utf-8')
                # Note: unicode filenames are not supported by zipfile.
                # UTF-8 is not supported by all Zip tools either,
                # but as some does, I think UTF-8 is the best option here.
                zipinfo.date_time = time.gmtime(new_node.last_modified)[:6]
                zipinfo.compress_type = ZIP_DEFLATED
                zipfile.writestr(zipinfo, new_node.get_content().read())
        zipfile.close()

        buf.seek(0, 2) # be sure to be at the end
        req.send_header("Content-Length", buf.tell())
        req.end_headers()

        req.write(buf.getvalue())
def zipadd(zipfile, data, fname):
    zinfo = ZipInfo()
    zinfo.filename = fname
    tlocal = time.localtime()
    zinfo.date_time = (tlocal[0], tlocal[1] + 1, tlocal[2] + 1, tlocal[3],
                       tlocal[4], tlocal[5])
    zinfo.compress_type = ZIP_DEFLATED
    zinfo.external_attr = 0o664 << 16
    zipfile.writestr(zinfo, data)
예제 #13
0
 def _extract_file(self, member: ZipInfo, dst_path: Path, zf: ZipFile):
     full_dst_path = self.dir / dst_path
     if full_dst_path.is_dir():
         raise ValueError(
             f"Cannot extract {dst_path}: a directory by that name exists"
         )
     if self.overwrite or not full_dst_path.is_file():
         member.filename = _zip_name(dst_path)
         zf.extract(member, self.dir)
     else:
         with zf.open(member, "r") as f:
             self._write_file(dst_path, f)
예제 #14
0
def _add_file_to_zip(zipfile, path, archive_dest=None):
    with open(path, 'r') as f:
        file_bytes = f.read()
        info = ZipInfo(path)
        info.date_time = time.localtime()
        # Set permissions to be executable
        info.external_attr = 0o100755 << 16

        # If archive dest was provided, use that as path
        if archive_dest:
            info.filename = archive_dest

        zipfile.writestr(info, file_bytes, ZIP_DEFLATED)
예제 #15
0
파일: ziplib.py 프로젝트: wflk/canarytokens
def make_dir_entry(name=None, date_time=None, mode=MODE_DIRECTORY):
    tt = date_time.timetuple()
    dir = ZipInfo()

    dir.filename        = name+('/' if name[-1] != '/' else '')
    dir.orig_filename   = dir.filename
    dir.date_time        = date_time.isocalendar() + (tt.tm_hour,
                                                tt.tm_min, tt.tm_sec)
    dir.compress_type   = 0
    dir.create_system   = 0
    dir.create_version  = 20
    dir.extract_version = 10
    dir.external_attr   = mode

    return dir
예제 #16
0
파일: ziplib.py 프로젝트: wflk/canarytokens
def make_file_entry(name=None, date_time=None, mode=MODE_FILE | MODE_ARCHIVE):
    tt = date_time.timetuple()
    file = ZipInfo()

    file.filename        = name
    file.orig_filename   = file.filename
    file.date_time        = date_time.isocalendar() + (tt.tm_hour,
                                                tt.tm_min, tt.tm_sec)
    file.compress_type   = 8
    file.create_system   = 0
    file.create_version  = 20
    file.extract_version = 20
    file.flag_bits       = 2
    file.external_attr   = mode

    return file
예제 #17
0
def zipinfo_fixup_filename(inf: zipfile.ZipInfo):
    # Support UTF-8 filenames using extra fields
    # Code from https://github.com/python/cpython/pull/23736
    extra = inf.extra
    unpack = struct.unpack

    while len(extra) >= 4:
        type_, length = struct.unpack("<HH", extra[:4])
        if length + 4 > len(extra):
            raise zipfile.BadZipFile(
                f"Corrupt extra field {type_:04x} (size={length})")

        if type_ == 0x7075:
            data = extra[4:length + 4]
            # Unicode Path Extra Field
            up_version, _up_name_crc = unpack("<BL", data[:5])
            up_unicode_name = data[5:].decode("utf-8")
            if up_version == 1:
                inf.filename = up_unicode_name

        extra = extra[length + 4:]
예제 #18
0
    def add_str(self, str_to_add, name, dt=datetime.now()):
        # type: (str,str,datetime) -> None
        """
        Add a string to the archive as zip entry named 'name'
        :param str_to_add: string to add
        :param name: name of the zip.entry
        :param dt: datetime, optional if not specified, current date time is assumed
        :return: None
        """

        # always use forward slash regardless of platform, this allows the calling
        # code to use os.path.join for names
        if os.pathsep in name:
            name = name.replace(os.pathsep, "/")

        info = ZipInfo()
        info.filename = self.uuid + "/" + name
        info.external_attr = 0o644 << 16
        info.compress_type = ZIP_DEFLATED
        info.date_time = (dt.year, dt.month, dt.day, dt.hour, dt.minute,
                          dt.second)
        self.zip.writestr(info, str_to_add)
예제 #19
0
        def zip_writer(dirpath, zippath):
            basedir = os.path.dirname(dirpath) + os.sep
            entry = ZipInfo()
            entry.compress_type = compression

            if os.path.isdir(dirpath):
                for root, dirs, files in os.walk(dirpath):
                    if os.path.basename(root).startswith('.'):
                        # skip hidden directories
                        continue
                    dirname = root.replace(basedir, '')
                    for f in files:
                        if f[-1] == '~' or f.startswith('.'):
                            # skip backup files and all hidden files
                            continue
                        src = root + '/' + f
                        entry = ZipInfo()
                        entry.compress_type = compression
                        entry.filename = dirname + '/' + f
                        entry.date_time = localtime(os.path.getmtime(src))[:6]

                        # hacky
                        if dirname.startswith("html"):
                            if self.source == True:
                                entry.filename = dirname.replace('html', 'doc', 1) + "/" + f
                            else:
                                entry.filename = dirname.replace('html/', '', 1) + "/" + f
                                entry.filename = entry.filename.replace('html/', '', 1)
                        if entry.filename.startswith("examples"):
                            entry.filename = "tutorials/" + entry.filename

                        file_data = open( src, 'rb').read()
                        self.package.writestr(entry, file_data)
            else:
                # top files
                entry.date_time = localtime(os.path.getmtime(dirpath))[:6]
                entry.filename = os.path.basename(zippath)
                file_data = open( dirpath, 'rb').read()
                self.package.writestr(entry, file_data)
예제 #20
0
    def _RealGetContents(self):
        """Read in the table of contents for the ZIP file."""
        try:
            endrec = _EndRecData(self.url)
        except IOError:
            raise BadZipfile("File is not a zip file")
        if not endrec:
            raise BadZipfile, "File is not a zip file"
        if self.debug > 1:
            print endrec
        size_cd = endrec[_ECD_SIZE]  # bytes in central directory
        offset_cd = endrec[_ECD_OFFSET]  # offset of central directory
        self.comment = endrec[_ECD_COMMENT]  # archive comment

        # "concat" is zero, unless zip was concatenated to another file
        concat = endrec[_ECD_LOCATION] - size_cd - offset_cd
        # if endrec[_ECD_SIGNATURE] == stringEndArchive64:
        #   # If Zip64 extension structures are present, account for them
        #   concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator)

        if self.debug > 2:
            inferred = concat + offset_cd
            print "given, inferred, offset", offset_cd, inferred, concat
            # self.start_dir:  Position of start of central directory
        self.start_dir = offset_cd + concat
        ECD = _http_get_partial_data(self.url, self.start_dir, self.start_dir + size_cd - 1)
        data = ECD.read()
        ECD.close()
        fp = cStringIO.StringIO(data)
        total = 0
        while total < size_cd:
            centdir = fp.read(sizeCentralDir)
            if centdir[0:4] != stringCentralDir:
                raise BadZipfile, "Bad magic number for central directory"
            centdir = struct.unpack(structCentralDir, centdir)
            if self.debug > 2:
                print centdir
            filename = fp.read(centdir[_CD_FILENAME_LENGTH])
            # Create ZipInfo instance to store file information
            x = ZipInfo(filename)
            x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH])
            x.comment = fp.read(centdir[_CD_COMMENT_LENGTH])
            x.header_offset = centdir[_CD_LOCAL_HEADER_OFFSET]
            (
                x.create_version,
                x.create_system,
                x.extract_version,
                x.reserved,
                x.flag_bits,
                x.compress_type,
                t,
                d,
                x.CRC,
                x.compress_size,
                x.file_size,
            ) = centdir[1:12]
            x.volume, x.internal_attr, x.external_attr = centdir[15:18]
            # Convert date/time code to (year, month, day, hour, min, sec)
            x._raw_time = t
            x.date_time = ((d >> 9) + 1980, (d >> 5) & 0xF, d & 0x1F, t >> 11, (t >> 5) & 0x3F, (t & 0x1F) * 2)

            x._decodeExtra()
            x.header_offset = x.header_offset + concat
            x.filename = x._decodeFilename()
            self.filelist.append(x)
            self.NameToInfo[x.filename] = x

            # update total bytes read from central directory
            total = (
                total
                + sizeCentralDir
                + centdir[_CD_FILENAME_LENGTH]
                + centdir[_CD_EXTRA_FIELD_LENGTH]
                + centdir[_CD_COMMENT_LENGTH]
            )

        if self.debug > 2:
            print "total", total
예제 #21
0
def _rename(info: zipfile.ZipInfo) -> None:
    """ヘルパー: `ZipInfo` のファイル名を SJIS でデコードし直す"""
    LANG_ENC_FLAG = 0x800
    encoding = 'utf-8' if info.flag_bits & LANG_ENC_FLAG else 'cp437'
    info.filename = info.filename.encode(encoding).decode('cp932')