ProDOS-Utilities/main.go

186 lines
5.6 KiB
Go
Raw Permalink Normal View History

// 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.
// This file provides a command line utility to read, write and delete
// files and directories on a ProDOS drive image as well as format
// new volumes
2021-06-06 03:22:30 +00:00
package main
import (
2021-06-07 00:15:41 +00:00
"flag"
2021-06-06 03:22:30 +00:00
"fmt"
"os"
"strings"
2021-06-06 03:22:30 +00:00
"github.com/tjboldt/ProDOS-Utilities/prodos"
)
2022-12-31 14:14:27 +00:00
const version = "0.4.1"
2021-06-06 03:22:30 +00:00
func main() {
2021-06-07 00:15:41 +00:00
var fileName string
var pathName string
var command string
var outFileName string
2021-06-26 01:15:20 +00:00
var inFileName string
2021-06-09 12:23:18 +00:00
var blockNumber int
var volumeSize int
var volumeName string
2021-06-27 11:53:50 +00:00
var fileType int
var auxType int
flag.StringVar(&fileName, "d", "", "A ProDOS format drive image")
flag.StringVar(&pathName, "p", "", "Path name in ProDOS drive image (default is root of volume)")
2022-12-30 11:12:41 +00:00
flag.StringVar(&command, "c", "ls", "Command to execute: ls, get, put, rm, mkdir, readblock, writeblock, create, putall")
flag.StringVar(&outFileName, "o", "", "Name of file to write")
flag.StringVar(&inFileName, "i", "", "Name of file to read")
flag.IntVar(&volumeSize, "s", 65535, "Number of blocks to create the volume with (default 65535, 64 to 65535, 0x0040 to 0xFFFF hex input accepted)")
flag.StringVar(&volumeName, "v", "NO.NAME", "Specifiy a name for the volume from 1 to 15 characters")
flag.IntVar(&blockNumber, "b", 0, "A block number to read/write from 0 to 65535 (0x0000 to 0xFFFF hex input accepted)")
2022-12-30 11:12:41 +00:00
flag.IntVar(&fileType, "t", 0, "ProDOS FileType: 0x04 for TXT, 0x06 for BIN, 0xFC for BAS, 0xFF for SYS etc., omit to autodetect")
flag.IntVar(&auxType, "a", 0, "ProDOS AuxType from 0 to 65535 (0x0000 to 0xFFFF hex input accepted), omit to autodetect")
2021-06-07 00:15:41 +00:00
flag.Parse()
if len(fileName) == 0 {
printReadme()
flag.PrintDefaults()
2021-06-06 12:00:20 +00:00
os.Exit(1)
2021-06-06 03:22:30 +00:00
}
2021-06-06 12:00:20 +00:00
2021-06-07 00:15:41 +00:00
switch command {
case "ls":
2021-06-09 12:23:18 +00:00
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
if err != nil {
fmt.Printf("Failed to open drive image %s:\n %s", fileName, err)
2021-06-09 12:23:18 +00:00
os.Exit(1)
}
defer file.Close()
pathName = strings.ToUpper(pathName)
volumeHeader, _, fileEntries, err := prodos.ReadDirectory(file, pathName)
if err != nil {
fmt.Printf("Error: %s", err)
}
if len(pathName) == 0 {
pathName = "/" + volumeHeader.VolumeName
2021-06-09 12:23:18 +00:00
}
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)
2021-06-07 00:15:41 +00:00
case "get":
2021-06-09 12:23:18 +00:00
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
if err != nil {
fmt.Printf("Failed to open drive image %s:\n %s", fileName, err)
2021-06-09 12:23:18 +00:00
os.Exit(1)
}
defer file.Close()
2021-06-07 00:15:41 +00:00
if len(pathName) == 0 {
fmt.Println("Missing pathname")
os.Exit(1)
}
2021-06-30 04:04:59 +00:00
getFile, err := prodos.LoadFile(file, pathName)
if err != nil {
2021-07-02 11:58:06 +00:00
fmt.Printf("Failed to read file %s: %s\n", pathName, err)
os.Exit(1)
2021-06-30 04:04:59 +00:00
}
2021-06-26 01:15:20 +00:00
if len(outFileName) == 0 {
_, outFileName = prodos.GetDirectoryAndFileNameFromPath(pathName)
}
2021-06-09 12:23:18 +00:00
outFile, err := os.Create(outFileName)
if err != nil {
2021-07-02 11:58:06 +00:00
fmt.Printf("Failed to create output file %s: %s\n", outFileName, err)
2021-06-09 12:23:18 +00:00
os.Exit(1)
}
if strings.HasSuffix(strings.ToLower(outFileName), ".bas") {
fmt.Fprintf(outFile, prodos.ConvertBasicToText(getFile))
} else {
outFile.Write(getFile)
}
2021-06-26 01:15:20 +00:00
case "put":
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
if err != nil {
fmt.Printf("Failed to open drive image %s:\n %s", fileName, err)
2021-06-26 01:15:20 +00:00
os.Exit(1)
}
defer file.Close()
2022-12-30 11:12:41 +00:00
err = prodos.WriteFileFromFile(file, pathName, fileType, auxType, inFileName)
2021-06-30 04:04:59 +00:00
if err != nil {
2022-12-30 11:12:41 +00:00
fmt.Printf("Failed to write file %s", err)
2021-06-30 04:04:59 +00:00
}
2021-06-09 12:23:18 +00:00
case "readblock":
2021-12-12 15:43:30 +00:00
fmt.Printf("Reading block 0x%04X (%d):\n\n", blockNumber, blockNumber)
2021-06-09 12:23:18 +00:00
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
if err != nil {
fmt.Printf("Failed to open drive image %s:\n %s", fileName, err)
2021-06-09 12:23:18 +00:00
os.Exit(1)
}
defer file.Close()
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)
2021-12-12 15:43:30 +00:00
case "writeblock":
fmt.Printf("Writing block 0x%04X (%d):\n\n", blockNumber, blockNumber)
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()
inFile, err := os.ReadFile(inFileName)
if err != nil {
fmt.Printf("Failed to open input file %s: %s", inFileName, err)
os.Exit(1)
}
prodos.WriteBlock(file, blockNumber, inFile)
case "create":
file, err := os.Create(fileName)
2021-06-09 12:23:18 +00:00
if err != nil {
fmt.Printf("failed to create file: %s\n", err)
return
2021-06-09 12:23:18 +00:00
}
defer file.Close()
prodos.CreateVolume(file, volumeName, volumeSize)
2022-12-30 11:12:41 +00:00
case "putall":
file, err := os.Create(fileName)
if err != nil {
fmt.Printf("failed to create file: %s\n", err)
return
}
defer file.Close()
2022-12-31 14:14:27 +00:00
err = prodos.AddFilesFromHostDirectory(file, inFileName)
2022-12-30 11:12:41 +00:00
if err != nil {
fmt.Printf("failed to add host files: %s\n", err)
return
}
case "rm":
2021-06-12 02:43:35 +00:00
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
if err != nil {
fmt.Printf("Failed to open drive image %s:\n %s", fileName, err)
2021-06-12 02:43:35 +00:00
os.Exit(1)
}
defer file.Close()
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)
2021-06-07 00:15:41 +00:00
default:
fmt.Printf("Invalid command: %s\n\n", command)
flag.PrintDefaults()
2021-06-07 00:15:41 +00:00
os.Exit(1)
2021-06-06 03:22:30 +00:00
}
}