-
Notifications
You must be signed in to change notification settings - Fork 1
CPM
This addresses some features that pertain specifically to CP/M disks.
You can use:
-
dir
in place ofcatalog
-
era
in place ofdelete
The nature of CP/M is that each vendor's format has to be supported specially. The kinds of CP/M disks that can be operated on at the file system level, as of this writing, are as follows:
- Apple 5.25 inch 140K (DSK or WOZ)
- Amstrad 3 inch 184K SSDD (IMD or TD0)
- Osborne 5.25 inch 100K SSSD (IMD or TD0)
- Osborne 5.25 inch 200K SSDD (IMD or TD0)
- Kaypro 5.25 inch 200K SSDD (IMD or TD0)
- Kaypro 5.25 inch 400K DSDD (IMD or TD0)
- Standard 8 inch 250K SSSD (IMD or TD0)
- TRS-80-M2 8 inch 600K SSDD (IMD or TD0)
- Nabu 8 inch 1M DSDD (IMD or TD0)
As usual, any supported disk image can be operated on at the sector level, even if the file system is not understood.
CP/M disks support up to 16 users, each with their own files. Two different users can own two distinct files with the same name. In order to specify a user number during file operations, prepend the file name with <n>:
where <n>
is the user number. For example, if user 9 owns a file called ITEMS.TXT
you could display it with
a2kit get -f 9:items.txt -t txt -d cpmdisk.woz
If the user number is omitted, user 0 is assumed. Most CP/M floppies will have only user 0.
You can use a2kit dir
to list files by user, see below.
Let us examine a file image found on a CP/M v3 disk:
{
"fimg_version": "2.1.0",
"file_system": "cpm",
"chunk_len": 1024,
"eof": "80000000",
"fs_type": "545854",
"aux": "",
"access": "48454C4C4F202020545854",
"accessed": "",
"created": "01001836",
"modified": "",
"version": "",
"min_version": "",
"full_path": "12:hello.txt",
"chunks": {
"0": "48492046524F4D20555345522031320D0A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141410D0A4141414141414141414141414141414141414141414141414141414141414141414141"
}
}
Because of the way the CP/M directory works, some of the metadata is not in direct correspondence with what is stored on disk. Things to note are as follows.
-
eof
field - this is the length of the data as a little endian unsigned integer. For CP/M this is usually padded to the nearest 128-byte record boundary. The way this information is stored in the CP/M directory, however, is not straightforward, so this is a case where the metadata field is not in direct correspondence with what is stored on disk. The file system interpreter has to do some work to translate. -
fs_type
field - CP/M filenames are in the form<base>.<extension>
, where the<base>
is up to 8 characters and<extension>
is up to 3 characters. The extension is interpreted as a file type. So what is stored infs_type
is simply<extension>
. It is stored exactly the way it is stored in the CP/M directory, i.e., padded with spaces, and with the high bits dependent on other file properties. -
access
field - In CP/M v2, access flags are stored in the high bits of the filename extension. Some variants also encode information in the high bits of the base name. Therefore theaccess
metadata is best represented by a direct copy of the filename and extension exactly as they occur in the directory. This includes padding and high bits. In the case shown above, none of the flags are set. -
created
field - this is the CP/M v3 timestamp. The other timestamps can be, and are in this case, empty, because CP/M has settings to control which timestamps are in use on any given disk. -
full_path
field - the user number can be included in the manner shown, but it is not required.
Using a2kit dir
on a CP/M disk will perform something like DIR
for user 0. Unlike the CP/M DIR
, this will show hidden files (in dimmed text) and will highlight read-only files in red. This will also display the label information if it exists.
You can use the -f
option to specify CP/M wildcards and command tails. For example,
a2kit dir -d cpm.dsk -f *.com[full]
will list all the COM
files in long format. The supported command tails are
-
att
- show user attributes -
dir
- show directory files -
exclude
- do not show files matching the wildcard pattern -
full
- display the long directory listing -
nosort
- do not sort alphabetically -
ro
- show read only files -
rw
- show read/write files -
size
- show file sizes -
sys
- show system files -
user
- show the given users
The syntax is the same as CP/M 3. For example, to list files of users 0, 3, and 5:
a2kit dir -d cpm.dsk -f [user=(0,3,5)]
Please note that, depending on the shell, you may need to quote or escape the command tail.
The a2kit retype
command works a bit differently on CP/M. Changing the type in the sense of the filename extension can be done with rename
. What retype
does is allow you to switch between hidden (system) and non-hidden (directory) files. It works the same as the usual retype
, except the only types are sys
and dir
.
When working with CP/M files, you will probably be using txt
, bin
, or any
. As usual, the any
type is the most fool-proof for copying or archiving a file. Regarding bin
, CP/M has no concept of a variable load address, so just specify an arbitrary one (e.g. 0
). You can also use raw
, but remember to get
using --trunc
if you want to keep the EOF (such as it is in CP/M).
As of this writing, a2kit
does not comprehend Microsoft BASIC, which is the version of BASIC most likely to be found on a CP/M disk. For BASIC programs that are not tokenized, you can get
them as txt
. If they are tokenized you can get them as bin
or any
(no data is lost, it just won't be readable).
Random access text files can be copied or archived using any
, but the rec
type, which would allow them to be viewed and copied to other file systems, is not yet supported.