Create sorted blocks on-the-fly, without storing them all in aux mem.

This commit is contained in:
Bobbi Webber-Manners 2020-06-01 19:49:25 -04:00
parent 7796124aff
commit 33368c8e24
2 changed files with 76 additions and 81 deletions

157
sortdir.c
View File

@ -3,10 +3,6 @@
* *
* Bobbi January-June 2020 * Bobbi January-June 2020
* *
* TODO: IDEA you only need one sorteddata block at a time. Do not allocate
* until writeout time and use one block buffer. Iterate through
* filelist[] collecting all entries for block 1, 2, 3 in turn.
* Huge aux memory savings!!
* TODO: Get working on drives >2 (S7D3, S7D4 etc.) * TODO: Get working on drives >2 (S7D3, S7D4 etc.)
* TODO: Enable free list functionality on ProDOS-8 * TODO: Enable free list functionality on ProDOS-8
* TODO: Get both ProDOS-8 and GNO versions to build from this source * TODO: Get both ProDOS-8 and GNO versions to build from this source
@ -29,6 +25,7 @@
* v0.63 Made code work properly with #undef CHECK. * v0.63 Made code work properly with #undef CHECK.
* v0.64 Fixed overflow in file count (entries). Added check to auxalloc(). * v0.64 Fixed overflow in file count (entries). Added check to auxalloc().
* v0.65 Fixed length passed to AUXMOVE in copyaux(). * v0.65 Fixed length passed to AUXMOVE in copyaux().
* v0.66 Modified to build sorted blocks on the fly rather than in aux memory.
*/ */
//#pragma debug 9 //#pragma debug 9
@ -119,16 +116,13 @@ struct pd_dirent {
/* /*
* Linked list of directory blocks read from disk * Linked list of directory blocks read from disk
* Original directory block is stored in data[] * Directory block is stored in data[]
* Directory block for sorted directory is stored in sorteddata[]
*/ */
struct block { struct block {
#ifdef AUXMEM #ifdef AUXMEM
char *data; /* Original contents of block */ char *data; /* Original contents of block */
char *sorteddata; /* Content block for sorted dir */
#else #else
char data[BLKSZ]; /* Original contents of block */ char data[BLKSZ]; /* Original contents of block */
char sorteddata[BLKSZ]; /* Content block for sorted dir */
#endif #endif
uint blocknum; /* Block number on disk */ uint blocknum; /* Block number on disk */
struct block *next; struct block *next;
@ -202,7 +196,9 @@ static uchar dowrite = 0; /* -w write option */
static uchar doverbose = 0; /* -v verbose option */ static uchar doverbose = 0; /* -v verbose option */
static uchar dodebug = 0; /* -V very verbose option */ static uchar dodebug = 0; /* -V very verbose option */
static uchar do_ctime = 0; /* -k ctime option */ static uchar do_ctime = 0; /* -k ctime option */
#ifdef FREELIST
static uchar dozero = 0; /* -z zero free blocks option */ static uchar dozero = 0; /* -z zero free blocks option */
#endif
static char sortopts[NLEVELS+1] = ""; /* -s:abc list of sort options */ static char sortopts[NLEVELS+1] = ""; /* -s:abc list of sort options */
static char caseopts[2] = ""; /* -c:x case conversion option */ static char caseopts[2] = ""; /* -c:x case conversion option */
static char fixopts[2] = ""; /* -f:x fix mode option */ static char fixopts[2] = ""; /* -f:x fix mode option */
@ -274,15 +270,18 @@ void sortlist(char s);
#endif #endif
void printlist(void); void printlist(void);
uint blockidxtoblocknum(uint idx); uint blockidxtoblocknum(uint idx);
void copyent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device); void copydirblkptrs(uint blkidx);
void sortblocks(uint device); void copydirent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device);
void sortblock(uint device, uint dstblk);
int writedir(uchar device); int writedir(uchar device);
void freeblocks(void); void freeblocks(void);
void interactive(void); void interactive(void);
void processdir(uint device, uint blocknum); void processdir(uint device, uint blocknum);
#ifdef FREELIST
void checkfreeandused(uchar device); void checkfreeandused(uchar device);
void zeroblock(uchar device, uint blocknum); void zeroblock(uchar device, uint blocknum);
void zerofreeblocks(uchar device, uint freeblks); void zerofreeblocks(uchar device, uint freeblks);
#endif
#ifdef CMDLINE #ifdef CMDLINE
void usage(void); void usage(void);
void parseargs(void); void parseargs(void);
@ -517,7 +516,7 @@ void lowercase(char *p, uchar len, uchar *minvers, uchar *vers) {
* Convert filename pointed to by p into upper case (which is recorded * Convert filename pointed to by p into upper case (which is recorded
* as a bitmap in the vers and minvers fields. * as a bitmap in the vers and minvers fields.
*/ */
void uppercase(char *p, uchar len, uchar *minvers, uchar *vers) { void uppercase(char*, uchar, uchar *minvers, uchar *vers) {
*vers = 0x00; *vers = 0x00;
*minvers = 0x00; *minvers = 0x00;
} }
@ -827,9 +826,11 @@ void checkblock(uint blk, char *msg) {
/* /*
* Count the blocks in a seedling file * Count the blocks in a seedling file
*/ */
int seedlingblocks(uchar device, uint keyblk, uint *blkcnt) {
#ifdef FREELIST #ifdef FREELIST
int seedlingblocks(uchar, uint keyblk, uint *blkcnt) {
checkblock(keyblk, "Data"); checkblock(keyblk, "Data");
#else
int seedlingblocks(uchar, uint, uint *blkcnt) {
#endif #endif
*blkcnt = 1; *blkcnt = 1;
return 0; return 0;
@ -1076,7 +1077,6 @@ int readdir(uint device, uint blocknum) {
static char namebuf[NMLEN+1]; static char namebuf[NMLEN+1];
struct pd_dirhdr *hdr; struct pd_dirhdr *hdr;
struct block *curblk; struct block *curblk;
struct datetime dt;
ulong eof; ulong eof;
uint filecount, idx, subdirs, blks, keyblk, hdrblk, count, entries; uint filecount, idx, subdirs, blks, keyblk, hdrblk, count, entries;
uchar blkentries, pd25, i; uchar blkentries, pd25, i;
@ -1095,7 +1095,6 @@ int readdir(uint device, uint blocknum) {
#ifdef AUXMEM #ifdef AUXMEM
curblk->data = auxalloc(BLKSZ); curblk->data = auxalloc(BLKSZ);
curblk->sorteddata = auxalloc(BLKSZ);
#endif #endif
#ifdef FREELIST #ifdef FREELIST
@ -1308,14 +1307,8 @@ int readdir(uint device, uint blocknum) {
blocknum = dirblkbuf[0x02] + 256U * dirblkbuf[0x03]; blocknum = dirblkbuf[0x02] + 256U * dirblkbuf[0x03];
#ifdef AUXMEM #ifdef AUXMEM
copyaux(dirblkbuf, curblk->data, BLKSZ, TOAUX); copyaux(dirblkbuf, curblk->data, BLKSZ, TOAUX);
bzero(buf, BLKSZ);
memcpy(buf, dirblkbuf, PTRSZ);
copyaux(buf, curblk->sorteddata, BLKSZ, TOAUX);
#else #else
memcpy(curblk->data, dirblkbuf, BLKSZ); memcpy(curblk->data, dirblkbuf, BLKSZ);
bzero(buf, BLKSZ);
memcpy(buf, dirblkbuf, PTRSZ);
memcpy(curblk->sorteddata, buf, BLKSZ);
#endif #endif
if (blocknum == 0) { if (blocknum == 0) {
break; break;
@ -1330,7 +1323,6 @@ int readdir(uint device, uint blocknum) {
#ifdef AUXMEM #ifdef AUXMEM
curblk->data = auxalloc(BLKSZ); curblk->data = auxalloc(BLKSZ);
curblk->sorteddata = auxalloc(BLKSZ);
#endif #endif
#ifdef FREELIST #ifdef FREELIST
@ -1359,14 +1351,8 @@ int readdir(uint device, uint blocknum) {
} }
#ifdef AUXMEM #ifdef AUXMEM
copyaux(dirblkbuf, curblk->data, BLKSZ, TOAUX); copyaux(dirblkbuf, curblk->data, BLKSZ, TOAUX);
bzero(buf, BLKSZ);
memcpy(buf, dirblkbuf, PTRSZ);
copyaux(buf, curblk->sorteddata, BLKSZ, TOAUX);
#else #else
memcpy(curblk->data, dirblkbuf, BLKSZ); memcpy(curblk->data, dirblkbuf, BLKSZ);
bzero(buf, BLKSZ);
memcpy(buf, dirblkbuf, PTRSZ);
memcpy(curblk->sorteddata, buf, BLKSZ);
#endif #endif
return errcount - errsbefore; return errcount - errsbefore;
@ -1730,21 +1716,36 @@ uint blockidxtoblocknum(uint idx) {
uint i; uint i;
struct block *p = blocks; struct block *p = blocks;
for (i = 1; i < idx; ++i) for (i = 1; i < idx; ++i)
if (p) p = p->next;
p = p->next;
else
err(FATAL, "Int error");
if (!p)
err(FATAL, "Int error");
return p->blocknum; return p->blocknum;
} }
/*
* Copy the 4 bytes of pointers from the directory block with index idx
* to the start of dirblkbuf[]; zeroes the rest of dirblkbuf[].
*/
void copydirblkptrs(uint idx) {
uint i;
struct block *p = blocks;
for (i = 1; i < idx; ++i)
p = p->next;
//while (--blkidx > 0)
// b = b->next;
bzero(dirblkbuf, BLKSZ);
#ifdef AUXMEM
copyaux(p->data, dirblkbuf, PTRSZ, FROMAUX);
#else
memcpy(dirblkbuf, p->data, PTRSZ);
#endif
}
/* /*
* Copy a file entry from one srcblk, srcent to dstblk, dstent * Copy a file entry from one srcblk, srcent to dstblk, dstent
* All indices are 1-based. * All indices are 1-based.
* dstblk is written to dirblkbuf[]
*/ */
void copyent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device) { void copydirent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device) {
struct block *source = blocks, *dest = blocks; struct block *source = blocks;
struct pd_dirent *ent; struct pd_dirent *ent;
struct pd_dirhdr *hdr; struct pd_dirhdr *hdr;
char *srcptr, *dstptr; char *srcptr, *dstptr;
@ -1755,32 +1756,26 @@ void copyent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device) {
printf(" to dirblk %03u entry %02u\n", dstblk, dstent); printf(" to dirblk %03u entry %02u\n", dstblk, dstent);
} }
parentblk = blockidxtoblocknum(dstblk);
while (--srcblk > 0) while (--srcblk > 0)
source = source->next; source = source->next;
while (--dstblk > 0)
dest = dest->next;
srcptr = source->data + PTRSZ + (srcent-1) * entsz; srcptr = source->data + PTRSZ + (srcent-1) * entsz;
dstptr = dest->sorteddata + PTRSZ + (dstent-1) * entsz; dstptr = dirblkbuf + PTRSZ + (dstent-1) * entsz;
#ifdef AUXMEM #ifdef AUXMEM
copyaux(srcptr, buf2, entsz, FROMAUX); copyaux(srcptr, dstptr, entsz, FROMAUX);
copyaux(buf2, dstptr, entsz, TOAUX);
#else #else
memcpy(dstptr, srcptr, entsz); memcpy(dstptr, srcptr, entsz);
#endif #endif
/* For directories, update the parent dir entry number */ /* For directories, update the parent dir entry number */
#ifdef AUXMEM
ent = (struct pd_dirent*)buf2;
#else
ent = (struct pd_dirent*)dstptr; ent = (struct pd_dirent*)dstptr;
#endif
if ((ent->typ_len & 0xf0) == 0xd0) { if ((ent->typ_len & 0xf0) == 0xd0) {
uint block = ent->keyptr[0] + 256U * ent->keyptr[1]; uint block = ent->keyptr[0] + 256U * ent->keyptr[1];
if (readdiskblock(device, block, buf) == -1) if (readdiskblock(device, block, buf) == -1)
err(FATAL, "Can't read subdir"); err(FATAL, "Can't read subdir");
hdr = (struct pd_dirhdr*)(buf + PTRSZ); hdr = (struct pd_dirhdr*)(buf + PTRSZ);
parentblk = blockidxtoblocknum(dstblk);
hdr->parptr[0] = parentblk & 0xff; hdr->parptr[0] = parentblk & 0xff;
hdr->parptr[1] = (parentblk >> 8) & 0xff; hdr->parptr[1] = (parentblk >> 8) & 0xff;
hdr->parentry = dstent; hdr->parentry = dstent;
@ -1792,39 +1787,40 @@ void copyent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device) {
} }
/* /*
* Use the sorted list in filelist[] to create a sorted set of directory * Build sorted directory block dstblk (1,2,3...) using the sorted list in
* blocks. Note that the block and entry numbers are 1-based indices. * filelist[]. Note that the block and entry numbers are 1-based indices.
*/ */
void sortblocks(uint device) { void sortblock(uint device, uint dstblk) {
uint i; uint i, firstlistent, lastlistent;
uchar destblk = 1; uchar destentry;
uchar destentry = 2; /* Skip header on first block */ copydirblkptrs(dstblk);
copyent(1, 1, 1, 1, device); /* Copy directory header */ if (dstblk == 1) {
for(i = 0; i < numfiles; ++i) { copydirent(1, 1, 1, 1, device); /* Copy directory header */
if (dodebug) destentry = 2; /* Skip header on first block */
puts(filelist[i].name); firstlistent = 0;
copyent(filelist[i].blockidx, filelist[i].entrynum, lastlistent = entperblk - 2;
destblk, destentry, device); } else {
if (destentry++ == entperblk) { destentry = 1;
++destblk; firstlistent = (dstblk - 1) * entperblk - 1;
destentry = 1; lastlistent = firstlistent + entperblk - 1;
} }
for (i = firstlistent; i <= lastlistent; ++i) {
copydirent(filelist[i].blockidx, filelist[i].entrynum,
dstblk, destentry++, device);
} }
} }
/* /*
* Write out the sorted directory * Build each sorted directory block in turn, then write them
* out to disk.
*/ */
int writedir(uchar device) { int writedir(uchar device) {
uint dstblk = 1;
struct block *b = blocks; struct block *b = blocks;
while (b) { while (b) {
#ifdef AUXMEM sortblock(device, dstblk++);
copyaux(b->sorteddata, dirblkbuf, BLKSZ, FROMAUX);
if (writediskblock(device, b->blocknum, dirblkbuf) == -1) { if (writediskblock(device, b->blocknum, dirblkbuf) == -1) {
#else err(NONFATAL, "Can't write blk %u", b->blocknum);
if (writediskblock(device, b->blocknum, b->sorteddata) == -1) {
#endif
err(NONFATAL, "Can't write block %u", b->blocknum);
return 1; return 1;
} }
b = b->next; b = b->next;
@ -1846,12 +1842,15 @@ void freeblocks(void) {
} }
void interactive(void) { void interactive(void) {
char w, l, d, f, z, wrt; char w, l, d, f, wrt;
#ifdef FREELIST
char z;
#endif
uchar level; uchar level;
doverbose = 1; doverbose = 1;
puts("S O R T D I R v0.65 alpha Use ^ to return to previous question"); puts("S O R T D I R v0.66 alpha Use ^ to return to previous question");
q1: q1:
fputs("\nEnter path (e.g.: /H1) of starting directory> ", stdout); fputs("\nEnter path (e.g.: /H1) of starting directory> ", stdout);
@ -1983,13 +1982,9 @@ void processdir(uint device, uint blocknum) {
printf("[%c] ", sortopts[i]); printf("[%c] ", sortopts[i]);
buildsorttable(sortopts[i], i); buildsorttable(sortopts[i], i);
sortlist(sortopts[i]); sortlist(sortopts[i]);
sortblocks(device);
} }
if (doverbose) if (doverbose)
putchar('\n'); putchar('\n');
//if (doverbose) {
// printlist();
//}
if (dowrite) { if (dowrite) {
puts("Writing dir ..."); puts("Writing dir ...");
errs = writedir(device); errs = writedir(device);
@ -2004,13 +1999,14 @@ done:
#endif #endif
} }
#ifdef FREELIST
/* /*
* Iterate through freelist[] and usedlist[] and see if all is well. * Iterate through freelist[] and usedlist[] and see if all is well.
* If we have visited all files and directories on the volume, every * If we have visited all files and directories on the volume, every
* block should either be marked free or marked used. * block should either be marked free or marked used.
*/ */
void checkfreeandused(uchar device) { void checkfreeandused(uchar device) {
#ifdef FREELIST
uint i, freeblks = 0; uint i, freeblks = 0;
printf("Total blks\t%u\n", totblks); printf("Total blks\t%u\n", totblks);
for (i = 0; i < totblks; ++i) for (i = 0; i < totblks; ++i)
@ -2041,13 +2037,11 @@ void checkfreeandused(uchar device) {
} }
if (dozero) if (dozero)
zerofreeblocks(device, freeblks); zerofreeblocks(device, freeblks);
#endif
} }
/* /*
* Zero block blocknum * Zero block blocknum
*/ */
#ifdef FREELIST
void zeroblock(uchar device, uint blocknum) { void zeroblock(uchar device, uint blocknum) {
bzero(buf, BLKSZ); bzero(buf, BLKSZ);
// DIORecGS dr; // DIORecGS dr;
@ -2061,12 +2055,10 @@ void zeroblock(uchar device, uint blocknum) {
// if (dr.transferCount != BLKSZ) // if (dr.transferCount != BLKSZ)
// err(FATAL, "Block write failed"); // err(FATAL, "Block write failed");
} }
#endif
/* /*
* Zero all free blocks on the volume * Zero all free blocks on the volume
*/ */
#ifdef FREELIST
void zerofreeblocks(uchar device, uint freeblks) { void zerofreeblocks(uchar device, uint freeblks) {
uint i, step = freeblks / 60, ctr = 0; uint i, step = freeblks / 60, ctr = 0;
puts("Zeroing free blocks ..."); puts("Zeroing free blocks ...");
@ -2082,6 +2074,7 @@ void zerofreeblocks(uchar device, uint freeblks) {
} }
puts("\nDone zeroing!"); puts("\nDone zeroing!");
} }
#endif #endif
#ifdef CMDLINE #ifdef CMDLINE
@ -2173,7 +2166,9 @@ void parseargs() {
//int main(int argc, char *argv[]) { //int main(int argc, char *argv[]) {
int main() { int main() {
#ifdef CMDLINE
int opt; int opt;
#endif
uchar dev; uchar dev;
uint blk; uint blk;
@ -2292,10 +2287,10 @@ int main() {
processdir(dev, blk); processdir(dev, blk);
} }
} }
#ifdef FREELIST
if (dowholedisk) if (dowholedisk)
checkfreeandused(dev); checkfreeandused(dev);
#ifdef FREELIST
free(freelist); free(freelist);
free(usedlist); free(usedlist);
#endif #endif

Binary file not shown.