[HECnet] installing LPs on RSX
Johnny Billquist
bqt at softjar.se
Mon Apr 27 15:47:45 PDT 2015
On 2015-04-28 00:42, Dave McGuire wrote:
> On 04/27/2015 06:39 PM, Johnny Billquist wrote:
>>>>> Uh-oh...That "HDR1" business looks like part of an ANSI tape label,
>>>>> not a filename. What do you think?
>>>>
>>>> Definitely a corrupted tape.
>>>
>>> Yup...After testing several other images from the trailing-edge
>>> archive, I'm finding the same sort of mess. I knew the BP2 v2.7 image
>>> was trashed, but it looks like quite a few others are as well. The
>>> f77_v5_4.tpc one is corrupt too.
>>>
>>> What a mess.
>>>
>>> Thanks for your help in diagnosing this.
>>>
>>> At least some earlier releases are intact, but do you know if any of
>>> those newer ones have been archived intact anywhere? Do you have them?
>>
>> I have most of them, but not BP2 V2.7. :-(
>
> Oh, very good news...To bad about BP2 2.7, but that's ok, hopefully
> it'll turn up somewhere.
I have already hunted for it for years without success... :-/
> Can you share the tapes that you have?
I'm still trying to figure out how to deal with this in general. I'm not
totally comfortable with just distributing this. I should talk a bit
with the Bitsavers people on how they reason.
>> I've also written a tool that can repair those broken tapes if they are
>> in BRU format. Unfortunately, a few (including the BP2 tape) are in DOS
>> format, and that format is much more difficult to repair.
>
> Hmm, very nice! Would you be willing to share that as well?
That one I can definitely share.
Attaching it here, for other who might also find it useful.
Johnny
--
Johnny Billquist || "I'm on a bus
|| on a psychedelic trip
email: bqt at softjar.se || Reading murder books
pdp is alive! || tryin' to stay hip" - B. Idol
-------------- next part --------------
/* fix.c
*
* (c) 2012 by Johnny Billquist
*
* A program to read/fix tpc format bru tapes
*
* Documentation of this program sucks.
*
* However, essentially, this program sucks in a
* TPC image tape, and tries to cerify that it is
* a BRU format tape, and if blocks have been reordered,
* it tries to fix this.
*
* Usage: fix [-x] infile outfile
*
* -x tells that the file format is hexadecimal numbers
* instead of binary values.
*
* All the rest is magic.
*
* And yes, this code is really ugly...
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BFSZ 32768 /* Max size of one tape block. */
#define LS 18
int debug=0;
int fmt=0;
struct buf {
struct buf *next;
int sz;
unsigned char b[BFSZ];
};
struct buf tape;
struct buf *cur;
int bl,col;
int gethex(FILE *f)
{
int v;
v = getc(f);
if (v < 0) {
return -1;
}
switch (v) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return (v - '0');
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
return (v - 'A' + 10);
default:
return gethex(f);
}
}
int getbyt(FILE *f)
{
int v1,v2;
if (fmt) {
v1 = gethex(f);
v2 = gethex(f);
if ((v1 < 0) || (v2 < 0)) return -1;
return v1*16+v2;
} else {
return getc(f);
}
}
int readbuf(struct buf *b, FILE *f)
{
int i,v;
b->sz = getbyt(f) + (getbyt(f) * 256);
if ((b->sz > 0) && (b->sz < 14)) {
b->sz = 0;
return 0;
}
for (i=0; i<b->sz; i++) {
v = getbyt(f);
if (v<0) {
b->sz = 0;
return 0;
}
b->b[i] = v;
}
return 1;
}
char asc(char c)
{
if (isprint(c)) return c;
return '.';
}
struct buf * block(int n, struct buf *p)
{
for (;n>=0;n--) {
if (p == NULL) return p;
p = p->next;
}
return p;
}
void dump(struct buf *b)
{
int i;
printf("(%d)\n", b->sz);
for (i=0; i<16; i++)
printf("%02x ",b->b[i]);
printf("\n");
for (i=0; i<16; i++)
printf("%c ",isprint(b->b[i]) ? b->b[i] : '.');
printf("\n");
}
int blkver(struct buf *p, char *str, int len)
{
if (!cur) return 0;
if (len >= 0) if (len != p->sz) return 0;
if (len < 0) {
if (p->sz == 0) return 0;
switch (len) {
case -512:
if ((p->sz % 512) != 0) return 0;
break;
case -48:
if ((p->sz % 512) != 48) return 0;
break;
default:
printf("Bad call to verify. Len = %d\n", len);
return 0;
}
}
return strncmp(p->b, str, strlen(str)) == 0;
}
struct buf *locbuf(struct buf *m)
{
struct buf *p = &tape;
while (p->next != m) p = p->next;
return p;
}
void recover(struct buf *p, char *str, int len, int eoff)
{
struct buf *x, *z;
struct buf *prev;
struct buf *tm1;
int c;
printf(" Error detected... Expected: %s (%d)\n",str,len);
prev = locbuf(p);
if ((prev->sz == 0) && (eoff == 0)) {
printf(" Previous was EOF. Trying to move current back to previous file.\n");
tm1 = locbuf(prev);
prev->next = p->next; /* Unlink */
p->next = tm1->next; /* Link in after TM1 */
tm1->next = p;
cur = prev->next;
bl++;
} else {
x = p;
c = 0;
while(!blkver(x,str,len)) {
x = block(0,x);
if (x == NULL) {
printf("Failed to recover.\n");
exit(1);
}
c++;
}
printf(" Found match. Delta = %d\n", c);
if (debug) dump(x);
tm1 = locbuf(x);
tm1->next = x->next; /* Unlink */
x->next = prev->next; /* Link in at before current */
prev->next = x;
cur = x;
}
printf("After recover. Cur bli is #%d\n",bl);
if (debug) dump(cur);
}
void recoverd(struct buf *p, char *str)
{
struct buf *x, *z;
struct buf *prev;
struct buf *tm1;
int c;
printf(" Error detected... Expected: %s or direct\n",str);
prev = locbuf(p);
x = p;
c = 0;
while(!(blkver(x,"",-512) || blkver(x,"UFD",80) || blkver(x,str,80))) {
x = block(0,x);
if (x == NULL) {
printf("Failed to recover from dir.\n");
exit(1);
}
c++;
}
printf(" Found match. Delta = %d\n", c);
if (debug) dump(x);
tm1 = locbuf(x);
tm1->next = x->next; /* Unlink */
x->next = prev->next; /* Link in at before current */
prev->next = x;
cur = prev;
bl--;
printf(" After recover. Cur bli is #%d\n",bl);
if (debug) dump(cur);
}
unsigned short cfno(struct buf *p)
{
return *((unsigned short *)(p->b));
}
unsigned short getfno(struct buf *p)
{
int i;
unsigned short fno,x;
fno = cfno(p);
for (i=1;i<8;i++) {
x = *(unsigned short *)(&(p->b[i*6]));
if (x == 0) return fno;
fno = x;
}
return fno;
}
void next(void)
{
cur = cur->next;
bl++;
if (debug) printf("Now analyzing block #%d\n",bl);
if (debug) if (cur) dump(cur);
}
int blkno(struct buf *p, int x)
{
int i;
for (i=0;i<x;i += 6) {
if ((p->b[i] == 0) && (p->b[i+1] == 0)) break;
}
return ((p->b[i-1] * 256) +
(p->b[i-2]) +
(p->b[i-4] * 65536));
}
void collect(void)
{
int c,found;
unsigned short fno;
struct buf *x;
if (debug) printf("Collecting data. Preliminary head:\n");
if (debug) dump(cur);
found = 0;
c = 0;
x = cur;
while(x && (c < 5) && !found) {
if (debug) printf("Head search\n");
if (debug) dump(x);
if (x->sz == 4144) {
found = 1;
} else {
x = block(0,x);
c++;
}
}
if (!found) {
x = cur;
c = 0;
while (x && (c < 5) && !found) {
if (debug) printf("Short head search\n");
if (debug) dump(x);
if ((x->sz % 512) == 48) {
found = 1;
} else {
x = block(0,x);
c++;
}
}
}
if (!found) {
printf("Expected data blocks, but none found!\n");
exit(1);
}
if (debug) printf("Located head: %d\n", c);
if (debug) dump(x);
if (c > 0) {
struct buf *tm1, *tm2;
tm1 = locbuf(cur);
tm2 = locbuf(x);
tm2->next = x->next;
x->next = tm1->next;
tm1->next = x;
cur = x;
}
if (debug) printf("Actual head:\n");
if (debug) dump(cur);
while (1) {
x = block(0,cur); /* Get next block. */
c = 0;
found = 0;
fno = getfno(cur); /* Get the last FNO of this block. */
if (debug) printf("Fileno: %d Bno: %d\n", fno,blkno(cur,6));
while (x && (c < 5) && !found) {
if ((x->sz % 512) == 48) { /* Next block data? */
if (debug) printf("Checking against %d\n", getfno(x));
if (debug) dump(x);
if (getfno(x) == fno) { /* Yes. Last FNO of next block same FNO? */
found = 1; /* Yes. */
} else {
x = block(0,x); /* No. Move on... */
c++;
}
} else {
x = block(0,x);
c++;
}
}
if (!found) { /* Nothing yet? */
if (debug) printf("No full block found. Continuing...\n");
x = block(0,cur); /* Get next block again. */
c = 0;
while (x && (c < 5) && !found) {
if ((x->sz % 512) == 48) { /* Data block? */
if (debug) printf("Checking against %d\n", cfno(x));
if (debug) dump(x);
if (cfno(x) == fno) { /* Yes. First same FNO? */
found = 1; /* Yes. */
} else {
x = block(0,x); /* No. Move on... */
c++;
}
} else {
x = block(0,x);
c++;
}
}
}
if (!found) { /* Not found yet? */
if (debug) printf("No fileno match. Searching for more blocks...\n");
x = block(0,cur); /* No. Get next block. */
c = 0;
while (x && (c < 5) && !found) {
if (debug) printf("Full block?\n");
if (debug) dump(x);
if (x->sz == 4144) { /* Data block? */
found = 1; /* Yes. Done. */
} else {
x = block(0,x); /* No. Keep searching. */
c++;
}
}
}
if (!found) { /* Not found yet? */
if (debug) printf("No fileno match. Searching for more blocks...\n");
x = block(0,cur); /* No. Get next block. */
c = 0;
while (x && (c < 5) && !found) {
if (debug) printf("Data block?\n");
if (debug) dump(x);
if ((x->sz % 512) == 48) { /* Data block? */
found = 1; /* Yes. Done. */
} else {
x = block(0,x); /* No. Keep searching. */
c++;
}
}
}
if (!found) { /* Nothing found? */
if (debug) printf("End of file.\n");
next(); /* Right. Go to next block. */
return; /* Done. Finish. */
}
if (debug) printf(" Collector found block.\n");
if (c > 0) { /* Something found. In order? */
struct buf *tm; /* No. Move to in order. */
printf(" Collector reorder. Block %d. Offset %d\n", bl, c);
tm = locbuf(x);
tm->next = x->next;
x->next = cur->next;
cur->next = x;
}
if (blkno(cur,48) > blkno(x,6)) {
struct buf *tm;
printf(" Collector reorder fix.\n");
tm = locbuf(cur);
cur->next = x->next;
x->next = tm->next;
tm->next = x;
bl++;
} else {
next(); /* Move to next block. */
}
}
}
void dumpbyt(int x, FILE *f)
{
if (fmt) {
fprintf(f, "%02X", x);
col += 2;
if (col == 80) {
fprintf(f, "\n");
col = 0;
}
} else {
fputc(x, f);
}
}
void dumpb2(struct buf *b, FILE *f)
{
int i,s;
s = b->sz;
dumpbyt(s & 255, f);
dumpbyt(s / 256, f);
for (i=0; i<s; i++) dumpbyt(b->b[i], f);
}
void dumpbuf(FILE *f)
{
struct buf *p=tape.next;
while(p) {
dumpb2(p,f);
p = p->next;
}
}
void analyze()
{
cur = block(0,&tape);
bl = 0;
if (blkver(cur,"VOL1",80)) { /* VOL1 */
printf("ANSI tape\n");
next();
if (!blkver(cur,"",512)) /* NOBOOT */
recover(cur,"",512,0);
next();
while (cur) {
if (!blkver(cur,"HDR1",80)) /* HDR1 */
recover(cur,"HDR1",80,0);
printf("New file: %-12.12s\n",&(cur->b[4]));
next();
if (!blkver(cur,"HDR2",80)) /* HDR2 */
recover(cur,"HDR2",80,0);
next();
if (!blkver(cur,"",0)) /* *TM* */
recover(cur,"",0,0);
next();
if (!blkver(cur,"",80)) /* BACKUP */
recover(cur,"",80,-1);
next();
if (!blkver(cur,"",512)) /* BOOT */
recover(cur,"",512,0);
next();
if (!blkver(cur,"",512)) /* HOME */
recover(cur,"",512,0);
next();
/* Go through the HEAD section */
while (!blkver(cur,"HEAD",80)) {
if (!blkver(cur,"UFD",80)) /* UFD */
recover(cur,"UFD",80,0);
next();
if (!blkver(cur,"",-512))
recover(cur,"",-512,0); /* Direct */
next();
while(!(blkver(cur,"UFD",80) || blkver(cur,"HEAD",80))) {
if (!blkver(cur,"",-512)) /* Direct */
recoverd(cur,"HEAD");
next();
}
}
next();
/* Go through the HDRS section */
while (!blkver(cur,"DATA",80)) {
if (!blkver(cur,"UFD",80))
recover(cur,"UFD",80,0); /* UFD */
next();
if (!blkver(cur,"",-512)) /* Direct */
recover(cur,"",-512,0);
next();
while (!(blkver(cur,"DATA",80) || blkver(cur,"UFD",80))) {
if (!blkver(cur,"",-512)) /* UFD contents */
recoverd(cur,"DATA");
next();
}
}
next();
collect(); /* DATA */
if (!blkver(cur,"",0)) /* *TM* */
recover(cur,"",0,0);
next();
if (!blkver(cur,"EOF1",80)) /* EOF1 */
recover(cur,"EOF1",80,-1);
next();
if (!blkver(cur,"EOF2",80)) /* EOF2 */
recover(cur,"EOF2",80,0);
next();
if (!blkver(cur,"",0)) /* *TM* */
recover(cur,"",0,0);
next();
while (blkver(cur,"",0)) /* Skip extra TM */
next();
}
printf("Done. %d blocks.\n",bl);
} else {
printf("Unknow tape format\n");
printf("Not implemented yet...\n");
}
}
void main(int argc, char *argv[])
{
FILE *f1, *f2;
int done=0;
char *cnam = argv[0];
cur = &tape;
argc--;
argv++;
if ((argc > 0) && (strcmp(argv[0],"-x") == 0)) {
fmt = 1;
argc--;
argv++;
}
if (argc != 2) {
printf("Usage: %s [-x] <intape> <outtape>\n", cnam);
exit(1);
}
if ((f1 = fopen(argv[0],"r")) == NULL) {
perror(argv[0]);
exit(1);
}
if ((f2 = fopen(argv[1],"w")) == NULL) {
perror(argv[1]);
exit(1);
}
done = 0;
bl = 0;
while (done < 4) {
bl++;
cur->next = malloc(sizeof(struct buf));
cur = cur->next;
cur->next = NULL;
if (!readbuf(cur, f1)) break;
if (cur->sz == 0) done++;
else done = 0;
}
fclose(f1);
printf("Read blocks: %d\n", bl);
printf("Analyzing tape format...\n");
analyze();
printf("Check...\n");
analyze();
col = 0;
dumpbuf(f2);
if (col !=0) fprintf(f2, "\n");
fclose(f2);
}
More information about the Hecnet-list
mailing list