1
0
mirror of https://github.com/gryf/uc1541.git synced 2026-02-02 19:55:46 +01:00

7 Commits
v2.7 ... v3.0

Author SHA1 Message Date
711695be2b Added initial Python3 support 2018-02-13 20:19:02 +01:00
197ba7a707 Corrected shebang 2018-02-13 20:18:09 +01:00
58d3fce340 Added urls for sourcecode 2015-09-21 21:35:58 +02:00
d4e3794c1c Added screenshots and test image file 2015-09-03 19:27:16 +02:00
7c2e6f19a9 Moved changelog to readme file 2015-09-03 19:26:35 +02:00
fa81fc0b57 Added license and README file 2015-09-02 21:58:45 +02:00
3822ad2531 Better treatment of non-dos disc 2014-01-04 10:40:13 +01:00
6 changed files with 196 additions and 90 deletions

24
LICENSE Normal file
View File

@@ -0,0 +1,24 @@
Copyright (c) 2015, Roman Dobosz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the organization nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ROMAN DOBOSZ BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

123
README.rst Normal file
View File

@@ -0,0 +1,123 @@
===================================================
Midnight Commander virtual filesystem for d64 files
===================================================
This extfs provides an access to disk image files for the Commodore
VIC20/C64/C128 for Midnight Commander. It requires the utility c1541 that comes
bundled with Vice, the emulator for the VIC20, C64, C128 and other computers
made by Commodore.
Features
========
* view, remove, copy files in and out of the image
* support for read from and write to d64 images
* gzipped disk images support
* onfly characters remapping (see below)
Remarks
=======
Due to different way of representing file entries on regular D64 disk images,
there could be issues with filenames that are transfered from/to the image.
Following rules was applied to represent a single file entry:
1. An extension is attached to the end of a filename depending on a file type.
Possible extensions are: ``prg``, ``del``, ``seq``, ``usr`` and ``rel``.
2. Every non-ASCII character (which could be some of characters specific to
PET-ASCII, or be a control character) will be replaced by dot (``.``), since
``c1541`` program will list them that way.
3. Every slash character (``/``) will be replaced by pipe character (``|``).
4. Leading space will be replaced by tilda (``~``).
While copying from D64 image to filesystem, filenames will be stored as they
are seen on a listing.
While copying from filesystem to D64 image, filename conversion will be done:
1. Every ``$`` and ``*`` characters will be replaced by question mark (``?``)
2. Every pipe (``|``) and backslash (``\``) characters will be replaced by
slash (``/``)
3. Every tilda (``~``) will be replaced by a space
4. ``prg`` extension will be truncated
Representation of a directory can be sometimes confusing - in case when one
copied file without extension it stays there in such form, till next access
(after flushing VFS). Also file sizes are not accurate, since D64 directory
entries have sizes stored as 256 bytes blocks.
Screens below shows how it looks like on real C64 machine and its representation
on Midnight Commander listing.
|image1| |image2|
In ``media`` directory you can find the ``test.d6z`` gzip compressed D64 image
file.
Rquirements
===========
* Python 2.7
* Vice installation (c1541 program in path)
Installation
============
* copy ``uc1541`` to ``~/.local/share/mc/extfs.d/``
* add or change entry for files handle in ``~/.config/mc/mc.ext``::
# Disk images for Commodore computers (VIC20, C64, C128)
regex/\.(d64|D64|d6z|D6z|d6Z|D6Z)$
Open=%cd %p/uc1541://
View=%view{ascii} c1541 %f -list
Extract=c1541 %f -extract
Configuration
=============
Here are specific for this script variable, which while set, can influence
script behaviour:
* ``UC1541_DEBUG`` - if set, uc1541 will produce log in /tmp/uc1541.log file.
* ``UC1541_VERBOSE`` - if set, script will be more verbose, i.e. error messages
form c1541 program will be passed to Midnight Commander, so that user will be
aware of error cause if any.
* ``UC1541_HIDE_DEL`` - if set, no DEL entries will be shown.
Changelog
=========
* **3.0** Added beta quality Python3 support
* **2.8** Treat non standard discs a bit better
* **2.7** Added support for gzipped disk images
* **2.6** Added mkdir and run handling (or rather lack of handling :). Minor
refactoring.
* **2.5** Fixed bug with filenames started with a '-' sign.
* **2.4** Fixed endless loop bug for reading directory in Python implemented
directory reader.
* **2.3** Re added and missing method _correct_fname used for writing files
into d64 image.
* **2.2** Fixed bug(?) with unusual sector end (marked as sector 0, not 255),
causing endless directory reading on random locations.
* **2.1** Fixed bug with filenames containing slash.
* **2.0** Added reading raw D64 image, and mapping for jokers. Now it is
possible to read files with PET-ASCII/control sequences in filenames. Working
with d64 images only. Added workaround for space at the beginning of the
filename.
* **1.2** Added configuration env variables: ``UC1541_VERBOSE`` and
``UC1541_HIDE_DEL``. First one, if set to any value, will cause that error
messages from ``c1541`` program will be redirected as a failure messages
visible in MC.
The other variable, when set to any value, cause *del* entries to be not
shown in the lister.
* **1.1** Added protect bits, added failsafe for ``argparse`` module
* **1.0** Initial release
License
=======
This software is licensed under 3-clause BSD license. See LICENSE file for
details.
.. |image1| image:: /media/vice_dir.png?raw=true
.. |image2| image:: /media/mc.png?raw=true

BIN
media/mc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
media/test.d6z Normal file

Binary file not shown.

BIN
media/vice_dir.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

137
uc1541
View File

@@ -2,81 +2,12 @@
""" """
UC1541 Virtual filesystem UC1541 Virtual filesystem
This extfs provides an access to disk image files for the Commodore
VIC20/C64/C128. It requires the utility c1541 that comes bundled with Vice,
the emulator for the VIC20, C64, C128 and other computers made by Commodore.
Remarks
-------
Due to different way of representing file entries on regular D64 disk images,
there could be issues with filenames that are transfered from/to the image.
Following rules was applied to represent a single file entry:
1. An extension is attached to the end of a filename depending on a file type.
Possible extensions are: prg, del, seq, usr and rel.
2. Every non-ASCII character (which could be some of characters specific to
PET-ASCII, or be a control character) will be replaced by dot (.), since
c1541 program will list them that way.
3. Every slash character (/) will be replaced by pipe character (|).
4. Leading space will be replaced by tilda (~).
While copying from D64 image to filesystem, filenames will be stored as they
are seen on a listing.
While copying from filesystem to D64 image, filename conversion will be done:
1. Every $ and * characters will be replaced by question mark (?)
2. Every pipe (|) and backslash (\) characters will be replaced by slash (/)
3. Every tilda (~) will be replaced by a space
4. 'prg' extension will be truncated
Representation of a directory can be sometimes confusing - in case when one
copied file without extension it stays there in such form, till next access
(after flushing VFS). Also file sizes are not accurate, since D64 directory
entries have sizes stored as 256 bytes blocks.
Configuration
-------------
Here are specific for this script variable, which while set, can influence
script behaviour:
UC1541_DEBUG - if set, uc1541 will produce log in /tmp/uc1541.log file
UC1541_VERBOSE - if set, script will be more verbose, i.e. error messages form
c1541 program will be passed to Midnight Commander, so that user will be aware
of error cause if any.
UC1541_HIDE_DEL - if set, no DEL entries will be shown
Changelog:
2.7 Added support for gzipped disk images
2.6 Added mkdir and run handling (or rather lack of handling :). Minor
refactoring.
2.5 Fixed bug with filenames started with a '-' sign.
2.4 Fixed endless loop bug for reading directory in Python implemented
directory reader.
2.3 Re added and missing method _correct_fname used for writing files
into d64 image.
2.2 Fixed bug(?) with unusual sector end (marked as sector 0, not 255),
causing endless directory reading on random locations.
2.1 Fixed bug with filenames containing slash.
2.0 Added reading raw D64 image, and mapping for jokers. Now it is
possible to read files with PET-ASCII/control sequences in filenames.
Working with d64 images only. Added workaround for space at the
beggining of the filename.
1.2 Added configuration env variables: UC1541_VERBOSE and UC1541_HIDE_DEL.
First one, if set to any value, will cause that error messages from
c1541 program will be redirected as a failure messages visible in MC.
The other variable, when set to any value, cause "del" entries to be
not shown in the lister.
1.1 Added protect bits, added failsafe for argparse module
1.0 Initial release
Author: Roman 'gryf' Dobosz <gryf73@gmail.com> Author: Roman 'gryf' Dobosz <gryf73@gmail.com>
Date: 2013-11-12 Date: 2018-02-13
Version: 2.7 Version: 3.0
Licence: BSD Licence: BSD
source: https://bitbucket.org/gryf/uc1541
mirror: https://github.com/gryf/uc1541
""" """
import sys import sys
@@ -121,6 +52,18 @@ else:
pass pass
def _ord(string_or_int):
"""
Return an int value for the (possible) string passed in argument. This
function is for compatibility between python2 and python3, where single
element in byte string array is a string or an int respectively.
"""
try:
return ord(string_or_int)
except TypeError:
return string_or_int
class D64(object): class D64(object):
""" """
Implement d64 directory reader Implement d64 directory reader
@@ -167,16 +110,16 @@ class D64(object):
def _get_raw(self, dimage): def _get_raw(self, dimage):
"""Try to get contents of the D64 image either it's gzip compressed or """Try to get contents of the D64 image either it's gzip compressed or
not.""" not."""
fobj = gzip.open(dimage) fobj = gzip.open(dimage, 'rb')
# Although the common approach with gzipped files is to check the # Although the common approach with gzipped files is to check the
# magic number, in this case there is no guarantee that first track # magic number, in this case there is no guarantee that first track
# does not contain exactly the same byte sequence as the magic number. # does not contain exactly the same byte sequence as the magic number.
# So the only way left is to actually try to uncompress the file. # So the only way left is to actually try to uncompress the file.
try: try:
self.raw = fobj.read() self.raw = fobj.read()
except IOError: except (IOError, OSError):
fobj.close() fobj.close()
fobj = open(dimage) fobj = open(dimage, 'rb')
self.raw = fobj.read() self.raw = fobj.read()
fobj.close() fobj.close()
@@ -189,10 +132,10 @@ class D64(object):
filename = list() filename = list()
for chr_ in string: for chr_ in string:
if ord(chr_) == 160: # shift+space character; $a0 if _ord(chr_) == 160: # shift+space character; $a0
break break
character = D64.CHAR_MAP.get(ord(chr_), '?') character = D64.CHAR_MAP.get(_ord(chr_), '?')
filename.append(character) filename.append(character)
# special cases # special cases
@@ -227,8 +170,13 @@ class D64(object):
self.current_sector_data = self.raw[offset:offset + 256] self.current_sector_data = self.raw[offset:offset + 256]
self.next_track = ord(self.current_sector_data[0]) # Guard for reading data out of bound - that happened for discs which
self.next_sector = ord(self.current_sector_data[1]) # store only raw data, even on 18 track
if not self.current_sector_data:
return False
self.next_track = _ord(self.current_sector_data[0])
self.next_sector = _ord(self.current_sector_data[1])
if (self.next_track, self.next_sector) in self._already_done: if (self.next_track, self.next_sector) in self._already_done:
# Just a failsafe. Endless loop is not what is expected. # Just a failsafe. Endless loop is not what is expected.
@@ -281,7 +229,7 @@ class D64(object):
sector = self.current_sector_data sector = self.current_sector_data
for dummy in range(8): for dummy in range(8):
entry = sector[:32] entry = sector[:32]
ftype = ord(entry[2]) ftype = _ord(entry[2])
if ftype == 0: # deleted if ftype == 0: # deleted
sector = sector[32:] sector = sector[32:]
@@ -289,12 +237,12 @@ class D64(object):
type_verbose = self._get_ftype(ftype) type_verbose = self._get_ftype(ftype)
protect = ord(entry[2]) & 64 and "<" or " " protect = _ord(entry[2]) & 64 and "<" or " "
fname = entry[5:21] fname = entry[5:21]
if ftype == 'rel': if ftype == 'rel':
size = ord(entry[23]) size = _ord(entry[23])
else: else:
size = ord(entry[30]) + ord(entry[31]) * 226 size = _ord(entry[30]) + _ord(entry[31]) * 226
self._dir_contents.append({'fname': self._map_filename(fname), self._dir_contents.append({'fname': self._map_filename(fname),
'ftype': type_verbose, 'ftype': type_verbose,
@@ -339,6 +287,11 @@ class Uc1541(object):
LOG.info("List contents of %s", self.arch) LOG.info("List contents of %s", self.arch)
directory = self._get_dir() directory = self._get_dir()
# If there is an error reading directory, show the reason to the user
if self.out.startswith("Error"):
sys.stderr.write(self.out.split("\n")[0] + "\n")
return 2
for entry in directory: for entry in directory:
sys.stdout.write("%(perms)s 1 %(uid)-8d %(gid)-8d %(size)8d " sys.stdout.write("%(perms)s 1 %(uid)-8d %(gid)-8d %(size)8d "
"Jan 01 1980 %(display_name)s\n" % entry) "Jan 01 1980 %(display_name)s\n" % entry)
@@ -508,14 +461,20 @@ class Uc1541(object):
dir/list dir/list
""" """
command = ['c1541', '-attach', self.arch, '-%s' % cmd] command = ['c1541', '-attach', self.arch, '-%s' % cmd]
if src and dst: if src:
command.append(src) command.append(src)
if dst:
command.append(dst) command.append(dst)
elif src or dst:
command.append(src and src or dst)
self.out, self.err = Popen(command, stdout=PIPE, LOG.debug('executing command: %s', ' '.join(command))
stderr=PIPE).communicate() # For some reason using write command and reading output confuses
# Python3 beneath MC and as a consequence MC report an error...
# therefore for write command let's not use universal_newlines...
self.out, self.err = Popen(command,
universal_newlines=(cmd != 'write'),
stdout=PIPE, stderr=PIPE).communicate()
LOG.debug('an err: %s', self.err)
return not self.err return not self.err