Update uadf to support py3

This commit is contained in:
2019-06-30 16:53:16 +02:00
parent 2e50401a18
commit 6b8684b1d7

74
uadf
View File

@@ -1,11 +1,11 @@
#! /usr/bin/env python #!/usr/bin/env python3
""" """
UADF Virtual filesystem UADF Virtual filesystem
This extfs provides quick and dirty read-only access to disk image files for This extfs provides quick and dirty read-only access to disk image files for
the Commodore Amiga adf or adz (gzipped adfs) and dms. the Commodore Amiga adf or adz (gzipped adfs) and dms.
It requires the unadf utility (unfortunately there is no original sources, It requires the unadf utility, unfortunately there is no original sources,
since authors page doesn't exists anymore. Luckily, there is a copy of the since authors page doesn't exists anymore. Luckily, there is a copy of the
source (and useful patches) in Debian repository: source (and useful patches) in Debian repository:
http://packages.debian.org/sid/unadf http://packages.debian.org/sid/unadf
@@ -15,16 +15,19 @@ There should be one change made to the source of unadf, though. While using
However there is no way to distinguish where filename ends and comment starts, However there is no way to distinguish where filename ends and comment starts,
if comment or filename already contains any comma. if comment or filename already contains any comma.
The patched sources are available from: https://github.com/lclevy/ADFlib
It also requires xdms utility, for optional dms support. It also requires xdms utility, for optional dms support.
Changelog: Changelog:
1.3 Switch to Python3
1.2 Added failsafe for filenames in archive with spaces and nodos message. 1.2 Added failsafe for filenames in archive with spaces and nodos message.
1.1 Moved common code into extfslib library 1.1 Moved common code into extfslib library
1.0 Initial release 1.0 Initial release
Author: Roman 'gryf' Dobosz <gryf73@gmail.com> Author: Roman 'gryf' Dobosz <gryf73@gmail.com>
Date: 2013-05-16 Date: 2019-06-30
Version: 1.2 Version: 1.3
Licence: BSD Licence: BSD
""" """
@@ -43,17 +46,17 @@ class UAdf(Archive):
""" """
Class for interact with c1541 program and MC Class for interact with c1541 program and MC
""" """
LINE_PAT = re.compile('\s*(?P<size>\d+)?' LINE_PAT = re.compile(b'\s*(?P<size>\d+)?'
'\s{2}(?P<date>\d{4}/\d{2}/\d{2})' b'\s{2}(?P<date>\d{4}/\d{2}/\d{2})'
'\s{2}\s?(?P<time>\d+:\d{2}:\d{2})' b'\s{2}\s?(?P<time>\d+:\d{2}:\d{2})'
'\s{2}(?P<fpath>.*)') b'\s{2}(?P<fpath>.*)')
ARCHIVER = "unadf" ARCHIVER = b"unadf"
DMS = "xdms" DMS = b"xdms"
CMDS = {"list": "-lr", CMDS = {"list": b"-lr",
"read": "r", "read": b"r",
"write": "w", "write": b"w",
"delete": "d"} "delete": b"d"}
DATETIME = "%s-%s-%s %02d:%s" DATETIME = b"%s-%s-%s %02d:%s"
def __init__(self, fname): def __init__(self, fname):
"""Prepare archive content for operations""" """Prepare archive content for operations"""
@@ -78,8 +81,8 @@ class UAdf(Archive):
def _parse_dt(self, date, time): def _parse_dt(self, date, time):
"""Return parsed datetime which fulfill extfs standards date.""" """Return parsed datetime which fulfill extfs standards date."""
year, month, day = date.split("/") year, month, day = date.split(b"/")
hours, minutes, _unused = time.split(":") hours, minutes, _unused = time.split(b":")
return self.DATETIME % (month, day, year, int(hours), minutes) return self.DATETIME % (month, day, year, int(hours), minutes)
def _ungzip(self): def _ungzip(self):
@@ -100,7 +103,7 @@ class UAdf(Archive):
os.close(fdesc) os.close(fdesc)
try: try:
check_call([self.DMS, '-q', 'u', self._arch, "+" + tmp_fname]) check_call([self.DMS, b'-q', b'u', self._arch, "+" + tmp_fname])
self._arch = tmp_fname self._arch = tmp_fname
self._clean = False self._clean = False
except (CalledProcessError, OSError): except (CalledProcessError, OSError):
@@ -116,20 +119,25 @@ class UAdf(Archive):
except CalledProcessError: except CalledProcessError:
return contents return contents
for line in out.split("\n"): for line in out.split(b"\n"):
match = self.LINE_PAT.match(line) match = self.LINE_PAT.match(line)
if not match: if not match:
continue continue
entry = match.groupdict() match_entry = match.groupdict()
entry['perms'] = "-rw-r--r--" entry = {}
if not entry['size']: for key in match_entry:
entry['perms'] = "drwxr-xr-x" entry[bytes(key, 'utf-8')] = match_entry[key]
entry['size'] = "0" del match_entry
entry['display_name'] = self._map_name(entry['fpath'])
entry['datetime'] = self._parse_dt(entry['date'], entry['time']) entry[b'perms'] = b"-rw-r--r--"
entry['uid'] = self._uid if not entry[b'size']:
entry['gid'] = self._gid entry[b'perms'] = b"drwxr-xr-x"
entry[b'size'] = b"0"
entry[b'display_name'] = self._map_name(entry[b'fpath'])
entry[b'datetime'] = self._parse_dt(entry[b'date'], entry[b'time'])
entry[b'uid'] = bytes(str(self._uid), 'utf-8')
entry[b'gid'] = bytes(str(self._gid), 'utf-8')
contents.append(entry) contents.append(entry)
return contents return contents
@@ -145,7 +153,7 @@ class UAdf(Archive):
return 1 return 1
for entry in self._contents: for entry in self._contents:
sys.stdout.write(self.ITEM % entry) sys.stdout.buffer.write(self.ITEM % entry)
return 0 return 0
def copyout(self, src, dst): def copyout(self, src, dst):
@@ -154,24 +162,26 @@ class UAdf(Archive):
if not real_src: if not real_src:
raise IOError("No such file or directory") raise IOError("No such file or directory")
if " " in real_src: if b" " in real_src:
sys.stderr.write("unadf is unable to operate on filepath with " sys.stderr.write("unadf is unable to operate on filepath with "
"space inside.\nUse affs to mount image and than" "space inside.\nUse affs to mount image and than"
" extract desired files.\n") " extract desired files.\n")
return 1 return 1
extract_dir = mkdtemp() extract_dir = mkdtemp()
cmd = ["unadf", self._arch, real_src, "-d", extract_dir] cmd = [self.ARCHIVER, self._arch, real_src, b"-d", extract_dir]
if check_call(cmd, stdout=open(os.devnull, 'wb'), if check_call(cmd, stdout=open(os.devnull, 'wb'),
stderr=open(os.devnull, 'wb')) != 0: stderr=open(os.devnull, 'wb')) != 0:
shutil.rmtree(extract_dir) shutil.rmtree(extract_dir)
sys.stderr.write("unadf returned with nonzero exit code\n") sys.stderr.write("unadf returned with nonzero exit code\n")
return 1 return 1
shutil.move(os.path.join(extract_dir, real_src), dst) shutil.move(os.path.join(bytes(extract_dir, "utf8"), real_src),
bytes(dst, "utf8"))
shutil.rmtree(extract_dir) shutil.rmtree(extract_dir)
return 0 return 0
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(parse_args(UAdf)) sys.exit(parse_args(UAdf))