diff --git a/mlb-rt11.c b/mlb-rt11.c index dfd79d1..386f1eb 100644 --- a/mlb-rt11.c +++ b/mlb-rt11.c @@ -40,13 +40,12 @@ DAMAGE. #include #include "rad50.h" - #include "stream2.h" - #include "mlb.h" - #include "util.h" +#define MLBDEBUG_OPEN 0 + static MLB *mlb_rt11_open( char *name, int allow_object_library); @@ -73,6 +72,9 @@ struct mlb_vtbl mlb_rt11_vtbl = { * * A MLB Macro Library Header differs a lot from an Object Library Header. */ + +#define BLOCKSIZE 512 + #define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8)) /* BYTEPOS calculates the byte position within the macro libray file. @@ -80,7 +82,8 @@ struct mlb_vtbl mlb_rt11_vtbl = { be able to calculate the entries' sizes, which isn't actually stored in the directory. */ -#define BYTEPOS(rec) ((WORD((rec)+4) & 32767) * 512 + (WORD((rec)+6) & 511)) +#define BYTEPOS(rec) ((WORD((rec)+4) & 32767) * BLOCKSIZE + \ + (WORD((rec)+6) & 511)) /* compare_position is the qsort callback function that compares byte locations within the macro library */ @@ -124,6 +127,9 @@ MLB *mlb_rt11_open( unsigned start_block; int i; +#if MLBDEBUG_OPEN + fprintf(stderr, "mlb_rt11_open('%s', %d)\n", name, allow_object_library); +#endif (void)allow_object_library; /* This parameter is not supported */ mlb->vtbl = &mlb_rt11_vtbl; mlb->directory = NULL; @@ -137,14 +143,12 @@ MLB *mlb_rt11_open( buff = memcheck(malloc(044)); /* Size of MLB library header */ if (fread(buff, 1, 044, mlb->fp) < 044) { - mlb_rt11_close(mlb); - free(buff); - return NULL; + goto error; /* Nope. */ } - if (WORD(buff) != 01001) { /* Is this really a macro library? */ - mlb_rt11_close(mlb); /* Nope. */ - return NULL; + if (WORD(buff) != 01001 || + WORD(buff + 2) != 0500) { /* Is this really a macro library? */ + goto error; /* Nope. */ } entsize = WORD(buff + 032); /* The size of each macro directory @@ -153,17 +157,34 @@ MLB *mlb_rt11_open( start_block = WORD(buff + 034); /* The start RT-11 block of the directory */ + if (entsize < 8) { /* Is this really a macro library? */ + fprintf(stderr, "mlb_rt11_open error: entsize too small: %d\n", entsize); + goto error; /* Nope. */ + } + + if (start_block < 1) { /* Is this really a macro library? */ + fprintf(stderr, "mlb_rt11_open error: start_block too small: %d\n", start_block); + goto error; /* Nope. */ + } + +#if MLBDEBUG_OPEN + fprintf(stderr, "entsize=%d, nr_entries=%d, start_block=%d\n", + entsize, nr_entries, start_block); +#endif free(buff); /* Done with that header. */ /* Allocate a buffer for the disk directory */ buff = memcheck(malloc(nr_entries * entsize)); - fseek(mlb->fp, start_block * 512, SEEK_SET); /* Go to the directory */ + /* Go to the directory */ + if (fseek(mlb->fp, start_block * BLOCKSIZE, SEEK_SET) == -1) { + fprintf(stderr, "mlb_rt11_open error: seek error: %d\n", start_block * BLOCKSIZE); + goto error; + } /* Read the disk directory */ if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) { - mlb_rt11_close(mlb); /* Sorry, read error. */ - free(buff); - return NULL; + fprintf(stderr, "mlb_rt11_open error: fread: not enough entries\n"); + goto error; /* Sorry, read error. */ } /* Shift occupied directory entries to the front of the array @@ -174,11 +195,14 @@ MLB *mlb_rt11_open( for (i = 0, j = nr_entries; i < j; i++) { char *ent1, *ent2; + int w1, w2; ent1 = buff + (i * entsize); + w1 = WORD(ent1); + w2 = WORD(ent1 + 2); /* Unused entries have 0177777 0177777 for the RAD50 name, which is not legal RAD50. */ - if (WORD(ent1) == 0177777 && WORD(ent1 + 2) == 0177777) { + if (w1 == 0177777 && w2 == 0177777) { while (--j > i && (ent2 = buff + (j * entsize), WORD(ent2) == 0177777 && WORD(ent2 + 2) == 0177777)) ; if (j <= i) @@ -187,12 +211,24 @@ MLB *mlb_rt11_open( into unused entry's space */ memset(ent2, 0377, entsize); /* Mark entry unused */ + } else { + if (w1 == 0000000 && w2 == 0000000) { + fprintf(stderr, "mlb_rt11_open error: bad file, null name\n"); + goto error; + } } } /* Now i contains the actual number of entries. */ mlb->nentries = i; +#if MLBDEBUG_OPEN + fprintf(stderr, "mlb->nentries=%d\n", mlb->nentries); +#endif + if (mlb->nentries == 0) { + fprintf(stderr, "mlb_rt11_open error: no entries\n"); + goto error; + } /* Sort the array by file position */ @@ -202,6 +238,11 @@ MLB *mlb_rt11_open( mlb->directory = memcheck(malloc(sizeof(MLBENT) * mlb->nentries)); memset(mlb->directory, 0, sizeof(MLBENT) * mlb->nentries); + unsigned long max_filepos; + + fseek(mlb->fp, 0, SEEK_END); + max_filepos = ftell(mlb->fp); + /* Build in-memory directory */ for (j = 0; j < i; j++) { char radname[16]; @@ -214,17 +255,25 @@ MLB *mlb_rt11_open( radname[6] = 0; trim(radname); + if (radname[0] == '\0' || strchr(radname, ' ')) { + fprintf(stderr, "mlb_rt11_open error: entry with space in name\n"); + goto error; + } mlb->directory[j].label = memcheck(strdup(radname)); mlb->directory[j].position = BYTEPOS(ent); + + if (mlb->directory[j].position > max_filepos) { + fprintf(stderr, "mlb_rt11_open error: entry past EOF\n"); + goto error; + } + if (j < i - 1) { mlb->directory[j].length = BYTEPOS(ent + entsize) - BYTEPOS(ent); } else { - unsigned long max; + unsigned long max = max_filepos; char c; - fseek(mlb->fp, 0, SEEK_END); - max = ftell(mlb->fp); /* Look for last non-zero */ do { max--; @@ -234,6 +283,13 @@ MLB *mlb_rt11_open( max++; mlb->directory[j].length = max - BYTEPOS(ent); } +#if MLBDEBUG_OPEN + fprintf(stderr, "entry #%d '%s' %ld length %d\n", + j, + mlb->directory[j].label, + mlb->directory[j].position, + mlb->directory[j].length); +#endif } free(buff); @@ -241,6 +297,14 @@ MLB *mlb_rt11_open( /* Done. Return the struct that represents the opened MLB. */ return mlb; + +error: +#if MLBDEBUG_OPEN + fprintf(stderr, "(mlb_rt11_open closing '%s' due to errors)\n", name); +#endif + mlb_rt11_close(mlb); /* Sorry, bad file. */ + free(buff); + return NULL; } /* mlb_rt11_close discards MLB and closes the file. */