Update uadf to support py3
This commit is contained in:
74
uadf
74
uadf
@@ -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))
|
||||||
|
|||||||
Reference in New Issue
Block a user