mirror of
https://github.com/tjboldt/ProDOS-Utilities.git
synced 2025-01-14 14:30:17 +00:00
Fix volume bitmap not writing full blocks (#8)
This commit is contained in:
parent
62bb781fca
commit
402f39da91
11
main.go
11
main.go
@ -17,7 +17,7 @@ import (
|
|||||||
"github.com/tjboldt/ProDOS-Utilities/prodos"
|
"github.com/tjboldt/ProDOS-Utilities/prodos"
|
||||||
)
|
)
|
||||||
|
|
||||||
const version = "0.3.0"
|
const version = "0.3.1"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var fileName string
|
var fileName string
|
||||||
@ -164,6 +164,15 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
prodos.DeleteFile(file, pathName)
|
prodos.DeleteFile(file, pathName)
|
||||||
|
case "dumpfile":
|
||||||
|
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to open drive image %s:\n %s", fileName, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
fileEntry, err := prodos.GetFileEntry(file, pathName)
|
||||||
|
prodos.DumpFileEntry(fileEntry)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Invalid command: %s\n\n", command)
|
fmt.Printf("Invalid command: %s\n\n", command)
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
|
@ -160,3 +160,96 @@ func ConvertBasicToText(basic []byte) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func ConvertTextToBasic(text string) ([]byte, error) {
|
||||||
|
// // convert line endings
|
||||||
|
// text = strings.Replace(text, "\r\n", "\n", -1)
|
||||||
|
// text = strings.Replace(text, "\r", "\n", -1)
|
||||||
|
|
||||||
|
// const startState = 0
|
||||||
|
// const lineNumberState = 1
|
||||||
|
// const tokenCheckState = 2
|
||||||
|
// const literalState = 3
|
||||||
|
// const stringState = 4
|
||||||
|
// const dataState = 5
|
||||||
|
// const endOfLineState = 6
|
||||||
|
|
||||||
|
// state := startState
|
||||||
|
|
||||||
|
// currentByte := 0x0801
|
||||||
|
// var lineNumberString string
|
||||||
|
// var tokenString string
|
||||||
|
|
||||||
|
// basicFile := new(bytes.Buffer)
|
||||||
|
// basicLine := new(bytes.Buffer)
|
||||||
|
|
||||||
|
// // parse character by character
|
||||||
|
// for _, c := range text {
|
||||||
|
|
||||||
|
// // skip initial whitespace and look for the start of a line number
|
||||||
|
// if state == startState {
|
||||||
|
// if c == ' ' {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// if c >= '0' && c <= '9' {
|
||||||
|
// state = lineNumberState
|
||||||
|
// } else {
|
||||||
|
// return nil, errors.New("unexpected character before line number")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // parse line number
|
||||||
|
// if state == lineNumberState {
|
||||||
|
// if c >= '0' && c <= '9' {
|
||||||
|
// lineNumberString += string(c)
|
||||||
|
// } else {
|
||||||
|
// lineNumber, err := strconv.ParseUint(lineNumberString, 10, 16)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// basicLine.WriteByte(byte(lineNumber % 256)) // low byte
|
||||||
|
// basicLine.WriteByte(byte(lineNumber / 256)) // high byte
|
||||||
|
// tokenString = ""
|
||||||
|
// tokenByte = 0
|
||||||
|
// state = tokenCheckState
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if state == tokenCheckState {
|
||||||
|
// // skip initial whitespace
|
||||||
|
// if c == ' ' && len(tokenString) == 0 {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // finish parsing token if
|
||||||
|
// if c == '\n' {
|
||||||
|
// state = endOfLineState
|
||||||
|
// } else if c == '"' {
|
||||||
|
// state = stringState
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return basicFile.Bytes(), nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func writeTokenOrBytes(parseString string, basicBytes []byte) bool {
|
||||||
|
// if len(parseString) == 0 {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
|
||||||
|
// upperToken := strings.ToUpper(parseString)
|
||||||
|
|
||||||
|
// for tokenByte, token := range tokens {
|
||||||
|
// if upperToken == token {
|
||||||
|
// return tokenByte
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if tokenByte > 0 {
|
||||||
|
// basicBytes.WriteByte(tokenByte)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return 0
|
||||||
|
// }
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
package prodos
|
package prodos
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -64,11 +65,35 @@ func writeVolumeBitmap(readerWriter ReaderWriterAt, bitmap []byte) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
volumeHeader := parseVolumeHeader(headerBlock)
|
|
||||||
|
|
||||||
for i := 0; i < len(bitmap)/512; i++ {
|
volumeHeader := parseVolumeHeader(headerBlock)
|
||||||
WriteBlock(readerWriter, volumeHeader.BitmapStartBlock+i, bitmap[i*512:i*512+512])
|
totalBitmapBytes := volumeHeader.TotalBlocks / 8
|
||||||
|
if volumeHeader.TotalBlocks%8 > 0 {
|
||||||
|
totalBitmapBytes++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalBitmapBlocks := totalBitmapBytes / 512
|
||||||
|
|
||||||
|
if totalBitmapBytes%512 > 0 {
|
||||||
|
totalBitmapBlocks++
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < totalBitmapBlocks; i++ {
|
||||||
|
bitmapBlock, err := ReadBlock(readerWriter, i+volumeHeader.BitmapStartBlock)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := 0; j < 512 && i*512+j < totalBitmapBytes; j++ {
|
||||||
|
bitmapBlock[j] = bitmap[i*512+j]
|
||||||
|
}
|
||||||
|
|
||||||
|
err = WriteBlock(readerWriter, volumeHeader.BitmapStartBlock+i, bitmapBlock)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +147,10 @@ func findFreeBlocks(volumeBitmap []byte, numberOfBlocks int) []int {
|
|||||||
blocks[blocksFound] = i
|
blocks[blocksFound] = i
|
||||||
blocksFound++
|
blocksFound++
|
||||||
if blocksFound == numberOfBlocks {
|
if blocksFound == numberOfBlocks {
|
||||||
|
for i := 0; i < len(blocks); i++ {
|
||||||
|
fmt.Printf("%04X ", blocks[i])
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
return blocks
|
return blocks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,3 +53,32 @@ func TestCheckFreeBlockInVolumeBitmap(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMarkBlockInVolumeBitmap(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
blocks int
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{0, false}, // boot block
|
||||||
|
{1, false}, // SOS boot block
|
||||||
|
{2, false}, // volume root
|
||||||
|
{21, false}, // end of volume bitmap
|
||||||
|
{22, true}, // beginning of free space
|
||||||
|
{999, false}, // end of volume bitmap
|
||||||
|
{8192, true}, // more free space
|
||||||
|
{65534, true}, // last free block
|
||||||
|
{65535, false}, // can't use last block because volume size is 0xFFFF, not 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("%d", tt.blocks)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
volumeBitMap := createVolumeBitmap(65535)
|
||||||
|
markBlockInVolumeBitmap(volumeBitMap, 999)
|
||||||
|
ans := checkFreeBlockInVolumeBitmap(volumeBitMap, tt.blocks)
|
||||||
|
if ans != tt.want {
|
||||||
|
t.Errorf("got %t, want %t", ans, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -117,7 +117,7 @@ func getFreeFileEntryInDirectory(reader io.ReaderAt, directory string) (FileEntr
|
|||||||
// if we ran out of blocks in the directory, return empty
|
// if we ran out of blocks in the directory, return empty
|
||||||
// TODO: expand the directory to add more entries
|
// TODO: expand the directory to add more entries
|
||||||
if blockNumber == 0 {
|
if blockNumber == 0 {
|
||||||
return FileEntry{}, errors.New("No free file entries found")
|
return FileEntry{}, errors.New("no free file entries found")
|
||||||
}
|
}
|
||||||
// else read the next block in the directory
|
// else read the next block in the directory
|
||||||
buffer, err = ReadBlock(reader, blockNumber)
|
buffer, err = ReadBlock(reader, blockNumber)
|
||||||
|
@ -9,6 +9,7 @@ package prodos
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -16,7 +17,7 @@ import (
|
|||||||
|
|
||||||
// LoadFile loads in a file from a ProDOS volume into a byte array
|
// LoadFile loads in a file from a ProDOS volume into a byte array
|
||||||
func LoadFile(reader io.ReaderAt, path string) ([]byte, error) {
|
func LoadFile(reader io.ReaderAt, path string) ([]byte, error) {
|
||||||
fileEntry, err := getFileEntry(reader, path)
|
fileEntry, err := GetFileEntry(reader, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -45,7 +46,7 @@ func LoadFile(reader io.ReaderAt, path string) ([]byte, error) {
|
|||||||
func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType int, buffer []byte) error {
|
func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType int, buffer []byte) error {
|
||||||
directory, fileName := GetDirectoryAndFileNameFromPath(path)
|
directory, fileName := GetDirectoryAndFileNameFromPath(path)
|
||||||
|
|
||||||
existingFileEntry, _ := getFileEntry(readerWriter, path)
|
existingFileEntry, _ := GetFileEntry(readerWriter, path)
|
||||||
if existingFileEntry.StorageType != StorageDeleted {
|
if existingFileEntry.StorageType != StorageDeleted {
|
||||||
DeleteFile(readerWriter, path)
|
DeleteFile(readerWriter, path)
|
||||||
}
|
}
|
||||||
@ -56,6 +57,11 @@ func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType i
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(blockList); i++ {
|
||||||
|
fmt.Printf("%04X ", blockList[i])
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
|
||||||
// seedling file
|
// seedling file
|
||||||
if len(buffer) <= 0x200 {
|
if len(buffer) <= 0x200 {
|
||||||
WriteBlock(readerWriter, blockList[0], buffer)
|
WriteBlock(readerWriter, blockList[0], buffer)
|
||||||
@ -66,9 +72,13 @@ func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType i
|
|||||||
writeSaplingFile(readerWriter, buffer, blockList)
|
writeSaplingFile(readerWriter, buffer, blockList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add tree file
|
// tree file needs master index and index blocks
|
||||||
if len(buffer) > 0x20000 {
|
if len(buffer) > 0x20000 && len(buffer) <= 0x1000000 {
|
||||||
return errors.New("files > 128KB not supported yet")
|
writeTreeFile(readerWriter, buffer, blockList)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(buffer) > 0x1000000 {
|
||||||
|
return errors.New("files > 16MB not supported by ProDOS")
|
||||||
}
|
}
|
||||||
|
|
||||||
updateVolumeBitmap(readerWriter, blockList)
|
updateVolumeBitmap(readerWriter, blockList)
|
||||||
@ -111,15 +121,15 @@ func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType i
|
|||||||
|
|
||||||
// DeleteFile deletes a file from a ProDOS volume
|
// DeleteFile deletes a file from a ProDOS volume
|
||||||
func DeleteFile(readerWriter ReaderWriterAt, path string) error {
|
func DeleteFile(readerWriter ReaderWriterAt, path string) error {
|
||||||
fileEntry, err := getFileEntry(readerWriter, path)
|
fileEntry, err := GetFileEntry(readerWriter, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("File not found")
|
return errors.New("file not found")
|
||||||
}
|
}
|
||||||
if fileEntry.StorageType == StorageDeleted {
|
if fileEntry.StorageType == StorageDeleted {
|
||||||
return errors.New("File already deleted")
|
return errors.New("file already deleted")
|
||||||
}
|
}
|
||||||
if fileEntry.StorageType == StorageDirectory {
|
if fileEntry.StorageType == StorageDirectory {
|
||||||
return errors.New("Directory deletion not supported")
|
return errors.New("directory deletion not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// free the blocks
|
// free the blocks
|
||||||
@ -173,15 +183,20 @@ func GetDirectoryAndFileNameFromPath(path string) (string, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateVolumeBitmap(readerWriter ReaderWriterAt, blockList []int) error {
|
func updateVolumeBitmap(readerWriter ReaderWriterAt, blockList []int) error {
|
||||||
|
for i := 0; i < len(blockList); i++ {
|
||||||
|
fmt.Printf("%04X ", blockList[i])
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
|
||||||
volumeBitmap, err := ReadVolumeBitmap(readerWriter)
|
volumeBitmap, err := ReadVolumeBitmap(readerWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Printf("%s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for i := 0; i < len(blockList); i++ {
|
for i := 0; i < len(blockList); i++ {
|
||||||
markBlockInVolumeBitmap(volumeBitmap, blockList[i])
|
markBlockInVolumeBitmap(volumeBitmap, blockList[i])
|
||||||
}
|
}
|
||||||
writeVolumeBitmap(readerWriter, volumeBitmap)
|
return writeVolumeBitmap(readerWriter, volumeBitmap)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeSaplingFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
func writeSaplingFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
||||||
@ -216,6 +231,10 @@ func writeSaplingFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeTreeFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Returns all blocks, including index blocks
|
// Returns all blocks, including index blocks
|
||||||
func getBlocklist(reader io.ReaderAt, fileEntry FileEntry) ([]int, error) {
|
func getBlocklist(reader io.ReaderAt, fileEntry FileEntry) ([]int, error) {
|
||||||
blocks := make([]int, fileEntry.BlocksUsed)
|
blocks := make([]int, fileEntry.BlocksUsed)
|
||||||
@ -273,39 +292,60 @@ func getDataBlocklist(reader io.ReaderAt, fileEntry FileEntry) ([]int, error) {
|
|||||||
blocks[i] = int(index[i]) + int(index[i+256])*256
|
blocks[i] = int(index[i]) + int(index[i+256])*256
|
||||||
}
|
}
|
||||||
return blocks, nil
|
return blocks, nil
|
||||||
|
// case StorageTree:
|
||||||
|
// blocks := make([]int, fileEntry.BlocksUsed-fileEntry.BlocksUsed/256-1)
|
||||||
|
// masterIndex := ReadBlock(reader, fileEntry.KeyPointer)
|
||||||
|
// for i := 0; i < 128; i++ {
|
||||||
|
// blockNumber := 0
|
||||||
|
// blocks[j] = int(index[i]) + int(index[i+256])*256
|
||||||
|
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("Unsupported file storage type")
|
return nil, errors.New("unsupported file storage type")
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBlockList(reader io.ReaderAt, fileSize int) ([]int, error) {
|
func createBlockList(reader io.ReaderAt, fileSize int) ([]int, error) {
|
||||||
numberOfBlocks := fileSize / 512
|
numberOfBlocks := fileSize / 512
|
||||||
|
//fmt.Printf("Number of blocks %d\n", numberOfBlocks)
|
||||||
|
|
||||||
if fileSize%512 > 0 {
|
if fileSize%512 > 0 {
|
||||||
|
//fmt.Printf("Adding block for partial usage\n")
|
||||||
numberOfBlocks++
|
numberOfBlocks++
|
||||||
}
|
}
|
||||||
|
|
||||||
if fileSize > 0x200 && fileSize <= 0x20000 {
|
if fileSize > 0x200 && fileSize <= 0x20000 {
|
||||||
|
//fmt.Printf("Adding index block for sapling file\n")
|
||||||
numberOfBlocks++ // add index block
|
numberOfBlocks++ // add index block
|
||||||
}
|
}
|
||||||
if fileSize > 0x20000 {
|
|
||||||
// add master index block
|
if fileSize > 0x20000 && fileSize < 0x1000000 {
|
||||||
numberOfBlocks++
|
//fmt.Printf("Tree file\n")
|
||||||
// add index blocks for each 128 blocks
|
// add index blocks for each 256 blocks
|
||||||
numberOfBlocks += numberOfBlocks / 128
|
numberOfBlocks += numberOfBlocks / 256
|
||||||
// add index block for any remaining blocks
|
// add index block for any remaining blocks
|
||||||
if numberOfBlocks%128 > 0 {
|
if numberOfBlocks%256 > 0 {
|
||||||
numberOfBlocks++
|
numberOfBlocks++
|
||||||
}
|
}
|
||||||
|
// add master index block
|
||||||
|
numberOfBlocks++
|
||||||
}
|
}
|
||||||
|
if fileSize > 0x1000000 {
|
||||||
|
return nil, errors.New("file size too large")
|
||||||
|
}
|
||||||
|
|
||||||
volumeBitmap, err := ReadVolumeBitmap(reader)
|
volumeBitmap, err := ReadVolumeBitmap(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fmt.Printf("findFreeBlocks %d\n", numberOfBlocks)
|
||||||
blockList := findFreeBlocks(volumeBitmap, numberOfBlocks)
|
blockList := findFreeBlocks(volumeBitmap, numberOfBlocks)
|
||||||
|
|
||||||
return blockList, nil
|
return blockList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileEntry(reader io.ReaderAt, path string) (FileEntry, error) {
|
func GetFileEntry(reader io.ReaderAt, path string) (FileEntry, error) {
|
||||||
directory, fileName := GetDirectoryAndFileNameFromPath(path)
|
directory, fileName := GetDirectoryAndFileNameFromPath(path)
|
||||||
_, _, fileEntries, err := ReadDirectory(reader, directory)
|
_, _, fileEntries, err := ReadDirectory(reader, directory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -313,7 +353,7 @@ func getFileEntry(reader io.ReaderAt, path string) (FileEntry, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fileEntries == nil || len(fileEntries) == 0 {
|
if fileEntries == nil || len(fileEntries) == 0 {
|
||||||
return FileEntry{}, errors.New("File entry not found")
|
return FileEntry{}, errors.New("file entry not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileEntry FileEntry
|
var fileEntry FileEntry
|
||||||
@ -325,7 +365,7 @@ func getFileEntry(reader io.ReaderAt, path string) (FileEntry, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fileEntry.StorageType == StorageDeleted {
|
if fileEntry.StorageType == StorageDeleted {
|
||||||
return FileEntry{}, errors.New("File not found")
|
return FileEntry{}, errors.New("file not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileEntry, nil
|
return fileEntry, nil
|
||||||
|
64
prodos/file_test.go
Normal file
64
prodos/file_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright Terence J. Boldt (c)2021-2022
|
||||||
|
// Use of this source code is governed by an MIT
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package prodos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreatBlocklist(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
fileSize int
|
||||||
|
wantBlocks int
|
||||||
|
}{
|
||||||
|
{1, 1},
|
||||||
|
{512, 1},
|
||||||
|
{513, 3},
|
||||||
|
{2048, 5},
|
||||||
|
{2049, 6},
|
||||||
|
{17128, 35},
|
||||||
|
}
|
||||||
|
|
||||||
|
virtualDisk := NewMemoryFile(0x2000000)
|
||||||
|
CreateVolume(virtualDisk, "VIRTUAL.DISK", 0xFFFE)
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("%d", tt.fileSize)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
blockList, err := createBlockList(virtualDisk, tt.fileSize)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error("got error, want nil")
|
||||||
|
}
|
||||||
|
if len(blockList) != tt.wantBlocks {
|
||||||
|
t.Errorf("got %d blocks, want %d", len(blockList), tt.wantBlocks)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateVolumeBitmap(t *testing.T) {
|
||||||
|
blockList := []int{10, 11, 12, 100, 120}
|
||||||
|
|
||||||
|
virtualDisk := NewMemoryFile(0x2000000)
|
||||||
|
CreateVolume(virtualDisk, "VIRTUAL.DISK", 0xFFFE)
|
||||||
|
updateVolumeBitmap(virtualDisk, blockList)
|
||||||
|
|
||||||
|
for _, tt := range blockList {
|
||||||
|
testname := fmt.Sprintf("%d", tt)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
|
||||||
|
volumeBitmap, err := ReadVolumeBitmap(virtualDisk)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("got error, want nil")
|
||||||
|
}
|
||||||
|
free := checkFreeBlockInVolumeBitmap(volumeBitmap, tt)
|
||||||
|
if free {
|
||||||
|
t.Errorf("got true, want false")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -11,14 +11,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// DateTimeToProDOS converts Time to ProDOS date time
|
// DateTimeToProDOS converts Time to ProDOS date time
|
||||||
// 49041 ($BF91) 49040 ($BF90)
|
// 49041 ($BF91) 49040 ($BF90)
|
||||||
//
|
//
|
||||||
// 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
// 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
||||||
// +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
// DATE: | year | month | day |
|
// DATE: | year | month | day |
|
||||||
// +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
//
|
//
|
||||||
// 49043 ($BF93) 49042 ($BF92)
|
// 49043 ($BF93) 49042 ($BF92)
|
||||||
//
|
//
|
||||||
// 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
// 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
||||||
// +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
|
Loading…
x
Reference in New Issue
Block a user