[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