/* lqmkfree.c -- Copyright 1989, 1990, 1996 Liam R. Quin. * All Rights Reserved. * This code is NOT in the public domain. * See the file COPYRIGHT for full details. */ /* lqmkfree - rebuild the free-file bitmap. Sometimes this can gain a few * extra blocks in the database, although I don't know why. * It's also useful if you think the free list may have got corrupted. * * $Id: lqmkfree.c,v 1.3 1996/08/14 17:03:00 lee Exp $ */ #include "globals.h" /* defines and declarations for database filenames */ #include "error.h" #include /* stderr, also for fileinfo.h */ #include #include #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #include #include "emalloc.h" #include "fileinfo.h" /* for wordinfo.h */ #include "wordinfo.h" #include "pblock.h" #include "blkheader.h" #include "lqutil.h" extern int AsciiTrace; #ifndef LINT static char *Revision = "@(#) $Id: lqmkfree.c,v 1.3 1996/08/14 17:03:00 lee Exp $"; #endif static void FollowChain( #ifdef HAVE_PROTO t_WID WID #endif ); char *progname = "lqtext/lqmkfree"; int main(argc, argv) int argc; char *argv[]; { extern int optind, getopt(); /** extern char *optarg; (unused at present) **/ int ch; int ErrorFlag = 0; progname = argv[0]; LQT_InitFromArgv(argc, argv); LQT_ObtainWriteAccess(); while ((ch = getopt(argc, argv, "Zz:ahpxVv")) != EOF) { switch (ch) { case 'z': case 'Z': break; /* done by LQT_InitFromArgv(); */ case 'V': fprintf(stderr, "%s version %s\n", progname, Revision); break; case 'v': /* same as -t 1 */ AsciiTrace = 1; break; case 'x': ErrorFlag = (-1); break; case '?': ErrorFlag = 1; } } if (ErrorFlag) { if (AsciiTrace) { fprintf(stderr, "%s - rebuild lqtext database free files\n", progname ); } fprintf(stderr, "Usage: %s [options]\n", progname); fprintf(stderr, "%s: options are:\n", progname); LQT_PrintDefaultUsage(); exit( ErrorFlag > 0 ? 1 : 0); /* 0 means -x was used */ } if (optind < argc) { Error(E_FATAL|E_USAGE|E_XHINT, "[options]"); } RebuildFreeFile(); return 0; } RebuildFreeFile() { struct stat statbuf; long FreeSize; t_WID CurrentWID = 0; t_WID BiggestWID; if (stat(DataBase, &statbuf) < 0) { Error(E_FATAL|E_SYS, "Couldn't stat data file \"%s\"", DataBase); } FreeSize = statbuf.st_size / (BLOCKSIZE * 8); if (stat(WidIndexFile, &statbuf) < 0) { Error(E_FATAL|E_SYS, "Couldn't stat index file \"%s\"", WidIndexFile); } BiggestWID = (t_WID) (statbuf.st_size / WIDBLOCKSIZE); (void) unlink(FreeFileName); OpenFiles(); /* Note: WID 0 is unused */ for (CurrentWID = 1; CurrentWID < BiggestWID; CurrentWID++) { FollowChain(CurrentWID); } CloseFiles(); } static int WIDFile; /* static int FreeFile; static int DataFile; */ #define S(String) ((String) ? ( (*(String)) ? String : "[empty]") : "[null]") OpenFiles() { OpenFile(&WIDFile, "Word Index File", WidIndexFile, "reading", O_RDONLY); /* OpenFile(&DataFile, "Data File", DataBase, "reading", O_RDONLY); OpenFile(&FreeFile, "Free Bit Map File", FreeFileName, "create and write", O_CREAT|O_RDWR); */ } OpenFile(Pointer, Description, Name, ModeName, Mode) int *Pointer; char *Name; char *Description; char *ModeName; int Mode; { if (!Pointer || !Name || !*Name || !Description || !*Description || !ModeName || !*ModeName) { Error(E_BUG, "OpenFile: Name %x=%s, Desc %x=%s, Pointer %x, Mode %x=%s, 0%o", Name, S(Name), Description, S(Description), Pointer, ModeName, S(ModeName), Mode ); } if ((*Pointer = open(Name, Mode, 0666)) < 0) { Error(E_FATAL|E_SYS, "Couldn't open %s \"%s\" for %s", Description, Name, ModeName ); } } CloseFiles() { if (close(WIDFile) < 0) { Error(E_WARN|E_SYS, "system error closing %d=\"%s\"", WIDFile, WidIndexFile); } #if 0 if (close(DataFile) < 0) { Error(E_WARN|E_SYS, "system error closing %d=\"%s\"", DataFile, DataBase); } if (close(FreeFile) < 0) { /* this one matters... */ Error(E_FATAL|E_SYS, "system error closing %d=\"%s\"", FreeFile, FreeFileName); } #endif LQT_FlushBlockCache(0); } unsigned long GetChainStart(WID) t_WID WID; { char WIDBuffer[WIDBLOCKSIZE]; long NextOffset; char *q; int i; (void) LQU_Elseek(E_SYS|E_FATAL, WidIndexFile, "Wid index file", WIDFile, WID * WIDBLOCKSIZE, SEEK_SET ); if (LQU_Eread(E_SYS|E_FATAL, WidIndexFile, "Wid index file", WIDFile, WIDBuffer, WIDBLOCKSIZE ) != WIDBLOCKSIZE) { Error(E_SYS|E_FATAL, "Couldn't read %d bytes from %d=\"%s\"", WIDBLOCKSIZE, WIDFile, WidIndexFile ); } /* First the word length */ q = WIDBuffer; i = LQT_sReadNumber(&q); /* then the word */ if (AsciiTrace) { char buf[WIDBLOCKSIZE]; (void) strncpy(buf, q, i); buf[i] = '\0'; fprintf(stderr, "%5d %s", WID, buf); } q += i; /* Now the offset into the data file */ NextOffset = LQT_sReadNumber(&q) * BLOCKSIZE; return NextOffset; } static void FollowChain(WID) t_WID WID; { long Offset; t_BlockHeader *BH; Offset = GetChainStart(WID); if (AsciiTrace) { printf("%ld: ", WID); } while (Offset) { char *Block; int NumberOfBlocks; unsigned long tmp; if ((Block = LQT_ReadBlock(Offset)) == (char *) 0) { Error(E_SYS|E_FATAL, "FollowChain(WID %ld) couldn't read %d bytes from %s at %ld", WID, BLOCKSIZE, DataBase, Offset ); } BH = (t_BlockHeader *) Block; LQT_Trace(LQT_VERBOSE, " %ld len %d", Offset, BH->NumberOfBlocks); for (NumberOfBlocks = BH->NumberOfBlocks; NumberOfBlocks > 0; NumberOfBlocks--) { LQT_SetBlockStatus(Offset, SET_BLOCK_AS_USED); Offset += BLOCKSIZE; } Offset = BH->NextOffset; } }