diff --git a/uc1541 b/uc1541 index 980957f..72da060 100755 --- a/uc1541 +++ b/uc1541 @@ -6,7 +6,52 @@ 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 - of 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.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. @@ -23,8 +68,8 @@ Changelog: 1.0 Initial release Author: Roman 'gryf' Dobosz -Date: 2012-09-21 -Version: 2.2 +Date: 2012-09-24 +Version: 2.3 Licence: BSD """ @@ -73,15 +118,15 @@ class D64(object): """ Implement d64 directory reader """ - CHAR_MAP = {32: ' ', 33: '!', 34: '"', 35: '#', 36: '$', 37: '%', 38: '&', - 39: "'", 40: '(', 41: ')', 42: '*', 43: '+', 44: ',', 45: '-', - 46: '.', 47: '/', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', - 53: '5', 54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 60: '<', - 61: '=', 62: '>', 63: '?', 64: '@', 65: 'a', 66: 'b', 67: 'c', - 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h', 73: 'i', 74: 'j', - 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', 80: 'p', 81: 'q', - 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', 87: 'w', 88: 'x', - 89: 'y', 90: 'z', 91: '[', 93: ']', 97: 'A', 98: 'B', 99: 'C', + CHAR_MAP = {32: ' ', 33: '!', 34: '"', 35: '#', 37: '%', 38: '&', 39: "'", + 40: '(', 41: ')', 42: '*', 43: '+', 44: ',', 45: '-', 46: '.', + 47: '/', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', + 54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 60: '<', 61: '=', + 62: '>', 63: '?', 64: '@', 65: 'a', 66: 'b', 67: 'c', 68: 'd', + 69: 'e', 70: 'f', 71: 'g', 72: 'h', 73: 'i', 74: 'j', 75: 'k', + 76: 'l', 77: 'm', 78: 'n', 79: 'o', 80: 'p', 81: 'q', 82: 'r', + 83: 's', 84: 't', 85: 'u', 86: 'v', 87: 'w', 88: 'x', 89: 'y', + 90: 'z', 91: '[', 93: ']', 97: 'A', 98: 'B', 99: 'C', 100: 'D', 101: 'E', 102: 'F', 103: 'G', 104: 'H', 105: 'I', 106: 'J', 107: 'K', 108: 'L', 109: 'M', 110: 'N', 111: 'O', 112: 'P', 113: 'Q', 114: 'R', 115: 'S', 116: 'T', 117: 'U', @@ -108,10 +153,9 @@ class D64(object): dimage.close() self.current_sector_data = None - self._sector_shift = 256 self.next_sector = 0 self.next_track = None - self._directory_contents = [] + self._dir_contents = [] def _map_filename(self, string): """ @@ -150,7 +194,7 @@ class D64(object): LOG.debug("Going to the track: %s,%s", self.next_track, self.next_sector) - self.current_sector_data = self.raw[offset:offset + self._sector_shift] + self.current_sector_data = self.raw[offset:offset + 256] self.next_track = ord(self.current_sector_data[0]) self.next_sector = ord(self.current_sector_data[1]) @@ -192,7 +236,7 @@ class D64(object): def _harvest_entries(self): """ - Traverse through sectors and store entries in _directory_contents + Traverse through sectors and store entries in _dir_contents """ sector = self.current_sector_data for x in range(8): @@ -212,10 +256,10 @@ class D64(object): else: size = ord(entry[30]) + ord(entry[31]) * 226 - self._directory_contents.append({'fname': self._map_filename(fname), - 'ftype': type_verbose, - 'size': size, - 'protect': protect}) + self._dir_contents.append({'fname': self._map_filename(fname), + 'ftype': type_verbose, + 'size': size, + 'protect': protect}) sector = sector[32:] def list_dir(self): @@ -226,7 +270,7 @@ class D64(object): while self._go_to_next_sector(): self._harvest_entries() - return self._directory_contents + return self._dir_contents class Uc1541(object): @@ -249,7 +293,7 @@ class Uc1541(object): def list(self): """ Output list contents of D64 image. - Convert filenames to be unix filesystem friendly + Convert filenames to be Unix filesystem friendly Add suffix to show user what kind of file do he dealing with. """ LOG.info("List contents of %s", self.arch) @@ -295,11 +339,11 @@ class Uc1541(object): def copyout(self, src, dst): """ Copy file form the D64 image. Source filename has to be corrected, - since it's representaion differ from the real one inside D64 image. + since it's representation differ from the real one inside D64 image. """ LOG.info("Copy form D64 %s as %s", src, dst) if not src.endswith(".prg"): - return "canot read" + return "cannot read" src = self._get_masked_fname(src) @@ -308,15 +352,38 @@ class Uc1541(object): return 0 + def _correct_fname(self, fname): + """ + Return filename with mapped characters, without .prg extension. + Characters like $, *, + in filenames are perfectly legal, but c1541 + program seem to have issues with it while writing, so it will also be + replaced. + """ + char_map = {'|': "/", + "\\": "/", + "~": " ", + "$": "?", + "*": "?"} + + if fname.lower().endswith(".prg"): + fname = fname[:-4] + + new_fname = [] + for char in fname: + trans = char_map.get(char) + new_fname.append(trans if trans else char) + + return "".join(new_fname) + def _get_masked_fname(self, fname): """ Return masked filename with '?' jokers instead of non ASCII - characters, usefull for copying or deleting files with c1541. In case + characters, useful for copying or deleting files with c1541. In case of several files with same name exists in directory, only first one will be operative (first as appeared in directory). - Warning! If there are two different names but the only differenc is in - non-ASCII characters (some PET ASCII or controll characters) there is + Warning! If there are two different names but the only difference is in + non-ASCII characters (some PET ASCII or control characters) there is a risk that one can remove both files. """ directory = self._get_dir()