From 821c2c5bb0d9093d1c9a5f8090db36770ebc670a Mon Sep 17 00:00:00 2001 From: Zellyn Hunter Date: Sun, 27 Nov 2016 20:23:31 -0500 Subject: [PATCH] Add error helper, supermon write/delete --- lib/errors/errors.go | 114 +++++++++++++++++++++++++++++++++++++++ lib/supermon/supermon.go | 75 ++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 lib/errors/errors.go diff --git a/lib/errors/errors.go b/lib/errors/errors.go new file mode 100644 index 0000000..e313f84 --- /dev/null +++ b/lib/errors/errors.go @@ -0,0 +1,114 @@ +// Copyright © 2016 Zellyn Hunter + +// Package errors contains helpers for creating and testing for +// certain types of errors. +package errors + +import ( + "errors" + "fmt" +) + +// Copy of errors.New, so you this package can be imported instead. +func New(text string) error { + return errors.New(text) +} + +// --------------------- Out of space + +// outOfSpace is an error that signals being out of space on a disk +// image. +type outOfSpace string + +// OutOfSpaceI is the tag interface used to mark out of space errors. +type OutOfSpaceI interface { + IsOutOfSpace() +} + +var _ OutOfSpaceI = outOfSpace("test") + +// Error returns the string message of an OutOfSpace error. +func (o outOfSpace) Error() string { + return string(o) +} + +// Tag method on our outOfSpace implementation. +func (o outOfSpace) IsOutOfSpace() { +} + +// OutOfSpacef is fmt.Errorf for OutOfSpace errors. +func OutOfSpacef(format string, a ...interface{}) error { + return outOfSpace(fmt.Sprintf(format, a...)) +} + +// IsOutOfSpace returns true if a given error is an OutOfSpace error. +func IsOutOfSpace(err error) bool { + _, ok := err.(OutOfSpaceI) + return ok +} + +// --------------------- File exists + +// fileExists is an error returned when a problem is caused by a file +// with the given name already existing. +type fileExists string + +// FileExistsI is the tag interface used to mark FileExists errors. +type FileExistsI interface { + IsFileExists() +} + +var _ FileExistsI = fileExists("test") + +// Error returns the string message of a FileExists error. +func (o fileExists) Error() string { + return string(o) +} + +// Tag method on our fileExists implementation. +func (o fileExists) IsFileExists() { +} + +// FileExistsf is fmt.Errorf for FileExists errors. +func FileExistsf(format string, a ...interface{}) error { + return fileExists(fmt.Sprintf(format, a...)) +} + +// IsFileExists returns true if a given error is a FileExists error. +func IsFileExists(err error) bool { + _, ok := err.(FileExistsI) + return ok +} + +// --------------------- File not found + +// fileNotFound is an error returned when a file with the given name +// cannot be found. +type fileNotFound string + +// FileNotFoundI is the tag interface used to mark FileNotFound errors. +type FileNotFoundI interface { + IsFileNotFound() +} + +var _ FileNotFoundI = fileNotFound("test") + +// Error returns the string message of a FileNotFound error. +func (o fileNotFound) Error() string { + return string(o) +} + +// Tag method on our fileNotFound implementation. +func (o fileNotFound) IsFileNotFound() { +} + +// FileNotFoundf is fmt.Errorf for FileNotFound errors. +func FileNotFoundf(format string, a ...interface{}) error { + return fileNotFound(fmt.Sprintf(format, a...)) +} + +// IsFileNotFound returns true if a given error is a FileNotFound error. +func IsFileNotFound(err error) bool { + _, ok := err.(FileNotFoundI) + return ok +} diff --git a/lib/supermon/supermon.go b/lib/supermon/supermon.go index eb5909a..1b1e4db 100644 --- a/lib/supermon/supermon.go +++ b/lib/supermon/supermon.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/zellyn/diskii/lib/disk" + "github.com/zellyn/diskii/lib/errors" ) const ( @@ -47,6 +48,37 @@ func LoadSectorMap(sd disk.SectorDisk) (SectorMap, error) { return sm, nil } +// Persist writes the current contenst of a sector map back back to +// disk. +func (sm SectorMap) Persist(sd disk.SectorDisk) error { + sector09, err := sd.ReadPhysicalSector(0, 9) + if err != nil { + return err + } + copy(sector09[0xd0:], sm[0:0x30]) + if err := sd.WritePhysicalSector(0, 9, sector09); err != nil { + return err + } + if err := sd.WritePhysicalSector(0, 0xA, sm[0x30:0x130]); err != nil { + return err + } + if err := sd.WritePhysicalSector(0, 0xB, sm[0x130:0x230]); err != nil { + return err + } + return nil +} + +// FreeSectors returns the number of blocks free in a sector map. +func (sm SectorMap) FreeSectors() int { + count := 0 + for _, file := range sm { + if file == FileFree { + count++ + } + } + return count +} + // Verify checks that we actually have a NakedOS disk. func (sm SectorMap) Verify() error { for sector := byte(0); sector <= 0xB; sector++ { @@ -118,6 +150,49 @@ func (sm SectorMap) ReadFile(sd disk.SectorDisk, file byte) ([]byte, error) { return result, nil } +// Delete deletes a file from the sector map. It does not persist the changes. +func (sm SectorMap) Delete(file byte) { + for i, f := range sm { + if f == file { + sm[i] = FileFree + } + } +} + +// WriteFile writes the contents of a file. +func (sm SectorMap) WriteFile(sd disk.SectorDisk, file byte, contents []byte, overwrite bool) error { + sectorsNeeded := (len(contents) + 255) / 256 + cts := make([]byte, 256*sectorsNeeded) + copy(cts, contents) + free := sm.FreeSectors() + len(sm.SectorsForFile(file)) + if free < sectorsNeeded { + return errors.OutOfSpacef("file requires %d sectors, but only %d are available") + } + sm.Delete(file) + + // TODO(zellyn): continue implementation. + return fmt.Errorf("WriteFile not implemented yet") + i := 0 +OUTER: + for track := byte(0); track < sd.Tracks(); track++ { + for sector := byte(0); sector < sd.Sectors(); sector++ { + if sm.FileForSector(track, sector) == file { + if err := sd.WritePhysicalSector(track, sector, cts[i*256:(i+1)*256]); err != nil { + return err + } + i++ + if i == sectorsNeeded { + break OUTER + } + } + } + } + if err := sm.Persist(sd); err != nil { + return err + } + return nil +} + // Symbol represents a single Super-Mon symbol. type Symbol struct { // Address is the memory address the symbol points to, or 0 for an