cffs-image-tool 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -13
- package/dist/cli.js +72 -33
- package/dist/cli.js.map +1 -1
- package/dist/lib/constants.d.ts +2 -0
- package/dist/lib/constants.js +7 -0
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/directory.d.ts +5 -4
- package/dist/lib/directory.js +8 -7
- package/dist/lib/directory.js.map +1 -1
- package/dist/lib/image.d.ts +10 -0
- package/dist/lib/image.js +23 -1
- package/dist/lib/image.js.map +1 -1
- package/dist/lib/operations.d.ts +17 -13
- package/dist/lib/operations.js +55 -40
- package/dist/lib/operations.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +75 -36
- package/src/lib/constants.ts +8 -0
- package/src/lib/directory.ts +8 -7
- package/src/lib/image.ts +27 -1
- package/src/lib/operations.ts +58 -41
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
A CLI tool for creating and managing CompactFlash filesystem images for the A.C. Wright 6502 project.
|
|
4
4
|
|
|
5
|
-
The
|
|
5
|
+
The card is divided into up to **256 "disk" banks of 1 MB each** (2048 sectors × 512 bytes), for a maximum usable capacity of **256 MB**. Each disk is an independent flat filesystem: a single 512-byte directory sector (holding up to 16 entries in 8.3 filename format) followed by contiguous data sectors. Disk 0 is the default; other commands target a disk with the `--disk` / `-d` flag. This mirrors the `DISK n` (BASIC) / `#NN` (Monitor) banking in the 6502 BIOS.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- Create blank CF images
|
|
10
|
-
- Add, remove, list, and extract files
|
|
11
|
-
- Defragment
|
|
12
|
-
- Display
|
|
9
|
+
- Create blank CF images by byte size or by disk-bank count
|
|
10
|
+
- Add, remove, list, and extract files on any of up to 256 disk banks
|
|
11
|
+
- Defragment a disk to reclaim gaps
|
|
12
|
+
- Display per-disk statistics
|
|
13
13
|
|
|
14
14
|
## Prerequisites
|
|
15
15
|
|
|
@@ -30,10 +30,16 @@ The compiled output is written to the `dist/` directory.
|
|
|
30
30
|
After building, run the tool directly with Node or via the `cffs` bin entry:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
# Create a
|
|
33
|
+
# Create a 1 MB image (a single disk bank; this is the default size)
|
|
34
|
+
npx cffs create disk.img
|
|
35
|
+
|
|
36
|
+
# Create a larger image by byte size (32 disk banks)
|
|
34
37
|
npx cffs create disk.img --size 32M
|
|
35
38
|
|
|
36
|
-
#
|
|
39
|
+
# Create an image sized by disk-bank count (256 disks = 256 MB)
|
|
40
|
+
npx cffs create disk.img --disks 256
|
|
41
|
+
|
|
42
|
+
# Add a file (defaults to disk 0)
|
|
37
43
|
npx cffs add disk.img firmware.bin
|
|
38
44
|
|
|
39
45
|
# List files
|
|
@@ -42,7 +48,7 @@ npx cffs list disk.img
|
|
|
42
48
|
# Extract a file
|
|
43
49
|
npx cffs extract disk.img FIRMWARE.BIN output.bin
|
|
44
50
|
|
|
45
|
-
# Show
|
|
51
|
+
# Show disk info
|
|
46
52
|
npx cffs info disk.img
|
|
47
53
|
|
|
48
54
|
# Remove a file
|
|
@@ -51,10 +57,30 @@ npx cffs remove disk.img FIRMWARE.BIN
|
|
|
51
57
|
# Defragment
|
|
52
58
|
npx cffs defrag disk.img
|
|
53
59
|
|
|
54
|
-
# Clear all entries
|
|
60
|
+
# Clear all entries on a disk
|
|
55
61
|
npx cffs clear disk.img
|
|
56
62
|
```
|
|
57
63
|
|
|
64
|
+
### Selecting a disk
|
|
65
|
+
|
|
66
|
+
All file commands (`add`, `remove`, `list`, `extract`, `defrag`, `clear`, `info`)
|
|
67
|
+
default to disk 0. Use `--disk` / `-d` (0–255) to target another bank:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Add a file to disk 3
|
|
71
|
+
npx cffs add disk.img map.dat --disk 3
|
|
72
|
+
|
|
73
|
+
# List disk 3
|
|
74
|
+
npx cffs list disk.img -d 3
|
|
75
|
+
|
|
76
|
+
# Show stats for disk 3
|
|
77
|
+
npx cffs info disk.img -d 3
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
A file may not spill past its disk's 1 MB region; adding a file that would
|
|
81
|
+
exceed it fails with a "not enough space on disk" error, matching the BIOS
|
|
82
|
+
disk-full guard. The chosen disk must also exist within the image's size.
|
|
83
|
+
|
|
58
84
|
### Development
|
|
59
85
|
|
|
60
86
|
Run directly from TypeScript without compiling:
|
|
@@ -65,10 +91,17 @@ npm run dev -- <command> [options]
|
|
|
65
91
|
|
|
66
92
|
## Filesystem Layout
|
|
67
93
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
94
|
+
The card is split into disk banks of 2048 sectors (1 MB) each. Disk `n`'s
|
|
95
|
+
directory sector lives at absolute LBA `n × 2048`, and its data sectors follow
|
|
96
|
+
contiguously within the same 1 MB region. Within a disk, layout is:
|
|
97
|
+
|
|
98
|
+
| Region | Disk-relative LBA | Size | Description |
|
|
99
|
+
|-----------|-------------------|------------|--------------------------------------|
|
|
100
|
+
| Directory | 0 | 512 bytes | Up to 16 × 32-byte directory entries |
|
|
101
|
+
| Data | 1 – 2047 | Remainder | Contiguous file data sectors |
|
|
102
|
+
|
|
103
|
+
Directory entry **start sectors are stored disk-relative** (1–2047); the tool
|
|
104
|
+
adds the disk's base LBA when reading or writing data.
|
|
72
105
|
|
|
73
106
|
Each directory entry is 32 bytes:
|
|
74
107
|
|
package/dist/cli.js
CHANGED
|
@@ -5,12 +5,13 @@ import { stdin, stdout } from 'node:process';
|
|
|
5
5
|
import { openImage, saveImage, createImage } from './lib/image.js';
|
|
6
6
|
import { formatName } from './lib/filename.js';
|
|
7
7
|
import { calcSectorCount } from './lib/directory.js';
|
|
8
|
+
import { SECTORS_PER_DISK, MAX_DISKS } from './lib/constants.js';
|
|
8
9
|
import { addFile, removeFile, listFiles, extractFile, defragment, clearImage, imageInfo, } from './lib/operations.js';
|
|
9
10
|
const program = new Command();
|
|
10
11
|
program
|
|
11
12
|
.name('cffs')
|
|
12
13
|
.description('CompactFlash Filesystem Image Tool for A.C. Wright 6502 Project')
|
|
13
|
-
.version('1.
|
|
14
|
+
.version('1.1.0');
|
|
14
15
|
/**
|
|
15
16
|
* Parse a size string like "32M", "512K", "1G", or a plain number (bytes).
|
|
16
17
|
*/
|
|
@@ -28,14 +29,36 @@ function parseSize(value) {
|
|
|
28
29
|
default: return num;
|
|
29
30
|
}
|
|
30
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Parse and validate a disk bank number (0 to MAX_DISKS-1).
|
|
34
|
+
*/
|
|
35
|
+
function parseDisk(value) {
|
|
36
|
+
const disk = parseInt(value, 10);
|
|
37
|
+
if (!Number.isInteger(disk) || disk < 0 || disk >= MAX_DISKS) {
|
|
38
|
+
throw new Error(`Invalid disk: "${value}". Must be 0-${MAX_DISKS - 1}.`);
|
|
39
|
+
}
|
|
40
|
+
return disk;
|
|
41
|
+
}
|
|
31
42
|
// ── create ──────────────────────────────────────────────────────────────────
|
|
32
43
|
program
|
|
33
44
|
.command('create')
|
|
34
45
|
.description('Create a blank CompactFlash image')
|
|
35
46
|
.argument('<image>', 'Path to image file to create')
|
|
36
|
-
.option('-s, --size <size>', 'Image size (e.g.
|
|
47
|
+
.option('-s, --size <size>', 'Image size (e.g. 1M, 512K); one disk bank is 1M', '1M')
|
|
48
|
+
.option('-D, --disks <count>', `Size by disk-bank count (1 MB each); overrides --size`)
|
|
37
49
|
.action((image, opts) => {
|
|
38
|
-
|
|
50
|
+
let totalBytes;
|
|
51
|
+
if (opts.disks !== undefined) {
|
|
52
|
+
const disks = parseInt(opts.disks, 10);
|
|
53
|
+
if (!Number.isInteger(disks) || disks < 1 || disks > MAX_DISKS) {
|
|
54
|
+
console.error(`Error: --disks must be 1-${MAX_DISKS}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
totalBytes = disks * SECTORS_PER_DISK * 512;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
totalBytes = parseSize(opts.size);
|
|
61
|
+
}
|
|
39
62
|
if (totalBytes % 512 !== 0) {
|
|
40
63
|
console.error('Error: size must be a multiple of 512 bytes');
|
|
41
64
|
process.exit(1);
|
|
@@ -43,18 +66,21 @@ program
|
|
|
43
66
|
const totalSectors = totalBytes / 512;
|
|
44
67
|
const buf = createImage(totalSectors);
|
|
45
68
|
saveImage(image, buf);
|
|
46
|
-
|
|
69
|
+
const diskCount = Math.floor(totalSectors / SECTORS_PER_DISK);
|
|
70
|
+
console.log(`Created ${image} (${totalBytes.toLocaleString()} bytes, ${totalSectors.toLocaleString()} sectors, ${diskCount} disk${diskCount === 1 ? '' : 's'})`);
|
|
47
71
|
});
|
|
48
72
|
// ── list ────────────────────────────────────────────────────────────────────
|
|
49
73
|
program
|
|
50
74
|
.command('list')
|
|
51
|
-
.description('List files in the image')
|
|
75
|
+
.description('List files on a disk in the image')
|
|
52
76
|
.argument('<image>', 'Path to image file')
|
|
53
|
-
.
|
|
77
|
+
.option('-d, --disk <n>', 'Disk bank to operate on (0-255)', parseDisk, 0)
|
|
78
|
+
.action((image, opts) => {
|
|
54
79
|
const buf = openImage(image);
|
|
55
|
-
const files = listFiles(buf);
|
|
80
|
+
const files = listFiles(buf, opts.disk);
|
|
81
|
+
console.log(`Disk ${opts.disk}`);
|
|
56
82
|
if (files.length === 0) {
|
|
57
|
-
console.log('No files
|
|
83
|
+
console.log('No files on disk.');
|
|
58
84
|
return;
|
|
59
85
|
}
|
|
60
86
|
console.log('Name Size Start Sectors');
|
|
@@ -70,61 +96,66 @@ program
|
|
|
70
96
|
// ── add ─────────────────────────────────────────────────────────────────────
|
|
71
97
|
program
|
|
72
98
|
.command('add')
|
|
73
|
-
.description('Add a host file to the image')
|
|
99
|
+
.description('Add a host file to a disk in the image')
|
|
74
100
|
.argument('<image>', 'Path to image file')
|
|
75
101
|
.argument('<file>', 'Host file to add')
|
|
76
102
|
.option('-n, --name <name>', 'Target 8.3 filename (default: source filename)')
|
|
103
|
+
.option('-d, --disk <n>', 'Disk bank to operate on (0-255)', parseDisk, 0)
|
|
77
104
|
.action((image, file, opts) => {
|
|
78
105
|
const buf = openImage(image);
|
|
79
|
-
addFile(buf, file, opts.name);
|
|
106
|
+
addFile(buf, file, opts.disk, opts.name);
|
|
80
107
|
saveImage(image, buf);
|
|
81
|
-
console.log(`Added ${opts.name ?? file} to ${image}`);
|
|
108
|
+
console.log(`Added ${opts.name ?? file} to disk ${opts.disk} of ${image}`);
|
|
82
109
|
});
|
|
83
110
|
// ── remove ──────────────────────────────────────────────────────────────────
|
|
84
111
|
program
|
|
85
112
|
.command('remove')
|
|
86
|
-
.description('Delete a file entry from the image')
|
|
113
|
+
.description('Delete a file entry from a disk in the image')
|
|
87
114
|
.argument('<image>', 'Path to image file')
|
|
88
115
|
.argument('<name>', 'Filename to remove (8.3 format)')
|
|
89
|
-
.
|
|
116
|
+
.option('-d, --disk <n>', 'Disk bank to operate on (0-255)', parseDisk, 0)
|
|
117
|
+
.action((image, name, opts) => {
|
|
90
118
|
const buf = openImage(image);
|
|
91
|
-
removeFile(buf, name);
|
|
119
|
+
removeFile(buf, name, opts.disk);
|
|
92
120
|
saveImage(image, buf);
|
|
93
|
-
console.log(`Removed ${name} from ${image}`);
|
|
121
|
+
console.log(`Removed ${name} from disk ${opts.disk} of ${image}`);
|
|
94
122
|
});
|
|
95
123
|
// ── extract ─────────────────────────────────────────────────────────────────
|
|
96
124
|
program
|
|
97
125
|
.command('extract')
|
|
98
|
-
.description('Extract a file from the image to the host filesystem')
|
|
126
|
+
.description('Extract a file from a disk in the image to the host filesystem')
|
|
99
127
|
.argument('<image>', 'Path to image file')
|
|
100
128
|
.argument('<name>', 'Filename to extract (8.3 format)')
|
|
101
129
|
.argument('[output]', 'Output path (default: original filename)')
|
|
102
|
-
.
|
|
130
|
+
.option('-d, --disk <n>', 'Disk bank to operate on (0-255)', parseDisk, 0)
|
|
131
|
+
.action((image, name, output, opts) => {
|
|
103
132
|
const buf = openImage(image);
|
|
104
|
-
extractFile(buf, name, output);
|
|
105
|
-
console.log(`Extracted ${name} from ${image}`);
|
|
133
|
+
extractFile(buf, name, output, opts.disk);
|
|
134
|
+
console.log(`Extracted ${name} from disk ${opts.disk} of ${image}`);
|
|
106
135
|
});
|
|
107
136
|
// ── defrag ──────────────────────────────────────────────────────────────────
|
|
108
137
|
program
|
|
109
138
|
.command('defrag')
|
|
110
|
-
.description('Defragment the image (compact files)')
|
|
139
|
+
.description('Defragment a disk in the image (compact files)')
|
|
111
140
|
.argument('<image>', 'Path to image file')
|
|
112
|
-
.
|
|
141
|
+
.option('-d, --disk <n>', 'Disk bank to operate on (0-255)', parseDisk, 0)
|
|
142
|
+
.action((image, opts) => {
|
|
113
143
|
const buf = openImage(image);
|
|
114
|
-
defragment(buf);
|
|
144
|
+
defragment(buf, opts.disk);
|
|
115
145
|
saveImage(image, buf);
|
|
116
|
-
console.log(`Defragmented ${image}`);
|
|
146
|
+
console.log(`Defragmented disk ${opts.disk} of ${image}`);
|
|
117
147
|
});
|
|
118
148
|
// ── clear ───────────────────────────────────────────────────────────────────
|
|
119
149
|
program
|
|
120
150
|
.command('clear')
|
|
121
|
-
.description(
|
|
151
|
+
.description("Clear a disk's directory entries")
|
|
122
152
|
.argument('<image>', 'Path to image file')
|
|
123
153
|
.option('-y, --yes', 'Skip confirmation prompt')
|
|
154
|
+
.option('-d, --disk <n>', 'Disk bank to operate on (0-255)', parseDisk, 0)
|
|
124
155
|
.action(async (image, opts) => {
|
|
125
156
|
if (!opts.yes) {
|
|
126
157
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
127
|
-
const answer = await rl.question(`Clear all entries
|
|
158
|
+
const answer = await rl.question(`Clear all entries on disk ${opts.disk} of ${image}? [y/N] `);
|
|
128
159
|
rl.close();
|
|
129
160
|
if (answer.toLowerCase() !== 'y') {
|
|
130
161
|
console.log('Aborted.');
|
|
@@ -132,22 +163,30 @@ program
|
|
|
132
163
|
}
|
|
133
164
|
}
|
|
134
165
|
const buf = openImage(image);
|
|
135
|
-
clearImage(buf);
|
|
166
|
+
clearImage(buf, opts.disk);
|
|
136
167
|
saveImage(image, buf);
|
|
137
|
-
console.log(`Cleared all directory entries
|
|
168
|
+
console.log(`Cleared all directory entries on disk ${opts.disk} of ${image}`);
|
|
138
169
|
});
|
|
139
170
|
// ── info ────────────────────────────────────────────────────────────────────
|
|
140
171
|
program
|
|
141
172
|
.command('info')
|
|
142
|
-
.description('Display image
|
|
173
|
+
.description('Display statistics for a disk in the image')
|
|
143
174
|
.argument('<image>', 'Path to image file')
|
|
144
|
-
.
|
|
175
|
+
.option('-d, --disk <n>', 'Disk bank to operate on (0-255)', parseDisk, 0)
|
|
176
|
+
.action((image, opts) => {
|
|
145
177
|
const buf = openImage(image);
|
|
146
|
-
const info = imageInfo(buf);
|
|
178
|
+
const info = imageInfo(buf, opts.disk);
|
|
147
179
|
console.log(`Image size: ${(info.totalSectors * 512).toLocaleString()} bytes (${info.totalSectors.toLocaleString()} sectors)`);
|
|
180
|
+
console.log(`Disks: ${info.totalDisks} × 1 MB (showing disk ${info.disk})`);
|
|
148
181
|
console.log(`Directory: ${info.usedEntries}/16 entries used, ${info.freeEntries} free`);
|
|
149
|
-
console.log(`Data sectors: ${info.usedDataSectors} used, ${info.freeDataSectors.toLocaleString()} free`);
|
|
150
|
-
console.log(`Next free sector: ${info.nextFreeSector}`);
|
|
182
|
+
console.log(`Data sectors: ${info.usedDataSectors} used, ${info.freeDataSectors.toLocaleString()} free (of ${(SECTORS_PER_DISK - 1).toLocaleString()} per disk)`);
|
|
183
|
+
console.log(`Next free sector: ${info.nextFreeSector} (disk-relative)`);
|
|
184
|
+
});
|
|
185
|
+
// Run, surfacing operational errors as clean one-line messages instead of
|
|
186
|
+
// raw Node stack traces. Commander's own usage errors are left untouched.
|
|
187
|
+
program.parseAsync().catch((err) => {
|
|
188
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
189
|
+
console.error(`Error: ${message}`);
|
|
190
|
+
process.exit(1);
|
|
151
191
|
});
|
|
152
|
-
program.parse();
|
|
153
192
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAC3C,UAAU,EAAE,UAAU,EAAE,SAAS,GAClC,MAAM,qBAAqB,CAAC;AAE7B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,iEAAiE,CAAC;KAC9E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB;;GAEG;AACH,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,kCAAkC,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,GAAG,CAAC,CAAC,OAAO,GAAG,GAAG,IAAI,CAAC;QAC5B,KAAK,GAAG,CAAC,CAAC,OAAO,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;QACnC,KAAK,GAAG,CAAC,CAAC,OAAO,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;QAC1C,OAAO,CAAC,CAAC,OAAO,GAAG,CAAC;IACtB,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,mCAAmC,CAAC;KAChD,QAAQ,CAAC,SAAS,EAAE,8BAA8B,CAAC;KACnD,MAAM,CAAC,mBAAmB,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/constants.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export declare const DIR_LBA = 0;
|
|
|
3
3
|
export declare const DATA_START = 1;
|
|
4
4
|
export declare const MAX_FILES = 16;
|
|
5
5
|
export declare const ENTRY_SIZE = 32;
|
|
6
|
+
export declare const SECTORS_PER_DISK = 2048;
|
|
7
|
+
export declare const MAX_DISKS = 256;
|
|
6
8
|
export declare const NAME_OFFSET = 0;
|
|
7
9
|
export declare const NAME_LENGTH = 8;
|
|
8
10
|
export declare const EXT_OFFSET = 8;
|
package/dist/lib/constants.js
CHANGED
|
@@ -3,6 +3,13 @@ export const DIR_LBA = 0;
|
|
|
3
3
|
export const DATA_START = 1;
|
|
4
4
|
export const MAX_FILES = 16;
|
|
5
5
|
export const ENTRY_SIZE = 32;
|
|
6
|
+
// Disk banking: the CF card is divided into up to 256 "disk" banks of
|
|
7
|
+
// SECTORS_PER_DISK sectors (1 MB) each. Disk n's directory lives at absolute
|
|
8
|
+
// LBA n * SECTORS_PER_DISK, and its data sectors follow contiguously. Start
|
|
9
|
+
// sectors in directory entries are stored relative to the disk's base LBA, and
|
|
10
|
+
// a file may not spill past its disk's region (matches BIOS FS_DISK_SECTORS).
|
|
11
|
+
export const SECTORS_PER_DISK = 2048; // 2048 * 512 = 1 MB
|
|
12
|
+
export const MAX_DISKS = 256; // 256 disks = 256 MB total
|
|
6
13
|
// Field offsets within a directory entry
|
|
7
14
|
export const NAME_OFFSET = 0;
|
|
8
15
|
export const NAME_LENGTH = 8;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAC/B,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC;AACzB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC;AAC5B,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,CAAC;AAE7B,yCAAyC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAElC,QAAQ;AACR,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAC/B,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC;AACzB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC;AAC5B,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,CAAC;AAE7B,sEAAsE;AACtE,6EAA6E;AAC7E,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,oBAAoB;AAC1D,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC,CAAS,2BAA2B;AAEjE,yCAAyC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAElC,QAAQ;AACR,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC"}
|
package/dist/lib/directory.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { DirEntry } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Parse all 16 directory entries from
|
|
3
|
+
* Parse all 16 directory entries from the given disk's directory sector.
|
|
4
|
+
* Start sectors are stored relative to the disk's base LBA.
|
|
4
5
|
*/
|
|
5
|
-
export declare function readDirectory(buf: Buffer): DirEntry[];
|
|
6
|
+
export declare function readDirectory(buf: Buffer, disk?: number): DirEntry[];
|
|
6
7
|
/**
|
|
7
|
-
* Serialize directory entries back to
|
|
8
|
+
* Serialize directory entries back to the given disk's directory sector.
|
|
8
9
|
*/
|
|
9
|
-
export declare function writeDirectory(buf: Buffer, entries: DirEntry[]): void;
|
|
10
|
+
export declare function writeDirectory(buf: Buffer, entries: DirEntry[], disk?: number): void;
|
|
10
11
|
/**
|
|
11
12
|
* Find a used directory entry by name and extension (space-padded, uppercase).
|
|
12
13
|
*/
|
package/dist/lib/directory.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { SECTOR_SIZE, DIR_LBA, MAX_FILES, ENTRY_SIZE, NAME_OFFSET, NAME_LENGTH, EXT_OFFSET, EXT_LENGTH, FLAGS_OFFSET, START_OFFSET, FSIZE_OFFSET, FLAG_USED, DATA_START, } from './constants.js';
|
|
2
|
-
import { readSector, writeSector } from './image.js';
|
|
2
|
+
import { readSector, writeSector, diskBaseLba } from './image.js';
|
|
3
3
|
/**
|
|
4
|
-
* Parse all 16 directory entries from
|
|
4
|
+
* Parse all 16 directory entries from the given disk's directory sector.
|
|
5
|
+
* Start sectors are stored relative to the disk's base LBA.
|
|
5
6
|
*/
|
|
6
|
-
export function readDirectory(buf) {
|
|
7
|
-
const sector = readSector(buf, DIR_LBA);
|
|
7
|
+
export function readDirectory(buf, disk = 0) {
|
|
8
|
+
const sector = readSector(buf, diskBaseLba(disk) + DIR_LBA);
|
|
8
9
|
const entries = [];
|
|
9
10
|
for (let i = 0; i < MAX_FILES; i++) {
|
|
10
11
|
const off = i * ENTRY_SIZE;
|
|
@@ -18,9 +19,9 @@ export function readDirectory(buf) {
|
|
|
18
19
|
return entries;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
|
-
* Serialize directory entries back to
|
|
22
|
+
* Serialize directory entries back to the given disk's directory sector.
|
|
22
23
|
*/
|
|
23
|
-
export function writeDirectory(buf, entries) {
|
|
24
|
+
export function writeDirectory(buf, entries, disk = 0) {
|
|
24
25
|
const sector = Buffer.alloc(SECTOR_SIZE);
|
|
25
26
|
for (const entry of entries) {
|
|
26
27
|
const off = entry.index * ENTRY_SIZE;
|
|
@@ -36,7 +37,7 @@ export function writeDirectory(buf, entries) {
|
|
|
36
37
|
sector.writeUInt16LE(entry.fileSize, off + FSIZE_OFFSET);
|
|
37
38
|
// Reserved bytes stay zeroed
|
|
38
39
|
}
|
|
39
|
-
writeSector(buf, DIR_LBA, sector);
|
|
40
|
+
writeSector(buf, diskBaseLba(disk) + DIR_LBA, sector);
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
42
43
|
* Find a used directory entry by name and extension (space-padded, uppercase).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directory.js","sourceRoot":"","sources":["../../src/lib/directory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAC3C,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAChD,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EACnD,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"directory.js","sourceRoot":"","sources":["../../src/lib/directory.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/image.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Absolute base LBA of a disk bank. Disk n starts at LBA n * SECTORS_PER_DISK,
|
|
3
|
+
* where its directory sector lives; data sectors follow contiguously.
|
|
4
|
+
*/
|
|
5
|
+
export declare function diskBaseLba(disk: number): number;
|
|
6
|
+
/**
|
|
7
|
+
* Validate a disk number and ensure its region fits within the image.
|
|
8
|
+
* Throws with a descriptive message otherwise.
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateDisk(buf: Buffer, disk: number): void;
|
|
1
11
|
/**
|
|
2
12
|
* Read an entire image file into a Buffer.
|
|
3
13
|
*/
|
package/dist/lib/image.js
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { SECTOR_SIZE } from './constants.js';
|
|
2
|
+
import { SECTOR_SIZE, SECTORS_PER_DISK, MAX_DISKS } from './constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* Absolute base LBA of a disk bank. Disk n starts at LBA n * SECTORS_PER_DISK,
|
|
5
|
+
* where its directory sector lives; data sectors follow contiguously.
|
|
6
|
+
*/
|
|
7
|
+
export function diskBaseLba(disk) {
|
|
8
|
+
return disk * SECTORS_PER_DISK;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Validate a disk number and ensure its region fits within the image.
|
|
12
|
+
* Throws with a descriptive message otherwise.
|
|
13
|
+
*/
|
|
14
|
+
export function validateDisk(buf, disk) {
|
|
15
|
+
if (!Number.isInteger(disk) || disk < 0 || disk >= MAX_DISKS) {
|
|
16
|
+
throw new Error(`Invalid disk: ${disk} (must be 0-${MAX_DISKS - 1})`);
|
|
17
|
+
}
|
|
18
|
+
const totalSectors = buf.length / SECTOR_SIZE;
|
|
19
|
+
const base = diskBaseLba(disk);
|
|
20
|
+
if (base + SECTORS_PER_DISK > totalSectors) {
|
|
21
|
+
const availableDisks = Math.floor(totalSectors / SECTORS_PER_DISK);
|
|
22
|
+
throw new Error(`Disk ${disk} does not fit in image: it holds ${availableDisks} disk(s) (0-${availableDisks - 1})`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
3
25
|
/**
|
|
4
26
|
* Read an entire image file into a Buffer.
|
|
5
27
|
*/
|
package/dist/lib/image.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/lib/image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/lib/image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE1E;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,GAAG,gBAAgB,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,IAAY;IACpD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,eAAe,SAAS,GAAG,CAAC,GAAG,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,GAAG,WAAW,CAAC;IAC9C,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,IAAI,GAAG,gBAAgB,GAAG,YAAY,EAAE,CAAC;QAC3C,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,gBAAgB,CAAC,CAAC;QACnE,MAAM,IAAI,KAAK,CACb,QAAQ,IAAI,oCAAoC,cAAc,eAAe,cAAc,GAAG,CAAC,GAAG,CACnG,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,GAAW;IACjD,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,YAAoB;IAC9C,OAAO,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,WAAW,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,GAAW;IACjD,MAAM,MAAM,GAAG,GAAG,GAAG,WAAW,CAAC;IACjC,IAAI,MAAM,GAAG,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,UAAU,GAAG,kCAAkC,GAAG,CAAC,MAAM,SAAS,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,GAAW,EAAE,IAAY;IAChE,MAAM,MAAM,GAAG,GAAG,GAAG,WAAW,CAAC;IACjC,IAAI,MAAM,GAAG,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,UAAU,GAAG,kCAAkC,GAAG,CAAC,MAAM,SAAS,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,CAAC,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC;IAChF,CAAC;IACD,wEAAwE;IACxE,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACzB,CAAC"}
|
package/dist/lib/operations.d.ts
CHANGED
|
@@ -1,33 +1,37 @@
|
|
|
1
1
|
import { DirEntry } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Add a host file to the
|
|
3
|
+
* Add a host file to the given disk. Optionally rename with targetName (8.3 format).
|
|
4
|
+
* Start sectors are disk-relative; a file may not spill past its disk's region.
|
|
4
5
|
*/
|
|
5
|
-
export declare function addFile(buf: Buffer, hostPath: string, targetName?: string): void;
|
|
6
|
+
export declare function addFile(buf: Buffer, hostPath: string, disk?: number, targetName?: string): void;
|
|
6
7
|
/**
|
|
7
8
|
* Remove a file by name (clears flags only, no compaction — matches BIOS FsDeleteFile).
|
|
8
9
|
*/
|
|
9
|
-
export declare function removeFile(buf: Buffer, nameInput: string): void;
|
|
10
|
+
export declare function removeFile(buf: Buffer, nameInput: string, disk?: number): void;
|
|
10
11
|
/**
|
|
11
|
-
* List all in-use directory entries.
|
|
12
|
+
* List all in-use directory entries on the given disk.
|
|
12
13
|
*/
|
|
13
|
-
export declare function listFiles(buf: Buffer): DirEntry[];
|
|
14
|
+
export declare function listFiles(buf: Buffer, disk?: number): DirEntry[];
|
|
14
15
|
/**
|
|
15
|
-
* Extract a file from the
|
|
16
|
+
* Extract a file from the given disk to the host filesystem.
|
|
16
17
|
*/
|
|
17
|
-
export declare function extractFile(buf: Buffer, nameInput: string, outputPath?: string): void;
|
|
18
|
+
export declare function extractFile(buf: Buffer, nameInput: string, outputPath?: string, disk?: number): void;
|
|
18
19
|
/**
|
|
19
|
-
* Defragment
|
|
20
|
+
* Defragment a disk: sort used entries by startSector, rewrite contiguously
|
|
21
|
+
* from the disk's first data sector, and zero the remainder of the disk region.
|
|
20
22
|
*/
|
|
21
|
-
export declare function defragment(buf: Buffer): void;
|
|
23
|
+
export declare function defragment(buf: Buffer, disk?: number): void;
|
|
22
24
|
/**
|
|
23
|
-
* Clear all directory entries (zero
|
|
25
|
+
* Clear all directory entries on the given disk (zero its directory sector).
|
|
24
26
|
*/
|
|
25
|
-
export declare function clearImage(buf: Buffer): void;
|
|
27
|
+
export declare function clearImage(buf: Buffer, disk?: number): void;
|
|
26
28
|
/**
|
|
27
|
-
* Return
|
|
29
|
+
* Return stats for the given disk.
|
|
28
30
|
*/
|
|
29
|
-
export declare function imageInfo(buf: Buffer): {
|
|
31
|
+
export declare function imageInfo(buf: Buffer, disk?: number): {
|
|
30
32
|
totalSectors: number;
|
|
33
|
+
totalDisks: number;
|
|
34
|
+
disk: number;
|
|
31
35
|
usedEntries: number;
|
|
32
36
|
freeEntries: number;
|
|
33
37
|
nextFreeSector: number;
|