trackfile.device API and DAControl Reference¶
trackfile.device (AmigaOS 3.2) is a trackdisk.device clone backed by ADF disk image files. Besides the usual device vectors it has library-style functions that start and stop units and insert and eject image files: the TF* calls declared in <devices/trackfile.h> and SFD/trackfile_lib.sfd. The DAControl shell command is the reference client for these calls, and the AmigaOS 3.2 installer uses it to swap virtual floppies.
This article covers the API in detail: function prototypes and registers, tags, error codes, the unit model, the DAControl template, and a minimal C client. For an overview of the driver and its source layout, see trackfile.device and DAControl.
Units and the control unit¶
| Constant | Value | Meaning |
|---|---|---|
TRACKFILENAME 3.2+ |
"trackfile.device" |
Device name for OpenDevice() |
TFUNIT_CONTROL 3.2+ |
-1 |
Control unit. Open it to use the TF* functions |
TFSU_NextAvailableUnit 3.2+ |
-1 |
Pass to TFStartUnitTagList() to pick the next unused unit number |
TFGUD_AllUnits 3.2+ |
-1 |
Pass to TFGetUnitData() to list all units |
TFEFS_Unsupported 3.2+ |
-1 |
Returned by TFExamineFileSize() for an unsupported size |
TF_MINIMUM_CACHE_SIZE 3.2+ |
46000 |
Minimum shared cache size (8 tracks) |
From the driver's --background-- autodoc (in trackfile_device.c):
trackdisk.devicehad at most 4 units, fixed at power-up.trackfile.deviceadds virtual drives as you need them, limited only by memory. Release note 2.35 says the cache code sets an upper limit of 8,388,608 units.- A unit accepts 880 KB (3.5" DD, 901,120 bytes) or 1760 KB (3.5" HD, 1,802,240 bytes) images in the Amiga 1.0 format. 40-track 5.25" images and IBM 720K/1440K formats are not supported.
- To call the library functions, open the device with unit
TFUNIT_CONTROL. Open a numbered unit (≥ 0) only for normal trackdisk-style I/O, and only after that unit has been started.
A unit has three states:
- Not started. No memory and no unit Process.
- Started (active), no medium.
TFStartUnitTagList()has allocated the unit and created its Process. It behaves like an empty drive. - Medium present.
TFInsertMediaTagList()has attached an image file. While inserted, the file stays open, so it cannot be deleted or moved.
The device does not create an AmigaDOS device such as DA0:. DAControl mounts one itself (see Mounting a DOS device).
Function table¶
trackfile_lib.sfd 2.3 uses base _TrackFileBase (type struct Device *) and bias 6. The first six slots are the private device vectors (Open, Close, Expunge, Reserved, BeginIO, AbortIO), so the public functions start at -42.
| LVO | Function | Registers | Since |
|---|---|---|---|
| -42 | LONG TFStartUnitTagList(LONG which_unit, CONST struct TagItem *tags) |
d0, a0 | V1 |
| -48 | LONG TFStopUnitTagList(LONG which_unit, CONST struct TagItem *tags) |
d0, a0 | V1 |
| -54 | LONG TFInsertMediaTagList(LONG which_unit, CONST struct TagItem *tags) |
d0, a0 | V1 |
| -60 | LONG TFEjectMediaTagList(LONG which_unit, CONST struct TagItem *tags) |
d0, a0 | V1 |
| -66 | struct TrackFileUnitData *TFGetUnitData(LONG which_unit) |
d0 | V1 |
| -72 | VOID TFFreeUnitData(struct TrackFileUnitData *tfud) |
a0 | V1 |
| -78 | LONG TFChangeUnitTagList(LONG which_unit, CONST struct TagItem *tags) |
d0, a0 | V2 |
| -84 | LONG TFExamineFileSize(LONG file_size) |
d0 | V2 |
Every ...TagList function also has a varargs form: TFStartUnitTags(), TFStopUnitTags(), TFInsertMediaTags(), TFEjectMediaTags(), TFChangeUnitTags(). The offsets match Include_I/lvo/trackfile_lib.i, and proto/trackfile.h declares extern struct Device *TrackFileBase.
Version check.
DAControlrequirestrackfile.device2.15 or later because it usesTFChangeUnitTagList()andTFExamineFileSize(). It checkslib_Version/lib_Revisionon the opened device. The function was first calledTFChangeMediaTagList()and was renamedTFChangeUnitTagList()in 2.37.Process only.
TFStartUnitTagList(),TFInsertMediaTagList()andTFEjectMediaTagList()returnTFERROR_Deniedwhen called from a plain Task, because they open and close files. Release note 2.26 says that API functions needing a Process "now return either an error code or NULL" instead of crashing.
Functions¶
TFStartUnitTagList¶
Allocates the unit and creates the unit Process. which_unit must be ≥ 0, or TFSU_NextAvailableUnit. It returns the unit number started (≥ 0) or a negative error code.
| Tag | Type | Meaning |
|---|---|---|
TF_DriveType 3.2+ |
LONG |
DRIVE3_5 (DD, default) or DRIVE3_5_150RPM (HD), from <devices/trackdisk.h> |
TF_EnableChecksums 3.2+ |
BOOL |
Keep track and disk checksums so that two images with the same contents cannot be inserted. Default FALSE |
TF_MaxCacheMemory 3.2+ |
ULONG |
Shared cache size in bytes. Only takes effect the first time, before the cache exists. Default 0 |
Errors: TFERROR_Denied, TFERROR_InvalidDriveType, TFERROR_UnitBusy (already started), TFERROR_OutOfMemory, TFERROR_ProcessFailed (check IoErr()).
TFStopUnitTagList¶
Shuts down an active unit and frees its Process. DAControl says this releases "between 12-17 KBytes of RAM". No tags are defined. It returns 0 or an error: TFERROR_UnitNotFound, ERROR_OBJECT_IN_USE (a medium is still inserted, so eject it first), or TFERROR_Aborted (the unit is already shutting down). A stopped unit can be started again.
TFInsertMediaTagList¶
Attaches an image file to a started, empty unit.
| Tag | Type | Meaning |
|---|---|---|
TF_ImageFileName 3.2+ |
STRPTR |
Path of the ADF, relative to the caller's current directory |
TF_ImageFileHandle 3.2+ |
BPTR |
An already-open file. If this is non-NULL, TF_ImageFileName is ignored. On success the unit takes ownership of the handle |
TF_WriteProtected 3.2+ |
BOOL |
Insert the image read-only (non-zero) or writable (FALSE) |
TF_EnableUnitCache 3.2+ |
BOOL |
Let this unit use the shared read cache. Default FALSE |
TF_PrefillUnitCache 3.2+ |
BOOL |
Read the whole image into the cache when it is inserted. Default FALSE |
The TF_WriteProtected autodoc says "Defaults to FALSE", but in functions.c the local write_protected starts as TRUE. Pass the tag explicitly. DAControl also inserts read-only unless you give WRITEPROTECTED=NO. A writable insert can still come out read-only if the image file or the volume it is on cannot be written.
Errors: TFERROR_Denied, TFERROR_UnitNotFound, TFERROR_AlreadyInUse (a medium is already present), TFERROR_InvalidFile, TFERROR_NoFileGiven, TFERROR_InvalidFileSize, TFERROR_DuplicateVolume, TFERROR_DuplicateDisk, TFERROR_OutOfMemory.
Insertions and ejections send the normal disk-change notifications, so software that uses TD_ADDCHANGEINT sees them as disk swaps (release note 2.31).
TFEjectMediaTagList¶
Detaches the image and writes back any buffered track data first.
| Tag | Type | Meaning |
|---|---|---|
TF_Timeout 3.2+ |
LONG |
Seconds to wait for the file system to "settle". Values below 5 mean eject immediately, which may fail while the disk is busy. Default 0 |
While a timeout is running, Ctrl-C cancels the wait and the function returns ERROR_BREAK. Other errors: TFERROR_Denied, TFERROR_UnitNotFound, TDERR_SeekError (the image size or attributes changed, so it may be truncated), TDERR_WriteProt (buffered data could no longer be written back), and TDERR_DiskChanged.
TFGetUnitData / TFFreeUnitData¶
TFGetUnitData(n) returns an independent snapshot of one unit. With TFGUD_AllUnits it returns a linked list of all units. On failure it returns NULL; check IoErr(). Always release the result with TFFreeUnitData(), which accepts NULL.
struct TrackFileUnitData {
struct TrackFileUnitData *tfud_Next; /* next unit or NULL */
ULONG tfud_Size; /* size of this structure */
LONG tfud_UnitNumber;
LONG tfud_DriveType; /* DRIVE3_5, DRIVE3_5_150RPM */
STRPTR tfud_DeviceName; /* e.g. "DA0", may be NULL */
STRPTR tfud_FileName; /* image path, may be NULL */
BOOL tfud_IsActive; /* unit Process running */
BOOL tfud_IsWritable;
BOOL tfud_MediumIsPresent;
BOOL tfud_IsBusy; /* I/O in progress ("motor on") */
BOOL tfud_ChecksumsEnabled;
struct TrackFileChecksum tfud_Checksum; /* 64-bit: tfc_high, tfc_low */
BOOL tfud_VolumeValid;
TEXT tfud_VolumeName[32];
struct DateStamp tfud_VolumeDate;
ULONG tfud_FileSysSignature; /* may be 0 */
ULONG tfud_BootBlockChecksum; /* may be 0 */
BOOL tfud_CacheEnabled;
ULONG tfud_CacheAccesses;
ULONG tfud_CacheMisses;
};
The volume, boot block and checksum fields are updated live as the image changes.
TFChangeUnitTagList (V2)¶
Changes settings on a running unit, or global settings when which_unit is TFUNIT_CONTROL.
| Tag | Type | Applies to | Meaning |
|---|---|---|---|
TF_WriteProtected 3.2+ |
BOOL |
unit ≥ 0 | Change the write protection without a manual eject. Clearing it fails if the volume or the file is read-only |
TF_EnableUnitCache 3.2+ |
BOOL |
unit ≥ 0 | Turn cache use on or off for this unit. Disabling it invalidates the unit's entries and resets its counters |
TF_MaxCacheMemory 3.2+ |
ULONG |
TFUNIT_CONTROL only |
Resize the shared cache. 0 disables it |
TF_TagItemFailed 3.2+ |
struct TagItem ** |
any | Receives the address of the tag that failed |
Tags are processed in order, and processing stops at the first error, so earlier tags may already have taken effect.
TFExamineFileSize (V2)¶
TFExamineFileSize(size) maps an image size to a drive type: DRIVE3_5 for 901,120 bytes, DRIVE3_5_150RPM for 1,802,240 bytes, otherwise TFEFS_Unsupported (-1). The autodoc also lists DRIVE5_25, but 5.25" images are not currently supported and the implementation's size table has no entry for them. DAControl calls this function before it inserts each wildcard match.
Error codes¶
TFStart/Stop/InsertMedia/EjectMedia can return these codes in addition to normal dos.library and trackdisk.device errors. The text column is the message DAControl prints (tools.c); a dash means DAControl has no specific text for that code.
| Code | Value | DAControl message |
|---|---|---|
TFERROR_UnitBusy 3.2+ |
-202041 | unit is busy |
TFERROR_OutOfMemory 3.2+ |
-202042 | out of memory |
TFERROR_UnitNotFound 3.2+ |
-202043 | unit not found |
TFERROR_AlreadyInUse 3.2+ |
-202044 | unit is already in use |
TFERROR_UnitNotActive 3.2+ |
-202045 | unit is not active |
TFERROR_InvalidFile 3.2+ |
-202046 | disk file is not valid |
TFERROR_InvalidFileSize 3.2+ |
-202047 | disk file size is not supported |
TFERROR_NoFileGiven 3.2+ |
-202048 | no disk file was given |
TFERROR_Aborted 3.2+ |
-202049 | command was aborted |
TFERROR_InvalidDriveType 3.2+ |
-202050 | — |
TFERROR_ProcessFailed 3.2+ |
-202051 | unit process creation has failed |
TFERROR_NoMediumPresent 3.2+ |
-202052 | no medium is present |
TFERROR_ReadOnlyVolume 3.2+ |
-202053 | image file parent volume is not writable |
TFERROR_ReadOnlyFile 3.2+ |
-202054 | image file is not writable |
TFERROR_DuplicateDisk 3.2+ |
-202055 | contents of image file are duplicate of an active file |
TFERROR_DuplicateVolume 3.2+ |
-202056 | contents would likely crash the Amiga file system |
TFERROR_Denied 3.2+ |
-202057 | — |
TFERROR_NotSupported 3.2+ |
-202058 | — |
Tag summary¶
All tags are based on TF_Dummy = TAG_USER + 0x20200400.
| Tag | Offset | Type | Used by |
|---|---|---|---|
TF_ImageFileName 3.2+ |
+1 | STRPTR |
Insert |
TF_ImageFileHandle 3.2+ |
+2 | BPTR |
Insert |
TF_WriteProtected 3.2+ |
+3 | BOOL |
Insert, Change |
TF_DriveType 3.2+ |
+4 | LONG |
Start |
TF_Timeout 3.2+ |
+5 | LONG |
Eject |
TF_EnableChecksums 3.2+ |
+6 | BOOL |
Start |
TF_TagItemFailed 3.2+ |
+7 | struct TagItem ** |
Change |
TF_MaxCacheMemory 3.2+ |
+8 | ULONG |
Start (control unit, once), Change (control unit) |
TF_EnableUnitCache 3.2+ |
+9 | ULONG/BOOL |
Insert, Change |
TF_PrefillUnitCache 3.2+ |
+10 | BOOL |
Insert |
Duplicate-disk protection¶
Two mounted volumes with the same root name and the same creation date can crash the AmigaDOS file system. trackfile.device guards against this in two ways:
TFERROR_DuplicateVolume(2.21 and later): before inserting, the driver reads the root block and compares its name and date with the volume nodes already in use.TFERROR_DuplicateDisk: when a unit hasTF_EnableChecksums, a 64-bit checksum over all tracks, with the file size added in (2.18), is compared with the other units. Turning this on means the whole image is read when it is inserted, so mounting is slower.DAControlturns it on withUSECHECKSUMS=YES.
The shared cache¶
The read cache is shared by all units and is enabled by default from 2.44. Each entry costs 32 + 5632 = 5664 bytes, and sizes are rounded to whole entries. Successful reads fill the cache, successful writes update existing entries only, and ejecting an image invalidates that unit's entries. According to the DAControl release notes, PREFILLCACHE only makes sense when the cache holds at least 901,120 bytes; otherwise the prefill evicts its own entries. Prefill is ignored when the image is larger than the cache.
Mounting a DOS device¶
The device only emulates the drive. To get a DAx: volume, DAControl (mount_floppy_file.c) builds a DosEnvec the way the floppy "strap" module does, and adds it with AddDosEntry() (not AddBootNode()). The main values:
| Field | Value |
|---|---|
de_TableSize |
DE_BOOTBLOCKS |
de_SizeBlock |
TD_SECTOR / 4 |
de_Surfaces |
2 |
de_BlocksPerTrack |
11 (DD) or 22 (HD) |
de_Reserved / de_BootBlocks |
2 |
de_LowCyl / de_HighCyl |
0 / 79 |
de_NumBuffers |
5 |
de_BootPri |
-128 (never bootable) |
de_DosType |
ID_DOS_DISK |
The file system comes from the FileSystem.resource entry with the matching DOS type (the highest version wins), or from the file named by FILESYSTEM. When it ejects or stops a unit, DAControl calls Inhibit() on the DOS device around TFEjectMediaTags().
Minimal C example¶
This example opens the control unit, starts a unit, inserts an image read-only, prints the unit list, then ejects the image and stops the unit. It does not mount a DOS device, so the data is reachable only through trackdisk-style I/O on the unit. Run it from the Shell, because the calls need a Process.
#include <exec/types.h>
#include <exec/io.h>
#include <dos/dos.h>
#include <devices/trackdisk.h>
#include <devices/trackfile.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/trackfile.h>
#include <string.h>
struct Device *TrackFileBase;
int main(int argc, char **argv)
{
struct IOStdReq ctrl;
struct TrackFileUnitData *tfud, *t;
struct FileInfoBlock *fib;
BPTR lock;
LONG drive_type = TFEFS_Unsupported;
LONG unit, error;
int rc = RETURN_FAIL;
if (argc != 2)
return RETURN_ERROR;
memset(&ctrl, 0, sizeof(ctrl));
if (OpenDevice(TRACKFILENAME, TFUNIT_CONTROL, (struct IORequest *)&ctrl, 0) != 0)
{
Printf("Cannot open %s\n", TRACKFILENAME);
return RETURN_FAIL;
}
TrackFileBase = ctrl.io_Device;
/* TFExamineFileSize() is V2; DAControl requires 2.15 */
if (TrackFileBase->dd_Library.lib_Version < 2)
goto out;
/* Pick the drive type from the image size */
if ((fib = AllocDosObject(DOS_FIB, NULL)) != NULL)
{
if ((lock = Lock(argv[1], SHARED_LOCK)) != 0)
{
if (Examine(lock, fib))
drive_type = TFExamineFileSize(fib->fib_Size);
UnLock(lock);
}
FreeDosObject(DOS_FIB, fib);
}
if (drive_type == TFEFS_Unsupported)
{
Printf("%s: not an 880K/1760K ADF\n", argv[1]);
goto out;
}
unit = TFStartUnitTags(TFSU_NextAvailableUnit,
TF_DriveType, drive_type,
TAG_DONE);
if (unit < 0)
{
Printf("Start failed (%ld)\n", unit);
goto out;
}
error = TFInsertMediaTags(unit,
TF_ImageFileName, argv[1],
TF_WriteProtected, TRUE,
TAG_DONE);
if (error != 0)
{
Printf("Insert failed (%ld)\n", error);
TFStopUnitTags(unit, TAG_DONE);
goto out;
}
tfud = TFGetUnitData(TFGUD_AllUnits);
for (t = tfud; t != NULL; t = t->tfud_Next)
{
Printf("unit %ld medium=%s file=%s volume=%s\n",
t->tfud_UnitNumber,
t->tfud_MediumIsPresent ? "yes" : "no",
t->tfud_FileName ? t->tfud_FileName : "-",
t->tfud_VolumeValid ? t->tfud_VolumeName : "-");
}
TFFreeUnitData(tfud);
/* Wait up to 5 seconds for the image to settle, then release it */
error = TFEjectMediaTags(unit, TF_Timeout, 5, TAG_DONE);
if (error == 0)
error = TFStopUnitTags(unit, TAG_DONE);
rc = (error == 0) ? RETURN_OK : RETURN_WARN;
out:
CloseDevice((struct IORequest *)&ctrl);
return rc;
}
DAControl command reference¶
C:DAControl (source revision 2.35; the release notes end at 2.34) loads, ejects, changes and creates ADF images. It needs trackfile.device 2.15 or later.
LOAD/S,EJECT/S,CHANGE/S,TIMEOUT/K/N,START/S,STOP/S,CREATE/S,
INSTALL=BOOTABLE/S,USECHECKSUMS/K,ENABLECACHE/K,PREFILLCACHE/K,
CACHESIZE/K/N,SAFEEJECT/K,FILESYSTEM/K,FILESYSTEMTYPE=FSTYPE/K,
OVERWRITE/S,DISKTYPE/K,LABEL/K,PROTECT=WRITEPROTECTED/K,
UNIT=DEVICE/K,INFO/S,SHOWCHECKSUMS/S,SHOWVOLUMES/S,
SHOWBOOTBLOCKS/S,SHOWCACHES/S,SETENV/S,SETVAR/S,QUIET/S,
VERBOSE/S,IGNORE/S,FILE/M
The cache keywords (ENABLECACHE, PREFILLCACHE, CACHESIZE, SHOWCACHES) are compiled in when ENABLE_CACHE is defined in cache.h, which it is by default since DAControl 2.30.
| Option | Effect |
|---|---|
LOAD |
Start or reuse a unit and mount the image(s). Wildcards are allowed |
EJECT |
Eject the medium of DEVICE. After this the file can be moved or deleted |
CHANGE |
Eject (if a medium is present) and load a new file. Without FILE, it changes the write protection or cache setting of a running unit |
TIMEOUT n |
Seconds to wait for a busy medium on eject. The minimum is 5. Ctrl-C or BREAK cancels |
START / STOP |
Start a unit without a medium, or stop one after ejecting. Combine with EJECT |
UNIT=DEVICE |
A unit number or a name such as DA0:. ANY picks or starts a free unit. LAST reads DA_LASTDEVICE |
WRITEPROTECTED=PROTECT |
YES (the default) or NO for a writable image |
USECHECKSUMS |
YES turns on disk and track checksums (duplicate-disk check) |
SAFEEJECT |
YES asks the file system to flush and release the medium, which is faster than waiting for the "motor" to stop. Some software may not notice that the volume has gone |
CREATE |
Create, format and mount a blank image (always writable). Refuses to overwrite an existing file unless you give OVERWRITE |
BOOTABLE=INSTALL |
Make the created image bootable |
DISKTYPE |
DD (880 KB) or HD (1.76 MB) for CREATE |
LABEL |
Volume name for CREATE |
FILESYSTEMTYPE=FSTYPE |
OFS or FFS, optionally +INTERNATIONAL, +DIRCACHE or +LONGNAMES |
FILESYSTEM |
Load this file system instead of the floppy default. It is reloaded on every use, so watch memory |
INFO |
List the units. Add SHOWCHECKSUMS, SHOWVOLUMES, SHOWBOOTBLOCKS or SHOWCACHES for more columns |
SETVAR / SETENV |
Store the last device used in the local or global variable DA_LASTDEVICE |
QUIET / VERBOSE |
Less or more output |
IGNORE |
Keep going past missing or unsuitable files (from 2.23) |
ENABLECACHE, PREFILLCACHE |
Per-unit cache use at insert time. PREFILLCACHE=YES implies ENABLECACHE=YES |
CACHESIZE n |
Shared cache size in bytes. 0 is valid and turns the cache off |
Examples¶
1> DAControl LOAD #?.adf
1> DAControl LOAD disk.adf DEVICE DA0:
1> DAControl LOAD adf/test1.adf WRITEPROTECTED=NO
1> DAControl CREATE LABEL=empty adf/empty.adf
1> DAControl CREATE FSTYPE=FFS+INTL adf/empty.adf
1> DAControl CHANGE DEVICE=DA0: PROTECT=YES
1> DAControl EJECT TIMEOUT=5 STOP UNIT 0
1> DAControl INFO
Device Type Active Access File
DA0 3.5" DD Yes read-only Archive:Demo 1.adf
DA2 3.5" DD Yes * read-only Archive:Mindwalker.adf
DA5 3.5" DD No - -
Yes * means the unit is busy (I/O in progress). A unit showing No has been stopped, but its DAx: entry remains and looks like an empty drive. SHOWCHECKSUMS prints the 64-bit disk checksum as an 11-character string.
In installation scripts¶
DAControl was written so that one install script works from any medium. A script typically loads a disk image into a fixed device, works with the volume, and ejects it:
DAControl LOAD ADF/Disk1.adf DEVICE DA0: QUIET
; ... copy files from the mounted volume ...
DAControl EJECT DEVICE DA0: TIMEOUT 10 QUIET
When the unit doesn't matter, combine DEVICE=ANY with SETVAR and then refer to $DA_LASTDEVICE or DEVICE=LAST.
Workbench icons¶
A project icon whose default tool is C:DAControl mounts its ADF when double-clicked. process_icons.c reads these tool types: WRITEPROTECTED (or PROTECTED), USECHECKSUMS, FILESYSTEM, ENABLECACHE, PREFILLCACHE, CACHESIZE.
Gotchas from the release notes¶
- Change interrupts: as with
trackdisk.device, anIOStdReqused forTD_ADDCHANGEINTis not replied. It stays queued untilTD_REMCHANGEINTis sent with the same request (2.46).TD_REMCHANGEINTandCMD_STARTalways run on the caller's context. - IOF_QUICK is honoured only when the flag is actually set (2.26), and only a small subset of commands support it.
- FFS V40 quirk: requests whose
mn_Lengthis 0 skip the message-length validity checks, because FFS V40 would otherwise fail to mount (2.25). - Old file systems: if the volume holding the image lacks
ExamineFH(),NameFromFH()and similar calls, the driver falls back, and the full path name or write-protect detection may not be available (2.32/2.33). - Stricter than trackdisk: trackfile rejects some invalid requests that
trackdisk.devicesilently accepts, such as a non-chipTD_RAWREADbuffer. A rejection usually points to undefined behaviour on real hardware too.
See Also¶
- trackfile.device and DAControl: overview and source layout
- trackdisk.device: the command set that trackfile emulates
- Device Driver Command-Set Rules
- New Style Device Commands
- ADF Format Specification
- DOS Device List
Sources: NDK 3.2 R4 SFD/trackfile_lib.sfd, FD/trackfile_lib.fd, Include_H/devices/trackfile.h, Include_H/devices/trackdisk.h, Include_I/lvo/trackfile_lib.i, Include_H/proto/trackfile.h, DAControl+trackfile/README, DAControl+trackfile/trackfile/{functions.c,trackfile_device.c}, DAControl+trackfile/DAControl/{cmd_main.c,start_unit.c,insert_media_by_name.c,mount_floppy_file.c,process_icons.c,tools.c,cache.h}, ReleaseNotes/trackfile-RelNotes, ReleaseNotes/DAControl-RelNotes Updated: 2026-11-13