mirror of
https://github.com/zellyn/diskii.git
synced 2024-12-26 10:32:37 +00:00
catalog working for all types, reorder added
This commit is contained in:
parent
9c66e2c5e6
commit
ef9115dcaf
57
README.md
57
README.md
@ -47,8 +47,8 @@ Current disk operations supported:
|
||||
| ---------------- | -------- | ------ | ------------------ |
|
||||
| basic structures | ✓ | ✓ | ✓ |
|
||||
| ls | ✓ | ✓ | ✓ |
|
||||
| dump | ✓ | ✗ | ✓ |
|
||||
| put | ✗ | ✗ | ✓ |
|
||||
| dump | ✗ | ✗ | ✗ |
|
||||
| put | ✗ | ✗ | ✗ |
|
||||
| dumptext | ✗ | ✗ | ✗ |
|
||||
| delete | ✗ | ✗ | ✗ |
|
||||
| rename | ✗ | ✗ | ✗ |
|
||||
@ -78,12 +78,9 @@ will be likely to get priority.
|
||||
- [x] Implement `GetFile` for DOS 3.3
|
||||
- [ ] Add and implement the `-l` flag for `ls`
|
||||
- [x] Add `Delete` to the `disk.Operator` interface
|
||||
- [x] Implement it for Super-Mon
|
||||
- [ ] Implement it for Super-Mon
|
||||
- [ ] Implement it for DOS 3.3
|
||||
- [ ] Make 13-sector DOS disks work
|
||||
- [ ] Read/write nybble formats
|
||||
- [ ] Read/write gzipped files
|
||||
- [ ] Add basic ProDOS structures
|
||||
- [x] Add basic ProDOS structures
|
||||
- [ ] Add ProDOS support
|
||||
|
||||
# Related tools
|
||||
@ -114,38 +111,34 @@ will be likely to get priority.
|
||||
|
||||
- `.do`
|
||||
- `.po`
|
||||
- `.dsk` - could be DO or PO.
|
||||
- `.dsk` - could be DO or PO. When in doubt, assume DO.
|
||||
|
||||
DOS 3.2.1: the 13 sectors are physically skewed on disk.
|
||||
|
||||
DOS 3.3+: the 16 physical sectors are stored in ascending order on disk, not physically skewed at all. The
|
||||
|
||||
|
||||
| Logical Sector | DOS 3.3 Physical Sector | ProDOS Physical Sector |
|
||||
| --------------- | -------------- | ------------- |
|
||||
| 0 | 0 | x |
|
||||
| 1 | D | x |
|
||||
| 2 | B | x |
|
||||
| 3 | 9 | x |
|
||||
| 4 | 7 | x |
|
||||
| 5 | 5 | x |
|
||||
| 6 | 3 | x |
|
||||
| 7 | 1 | x |
|
||||
| 8 | E | x |
|
||||
| 9 | C | x |
|
||||
| A | A | x |
|
||||
| B | 8 | x |
|
||||
| C | 6 | x |
|
||||
| D | 4 | x |
|
||||
| E | 2 | x |
|
||||
| F | F | x |
|
||||
| Physical Sectors | DOS 3.2 Logical | DOS 3.3 Logical | ProDOS/Pascal Logical | CP/M Logical |
|
||||
|------------------|-----------------|-----------------|-----------------------|------------- |
|
||||
| 0 | 0 | 0 | 0.0 | 0.0 |
|
||||
| 1 | 1 | 7 | 4.0 | 2.3 |
|
||||
| 2 | 2 | E | 0.1 | 1.2 |
|
||||
| 3 | 3 | 6 | 4.1 | 0.1 |
|
||||
| 4 | 4 | D | 1.0 | 3.0 |
|
||||
| 5 | 5 | 5 | 5.0 | 1.3 |
|
||||
| 6 | 6 | C | 1.1 | 0.2 |
|
||||
| 7 | 7 | 4 | 5.1 | 3.1 |
|
||||
| 8 | 8 | B | 2.0 | 2.0 |
|
||||
| 9 | 9 | 3 | 6.0 | 0.3 |
|
||||
| A | A | A | 2.1 | 3.2 |
|
||||
| B | B | 2 | 6.1 | 2.1 |
|
||||
| C | C | 9 | 3.0 | 1.0 |
|
||||
| D | | 1 | 7.0 | 3.3 |
|
||||
| E | | 8 | 3.1 | 2.2 |
|
||||
| F | | F | 7.1 | 1.1 |
|
||||
|
||||
_Note: DOS 3.2 rearranged the physical sectors on disk to achieve interleaving._
|
||||
### RWTS - DOS
|
||||
|
||||
Sector mapping:
|
||||
http://www.textfiles.com/apple/ANATOMY/rwts.s.txt and search for INTRLEAV
|
||||
|
||||
Mapping from specified sector to physical sector (the reverse of what the comment says):
|
||||
Mapping from specified sector to physical sector:
|
||||
|
||||
`00 0D 0B 09 07 05 03 01 0E 0C 0A 08 06 04 02 0F`
|
||||
|
||||
|
@ -10,19 +10,19 @@ import (
|
||||
"github.com/zellyn/diskii/types"
|
||||
)
|
||||
|
||||
var shortnames bool // flag for whether to print short filenames
|
||||
var debug bool
|
||||
|
||||
type LsCmd struct {
|
||||
Order string `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
|
||||
System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"`
|
||||
|
||||
ShortNames bool `kong:"short='s',help='Whether to print short filenames (only makes a difference on Super-Mon disks).'"`
|
||||
Image *os.File `kong:"arg,required,help='Disk/device image to read.'"`
|
||||
Directory string `kong:"arg,optional,help='Directory to list (ProDOS only).'"`
|
||||
}
|
||||
|
||||
func (l *LsCmd) Run(globals *types.Globals) error {
|
||||
op, order, err := disk.OpenImage(l.Image, globals)
|
||||
op, order, err := disk.OpenImage(l.Image, l.Order, l.System, globals)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("%w: %s", err, l.Image.Name())
|
||||
}
|
||||
if globals.Debug {
|
||||
fmt.Fprintf(os.Stderr, "Opened disk with order %q, system %q\n", order, op.Name())
|
||||
@ -38,7 +38,7 @@ func (l *LsCmd) Run(globals *types.Globals) error {
|
||||
return err
|
||||
}
|
||||
for _, fd := range fds {
|
||||
if !shortnames && fd.Fullname != "" {
|
||||
if !l.ShortNames && fd.Fullname != "" {
|
||||
fmt.Println(fd.Fullname)
|
||||
} else {
|
||||
fmt.Println(fd.Name)
|
||||
|
101
cmd/reorder.go
Normal file
101
cmd/reorder.go
Normal file
@ -0,0 +1,101 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/zellyn/diskii/disk"
|
||||
"github.com/zellyn/diskii/helpers"
|
||||
"github.com/zellyn/diskii/types"
|
||||
)
|
||||
|
||||
type ReorderCmd struct {
|
||||
Order string `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
|
||||
NewOrder string `kong:"default='auto',enum='auto,do,po',help='New Logical-to-physical sector order.'"`
|
||||
Force bool `kong:"short='s',help='Overwrite existing file?'"`
|
||||
|
||||
DiskImage string `kong:"arg,required,type='existingfile',help='Disk image to read.'"`
|
||||
NewDiskImage string `kong:"arg,optional,type='path',help='Disk image to write, if different.'"`
|
||||
}
|
||||
|
||||
func (r *ReorderCmd) Run(globals *types.Globals) error {
|
||||
fromOrderName, toOrderName, err := getOrders(r.DiskImage, r.Order, r.NewDiskImage, r.NewOrder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frombytes, err := helpers.FileContentsOrStdIn(r.DiskImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fromOrder, ok := disk.LogicalToPhysicalByName[fromOrderName]
|
||||
if !ok {
|
||||
return fmt.Errorf("internal error: disk order '%s' not found", fromOrderName)
|
||||
}
|
||||
toOrder, ok := disk.PhysicalToLogicalByName[toOrderName]
|
||||
if !ok {
|
||||
return fmt.Errorf("internal error: disk order '%s' not found", toOrderName)
|
||||
}
|
||||
rawbytes, err := disk.Swizzle(frombytes, fromOrder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tobytes, err := disk.Swizzle(rawbytes, toOrder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return helpers.WriteOutput(r.NewDiskImage, tobytes, r.DiskImage, r.Force)
|
||||
}
|
||||
|
||||
// getOrders returns the input order, and the output order.
|
||||
func getOrders(inFilename string, inOrder string, outFilename string, outOrder string) (string, string, error) {
|
||||
if inOrder == "auto" && outOrder != "auto" {
|
||||
return oppositeOrder(outOrder), outOrder, nil
|
||||
}
|
||||
if outOrder == "auto" && inOrder != "auto" {
|
||||
return inOrder, oppositeOrder(inOrder), nil
|
||||
}
|
||||
if inOrder != outOrder {
|
||||
return inOrder, outOrder, nil
|
||||
}
|
||||
if inOrder != "auto" {
|
||||
return "", "", fmt.Errorf("identical order and new-order")
|
||||
}
|
||||
|
||||
inGuess, outGuess := orderFromFilename(inFilename), orderFromFilename(outFilename)
|
||||
if inGuess == outGuess {
|
||||
if inGuess == "" {
|
||||
return "", "", fmt.Errorf("cannot determine input or output order from file extensions")
|
||||
}
|
||||
return "", "", fmt.Errorf("guessed order (%s) from file %q is the same as guessed order (%s) from file %q", inGuess, inFilename, outGuess, outFilename)
|
||||
}
|
||||
|
||||
if inGuess == "" {
|
||||
return oppositeOrder(outGuess), outGuess, nil
|
||||
}
|
||||
if outGuess == "" {
|
||||
return inGuess, oppositeOrder(inGuess), nil
|
||||
}
|
||||
return inGuess, outGuess, nil
|
||||
}
|
||||
|
||||
// oppositeOrder returns the opposite order from the input.
|
||||
func oppositeOrder(order string) string {
|
||||
if order == "do" {
|
||||
return "po"
|
||||
}
|
||||
return "do"
|
||||
}
|
||||
|
||||
// orderFromFilename tries to guess the disk order from the filename, using the extension.
|
||||
func orderFromFilename(filename string) string {
|
||||
ext := strings.ToLower(path.Ext(filename))
|
||||
switch ext {
|
||||
case ".dsk", ".do":
|
||||
return "do"
|
||||
case ".po":
|
||||
return "po"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
12
data/data.go
12
data/data.go
@ -3,16 +3,20 @@ package data
|
||||
import _ "embed"
|
||||
|
||||
// DOS 3.3 Master Disk.
|
||||
//go:embed disks/dos33mst.dsk
|
||||
//go:embed disks/dos33master.dsk
|
||||
var DOS33master_dsk []byte
|
||||
|
||||
// DOS 3.3 Master Disk, as a .woz file.
|
||||
//go:embed disks/dos33master.woz
|
||||
var DOS33master_woz []byte
|
||||
|
||||
// John Brooks' update to ProDOS.
|
||||
// Website: https://prodos8.com
|
||||
// Announcements: https://www.callapple.org/author/jbrooks/
|
||||
//go:embed disks/ProDOS_2_4_2.dsk
|
||||
var ProDOS242_dsk []byte
|
||||
//go:embed disks/ProDOS_2_4_2.po
|
||||
var ProDOS242_po []byte
|
||||
|
||||
// The new ProDOS sector 0, used on and after the IIGS System 4.0.
|
||||
// The new ProDOS sector 0, used on and after the IIGS System 4.0. Understands sparse PRODOS.SYSTEM files.
|
||||
//go:embed boot/prodos-new-boot0.bin
|
||||
var ProDOSNewBootSector0 []byte
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
data/disks/ProDOS_2_4_2.po
Normal file
BIN
data/disks/ProDOS_2_4_2.po
Normal file
Binary file not shown.
Binary file not shown.
@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// A ProDOS block.
|
||||
type Block [256]byte
|
||||
type Block [512]byte
|
||||
|
||||
// Dev represents a .po disk image.
|
||||
type Dev struct {
|
||||
|
14
disk/disk.go
14
disk/disk.go
@ -41,6 +41,20 @@ var ProDosPhysicalToLogicalSectorMap = []int{
|
||||
0x04, 0x0C, 0x05, 0x0D, 0x06, 0x0E, 0x07, 0x0F,
|
||||
}
|
||||
|
||||
// LogicalToPhysicalByName maps from "do" and "po" to the corresponding
|
||||
// logical-to-physical ordering.
|
||||
var LogicalToPhysicalByName map[string][]int = map[string][]int{
|
||||
"do": Dos33LogicalToPhysicalSectorMap,
|
||||
"po": ProDOSLogicalToPhysicalSectorMap,
|
||||
}
|
||||
|
||||
// PhysicalToLogicalByName maps from "do" and "po" to the corresponding
|
||||
// physical-to-logical ordering.
|
||||
var PhysicalToLogicalByName map[string][]int = map[string][]int{
|
||||
"do": Dos33PhysicalToLogicalSectorMap,
|
||||
"po": ProDosPhysicalToLogicalSectorMap,
|
||||
}
|
||||
|
||||
// TrackSector is a pair of track/sector bytes.
|
||||
type TrackSector struct {
|
||||
Track byte
|
||||
|
30
disk/open.go
30
disk/open.go
@ -10,36 +10,30 @@ import (
|
||||
"github.com/zellyn/diskii/types"
|
||||
)
|
||||
|
||||
var diskOrdersByName map[string][]int = map[string][]int{
|
||||
"do": Dos33LogicalToPhysicalSectorMap,
|
||||
"po": ProDOSLogicalToPhysicalSectorMap,
|
||||
"raw": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF},
|
||||
}
|
||||
|
||||
// OpenImage attempts to open an image on disk, using the provided ordering and system type.
|
||||
func OpenImage(file *os.File, globals *types.Globals) (types.Operator, string, error) {
|
||||
func OpenImage(file *os.File, order string, system string, globals *types.Globals) (types.Operator, string, error) {
|
||||
bb, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if len(bb) == FloppyDiskBytes {
|
||||
return openDoOrPo(bb, globals, strings.ToLower(path.Ext(file.Name())))
|
||||
return openDoOrPo(bb, order, system, globals, strings.ToLower(path.Ext(file.Name())))
|
||||
}
|
||||
return nil, "", fmt.Errorf("OpenImage not implemented yet for non-disk-sized images")
|
||||
}
|
||||
|
||||
func openDoOrPo(diskbytes []byte, globals *types.Globals, ext string) (types.Operator, string, error) {
|
||||
func openDoOrPo(diskbytes []byte, order string, system string, globals *types.Globals, ext string) (types.Operator, string, error) {
|
||||
var factories []types.OperatorFactory
|
||||
for _, factory := range globals.DiskOperatorFactories {
|
||||
if globals.System == "auto" || globals.System == factory.Name() {
|
||||
if system == "auto" || system == factory.Name() {
|
||||
factories = append(factories, factory)
|
||||
}
|
||||
}
|
||||
if len(factories) == 0 {
|
||||
return nil, "", fmt.Errorf("cannot find disk system with name %q", globals.System)
|
||||
return nil, "", fmt.Errorf("cannot find disk system with name %q", system)
|
||||
}
|
||||
orders := []string{globals.Order}
|
||||
switch globals.Order {
|
||||
orders := []string{order}
|
||||
switch order {
|
||||
case "do", "po":
|
||||
// nothing more
|
||||
case "auto":
|
||||
@ -54,16 +48,16 @@ func openDoOrPo(diskbytes []byte, globals *types.Globals, ext string) (types.Ope
|
||||
return nil, "", fmt.Errorf("unknown disk image extension: %q", ext)
|
||||
}
|
||||
default:
|
||||
return nil, "", fmt.Errorf("disk order %q invalid for %d-byte disk images", globals.Order, FloppyDiskBytes)
|
||||
return nil, "", fmt.Errorf("disk order %q invalid for %d-byte disk images", order, FloppyDiskBytes)
|
||||
}
|
||||
|
||||
for _, order := range orders {
|
||||
swizzled, err := Swizzle(diskbytes, diskOrdersByName[order])
|
||||
swizzled, err := Swizzle(diskbytes, LogicalToPhysicalByName[order])
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
for _, factory := range factories {
|
||||
if len(orders) == 1 && globals.System != "auto" {
|
||||
if len(orders) == 1 && system != "auto" {
|
||||
if globals.Debug {
|
||||
fmt.Fprintf(os.Stderr, "Attempting to open with order=%s, system=%s.\n", order, factory.Name())
|
||||
}
|
||||
@ -88,14 +82,14 @@ func openDoOrPo(diskbytes []byte, globals *types.Globals, ext string) (types.Ope
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, "", fmt.Errorf("openDoOrPo not implemented yet")
|
||||
return nil, "", fmt.Errorf("unabled to open disk image")
|
||||
}
|
||||
|
||||
// Swizzle changes the sector ordering according to the order parameter. If
|
||||
// order is nil, it leaves the order unchanged.
|
||||
func Swizzle(diskimage []byte, order []int) ([]byte, error) {
|
||||
if len(diskimage) != FloppyDiskBytes {
|
||||
return nil, fmt.Errorf("swizzling only works on disk images of %d bytes; got %d", FloppyDiskBytes, len(diskimage))
|
||||
return nil, fmt.Errorf("reordering only works on disk images of %d bytes; got %d", FloppyDiskBytes, len(diskimage))
|
||||
}
|
||||
if err := validateOrder(order); err != nil {
|
||||
return nil, fmt.Errorf("called Swizzle with weird order: %w", err)
|
||||
|
24
dos3/dos3.go
24
dos3/dos3.go
@ -7,7 +7,6 @@ package dos3
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/zellyn/diskii/disk"
|
||||
@ -500,9 +499,6 @@ func readCatalogSectors(diskbytes []byte, debug bool) ([]CatalogSector, error) {
|
||||
if err := v.Validate(); err != nil {
|
||||
return nil, fmt.Errorf("Invalid VTOC sector: %v", err)
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "Read VTOC sector: %#v\n", v)
|
||||
}
|
||||
|
||||
nextTrack := v.CatalogTrack
|
||||
nextSector := v.CatalogSector
|
||||
@ -686,9 +682,13 @@ func (of OperatorFactory) Name() string {
|
||||
|
||||
// SeemsToMatch returns true if the []byte disk image seems to match the
|
||||
// system of this operator.
|
||||
func (of OperatorFactory) SeemsToMatch(diskbytes []byte, debug bool) bool {
|
||||
func (of OperatorFactory) SeemsToMatch(rawbytes []byte, debug bool) bool {
|
||||
// For now, just return true if we can run Catalog successfully.
|
||||
_, _, err := ReadCatalog(diskbytes, debug)
|
||||
swizzled, err := of.swizzle(rawbytes)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
_, _, err = ReadCatalog(swizzled, debug)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@ -696,6 +696,14 @@ func (of OperatorFactory) SeemsToMatch(diskbytes []byte, debug bool) bool {
|
||||
}
|
||||
|
||||
// Operator returns an Operator for the []byte disk image.
|
||||
func (of OperatorFactory) Operator(diskbytes []byte, debug bool) (types.Operator, error) {
|
||||
return operator{data: diskbytes, debug: debug}, nil
|
||||
func (of OperatorFactory) Operator(rawbytes []byte, debug bool) (types.Operator, error) {
|
||||
swizzled, err := of.swizzle(rawbytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return operator{data: swizzled, debug: debug}, nil
|
||||
}
|
||||
|
||||
func (of OperatorFactory) swizzle(rawbytes []byte) ([]byte, error) {
|
||||
return disk.Swizzle(rawbytes, disk.Dos33PhysicalToLogicalSectorMap)
|
||||
}
|
||||
|
@ -5,7 +5,10 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
)
|
||||
|
||||
@ -13,7 +16,23 @@ import (
|
||||
// is "-", in which case it reads from stdin.
|
||||
func FileContentsOrStdIn(s string) ([]byte, error) {
|
||||
if s == "-" {
|
||||
return ioutil.ReadAll(os.Stdin)
|
||||
return io.ReadAll(os.Stdin)
|
||||
}
|
||||
return ioutil.ReadFile(s)
|
||||
return os.ReadFile(s)
|
||||
}
|
||||
|
||||
func WriteOutput(outfilename string, contents []byte, infilename string, force bool) error {
|
||||
if outfilename == "" {
|
||||
outfilename = infilename
|
||||
}
|
||||
if outfilename == "-" {
|
||||
_, err := os.Stdout.Write(contents)
|
||||
return err
|
||||
}
|
||||
if !force {
|
||||
if _, err := os.Stat(outfilename); !errors.Is(err, fs.ErrNotExist) {
|
||||
return fmt.Errorf("cannot overwrite file %q without --force (-f)", outfilename)
|
||||
}
|
||||
}
|
||||
return os.WriteFile(outfilename, contents, 0666)
|
||||
}
|
||||
|
17
main.go
17
main.go
@ -5,6 +5,8 @@ package main
|
||||
import (
|
||||
"github.com/zellyn/diskii/cmd"
|
||||
"github.com/zellyn/diskii/dos3"
|
||||
"github.com/zellyn/diskii/prodos"
|
||||
"github.com/zellyn/diskii/supermon"
|
||||
"github.com/zellyn/diskii/types"
|
||||
|
||||
"fmt"
|
||||
@ -14,11 +16,10 @@ import (
|
||||
)
|
||||
|
||||
var cli struct {
|
||||
Debug bool `kong:"short='v',help='Enable debug mode.'"`
|
||||
Order string `kong:"default='auto',enum='auto,raw,do,po',help='Logical-to-physical sector order.'"`
|
||||
System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"`
|
||||
Debug bool `kong:"short='v',help='Enable debug mode.'"`
|
||||
|
||||
Ls cmd.LsCmd `cmd:"" aliases:"cat,catalog" help:"List paths."`
|
||||
Ls cmd.LsCmd `cmd:"" aliases:"cat,catalog" help:"List paths."`
|
||||
Reorder cmd.ReorderCmd `cmd:"" help:"Reorder disk images."`
|
||||
}
|
||||
|
||||
func run() error {
|
||||
@ -34,13 +35,11 @@ func run() error {
|
||||
)
|
||||
|
||||
globals := &types.Globals{
|
||||
Debug: cli.Debug,
|
||||
Order: cli.Order,
|
||||
System: cli.System,
|
||||
Debug: cli.Debug,
|
||||
DiskOperatorFactories: []types.OperatorFactory{
|
||||
dos3.OperatorFactory{},
|
||||
// supermon.OperatorFactory,
|
||||
// prodos.DiskOperatorFactory,
|
||||
supermon.OperatorFactory{},
|
||||
prodos.OperatorFactory{},
|
||||
},
|
||||
}
|
||||
// Call the Run() method of the selected parsed command.
|
||||
|
@ -85,3 +85,8 @@ F8 CLD
|
||||
|
||||
echo -n -e '\x20\x40\x03\x6D\x01\xDC\x2C\x02\xDF\x2C\x00\x60\xF8\x4C\x00\x60' | diskii put -f ./lib/supermon/testdata/chacha20.dsk DF01:FHELLO -
|
||||
echo -n -e '\x20\x58\xFC\xA2\x00\xBD\x13\x60\xF0\x06\x20\xED\xFD\xE8\xD0\xF5\x4C\x10\x60\xC8\xC5\xCC\xCC\xCF\xAC\xA0\xD7\xCF\xD2\xCC\xC4\x00' | diskii put -f ./lib/supermon/testdata/chacha20.dsk DF02:FWORLD -
|
||||
|
||||
* Sources
|
||||
|
||||
** ProDOS
|
||||
[[https://www.apple.asimov.net/documentation/source_code/Apple%20ProDOS%20Boot%20Source.pdf][ProDOS boot source]]
|
||||
|
116
prodos/prodos.go
116
prodos/prodos.go
@ -7,9 +7,9 @@ package prodos
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/zellyn/diskii/disk"
|
||||
"github.com/zellyn/diskii/types"
|
||||
)
|
||||
|
||||
// Storage types.
|
||||
@ -104,11 +104,11 @@ func (vbm VolumeBitMap) IsFree(block uint16) bool {
|
||||
|
||||
// readVolumeBitMap reads the entire volume bitmap from a block
|
||||
// device.
|
||||
func readVolumeBitMap(bd disk.BlockDevice, startBlock uint16) (VolumeBitMap, error) {
|
||||
blocks := bd.Blocks() / 4096
|
||||
func readVolumeBitMap(devicebytes []byte, startBlock uint16) (VolumeBitMap, error) {
|
||||
blocks := uint16(len(devicebytes) / 512 / 4096)
|
||||
vbm := NewVolumeBitMap(startBlock, blocks)
|
||||
for i := 0; i < len(vbm); i++ {
|
||||
if err := disk.UnmarshalBlock(bd, &vbm[i], vbm[i].GetBlock()); err != nil {
|
||||
if err := disk.UnmarshalBlock(devicebytes, &vbm[i], vbm[i].GetBlock()); err != nil {
|
||||
return nil, fmt.Errorf("cannot read block %d (device block %d) of Volume Bit Map: %v", i, vbm[i].GetBlock(), err)
|
||||
}
|
||||
}
|
||||
@ -116,9 +116,9 @@ func readVolumeBitMap(bd disk.BlockDevice, startBlock uint16) (VolumeBitMap, err
|
||||
}
|
||||
|
||||
// Write writes the Volume Bit Map to a block device.
|
||||
func (vbm VolumeBitMap) Write(bd disk.BlockDevice) error {
|
||||
func (vbm VolumeBitMap) Write(devicebytes []byte) error {
|
||||
for i, bp := range vbm {
|
||||
if err := disk.MarshalBlock(bd, bp); err != nil {
|
||||
if err := disk.MarshalBlock(devicebytes, bp); err != nil {
|
||||
return fmt.Errorf("cannot write block %d (device block %d) of Volume Bit Map: %v", i, bp.GetBlock(), err)
|
||||
}
|
||||
}
|
||||
@ -351,14 +351,14 @@ type FileDescriptor struct {
|
||||
HeaderPointer uint16 // Block number of the key block for the directory which describes this file.
|
||||
}
|
||||
|
||||
// descriptor returns a disk.Descriptor for a FileDescriptor.
|
||||
func (fd FileDescriptor) descriptor() disk.Descriptor {
|
||||
desc := disk.Descriptor{
|
||||
// descriptor returns a types.Descriptor for a FileDescriptor.
|
||||
func (fd FileDescriptor) descriptor() types.Descriptor {
|
||||
desc := types.Descriptor{
|
||||
Name: fd.Name(),
|
||||
Blocks: int(fd.BlocksUsed),
|
||||
Length: int(fd.Eof[0]) + int(fd.Eof[1])<<8 + int(fd.Eof[2])<<16,
|
||||
Locked: false, // TODO(zellyn): use prodos-style access in disk.Descriptor
|
||||
Type: disk.Filetype(fd.FileType),
|
||||
Locked: false, // TODO(zellyn): use prodos-style access in types.Descriptor
|
||||
Type: types.Filetype(fd.FileType),
|
||||
}
|
||||
return desc
|
||||
}
|
||||
@ -652,18 +652,18 @@ func (v Volume) subdirDescriptors() []FileDescriptor {
|
||||
|
||||
// readVolume reads the entire volume and subdirectories from a device
|
||||
// into memory.
|
||||
func readVolume(bd disk.BlockDevice, keyBlock uint16) (Volume, error) {
|
||||
func readVolume(devicebytes []byte, keyBlock uint16) (Volume, error) {
|
||||
v := Volume{
|
||||
keyBlock: &VolumeDirectoryKeyBlock{},
|
||||
subdirsByBlock: make(map[uint16]*Subdirectory),
|
||||
subdirsByName: make(map[string]*Subdirectory),
|
||||
}
|
||||
|
||||
if err := disk.UnmarshalBlock(bd, v.keyBlock, keyBlock); err != nil {
|
||||
if err := disk.UnmarshalBlock(devicebytes, v.keyBlock, keyBlock); err != nil {
|
||||
return v, fmt.Errorf("cannot read first block of volume directory (block %d): %v", keyBlock, err)
|
||||
}
|
||||
|
||||
if vbm, err := readVolumeBitMap(bd, v.keyBlock.Header.BitMapPointer); err != nil {
|
||||
if vbm, err := readVolumeBitMap(devicebytes, v.keyBlock.Header.BitMapPointer); err != nil {
|
||||
return v, err
|
||||
} else {
|
||||
v.bitmap = &vbm
|
||||
@ -671,7 +671,7 @@ func readVolume(bd disk.BlockDevice, keyBlock uint16) (Volume, error) {
|
||||
|
||||
for block := v.keyBlock.Next; block != 0; block = v.blocks[len(v.blocks)-1].Next {
|
||||
vdb := VolumeDirectoryBlock{}
|
||||
if err := disk.UnmarshalBlock(bd, &vdb, block); err != nil {
|
||||
if err := disk.UnmarshalBlock(devicebytes, &vdb, block); err != nil {
|
||||
return v, err
|
||||
}
|
||||
v.blocks = append(v.blocks, &vdb)
|
||||
@ -681,7 +681,7 @@ func readVolume(bd disk.BlockDevice, keyBlock uint16) (Volume, error) {
|
||||
|
||||
for i := 0; i < len(sdds); i++ {
|
||||
sdd := sdds[i]
|
||||
sub, err := readSubdirectory(bd, sdd)
|
||||
sub, err := readSubdirectory(devicebytes, sdd)
|
||||
if err != nil {
|
||||
return v, err
|
||||
}
|
||||
@ -751,18 +751,18 @@ func parentDirName(parentDirectoryBlock uint16, keyBlock uint16, subdirMap map[u
|
||||
|
||||
// readSubdirectory reads a single subdirectory from a device into
|
||||
// memory.
|
||||
func readSubdirectory(bd disk.BlockDevice, fd FileDescriptor) (Subdirectory, error) {
|
||||
func readSubdirectory(devicebytes []byte, fd FileDescriptor) (Subdirectory, error) {
|
||||
s := Subdirectory{
|
||||
keyBlock: &SubdirectoryKeyBlock{},
|
||||
}
|
||||
|
||||
if err := disk.UnmarshalBlock(bd, s.keyBlock, fd.KeyPointer); err != nil {
|
||||
if err := disk.UnmarshalBlock(devicebytes, s.keyBlock, fd.KeyPointer); err != nil {
|
||||
return s, fmt.Errorf("cannot read first block of subdirectory %q (block %d): %v", fd.Name(), fd.KeyPointer, err)
|
||||
}
|
||||
|
||||
for block := s.keyBlock.Next; block != 0; block = s.blocks[len(s.blocks)-1].Next {
|
||||
sdb := SubdirectoryBlock{}
|
||||
if err := disk.UnmarshalBlock(bd, &sdb, block); err != nil {
|
||||
if err := disk.UnmarshalBlock(devicebytes, &sdb, block); err != nil {
|
||||
return s, err
|
||||
}
|
||||
s.blocks = append(s.blocks, &sdb)
|
||||
@ -783,10 +783,11 @@ func copyBytes(dst, src []byte) int {
|
||||
// operator is a disk.Operator - an interface for performing
|
||||
// high-level operations on files and directories.
|
||||
type operator struct {
|
||||
dev disk.BlockDevice
|
||||
data []byte
|
||||
debug bool
|
||||
}
|
||||
|
||||
var _ disk.Operator = operator{}
|
||||
var _ types.Operator = operator{}
|
||||
|
||||
// operatorName is the keyword name for the operator that undestands
|
||||
// prodos disks/devices.
|
||||
@ -797,11 +798,6 @@ func (o operator) Name() string {
|
||||
return operatorName
|
||||
}
|
||||
|
||||
// Order returns the sector or block order of the underlying storage.
|
||||
func (o operator) Order() string {
|
||||
return o.dev.Order()
|
||||
}
|
||||
|
||||
// HasSubdirs returns true if the underlying operating system on the
|
||||
// disk allows subdirectories.
|
||||
func (o operator) HasSubdirs() bool {
|
||||
@ -810,14 +806,14 @@ func (o operator) HasSubdirs() bool {
|
||||
|
||||
// Catalog returns a catalog of disk entries. subdir should be empty
|
||||
// for operating systems that do not support subdirectories.
|
||||
func (o operator) Catalog(subdir string) ([]disk.Descriptor, error) {
|
||||
func (o operator) Catalog(subdir string) ([]types.Descriptor, error) {
|
||||
|
||||
vol, err := readVolume(o.dev, 2)
|
||||
vol, err := readVolume(o.data, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []disk.Descriptor
|
||||
var result []types.Descriptor
|
||||
|
||||
if subdir == "" {
|
||||
for _, desc := range vol.descriptors() {
|
||||
@ -842,8 +838,8 @@ func (o operator) Catalog(subdir string) ([]disk.Descriptor, error) {
|
||||
}
|
||||
|
||||
// GetFile retrieves a file by name.
|
||||
func (o operator) GetFile(filename string) (disk.FileInfo, error) {
|
||||
return disk.FileInfo{}, fmt.Errorf("%s doesn't implement GetFile yet", operatorName)
|
||||
func (o operator) GetFile(filename string) (types.FileInfo, error) {
|
||||
return types.FileInfo{}, fmt.Errorf("%s doesn't implement GetFile yet", operatorName)
|
||||
}
|
||||
|
||||
// Delete deletes a file by name. It returns true if the file was
|
||||
@ -855,37 +851,49 @@ func (o operator) Delete(filename string) (bool, error) {
|
||||
// PutFile writes a file by name. If the file exists and overwrite
|
||||
// is false, it returns with an error. Otherwise it returns true if
|
||||
// an existing file was overwritten.
|
||||
func (o operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool, err error) {
|
||||
func (o operator) PutFile(fileInfo types.FileInfo, overwrite bool) (existed bool, err error) {
|
||||
return false, fmt.Errorf("%s doesn't implement PutFile yet", operatorName)
|
||||
}
|
||||
|
||||
// Write writes the underlying device blocks to the given writer.
|
||||
func (o operator) Write(w io.Writer) (int, error) {
|
||||
return o.dev.Write(w)
|
||||
// OperatorFactory is a types.OperatorFactory for ProDos disks.
|
||||
type OperatorFactory struct {
|
||||
}
|
||||
|
||||
// deviceOperatorFactory is the factory that returns prodos operators
|
||||
// given device images.
|
||||
func deviceOperatorFactory(bd disk.BlockDevice) (disk.Operator, error) {
|
||||
op := operator{dev: bd}
|
||||
_, err := op.Catalog("")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot read catalog. Underlying error: %v", err)
|
||||
// Name returns the name of the operator.
|
||||
func (of OperatorFactory) Name() string {
|
||||
return operatorName
|
||||
}
|
||||
|
||||
// SeemsToMatch returns true if the []byte disk image seems to match the
|
||||
// system of this operator.
|
||||
func (of OperatorFactory) SeemsToMatch(devicebytes []byte, debug bool) bool {
|
||||
// For now, just return true if we can run Catalog successfully.
|
||||
if len(devicebytes) == disk.FloppyDiskBytes {
|
||||
swizzled, err := of.swizzle(devicebytes)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
devicebytes = swizzled
|
||||
}
|
||||
return op, nil
|
||||
}
|
||||
|
||||
// DiskOperatorFactory is the factory that returns dos3 operators
|
||||
// given disk images.
|
||||
func DiskOperatorFactory(sd disk.SectorDisk) (disk.Operator, error) {
|
||||
bd, err := disk.BlockDeviceFromSectorDisk(sd)
|
||||
_, err := readVolume(devicebytes, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return false
|
||||
}
|
||||
return deviceOperatorFactory(bd)
|
||||
return true
|
||||
}
|
||||
|
||||
func init() {
|
||||
disk.RegisterDeviceOperatorFactory(operatorName, deviceOperatorFactory)
|
||||
disk.RegisterDiskOperatorFactory(operatorName, DiskOperatorFactory)
|
||||
// Operator returns an Operator for the []byte disk image.
|
||||
func (of OperatorFactory) Operator(devicebytes []byte, debug bool) (types.Operator, error) {
|
||||
if len(devicebytes) == disk.FloppyDiskBytes {
|
||||
swizzled, err := of.swizzle(devicebytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
devicebytes = swizzled
|
||||
}
|
||||
return operator{data: devicebytes, debug: debug}, nil
|
||||
}
|
||||
|
||||
func (of OperatorFactory) swizzle(rawbytes []byte) ([]byte, error) {
|
||||
return disk.Swizzle(rawbytes, disk.ProDosPhysicalToLogicalSectorMap)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/zellyn/diskii/disk"
|
||||
"github.com/zellyn/diskii/errors"
|
||||
"github.com/zellyn/diskii/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -253,14 +254,14 @@ func decodeSymbol(five []byte, extra byte) string {
|
||||
value := uint64(five[0]) + uint64(five[1])<<8 + uint64(five[2])<<16 + uint64(five[3])<<24 + uint64(five[4])<<32 + uint64(extra)<<40
|
||||
for value&0x1f > 0 {
|
||||
if value&0x1f < 27 {
|
||||
result = result + string(value&0x1f+'@')
|
||||
result = result + string(rune(value&0x1f+'@'))
|
||||
value >>= 5
|
||||
continue
|
||||
}
|
||||
if value&0x20 == 0 {
|
||||
result = result + string((value&0x1f)-0x1b+'0')
|
||||
result = result + string(rune((value&0x1f)-0x1b+'0'))
|
||||
} else {
|
||||
result = result + string((value&0x1f)-0x1b+'5')
|
||||
result = result + string(rune((value&0x1f)-0x1b+'5'))
|
||||
}
|
||||
value >>= 6
|
||||
}
|
||||
@ -639,74 +640,75 @@ func (st SymbolTable) FilesForCompoundName(filename string) (numFile byte, named
|
||||
return numFile, namedFile, parts[1], nil
|
||||
}
|
||||
|
||||
// Operator is a disk.Operator - an interface for performing
|
||||
// operator is a disk.Operator - an interface for performing
|
||||
// high-level operations on files and directories.
|
||||
type Operator struct {
|
||||
data []byte
|
||||
SM SectorMap
|
||||
ST SymbolTable
|
||||
type operator struct {
|
||||
data []byte
|
||||
SM SectorMap
|
||||
ST SymbolTable
|
||||
debug bool
|
||||
}
|
||||
|
||||
var _ disk.Operator = Operator{}
|
||||
var _ types.Operator = operator{}
|
||||
|
||||
// operatorName is the keyword name for the operator that undestands
|
||||
// NakedOS/Super-Mon disks.
|
||||
const operatorName = "nakedos"
|
||||
|
||||
// Name returns the name of the Operator.
|
||||
func (o Operator) Name() string {
|
||||
func (o operator) Name() string {
|
||||
return operatorName
|
||||
}
|
||||
|
||||
// HasSubdirs returns true if the underlying operating system on the
|
||||
// disk allows subdirectories.
|
||||
func (o Operator) HasSubdirs() bool {
|
||||
func (o operator) HasSubdirs() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Catalog returns a catalog of disk entries. subdir should be empty
|
||||
// for operating systems that do not support subdirectories.
|
||||
func (o Operator) Catalog(subdir string) ([]disk.Descriptor, error) {
|
||||
var descs []disk.Descriptor
|
||||
func (o operator) Catalog(subdir string) ([]types.Descriptor, error) {
|
||||
var descs []types.Descriptor
|
||||
sectorsByFile := o.SM.SectorsByFile()
|
||||
for file := byte(1); file < FileReserved; file++ {
|
||||
l := len(sectorsByFile[file])
|
||||
if l == 0 {
|
||||
continue
|
||||
}
|
||||
descs = append(descs, disk.Descriptor{
|
||||
descs = append(descs, types.Descriptor{
|
||||
Name: NameForFile(file, o.ST),
|
||||
Fullname: FullnameForFile(file, o.ST),
|
||||
Sectors: l,
|
||||
Length: l * 256,
|
||||
Locked: false,
|
||||
Type: disk.FiletypeBinary,
|
||||
Type: types.FiletypeBinary,
|
||||
})
|
||||
}
|
||||
return descs, nil
|
||||
}
|
||||
|
||||
// GetFile retrieves a file by name.
|
||||
func (o Operator) GetFile(filename string) (disk.FileInfo, error) {
|
||||
func (o operator) GetFile(filename string) (types.FileInfo, error) {
|
||||
file, err := o.ST.FileForName(filename)
|
||||
if err != nil {
|
||||
return disk.FileInfo{}, err
|
||||
return types.FileInfo{}, err
|
||||
}
|
||||
data, err := o.SM.ReadFile(o.data, file)
|
||||
if err != nil {
|
||||
return disk.FileInfo{}, fmt.Errorf("error reading file DF%02x: %v", file, err)
|
||||
return types.FileInfo{}, fmt.Errorf("error reading file DF%02x: %v", file, err)
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return disk.FileInfo{}, fmt.Errorf("file DF%02x not fount", file)
|
||||
return types.FileInfo{}, fmt.Errorf("file DF%02x not fount", file)
|
||||
}
|
||||
desc := disk.Descriptor{
|
||||
desc := types.Descriptor{
|
||||
Name: NameForFile(file, o.ST),
|
||||
Sectors: len(data) / 256,
|
||||
Length: len(data),
|
||||
Locked: false,
|
||||
Type: disk.FiletypeBinary,
|
||||
Type: types.FiletypeBinary,
|
||||
}
|
||||
fi := disk.FileInfo{
|
||||
fi := types.FileInfo{
|
||||
Descriptor: desc,
|
||||
Data: data,
|
||||
}
|
||||
@ -718,7 +720,7 @@ func (o Operator) GetFile(filename string) (disk.FileInfo, error) {
|
||||
|
||||
// Delete deletes a file by name. It returns true if the file was
|
||||
// deleted, false if it didn't exist.
|
||||
func (o Operator) Delete(filename string) (bool, error) {
|
||||
func (o operator) Delete(filename string) (bool, error) {
|
||||
file, err := o.ST.FileForName(filename)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -742,8 +744,8 @@ func (o Operator) Delete(filename string) (bool, error) {
|
||||
// PutFile writes a file by name. If the file exists and overwrite
|
||||
// is false, it returns with an error. Otherwise it returns true if
|
||||
// an existing file was overwritten.
|
||||
func (o Operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool, err error) {
|
||||
if fileInfo.Descriptor.Type != disk.FiletypeBinary {
|
||||
func (o operator) PutFile(fileInfo types.FileInfo, overwrite bool) (existed bool, err error) {
|
||||
if fileInfo.Descriptor.Type != types.FiletypeBinary {
|
||||
return false, fmt.Errorf("%s: only binary file type supported", operatorName)
|
||||
}
|
||||
if fileInfo.Descriptor.Length != len(fileInfo.Data) {
|
||||
@ -783,9 +785,9 @@ func (o Operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool,
|
||||
return existed, nil
|
||||
}
|
||||
|
||||
// OperatorFactory is the factory that returns supermon operators
|
||||
// XOperatorFactory is the factory that returns supermon operators
|
||||
// given disk images.
|
||||
func OperatorFactory(diskbytes []byte) (disk.Operator, error) {
|
||||
func XOperatorFactory(diskbytes []byte) (types.Operator, error) {
|
||||
sm, err := LoadSectorMap(diskbytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -794,7 +796,50 @@ func OperatorFactory(diskbytes []byte) (disk.Operator, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
op := Operator{data: diskbytes, SM: sm}
|
||||
op := operator{data: diskbytes, SM: sm}
|
||||
|
||||
st, err := sm.ReadSymbolTable(diskbytes)
|
||||
if err == nil {
|
||||
op.ST = st
|
||||
}
|
||||
|
||||
return op, nil
|
||||
}
|
||||
|
||||
// OperatorFactory is a types.OperatorFactory for DOS 3.3 disks.
|
||||
type OperatorFactory struct {
|
||||
}
|
||||
|
||||
// Name returns the name of the operator.
|
||||
func (of OperatorFactory) Name() string {
|
||||
return operatorName
|
||||
}
|
||||
|
||||
// SeemsToMatch returns true if the []byte disk image seems to match the
|
||||
// system of this operator.
|
||||
func (of OperatorFactory) SeemsToMatch(diskbytes []byte, debug bool) bool {
|
||||
// For now, just return true if we can run Catalog successfully.
|
||||
sm, err := LoadSectorMap(diskbytes)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if err := sm.Verify(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Operator returns an Operator for the []byte disk image.
|
||||
func (of OperatorFactory) Operator(diskbytes []byte, debug bool) (types.Operator, error) {
|
||||
sm, err := LoadSectorMap(diskbytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := sm.Verify(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
op := operator{data: diskbytes, SM: sm, debug: debug}
|
||||
|
||||
st, err := sm.ReadSymbolTable(diskbytes)
|
||||
if err == nil {
|
||||
|
@ -3,12 +3,14 @@
|
||||
package supermon
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kr/pretty"
|
||||
"github.com/zellyn/diskii/disk"
|
||||
"github.com/zellyn/diskii/types"
|
||||
)
|
||||
|
||||
const testDisk = "testdata/chacha20.dsk"
|
||||
@ -27,16 +29,36 @@ No more; and by a sleep, to say we end
|
||||
|
||||
// loadSectorMap loads a sector map for the disk image contained in
|
||||
// filename. It returns the sector map and a sector disk.
|
||||
func loadSectorMap(filename string) (SectorMap, disk.SectorDisk, error) {
|
||||
sd, err := disk.LoadDSK(filename)
|
||||
func loadSectorMap(filename string) (SectorMap, []byte, error) {
|
||||
rawbytes, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sm, err := LoadSectorMap(sd)
|
||||
diskbytes, err := disk.Swizzle(rawbytes, disk.Dos33LogicalToPhysicalSectorMap)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return sm, sd, nil
|
||||
sm, err := LoadSectorMap(diskbytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return sm, diskbytes, nil
|
||||
}
|
||||
|
||||
// getOperator gets a types.Operator for the given NakedOS disk, assumed to be
|
||||
// in "do" order.
|
||||
func getOperator(filename string) (types.Operator, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
op, _, err := disk.OpenImage(f, "do", "nakedos", &types.Globals{
|
||||
DiskOperatorFactories: []types.OperatorFactory{OperatorFactory{}},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return op, nil
|
||||
}
|
||||
|
||||
// TestReadSectorMap tests the reading of the sector map of a test
|
||||
@ -126,11 +148,7 @@ func TestReadSymbolTable(t *testing.T) {
|
||||
// TestGetFile tests the retrieval of a file's contents, using the
|
||||
// Operator interface.
|
||||
func TestGetFile(t *testing.T) {
|
||||
sd, err := disk.OpenDisk(testDisk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
op, err := disk.OperatorForDisk(sd)
|
||||
op, err := getOperator(testDisk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -213,20 +231,16 @@ func TestReadWriteSymbolTable(t *testing.T) {
|
||||
// TestPutFile tests the creation of a file, using the Operator
|
||||
// interface.
|
||||
func TestPutFile(t *testing.T) {
|
||||
sd, err := disk.OpenDisk(testDisk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
op, err := disk.OperatorForDisk(sd)
|
||||
op, err := getOperator(testDisk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
contents := []byte(cities)
|
||||
fileInfo := disk.FileInfo{
|
||||
Descriptor: disk.Descriptor{
|
||||
fileInfo := types.FileInfo{
|
||||
Descriptor: types.Descriptor{
|
||||
Name: "FNEWFILE",
|
||||
Length: len(contents),
|
||||
Type: disk.FiletypeBinary,
|
||||
Type: types.FiletypeBinary,
|
||||
},
|
||||
Data: contents,
|
||||
}
|
||||
|
@ -2,9 +2,7 @@ package types
|
||||
|
||||
// Globals holds flags and configuration that are shared globally.
|
||||
type Globals struct {
|
||||
Debug bool
|
||||
Order string //Logical-to-physical sector order
|
||||
System string // DOS system used for image
|
||||
Debug bool
|
||||
|
||||
DiskOperatorFactories []OperatorFactory
|
||||
}
|
||||
|
@ -9,8 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBasicLoad(t *testing.T) {
|
||||
bb := data.MustAsset("data/disks/dos33master.woz")
|
||||
wz, err := woz.Decode(bytes.NewReader(bb))
|
||||
wz, err := woz.Decode(bytes.NewReader(data.DOS33master_woz))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user