Skip to content

Commit 348765d

Browse files
al20878tlhackque
authored andcommitted
IMD2DSK: Allow to skip maps, specify a filler byte, and improve cyl counting
This PR adds a second invocation for the -i option to skip sector maps. Also, it adds the -c option to be used a fill byte value for sectors stored with error marks or not stored at all -- that helps a lot in discovery of location of such blocks in the .DSK image file, when an assessment of the file system damage is necessary. Finally, it improves cylinder counting for IMD files missing some tracks
1 parent ca2930c commit 348765d

1 file changed

Lines changed: 78 additions & 44 deletions

File tree

converters/imd2dsk/imd2dsk.c

Lines changed: 78 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* IMD -> DSK (pure data) file converter
33
*
4-
* Copyright (c) 2024 Tony Lawrence
4+
* Copyright (c) 2024-2025 Tony Lawrence
55
*
66
* Redistribution and use in source and binary forms, with or
77
* without modification, are permitted provided that the
@@ -40,6 +40,7 @@
4040

4141
#include <assert.h>
4242
#include <ctype.h>
43+
#include <errno.h>
4344
#include <stdio.h>
4445
#include <stdint.h>
4546
#include <stdlib.h>
@@ -69,8 +70,8 @@ typedef int32_t int4;
6970
/* IMD track header */
7071
PACKED(struct S_IMDTrkHdr {
7172
uint1 mode; /* Track write mode (check only) */
72-
uint1 cyl; /* Cylinder # */
73-
uint1 head; /* Head(side) 0|1 and map flags */
73+
uint1 cyl; /* Physical cylinder # */
74+
uint1 head; /* Phys head(side) 0|1 and map flags*/
7475
uint1 nsect; /* Number of sectors to follow */
7576
uint1 ssize; /* Sector size or 0xFF for size tbl */
7677
});
@@ -189,7 +190,7 @@ static int/*bool*/ x_skip_sector(FILE* fp, uint2 ssize)
189190
return 0/*false*/;
190191
if (ch < 0 || ch > 8)
191192
return 0/*false*/;
192-
if (ch == 0)
193+
if (!ch)
193194
return 1/*true*/;
194195
return fseek(fp, ch & 1 ? ssize : 1, SEEK_CUR) == 0 ? 1/*T*/ : 0/*F*/;
195196
}
@@ -200,8 +201,15 @@ static int cyls = 0;
200201
static int heads = 0;
201202
static int sectors = 0;
202203
static int sector_size = 0;
204+
static uint1 sector_filler = 0;
205+
static uint1 sector[SECTOR_SIZE_MAX];
206+
207+
#define DA(C, H, S) (((C) * heads + (H)) * sectors + (S) - one_based)
208+
#define DA_OFFSET(da) ((da) * sector_size)
209+
203210

204211
/* Sector numbering */
212+
static int no_maps = 0; /* =1 no cyl/head maps; =2 no sector maps, either */
205213
static int max_sect = 0;
206214
static int zero_sect = 0;
207215
static int one_based = 1;
@@ -211,7 +219,6 @@ static int one_based = 1;
211219
static int x_scan_tracks(FILE* fp, const char* file)
212220
{
213221
const char* problem = 0;
214-
uint1 smap[256];
215222
char buf[80];
216223
int track;
217224

@@ -259,23 +266,29 @@ static int x_scan_tracks(FILE* fp, const char* file)
259266
}
260267
if (heads <= n)
261268
heads++;
269+
if (cyls <= hdr.cyl)
270+
cyls = hdr.cyl + 1;
262271
if (!hdr.nsect)
263272
continue;
264273
if (sectors < hdr.nsect)
265274
sectors = hdr.nsect;
266-
if (fread(smap, hdr.nsect, 1, fp) != 1) {
267-
problem = "Cannot read sector map";
268-
goto out;
269-
}
270-
for (n = 0; n < hdr.nsect; ++n) {
271-
if (!smap[n]) {
272-
++zero_sect;
273-
continue;
275+
if (no_maps < 2) {
276+
uint1 smap[256];
277+
if (fread(smap, hdr.nsect, 1, fp) != 1) {
278+
problem = "Cannot read sector map";
279+
goto out;
274280
}
275-
if (max_sect < smap[n])
276-
max_sect = smap[n];
277-
}
278-
skip = 0;
281+
for (n = 0; n < hdr.nsect; ++n) {
282+
if (!smap[n]) {
283+
++zero_sect;
284+
continue;
285+
}
286+
if (max_sect < smap[n])
287+
max_sect = smap[n];
288+
}
289+
skip = 0;
290+
} else
291+
skip = hdr.nsect;
279292
if (hdr.head & SECTOR_CYL_MAP)
280293
skip += hdr.nsect;
281294
if (hdr.head & SECTOR_HEAD_MAP)
@@ -349,14 +362,13 @@ static int/*bool*/ x_extract_sector(int C, int H, int S, int track,
349362
FILE* in, const char* infile,
350363
FILE* out, const char* outfile)
351364
{
352-
static uint1 sector[SECTOR_SIZE_MAX];
353365
int/*bool*/ duplicate = 0/*false*/;
354366
const char* problem = 0;
355367
const char* file = 0;
356368
int ch;
357369

358370
/* Disk Address */
359-
int da = (C * heads + H) * sectors + S - one_based;
371+
long da = DA(C, H, S);
360372
assert(0 <= da && da < cyls * heads * sectors);
361373

362374
if (map[da >> 3] & (1 << (da & 7))) {
@@ -377,17 +389,17 @@ static int/*bool*/ x_extract_sector(int C, int H, int S, int track,
377389
case 0:
378390
problem = "Sector data unavailable";
379391
break;
380-
case 1: case 2:
392+
case 2: case 1:
381393
/* normal sector data */
382394
assert(!problem);
383395
break;
384-
case 3: case 4:
396+
case 4: case 3:
385397
problem = "Deleted data";
386398
break;
387-
case 5: case 6:
399+
case 6: case 5:
388400
problem = "Sector data with error";
389401
break;
390-
case 7: case 8:
402+
case 8: case 7:
391403
problem = "Deleted data with error";
392404
break;
393405
default:
@@ -412,14 +424,14 @@ static int/*bool*/ x_extract_sector(int C, int H, int S, int track,
412424
file = infile;
413425
goto out;
414426
}
415-
} /* else: technically it's still a "compressed" sector */
427+
} else/* technically it's still a "compressed" sector */
428+
ch = sector_filler;
416429
memset(sector, ch, sector_size);
417430
if (!duplicate)
418431
++n_compressed;
419432
}
420433

421-
da *= sector_size;
422-
if (fseek(out, da, SEEK_SET) != 0) {
434+
if (fseek(out, DA_OFFSET(da), SEEK_SET) != 0) {
423435
problem = "File positioning error";
424436
file = outfile;
425437
goto out;
@@ -442,7 +454,7 @@ static int/*bool*/ x_extract_sector(int C, int H, int S, int track,
442454
}
443455

444456

445-
static int/*bool*/ x_extract_track(int track, int/*bool*/ no_map,
457+
static int/*bool*/ x_extract_track(int track,
446458
FILE* in, const char* infile,
447459
FILE* out, const char* outfile)
448460
{
@@ -466,12 +478,15 @@ static int/*bool*/ x_extract_track(int track, int/*bool*/ no_map,
466478
if (!hdr.nsect)
467479
return 1/*true*/;
468480

469-
if (fread(smap, hdr.nsect, 1, in) != 1) {
470-
problem = "Cannot read sector map";
471-
goto out;
472-
}
473-
skip = 0;
474-
if (no_map) {
481+
if (no_maps < 2) {
482+
if (fread(smap, hdr.nsect, 1, in) != 1) {
483+
problem = "Cannot read sector map";
484+
goto out;
485+
}
486+
skip = 0;
487+
} else
488+
skip = hdr.nsect;
489+
if (no_maps) {
475490
if (hdr.head & SECTOR_CYL_MAP)
476491
skip += hdr.nsect;
477492
if (hdr.head & SECTOR_HEAD_MAP)
@@ -498,8 +513,8 @@ static int/*bool*/ x_extract_track(int track, int/*bool*/ no_map,
498513

499514
for (n = 0; n < hdr.nsect; ++n) {
500515
int C = hdr.head & SECTOR_CYL_MAP ? cmap[n] : hdr.cyl;
501-
int H = hdr.head & SECTOR_HEAD_MAP ? hmap[n] : hdr.head & 0xF;
502-
int S = smap[n];
516+
int H = hdr.head & SECTOR_HEAD_MAP ? hmap[n] : hdr.head & 1;
517+
int S = no_maps < 2 ? smap[n] : n + 1;
503518
if (verbose >= VERBOSE_SECTOR)
504519
fprintf(stderr, "Extracting: %d/%d/%d\n", C, H, S);
505520
if (C < 0 || C >= cyls) {
@@ -536,8 +551,9 @@ __attribute__((noreturn))
536551
#endif
537552
static void usage(const char* prog)
538553
{
539-
fprintf(stderr, "%s [-i] [-v...] infile outfile\n\n", prog);
540-
fprintf(stderr, "-i = Ignore cylinder / head maps\n"
554+
fprintf(stderr, "%s [-i] [-i] [-c val] [-v...] infile outfile\n\n", prog);
555+
fprintf(stderr, "-i = Ignore cylinder / head maps; second -i: Ignore sector maps, too\n"
556+
"-c = Use 'val' as byte-filler in missing sectors (default: 0)\n"
541557
"-v = Increase verbosity with each occurrence\n");
542558
exit(2);
543559
}
@@ -554,8 +570,6 @@ static void usage(const char* prog)
554570

555571
int main(int argc, char* argv[])
556572
{
557-
/* whether to ignore cyl / head maps */
558-
int/*bool*/ no_map = 0/*false*/;
559573
const char* infile;
560574
const char* outfile;
561575
int p, q, tracks;
@@ -570,11 +584,20 @@ int main(int argc, char* argv[])
570584
++verbose;
571585
continue;
572586
}
587+
if (strcmp(argv[p], "-c") == 0) {
588+
char* end;
589+
errno = 0;
590+
if (sector_filler || !argv[++p] ||
591+
!(sector_filler = strtol(argv[p], &end, 0)) || errno || *end) {
592+
usage(argv[0]);
593+
}
594+
continue;
595+
}
573596
if (strcmp(argv[p], "-i") != 0)
574597
break;
575-
if (no_map)
598+
if (no_maps > 1)
576599
usage(argv[0]);
577-
no_map = 1/*ignore map*/;
600+
++no_maps;
578601
} while (argv[++p]);
579602
}
580603
if (p < argc && strcmp(argv[p], "--") == 0)
@@ -602,7 +625,7 @@ int main(int argc, char* argv[])
602625
assert(heads <= 2 && sectors <= 255 && sector_size <= SECTOR_SIZE_MAX);
603626

604627
if (heads <= 0 || sectors <= 0 || sector_size <= 0
605-
|| (cyls = (tracks + heads - 1) / heads) <= 0 || 255 < cyls) {
628+
|| cyls < (tracks + heads - 1) / heads || 255 < cyls) {
606629
fprintf(stderr, "%s: Failed to determine disk geometry, sorry\n", infile);
607630
return EXIT_FAILURE;
608631
}
@@ -633,10 +656,12 @@ int main(int argc, char* argv[])
633656
}
634657

635658
for (p = 0; p < tracks; ++p) {
636-
if (!x_extract_track(p, no_map, in, infile, out, outfile))
659+
if (!x_extract_track(p, in, infile, out, outfile))
637660
return EXIT_FAILURE;
638661
}
639662

663+
if (sector_filler)
664+
memset(sector, sector_filler, sector_size);
640665
for (p = 0; p < q; p += 8) {
641666
int k, n = p >> 3;
642667
if (map[n] == (1 << 8) - 1)
@@ -651,8 +676,17 @@ int main(int argc, char* argv[])
651676
S %= sectors;
652677
C = H / heads;
653678
H %= heads;
679+
S += one_based;
654680
fprintf(stderr, "%s: WARNING -- Sector not stored: %d/%d/%d\n",
655-
outfile, C, H, S + one_based);
681+
outfile, C, H, S);
682+
if (sector_filler) {
683+
long da = DA(C, H, S);
684+
assert(0 <= da && da < cyls * heads * sectors);
685+
if (fseek(out, DA_OFFSET(da), SEEK_SET) != 0
686+
|| fwrite(sector, sector_size, 1, out) != 1) {
687+
fprintf(stderr, "%s: Error writing sector filler\n", outfile);
688+
}
689+
}
656690
}
657691
}
658692

0 commit comments

Comments
 (0)