Skip to content

Roland D-20 filesystem updates can exceed bounds and corrupt filenames #871

Description

@rjburrows

Summary

Direct filesystem updates on Roland D-20 disks can select out-of-bounds blocks and rewrite existing filenames incorrectly.

Reproduction

fluxengine putfile -c rolandd20 -f drive:1 \  -l TESTSND.333 -p TESTSND2.333

The disk uses the rolandd20 profile and a Greaseweazle-connected 80-track PC drive.

Observed behavior

  1. The initial write failed with:
Error: invalid filesystem: sector 972 is out of bounds

The D-20 format has 78 tracks × 12 sectors, so sector 972 is outside its filesystem.

  1. After the allocation issue was worked around, a directory rewrite changed existing names while retaining their original byte counts and file data:
TESTALL.111  -> TESTALL.11.1
TESTSONG.222 -> TESTSONG.2.22
TESTSND.333  -> TESTSND.33.3
TESTRHY.444  -> TESTRHY.44.4

The newly added name TESTSND2.333 was correct.

Likely causes and proposed fixes

Allocation bounds

RolandFsFilesystem::init() derives its allocation count from the drive-probed sector count. A physical probe can expose extra tracks that are not part of the D-20 filesystem, allowing allocation to target an invalid block.

For the current Roland GCRDOS layout, allocation should be bounded by the tracks arranged around the directory track:

_filesystemBlocks = _config.directory_track() * 2;
_midBlock = _config.directory_track();

A more general option would be an explicit filesystem-block-count field in RolandFsProto.

Filename encoding

RolandDirent::filename should remain the human-readable name. It is currently sometimes pre-mangled before directory serialization, while existing entries are human-readable after mounting. Rewriting then puts the literal dot in the fixed 13-byte on-disk field, shifting the extension when the disk is read again.

Suggested changes:

// putFile
auto de = std::make_shared<RolandDirent>(path.front());

// moveFile
de->rename(newName.front());

// rewriteDirectory
const std::string mangledFilename = mangleFilename(de->filename);
bw.append(mangledFilename);
bw.pad(13 - mangledFilename.size(), '_');

This keeps file data and directory metadata separate and preserves names through directory rewrites.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions