From 876564d2614467327dd63010df676339f8c58054 Mon Sep 17 00:00:00 2001 From: Terence Boldt Date: Thu, 19 Jan 2023 00:30:17 -0500 Subject: [PATCH] Add directory creation --- main.go | 12 +++++ prodos/directory.go | 129 ++++++++++++++++++++++++++++++++++++++++---- prodos/file.go | 5 +- prodos/text.go | 1 + 4 files changed, 136 insertions(+), 11 deletions(-) diff --git a/main.go b/main.go index 18ef9ac..a7b3351 100644 --- a/main.go +++ b/main.go @@ -169,6 +169,18 @@ func main() { } defer file.Close() prodos.DeleteFile(file, pathName) + case "mkdir": + 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() + err = prodos.CreateDirectory(file, pathName) + if err != nil { + fmt.Printf("failed to create directory %s: %s\n", pathName, err) + return + } case "dumpfile": file, err := os.OpenFile(fileName, os.O_RDWR, 0755) if err != nil { diff --git a/prodos/directory.go b/prodos/directory.go index 6e9ec84..f6cad1d 100644 --- a/prodos/directory.go +++ b/prodos/directory.go @@ -31,11 +31,20 @@ type VolumeHeader struct { // DirectoryHeader from ProDOS type DirectoryHeader struct { - Name string - ActiveFileCount int - StartingBlock int - PreviousBlock int - NextBlock int + PreviousBlock int + NextBlock int + Name string + CreationTime time.Time + Version int + MinVersion int + Access int + EntryLength int + EntriesPerBlock int + ActiveFileCount int + StartingBlock int + ParentBlock int + ParentEntry int + ParentEntryLength int } const ( @@ -97,6 +106,75 @@ func ReadDirectory(reader io.ReaderAt, path string) (VolumeHeader, DirectoryHead return volumeHeader, directoryHeader, fileEntries, nil } +func CreateDirectory(readerWriter ReaderWriterAt, path string) error { + parentPath, newDirectory := GetDirectoryAndFileNameFromPath(path) + + existingFileEntry, _ := GetFileEntry(readerWriter, path) + if existingFileEntry.StorageType != StorageDeleted { + //DeleteFile(readerWriter, path) + return errors.New("directory already exists") + } + + fileEntry, err := getFreeFileEntryInDirectory(readerWriter, parentPath) + if err != nil { + errString := fmt.Sprintf("failed to create directory: %s", err) + return errors.New(errString) + } + + // get list of blocks to write file to + blockList, err := createBlockList(readerWriter, 512) + if err != nil { + errString := fmt.Sprintf("failed to create directory: %s", err) + return errors.New(errString) + } + + updateVolumeBitmap(readerWriter, blockList) + + fileEntry.FileName = newDirectory + fileEntry.BlocksUsed = 1 + fileEntry.CreationTime = time.Now() + fileEntry.ModifiedTime = time.Now() + fileEntry.AuxType = 0 + fileEntry.EndOfFile = 0x200 + fileEntry.FileType = 0x0F + fileEntry.KeyPointer = blockList[0] + fileEntry.Access = 0b11100011 + fileEntry.StorageType = StorageDirectory + + writeFileEntry(readerWriter, fileEntry) + + err = incrementFileCount(readerWriter, fileEntry) + if err != nil { + errString := fmt.Sprintf("failed to create directory: %s", err) + return errors.New(errString) + } + + directoryEntry := DirectoryHeader{ + PreviousBlock: 0, + NextBlock: 0, + Name: newDirectory, + CreationTime: time.Now(), + Version: 0x24, + MinVersion: 0, + Access: 0xE3, + EntryLength: 0x27, + EntriesPerBlock: 0x0D, + ActiveFileCount: 0, + StartingBlock: blockList[0], + ParentBlock: fileEntry.DirectoryBlock, + ParentEntry: fileEntry.DirectoryOffset, + ParentEntryLength: 0x27, + } + + err = writeDirectoryHeader(readerWriter, directoryEntry) + if err != nil { + errString := fmt.Sprintf("failed to create directory: %s", err) + return errors.New(errString) + } + + return nil +} + func getFreeFileEntryInDirectory(reader io.ReaderAt, directory string) (FileEntry, error) { _, directoryHeader, _, err := ReadDirectory(reader, directory) if err != nil { @@ -305,14 +383,32 @@ func parseDirectoryHeader(buffer []byte, blockNumber int) DirectoryHeader { nextBlock := int(buffer[0x02]) + int(buffer[0x03])*256 filenameLength := buffer[0x04] & 15 name := string(buffer[0x05 : filenameLength+0x05]) + creationTime := DateTimeFromProDOS(buffer[0x1C:0x20]) + version := int(buffer[0x20]) + minVersion := int(buffer[0x21]) + access := int(buffer[0x22]) + entryLength := int(buffer[0x23]) + entriesPerBlock := int(buffer[0x24]) fileCount := int(buffer[0x25]) + int(buffer[0x26])*256 + parentBlock := int(buffer[0x27]) + int(buffer[0x28])*256 + parentEntry := int(buffer[0x29]) + parentEntryLength := int(buffer[0x2A]) directoryEntry := DirectoryHeader{ - PreviousBlock: previousBlock, - NextBlock: nextBlock, - StartingBlock: blockNumber, - Name: name, - ActiveFileCount: fileCount, + PreviousBlock: previousBlock, + NextBlock: nextBlock, + StartingBlock: blockNumber, + Name: name, + CreationTime: creationTime, + Version: version, + MinVersion: minVersion, + Access: access, + EntryLength: entryLength, + EntriesPerBlock: entriesPerBlock, + ActiveFileCount: fileCount, + ParentBlock: parentBlock, + ParentEntry: parentEntry, + ParentEntryLength: parentEntryLength, } return directoryEntry @@ -331,8 +427,21 @@ func writeDirectoryHeader(readerWriter ReaderWriterAt, directoryHeader Directory for i := 0; i < len(directoryHeader.Name); i++ { buffer[0x05+i] = directoryHeader.Name[i] } + creationTime := DateTimeToProDOS(directoryHeader.CreationTime) + for i := 0; i < 4; i++ { + buffer[0x1C+i] = creationTime[i] + } + buffer[0x20] = byte(directoryHeader.Version) + buffer[0x21] = byte(directoryHeader.MinVersion) + buffer[0x22] = byte(directoryHeader.Access) + buffer[0x23] = byte(directoryHeader.EntryLength) + buffer[0x24] = byte(directoryHeader.EntriesPerBlock) buffer[0x25] = byte(directoryHeader.ActiveFileCount & 0x00FF) buffer[0x26] = byte(directoryHeader.ActiveFileCount >> 8) + buffer[0x27] = byte(directoryHeader.ParentBlock & 0x00FF) + buffer[0x28] = byte(directoryHeader.ParentBlock >> 8) + buffer[0x29] = byte(directoryHeader.ParentEntry) + buffer[0x2A] = byte(directoryHeader.ParentEntryLength) WriteBlock(readerWriter, directoryHeader.StartingBlock, buffer) return nil diff --git a/prodos/file.go b/prodos/file.go index 89cae3e..974b2b2 100644 --- a/prodos/file.go +++ b/prodos/file.go @@ -102,7 +102,10 @@ func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType i writeFileEntry(readerWriter, fileEntry) - // increment file count + return incrementFileCount(readerWriter, fileEntry) +} + +func incrementFileCount(readerWriter ReaderWriterAt, fileEntry FileEntry) error { directoryHeaderBlock, err := ReadBlock(readerWriter, fileEntry.HeaderPointer) if err != nil { return err diff --git a/prodos/text.go b/prodos/text.go index 5bf55bf..c5b30e5 100644 --- a/prodos/text.go +++ b/prodos/text.go @@ -99,6 +99,7 @@ func DumpFileEntry(fileEntry FileEntry) { fmt.Printf("File type: %02X\n", fileEntry.FileType) fmt.Printf("Storage type: %02X\n", fileEntry.StorageType) fmt.Printf("Header pointer: %04X\n", fileEntry.HeaderPointer) + fmt.Printf("Access: %04X\n", fileEntry.Access) fmt.Printf("\n") }