This should illustrate. Sorry, C, not python...
/*-------------------------------------------------------------------*/
/* vdkshow.c (c) Copyright Mike Noel, 2001-2023 */
/* */
/* This is part of an emulator for the Alpha-Micro AM-100 computer. */
/* It is copyright by Michael Noel and licensed for non-commercial */
/* hobbyist use under terms of the "Q public license", an open */
/* source certified license. A copy of that license may be found */
/* here:
http://kicksfortso.com/Am100/license.html */
/* */
/*-------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *vdkdsk[32];
long vdkoff[32]; // byteoffset of first block (relative of 0)
long vdkmax[32]; // max byteoffset (relative of vdkoff)
short drv_flag[32]; // bmsize & base file indicator
char drv_name[32][255];
void usage (void);
void vdkdvr_start (void);
void vdkdvr_show (void);
void vdkdvr_stop (void);
int vdk_analysis (FILE *in, int drv);
int main (int argc, char *argv[]) {
vdkdvr_start();
// vdkdvr_show();
vdkdvr_stop();
}
void usage (void){ // HaHa -- no way to get here!!
printf("vdkshow\n");
printf(" USAGE...\n");
printf(" \n");
printf(" Vdkshow is a program to display all the VAM logical\n");
printf(" drives in 'stacked' container(s).\n");
printf(" \n");
printf(" It takes no arguments.\n");
printf(" \n");
printf(" Based on the 'vdkdvr_analysis' routine from hwassit.c \n");
printf(" this utility operates on 'utl?\?-container' files, typically\n");
printf(" links to '.hda' or such real files, each of which may contain\n");
printf(" several logicals.\n");
exit(-1);
}
/*-------------------------------------------------------------------*/
/* Initialize the virtual disk driver... */
/*-------------------------------------------------------------------*/
void vdkdvr_start (void) {
int drv, err;
for (drv = 0; drv < 32; drv++) {
vdkdsk[drv] = NULL;
vdkoff[drv] = 0;
vdkmax[drv] = 0;
drv_flag[drv] = 0;
drv_name[drv][0] = '\0';
}
for (drv = 0; drv < 32; drv++) {
sprintf ((char *) &drv_name[drv][0], "utl%d-container", drv);
vdkdsk[drv] = fopen ((char *) &drv_name[drv][0], "r+");
if (vdkdsk[drv] != NULL) {
err = vdk_analysis(vdkdsk[drv], drv);
switch (err) {
case -5: // bitmap corrupt
case -4: // no label record
case -3: // to small or to big
case -2: // size not divisible by 512
fclose(vdkdsk[drv]);
case -1: // didn't open
drv_name[drv][0] = '\0';
break;
default:
drv += err-1; // bypass overlaps
}
}
else
drv_name[drv][0] = '\0';
}
vdkdvr_show();
}
/*-------------------------------------------------------------------*/
/* */
/*-------------------------------------------------------------------*/
void vdkdvr_show (void) {
int drv;
char c[514];
for (drv = 0; drv < 32; drv++) {
if (vdkdsk[drv] != NULL) {
if(drv_flag[drv] == 0) printf("- ");
else printf(" ");
printf("%02d ", drv);
fseek (vdkdsk[drv], vdkoff[drv], SEEK_SET);
fread (&c, 512, 1, vdkdsk[drv]);
printf("%-20s ", &c[4]);
printf("at %09ld ", vdkoff[drv]);
printf("to %09ld, ", vdkmax[drv]);
printf("Len %08ld", vdkmax[drv]-vdkoff[drv]);
if(drv_flag[drv] != 0)
printf(", BM=%d", drv_flag[drv]);
printf("\n");
}
}
}
/*-------------------------------------------------------------------*/
/* Stop the virtual disk driver... */
/*-------------------------------------------------------------------*/
void vdkdvr_stop (void) {
int drv;
for (drv = 0; drv < 32; drv++) {
if(drv_flag[drv] != 0)
if (vdkdsk[drv] != NULL) fclose (vdkdsk[drv]);
vdkoff[drv] = 0;
vdkmax[drv] = 0;
vdkdsk[drv] = NULL;
drv_flag[drv] = 0;
}
}
/*-------------------------------------------------------------------*/
/* */
/*-------------------------------------------------------------------*/
int vdk_analysis(FILE *in, int drv) {
static char lblflag[4] = {0xAA, 0xAA, 0x55, 0x55};
long HWBLKS, DOFF[32], DMAX[32];
long fileLen, pos;
int i, j, NUMDSK, BMSIZ;
unsigned short words[255]; // assumes short is 16 bits...
long long myCS, hisCS;
if (in != NULL) {
fseek (in, 0, SEEK_END);
fileLen = ftell (in);
}
else {
// printf ("did not open\n");
return(-1);
}
// make sure it's divisible by 512 without remainder
if ((fileLen % 512) != 0) {
// printf ("image size not evenly divisible by 512!\n");
return(-2);
}
// get number of 512 byte records
HWBLKS = fileLen / 512;
// make sure the number of records resonable
if ((HWBLKS < 10) | (HWBLKS > 2190000)) {
// printf ("image too small or to big!\n");
return(-3);
}
// preset initial platter offset to zero
// check if that record is label..
DOFF[0] = 0;
while (DOFF[0] < 513) {
pos = DOFF[0];
fseek (in, pos, SEEK_SET);
fread((char*)words, 512, 1, in);
if (strncmp((char*)words, lblflag, 4) == 0) break;
else DOFF[0] += 512;
}
if (DOFF[0] > 512) {
// printf ("cant find label record!\n");
return(-4);
}
// MFD follows label record
pos += 512;
// first block of the bitmap follows the MFD
// scan thru whole bitmap (max 16 blocks)
myCS = hisCS = 0; BMSIZ = 0;
for (i = 0; i<16; i++) {
pos += 512;
fseek (in, pos, SEEK_SET);
fread((char*)words, 512, 1, in);
for (j=0; j<256; j++) { // sum bitmap
if (j < 254) {
// presume on-disk CS cant span blocks...
hisCS = 65536 * words[j+2] + words[j+1];
}
myCS = myCS + words[j];
if (myCS == hisCS)
BMSIZ = (j+1) + 256 * i;
if (BMSIZ > 0) break;
} // for j...
if (BMSIZ > 0) break;
} // for i...
if (BMSIZ == 0) {
// printf ("bitmap currupt, can't continue!\n");
return(-5);
}
// bitmap size should point to the end of this disk image
DMAX[0] = DOFF[0] + ((BMSIZ * 16) * 512);
// BUT IT MIGHT NOT!!
// find next label record. it might be less than DMAX
// by up to one word of bitmap (16 records)
// ** this seems wrong, but is OK as long as the the
// bits for records beyond DMAX are always ones...
for (i=0; i<15; i++) {
pos = DMAX[0] - (512 * i);
fseek (in, pos, SEEK_SET);
fread((char*)words, 512, 1, in);
if (strncmp((char*)words, lblflag, 4) == 0) {
DMAX[0] = pos;
break;
}
}
// finally DMAX really points to the next image...
i = 1;
while(1) {
DOFF
= DMAX[i-1];
DMAX = DOFF + DMAX[0] - DOFF[0];
pos = DOFF;
fseek (in, pos, SEEK_SET);
fread((char*)words, 512, 1, in);
if (strncmp((char*)words, lblflag, 4) == 0)
i = i + 1;
else
break;
}
NUMDSK = i;
// copy discovered data to globals
for (i=0; i<NUMDSK; i++) {
vdkdsk[drv+i] = in;
vdkoff[drv+i] = DOFF;
vdkmax[drv+i] = DMAX;
drv_flag[drv+i] = 0;
if(i==0) drv_flag[drv] = BMSIZ;
}
return(NUMDSK);
}