mirror of
https://github.com/tjboldt/ProDOS-Utilities.git
synced 2024-12-27 05:29:49 +00:00
parent
30a221c177
commit
62bb781fca
25
main.go
25
main.go
@ -17,7 +17,7 @@ import (
|
||||
"github.com/tjboldt/ProDOS-Utilities/prodos"
|
||||
)
|
||||
|
||||
const version = "0.2.0"
|
||||
const version = "0.3.0"
|
||||
|
||||
func main() {
|
||||
var fileName string
|
||||
@ -57,11 +57,18 @@ func main() {
|
||||
}
|
||||
defer file.Close()
|
||||
pathName = strings.ToUpper(pathName)
|
||||
volumeHeader, _, fileEntries := prodos.ReadDirectory(file, pathName)
|
||||
volumeHeader, _, fileEntries, err := prodos.ReadDirectory(file, pathName)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %s", err)
|
||||
}
|
||||
if len(pathName) == 0 {
|
||||
pathName = "/" + volumeHeader.VolumeName
|
||||
}
|
||||
volumeBitmap := prodos.ReadVolumeBitmap(file)
|
||||
volumeBitmap, err := prodos.ReadVolumeBitmap(file)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to open drive image %s:\n %s", fileName, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
freeBlocks := prodos.GetFreeBlockCount(volumeBitmap, volumeHeader.TotalBlocks)
|
||||
prodos.DumpDirectory(freeBlocks, volumeHeader.TotalBlocks, pathName, fileEntries)
|
||||
case "get":
|
||||
@ -109,7 +116,7 @@ func main() {
|
||||
fmt.Printf("Failed to open input file %s: %s", inFileName, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = prodos.WriteFile(file, file, pathName, fileType, auxType, inFile)
|
||||
err = prodos.WriteFile(file, pathName, fileType, auxType, inFile)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to write file %s: %s", pathName, err)
|
||||
}
|
||||
@ -121,7 +128,11 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer file.Close()
|
||||
block := prodos.ReadBlock(file, blockNumber)
|
||||
block, err := prodos.ReadBlock(file, blockNumber)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to open drive image %s:\n %s", fileName, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
prodos.DumpBlock(block)
|
||||
case "writeblock":
|
||||
fmt.Printf("Writing block 0x%04X (%d):\n\n", blockNumber, blockNumber)
|
||||
@ -144,7 +155,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
prodos.CreateVolume(file, file, volumeName, volumeSize)
|
||||
prodos.CreateVolume(file, volumeName, volumeSize)
|
||||
case "rm":
|
||||
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
|
||||
if err != nil {
|
||||
@ -152,7 +163,7 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer file.Close()
|
||||
prodos.DeleteFile(file, file, pathName)
|
||||
prodos.DeleteFile(file, pathName)
|
||||
default:
|
||||
fmt.Printf("Invalid command: %s\n\n", command)
|
||||
flag.PrintDefaults()
|
||||
|
@ -12,8 +12,11 @@ import (
|
||||
)
|
||||
|
||||
// ReadVolumeBitmap reads the volume bitmap from a ProDOS image
|
||||
func ReadVolumeBitmap(reader io.ReaderAt) []byte {
|
||||
headerBlock := ReadBlock(reader, 2)
|
||||
func ReadVolumeBitmap(reader io.ReaderAt) ([]byte, error) {
|
||||
headerBlock, err := ReadBlock(reader, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
volumeHeader := parseVolumeHeader(headerBlock)
|
||||
|
||||
@ -31,14 +34,17 @@ func ReadVolumeBitmap(reader io.ReaderAt) []byte {
|
||||
}
|
||||
|
||||
for i := 0; i < totalBitmapBlocks; i++ {
|
||||
bitmapBlock := ReadBlock(reader, i+volumeHeader.BitmapStartBlock)
|
||||
bitmapBlock, err := ReadBlock(reader, i+volumeHeader.BitmapStartBlock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for j := 0; j < 512 && i*512+j < totalBitmapBytes; j++ {
|
||||
bitmap[i*512+j] = bitmapBlock[j]
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap
|
||||
return bitmap, nil
|
||||
}
|
||||
|
||||
// GetFreeBlockCount gets the number of free blocks on a ProDOS image
|
||||
@ -53,14 +59,17 @@ func GetFreeBlockCount(volumeBitmap []byte, totalBlocks int) int {
|
||||
return freeBlockCount
|
||||
}
|
||||
|
||||
func writeVolumeBitmap(writer io.WriterAt, reader io.ReaderAt, bitmap []byte) {
|
||||
headerBlock := ReadBlock(reader, 2)
|
||||
|
||||
func writeVolumeBitmap(readerWriter ReaderWriterAt, bitmap []byte) error {
|
||||
headerBlock, err := ReadBlock(readerWriter, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
volumeHeader := parseVolumeHeader(headerBlock)
|
||||
|
||||
for i := 0; i < len(bitmap)/512; i++ {
|
||||
WriteBlock(writer, volumeHeader.BitmapStartBlock+i, bitmap[i*512:i*512+512])
|
||||
WriteBlock(readerWriter, volumeHeader.BitmapStartBlock+i, bitmap[i*512:i*512+512])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createVolumeBitmap(numberOfBlocks int) []byte {
|
||||
|
@ -12,15 +12,16 @@ import (
|
||||
)
|
||||
|
||||
// ReadBlock reads a block from a ProDOS volume into a byte array
|
||||
func ReadBlock(reader io.ReaderAt, block int) []byte {
|
||||
func ReadBlock(reader io.ReaderAt, block int) ([]byte, error) {
|
||||
buffer := make([]byte, 512)
|
||||
|
||||
reader.ReadAt(buffer, int64(block)*512)
|
||||
_, err := reader.ReadAt(buffer, int64(block)*512)
|
||||
|
||||
return buffer
|
||||
return buffer, err
|
||||
}
|
||||
|
||||
// WriteBlock writes a block to a ProDOS volume from a byte array
|
||||
func WriteBlock(writer io.WriterAt, block int, buffer []byte) {
|
||||
writer.WriteAt(buffer, int64(block)*512)
|
||||
func WriteBlock(writer io.WriterAt, block int, buffer []byte) error {
|
||||
_, err := writer.WriteAt(buffer, int64(block)*512)
|
||||
return err
|
||||
}
|
||||
|
@ -74,8 +74,11 @@ type FileEntry struct {
|
||||
|
||||
// ReadDirectory reads the directory information from a specified path
|
||||
// on a ProDOS image
|
||||
func ReadDirectory(reader io.ReaderAt, path string) (VolumeHeader, DirectoryHeader, []FileEntry) {
|
||||
buffer := ReadBlock(reader, 2)
|
||||
func ReadDirectory(reader io.ReaderAt, path string) (VolumeHeader, DirectoryHeader, []FileEntry, error) {
|
||||
buffer, err := ReadBlock(reader, 2)
|
||||
if err != nil {
|
||||
return VolumeHeader{}, DirectoryHeader{}, nil, err
|
||||
}
|
||||
|
||||
volumeHeader := parseVolumeHeader(buffer)
|
||||
|
||||
@ -86,17 +89,25 @@ func ReadDirectory(reader io.ReaderAt, path string) (VolumeHeader, DirectoryHead
|
||||
path = strings.ToUpper(path)
|
||||
paths := strings.Split(path, "/")
|
||||
|
||||
directoryHeader, fileEntries := getFileEntriesInDirectory(reader, 2, 1, paths)
|
||||
directoryHeader, fileEntries, err := getFileEntriesInDirectory(reader, 2, 1, paths)
|
||||
if err != nil {
|
||||
return VolumeHeader{}, DirectoryHeader{}, nil, err
|
||||
}
|
||||
|
||||
return volumeHeader, directoryHeader, fileEntries
|
||||
return volumeHeader, directoryHeader, fileEntries, nil
|
||||
}
|
||||
|
||||
func getFreeFileEntryInDirectory(reader io.ReaderAt, directory string) (FileEntry, error) {
|
||||
_, directoryHeader, _ := ReadDirectory(reader, directory)
|
||||
_, directoryHeader, _, err := ReadDirectory(reader, directory)
|
||||
if err != nil {
|
||||
return FileEntry{}, err
|
||||
}
|
||||
//DumpDirectoryHeader(directoryHeader)
|
||||
blockNumber := directoryHeader.StartingBlock
|
||||
buffer := ReadBlock(reader, blockNumber)
|
||||
|
||||
buffer, err := ReadBlock(reader, blockNumber)
|
||||
if err != nil {
|
||||
return FileEntry{}, err
|
||||
}
|
||||
entryOffset := 43 // start at offset after header
|
||||
entryNumber := 2 // header is essentially the first entry so start at 2
|
||||
|
||||
@ -109,7 +120,10 @@ func getFreeFileEntryInDirectory(reader io.ReaderAt, directory string) (FileEntr
|
||||
return FileEntry{}, errors.New("No free file entries found")
|
||||
}
|
||||
// else read the next block in the directory
|
||||
buffer = ReadBlock(reader, blockNumber)
|
||||
buffer, err = ReadBlock(reader, blockNumber)
|
||||
if err != nil {
|
||||
return FileEntry{}, nil
|
||||
}
|
||||
entryOffset = 4
|
||||
entryNumber = 1
|
||||
}
|
||||
@ -127,8 +141,11 @@ func getFreeFileEntryInDirectory(reader io.ReaderAt, directory string) (FileEntr
|
||||
}
|
||||
}
|
||||
|
||||
func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath int, paths []string) (DirectoryHeader, []FileEntry) {
|
||||
buffer := ReadBlock(reader, blockNumber)
|
||||
func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath int, paths []string) (DirectoryHeader, []FileEntry, error) {
|
||||
buffer, err := ReadBlock(reader, blockNumber)
|
||||
if err != nil {
|
||||
return DirectoryHeader{}, nil, err
|
||||
}
|
||||
|
||||
directoryHeader := parseDirectoryHeader(buffer, blockNumber)
|
||||
|
||||
@ -143,7 +160,7 @@ func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath
|
||||
|
||||
if !matchedDirectory && (currentPath == len(paths)-1) {
|
||||
// path not matched by last path part
|
||||
return DirectoryHeader{}, nil
|
||||
return DirectoryHeader{}, nil, errors.New("path not matched")
|
||||
}
|
||||
|
||||
for {
|
||||
@ -151,16 +168,19 @@ func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath
|
||||
entryOffset = 4
|
||||
entryNumber = 1
|
||||
if blockNumber == 0 {
|
||||
return DirectoryHeader{}, nil
|
||||
return DirectoryHeader{}, nil, nil
|
||||
}
|
||||
buffer, err = ReadBlock(reader, nextBlock)
|
||||
if err != nil {
|
||||
return DirectoryHeader{}, nil, err
|
||||
}
|
||||
buffer = ReadBlock(reader, nextBlock)
|
||||
nextBlock = int(buffer[2]) + int(buffer[3])*256
|
||||
}
|
||||
fileEntry := parseFileEntry(buffer[entryOffset:entryOffset+40], blockNumber, entryOffset)
|
||||
|
||||
if fileEntry.StorageType != StorageDeleted {
|
||||
if matchedDirectory && activeEntries == directoryHeader.ActiveFileCount {
|
||||
return directoryHeader, fileEntries[0:activeEntries]
|
||||
return directoryHeader, fileEntries[0:activeEntries], nil
|
||||
}
|
||||
if matchedDirectory {
|
||||
fileEntries[activeEntries] = fileEntry
|
||||
@ -298,8 +318,11 @@ func parseDirectoryHeader(buffer []byte, blockNumber int) DirectoryHeader {
|
||||
return directoryEntry
|
||||
}
|
||||
|
||||
func writeDirectoryHeader(writer io.WriterAt, reader io.ReaderAt, directoryHeader DirectoryHeader) {
|
||||
buffer := ReadBlock(reader, directoryHeader.StartingBlock)
|
||||
func writeDirectoryHeader(readerWriter ReaderWriterAt, directoryHeader DirectoryHeader) error {
|
||||
buffer, err := ReadBlock(readerWriter, directoryHeader.StartingBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer[0x00] = byte(directoryHeader.PreviousBlock & 0x00FF)
|
||||
buffer[0x01] = byte(directoryHeader.PreviousBlock >> 8)
|
||||
buffer[0x02] = byte(directoryHeader.NextBlock & 0x00FF)
|
||||
@ -310,5 +333,7 @@ func writeDirectoryHeader(writer io.WriterAt, reader io.ReaderAt, directoryHeade
|
||||
}
|
||||
buffer[0x25] = byte(directoryHeader.ActiveFileCount & 0x00FF)
|
||||
buffer[0x26] = byte(directoryHeader.ActiveFileCount >> 8)
|
||||
WriteBlock(writer, directoryHeader.StartingBlock, buffer)
|
||||
WriteBlock(readerWriter, directoryHeader.StartingBlock, buffer)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -29,7 +29,10 @@ func LoadFile(reader io.ReaderAt, path string) ([]byte, error) {
|
||||
buffer := make([]byte, fileEntry.EndOfFile)
|
||||
|
||||
for i := 0; i < len(blockList); i++ {
|
||||
block := ReadBlock(reader, blockList[i])
|
||||
block, err := ReadBlock(reader, blockList[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for j := 0; j < 512 && i*512+j < fileEntry.EndOfFile; j++ {
|
||||
buffer[i*512+j] = block[j]
|
||||
}
|
||||
@ -39,25 +42,28 @@ func LoadFile(reader io.ReaderAt, path string) ([]byte, error) {
|
||||
}
|
||||
|
||||
// WriteFile writes a file to a ProDOS volume from a byte array
|
||||
func WriteFile(writer io.WriterAt, reader io.ReaderAt, 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)
|
||||
|
||||
existingFileEntry, _ := getFileEntry(reader, path)
|
||||
existingFileEntry, _ := getFileEntry(readerWriter, path)
|
||||
if existingFileEntry.StorageType != StorageDeleted {
|
||||
DeleteFile(writer, reader, path)
|
||||
DeleteFile(readerWriter, path)
|
||||
}
|
||||
|
||||
// get list of blocks to write file to
|
||||
blockList := createBlockList(reader, len(buffer))
|
||||
blockList, err := createBlockList(readerWriter, len(buffer))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// seedling file
|
||||
if len(buffer) <= 0x200 {
|
||||
WriteBlock(writer, blockList[0], buffer)
|
||||
WriteBlock(readerWriter, blockList[0], buffer)
|
||||
}
|
||||
|
||||
// sapling file needs index block
|
||||
if len(buffer) > 0x200 && len(buffer) <= 0x20000 {
|
||||
writeSaplingFile(writer, buffer, blockList)
|
||||
writeSaplingFile(readerWriter, buffer, blockList)
|
||||
}
|
||||
|
||||
// TODO: add tree file
|
||||
@ -65,10 +71,10 @@ func WriteFile(writer io.WriterAt, reader io.ReaderAt, path string, fileType int
|
||||
return errors.New("files > 128KB not supported yet")
|
||||
}
|
||||
|
||||
updateVolumeBitmap(writer, reader, blockList)
|
||||
updateVolumeBitmap(readerWriter, blockList)
|
||||
|
||||
// add file entry to directory
|
||||
fileEntry, err := getFreeFileEntryInDirectory(reader, directory)
|
||||
fileEntry, err := getFreeFileEntryInDirectory(readerWriter, directory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -89,20 +95,23 @@ func WriteFile(writer io.WriterAt, reader io.ReaderAt, path string, fileType int
|
||||
fileEntry.StorageType = StorageTree
|
||||
}
|
||||
|
||||
writeFileEntry(writer, fileEntry)
|
||||
writeFileEntry(readerWriter, fileEntry)
|
||||
|
||||
// increment file count
|
||||
directoryHeaderBlock := ReadBlock(reader, fileEntry.HeaderPointer)
|
||||
directoryHeaderBlock, err := ReadBlock(readerWriter, fileEntry.HeaderPointer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
directoryHeader := parseDirectoryHeader(directoryHeaderBlock, fileEntry.HeaderPointer)
|
||||
directoryHeader.ActiveFileCount++
|
||||
writeDirectoryHeader(writer, reader, directoryHeader)
|
||||
writeDirectoryHeader(readerWriter, directoryHeader)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteFile deletes a file from a ProDOS volume
|
||||
func DeleteFile(writer io.WriterAt, reader io.ReaderAt, path string) error {
|
||||
fileEntry, err := getFileEntry(reader, path)
|
||||
func DeleteFile(readerWriter ReaderWriterAt, path string) error {
|
||||
fileEntry, err := getFileEntry(readerWriter, path)
|
||||
if err != nil {
|
||||
return errors.New("File not found")
|
||||
}
|
||||
@ -114,27 +123,33 @@ func DeleteFile(writer io.WriterAt, reader io.ReaderAt, path string) error {
|
||||
}
|
||||
|
||||
// free the blocks
|
||||
blocks, err := getBlocklist(reader, fileEntry)
|
||||
blocks, err := getBlocklist(readerWriter, fileEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
volumeBitmap, err := ReadVolumeBitmap(readerWriter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
volumeBitmap := ReadVolumeBitmap(reader)
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
freeBlockInVolumeBitmap(volumeBitmap, blocks[i])
|
||||
}
|
||||
writeVolumeBitmap(writer, reader, volumeBitmap)
|
||||
writeVolumeBitmap(readerWriter, volumeBitmap)
|
||||
|
||||
// decrement the directory entry count
|
||||
directoryBlock := ReadBlock(reader, fileEntry.HeaderPointer)
|
||||
directoryBlock, err := ReadBlock(readerWriter, fileEntry.HeaderPointer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
directoryHeader := parseDirectoryHeader(directoryBlock, fileEntry.HeaderPointer)
|
||||
|
||||
directoryHeader.ActiveFileCount--
|
||||
writeDirectoryHeader(writer, reader, directoryHeader)
|
||||
writeDirectoryHeader(readerWriter, directoryHeader)
|
||||
|
||||
// zero out directory entry
|
||||
fileEntry.StorageType = 0
|
||||
fileEntry.FileName = ""
|
||||
writeFileEntry(writer, fileEntry)
|
||||
writeFileEntry(readerWriter, fileEntry)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -157,12 +172,16 @@ func GetDirectoryAndFileNameFromPath(path string) (string, string) {
|
||||
return directory, fileName
|
||||
}
|
||||
|
||||
func updateVolumeBitmap(writer io.WriterAt, reader io.ReaderAt, blockList []int) {
|
||||
volumeBitmap := ReadVolumeBitmap(reader)
|
||||
func updateVolumeBitmap(readerWriter ReaderWriterAt, blockList []int) error {
|
||||
volumeBitmap, err := ReadVolumeBitmap(readerWriter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < len(blockList); i++ {
|
||||
markBlockInVolumeBitmap(volumeBitmap, blockList[i])
|
||||
}
|
||||
writeVolumeBitmap(writer, reader, volumeBitmap)
|
||||
writeVolumeBitmap(readerWriter, volumeBitmap)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeSaplingFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
||||
@ -206,17 +225,26 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry) ([]int, error) {
|
||||
blocks[0] = fileEntry.KeyPointer
|
||||
return blocks, nil
|
||||
case StorageSapling:
|
||||
index := ReadBlock(reader, fileEntry.KeyPointer)
|
||||
index, err := ReadBlock(reader, fileEntry.KeyPointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blocks[0] = fileEntry.KeyPointer
|
||||
for i := 0; i < fileEntry.BlocksUsed-1; i++ {
|
||||
blocks[i+1] = int(index[i]) + int(index[i+256])*256
|
||||
}
|
||||
return blocks, nil
|
||||
case StorageTree:
|
||||
masterIndex := ReadBlock(reader, fileEntry.KeyPointer)
|
||||
masterIndex, err := ReadBlock(reader, fileEntry.KeyPointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blocks[0] = fileEntry.KeyPointer
|
||||
for i := 0; i < 128; i++ {
|
||||
index := ReadBlock(reader, int(masterIndex[i])+int(masterIndex[i+256])*256)
|
||||
index, err := ReadBlock(reader, int(masterIndex[i])+int(masterIndex[i+256])*256)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for j := 0; j < 256 && i*256+j < fileEntry.BlocksUsed; j++ {
|
||||
if (int(index[j]) + int(index[j+256])*256) == 0 {
|
||||
return blocks, nil
|
||||
@ -237,7 +265,10 @@ func getDataBlocklist(reader io.ReaderAt, fileEntry FileEntry) ([]int, error) {
|
||||
return blocks, nil
|
||||
case StorageSapling:
|
||||
blocks := make([]int, fileEntry.BlocksUsed-1)
|
||||
index := ReadBlock(reader, fileEntry.KeyPointer)
|
||||
index, err := ReadBlock(reader, fileEntry.KeyPointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < fileEntry.BlocksUsed-1; i++ {
|
||||
blocks[i] = int(index[i]) + int(index[i+256])*256
|
||||
}
|
||||
@ -247,7 +278,7 @@ func getDataBlocklist(reader io.ReaderAt, fileEntry FileEntry) ([]int, error) {
|
||||
return nil, errors.New("Unsupported file storage type")
|
||||
}
|
||||
|
||||
func createBlockList(reader io.ReaderAt, fileSize int) []int {
|
||||
func createBlockList(reader io.ReaderAt, fileSize int) ([]int, error) {
|
||||
numberOfBlocks := fileSize / 512
|
||||
if fileSize%512 > 0 {
|
||||
numberOfBlocks++
|
||||
@ -265,15 +296,21 @@ func createBlockList(reader io.ReaderAt, fileSize int) []int {
|
||||
numberOfBlocks++
|
||||
}
|
||||
}
|
||||
volumeBitmap := ReadVolumeBitmap(reader)
|
||||
volumeBitmap, err := ReadVolumeBitmap(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockList := findFreeBlocks(volumeBitmap, numberOfBlocks)
|
||||
|
||||
return blockList
|
||||
return blockList, nil
|
||||
}
|
||||
|
||||
func getFileEntry(reader io.ReaderAt, path string) (FileEntry, error) {
|
||||
directory, fileName := GetDirectoryAndFileNameFromPath(path)
|
||||
_, _, fileEntries := ReadDirectory(reader, directory)
|
||||
_, _, fileEntries, err := ReadDirectory(reader, directory)
|
||||
if err != nil {
|
||||
return FileEntry{}, err
|
||||
}
|
||||
|
||||
if fileEntries == nil || len(fileEntries) == 0 {
|
||||
return FileEntry{}, errors.New("File entry not found")
|
||||
|
@ -8,14 +8,13 @@ package prodos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CreateVolume formats a new ProDOS volume including boot block,
|
||||
// volume bitmap and empty directory
|
||||
func CreateVolume(writer io.WriterAt, reader io.ReaderAt, volumeName string, numberOfBlocks int) {
|
||||
func CreateVolume(readerWriter ReaderWriterAt, volumeName string, numberOfBlocks int) {
|
||||
if numberOfBlocks > 65535 || numberOfBlocks < 64 {
|
||||
return
|
||||
}
|
||||
@ -28,7 +27,7 @@ func CreateVolume(writer io.WriterAt, reader io.ReaderAt, volumeName string, num
|
||||
|
||||
blankBlock := make([]byte, 512)
|
||||
for i := 0; i < numberOfBlocks; i++ {
|
||||
WriteBlock(writer, i, blankBlock)
|
||||
WriteBlock(readerWriter, i, blankBlock)
|
||||
}
|
||||
|
||||
volumeHeader := [43]byte{}
|
||||
@ -63,10 +62,10 @@ func CreateVolume(writer io.WriterAt, reader io.ReaderAt, volumeName string, num
|
||||
volumeHeader[0x29] = byte(numberOfBlocks & 0xFF)
|
||||
volumeHeader[0x2A] = byte(numberOfBlocks >> 8)
|
||||
|
||||
writer.WriteAt(volumeHeader[:], 1024)
|
||||
readerWriter.WriteAt(volumeHeader[:], 1024)
|
||||
|
||||
// boot block 0
|
||||
WriteBlock(writer, 0, getBootBlock())
|
||||
WriteBlock(readerWriter, 0, getBootBlock())
|
||||
|
||||
// pointers to volume directory blocks
|
||||
for i := 2; i < 6; i++ {
|
||||
@ -83,12 +82,12 @@ func CreateVolume(writer io.WriterAt, reader io.ReaderAt, volumeName string, num
|
||||
pointers[2] = byte(i + 1)
|
||||
}
|
||||
pointers[3] = 0x00
|
||||
writer.WriteAt(pointers, int64(i*512))
|
||||
readerWriter.WriteAt(pointers, int64(i*512))
|
||||
}
|
||||
|
||||
// volume bit map starting at block 6
|
||||
volumeBitmap := createVolumeBitmap(numberOfBlocks)
|
||||
writeVolumeBitmap(writer, reader, volumeBitmap)
|
||||
writeVolumeBitmap(readerWriter, volumeBitmap)
|
||||
}
|
||||
|
||||
func getBootBlock() []byte {
|
||||
|
@ -21,9 +21,9 @@ func TestCreateVolume(t *testing.T) {
|
||||
t.Run(testname, func(t *testing.T) {
|
||||
file := NewMemoryFile(0x2000000)
|
||||
|
||||
CreateVolume(file, file, tt.wantVolumeName, tt.blocks)
|
||||
CreateVolume(file, tt.wantVolumeName, tt.blocks)
|
||||
|
||||
volumeHeader, _, fileEntries := ReadDirectory(file, "")
|
||||
volumeHeader, _, fileEntries, _ := ReadDirectory(file, "")
|
||||
if volumeHeader.VolumeName != tt.wantVolumeName {
|
||||
t.Errorf("got volume name %s, want %s", volumeHeader.VolumeName, tt.wantVolumeName)
|
||||
}
|
||||
@ -34,7 +34,7 @@ func TestCreateVolume(t *testing.T) {
|
||||
t.Errorf("got files %d, want 0", len(fileEntries))
|
||||
}
|
||||
|
||||
volumeBitmap := ReadVolumeBitmap(file)
|
||||
volumeBitmap, _ := ReadVolumeBitmap(file)
|
||||
freeBlockCount := GetFreeBlockCount(volumeBitmap, tt.blocks)
|
||||
if freeBlockCount != tt.wantFreeBlocks {
|
||||
t.Errorf("got free blocks: %d, want %d", freeBlockCount, tt.wantFreeBlocks)
|
||||
|
@ -12,6 +12,11 @@ type MemoryFile struct {
|
||||
size int
|
||||
}
|
||||
|
||||
type ReaderWriterAt interface {
|
||||
ReadAt(data []byte, offset int64) (int, error)
|
||||
WriteAt(data []byte, offset int64) (int, error)
|
||||
}
|
||||
|
||||
// NewMemoryFile creates an in-memory file of the specified size in bytes
|
||||
func NewMemoryFile(size int) *MemoryFile {
|
||||
return &MemoryFile{make([]byte, size), size}
|
||||
|
Loading…
Reference in New Issue
Block a user