1
0
mirror of https://github.com/openSUSE/osc.git synced 2026-01-29 09:13:02 +01:00

rebase ar.py with master

This commit is contained in:
lethliel
2019-02-08 11:02:02 +01:00
parent a8450e4355
commit 34988232b4

View File

@@ -20,14 +20,8 @@ import re
import sys
import stat
#XXX: python 2.7 contains io.StringIO, which needs unicode instead of str
#therefor try to import old stuff before new one here
try:
from StringIO import StringIO as MyIO
except ImportError:
from io import BytesIO as MyIO
from io import BytesIO
from osc.util.helper import decode_it
# workaround for python24
if not hasattr(os, 'SEEK_SET'):
@@ -50,6 +44,9 @@ class ArHdr:
self.date = date.strip()
self.uid = uid.strip()
self.gid = gid.strip()
if not mode.strip():
# provide a dummy mode for the ext_fn hdr
mode = '0'
self.mode = stat.S_IMODE(int(mode, 8))
self.size = int(size)
self.fmag = fmag
@@ -59,10 +56,10 @@ class ArHdr:
def __str__(self):
return '%16s %d' % (self.file, self.size)
class ArFile(MyIO):
class ArFile(BytesIO):
"""Represents a file which resides in the archive"""
def __init__(self, fn, uid, gid, mode, buf):
MyIO.__init__(self, buf)
BytesIO.__init__(self, buf)
self.name = fn
self.uid = uid
self.gid = gid
@@ -77,9 +74,8 @@ class ArFile(MyIO):
if not dir:
dir = os.getcwd()
fn = os.path.join(dir, self.name)
f = open(fn, 'wb')
f.write(self.getvalue())
f.close()
with open(fn, 'wb') as f:
f.write(self.getvalue())
os.chmod(fn, self.mode)
uid = self.uid
if uid != os.geteuid() or os.geteuid() != 0:
@@ -99,11 +95,12 @@ class Ar:
Readonly access.
"""
hdr_len = 60
hdr_pat = re.compile('^(.{16})(.{12})(.{6})(.{6})(.{8})(.{10})(.{2})', re.DOTALL)
hdr_pat = re.compile(b'^(.{16})(.{12})(.{6})(.{6})(.{8})(.{10})(.{2})',
re.DOTALL)
def __init__(self, fn = None, fh = None):
if fn == None and fh == None:
raise ArError('either \'fn\' or \'fh\' must be != None')
raise ValueError('either \'fn\' or \'fh\' must be != None')
if fh != None:
self.__file = fh
self.__closefile = False
@@ -125,7 +122,7 @@ class Ar:
def _appendHdr(self, hdr):
# GNU uses an internal '//' file to store very long filenames
if hdr.file.startswith('//'):
if hdr.file.startswith(b'//'):
self.ext_fnhdr = hdr
else:
self.hdrs.append(hdr)
@@ -139,11 +136,11 @@ class Ar:
Another special file is the '/' which contains the symbol lookup table.
"""
for h in self.hdrs:
if h.file == '/':
if h.file == b'/':
continue
# remove slashes which are appended by ar
h.file = h.file.rstrip('/')
if not h.file.startswith('/'):
h.file = h.file.rstrip(b'/')
if not h.file.startswith(b'/'):
continue
# handle long filename
off = int(h.file[1:len(h.file)])
@@ -152,11 +149,11 @@ class Ar:
# XXX: is it safe to read all the data in one chunk? I assume the '//' data section
# won't be too large
data = self.__file.read(self.ext_fnhdr.size)
end = data.find('/')
end = data.find(b'/')
if end != -1:
h.file = data[0:end]
else:
raise ArError('//', 'invalid data section - trailing slash (off: %d)' % start)
raise ArError(b'//', 'invalid data section - trailing slash (off: %d)' % start)
def _get_file(self, hdr):
self.__file.seek(hdr.dataoff, os.SEEK_SET)
@@ -164,20 +161,9 @@ class Ar:
self.__file.read(hdr.size))
def read(self):
"""reads in the archive. It tries to use mmap due to performance reasons (in case of large files)"""
"""reads in the archive."""
if not self.__file:
import mmap
self.__file = open(self.filename, 'rb')
try:
if sys.platform[:3] != 'win':
self.__file = mmap.mmap(self.__file.fileno(), os.path.getsize(self.__file.name), prot=mmap.PROT_READ)
else:
self.__file = mmap.mmap(self.__file.fileno(), os.path.getsize(self.__file.name))
except EnvironmentError as e:
if e.errno == 19 or ( hasattr(e, 'winerror') and e.winerror == 5 ):
print('cannot use mmap to read the file, falling back to the default io', file=sys.stderr)
else:
raise e
else:
self.__file.seek(0, os.SEEK_SET)
self._init_datastructs()
@@ -191,7 +177,7 @@ class Ar:
if not data:
break
pos += self.hdr_len
m = self.hdr_pat.search(decode_it(data))
m = self.hdr_pat.search(data)
if not m:
raise ArError(self.filename, 'unexpected hdr entry')
args = m.groups() + (pos, )
@@ -210,7 +196,19 @@ class Ar:
def __iter__(self):
for h in self.hdrs:
if h.file == '/':
if h.file == b'/':
continue
yield self._get_file(h)
raise StopIteration()
if __name__ == '__main__':
if len(sys.argv) != 2:
print('usage: %s <arfile>' % sys.argv[0])
sys.exit(1)
# a potential user might want to pass a bytes instead of a str
# to make sure that the ArError's file attribute is always a
# bytes
ar = Ar(fn=sys.argv[1])
ar.read()
for hdr in ar.hdrs:
print(hdr)