*** *** CrashRec.Prg *** * * MG 07/10/94 * * * This program scans the dbfs in a passed directory (xDatadir). * Each file is diagnosed. If it can be 'USE'd exclusively it passes * the test. If it cannot be used because it is in used by someone else * it assumed to pass the test. * * If on the other hand it cannot be used, then it mus be recovered. * This is done by adjusting the number of records in the header to * the other parameters of the file (The file length in bytes, the * record length and the header length following the dbfs header). * * Recovery for a file can be prevented by pressing escape when * prompted. The number of missing records is displayed as well as * whether or not figures balance out. If they do not balance out, * it is adviseable, but not required, to investigate further before * allowing the recovery. * * DISCLAIMER * ---------- * * The program is used at the risk of the person who invokes it. * * LIMITATION * ---------- * * This program only solves one of the many corruptions that a database * can encounter. Specifically, dbfs that where being updated during * a server crash tend to respond favorably to this recovery program. * * In fact after running the program, you will * probably be able to USE the files again, but some of your data will * be lost. * * Explicitly, but not exhaustively left out of this program, are * corrupted memofiles. * parameter xDatadir private all like x* xP=0 xR=0 xR1=0 xL=0 xF=0 if parameters()=0 xDataDir="" endif define window CrashRec; from 5,5 to srows()-3,75; title "Crash recovery" activate window CrashRec =adir(xFiles,(xDatadir+"*.dbf")) ? " Please note that this program could inflict major damage to " ? " your data." ? " You use it at your own risk." xSetEsc= set("ESCAPE")="ON" set escape off wait "Press any key to proceed, or ESCAPE to terminate" if lastkey()=27 if xSetEsc set escape on endif clear window release window return endif if xSetEsc set escape on endif ? "There are " ?? alltrim(str(alen(xFiles,1))) ?? " dbfs to be checked" ? xErrStat= 0 xErrHandl= on("Error") xEl=0 for xEl=1 to alen(xFiles,1) if !xDiagnose() if !xRecover() exit endif endif wait "" timeout 2 endfor do xCleanup *** *** ----------------------------------- *** procedure xAdjust wait "adjusting" window nowait xB7= int(xR1/256^3) xRest= xR1-xB7*256^3 xB6= int(xRest/256^2) xRest= xRest-xB6*256^2 xB5= int(xRest/256) xB4= xRest-xB5*256 xChr7= chr(xB7) xChr6= chr(xB6) xChr5= chr(xB5) xChr4= chr(xB4) xH= fopen(xDatadir+xFiles(xEl,1),12) xDummy= fseek(xH,4) xDummy= fwrite(xH,xChr4) xDummy= fseek(xH,5) xDummy= fwrite(xH,xChr5) xDummy= fseek(xH,6) xDummy= fwrite(xH,xChr6) xDummy= fseek(xH,7) xDummy= fwrite(xH,xChr7) =fClose(xH) wait clear *** *** ----------------------------------- *** procedure xCleanup on error &xErrHandl release window CrashRec *** *** ----------------------------------- *** procedure xDiagnose ? "Checking "+xFiles(xEl,1) xErrStat=0 on error do xError use xdatadir+xFiles(xEl,1) exclu in 0 on error &xErrHandl do case case xErrStat=0 use ? "Passed" ? return case xErrStat=1 use ? "Must be recovered" return .f. case xErrStat= 2 ? "File is in use" ? "Assumed ok" ? case xErrStat= 3 ? "File is in use by current station " ? "Assumed ok" ? endcase *** *** ----------------------------------- *** procedure xError on error &xErrHandl xErr= error() do case case (xErr= 125) or (xErr=108) * * File in use ... assume it is ok * xErrStat=2 return case xErr= 15 * * "Not a DBF file ...‚ * xErrStat= 1 case xErr= 3 * * "File in use" * xErrStat= 3 otherwise ? "Terminal Error" do xCleanup &xErrHandl endcase *** *** ----------------------------------- *** procedure xRPL xH= fopen(xDatadir+xFiles(xEl,1),12) xR=0 xDummy= fseek(xH,4) xBuffer= fread(xH,1) xR= asc(xBuffer) xDummy= fseek(xH,5) xBuffer= fread(xH,1) xR= asc(xBuffer)*256+xR xDummy= fseek(xH,6) xBuffer= fread(xH,1) xR= asc(xBuffer)*256^2+xR xDummy= fseek(xH,7) xBuffer= fread(xH,1) xR= asc(xBuffer)*256^3+xR * xP=0 xDummy= fseek(xH,8) xBuffer= fread(xH,1) xP= asc(xBuffer) xDummy= fseek(xH,9) xBuffer= fread(xH,1) xP= asc(xBuffer)*256+xP * xL=0 xDummy= fseek(xH,10) xBuffer= fread(xH,1) xL= asc(xBuffer) xDummy= fseek(xH,11) xBuffer= fread(xH,1) xL= asc(xBuffer)*256+xL =fClose(xH) *** *** ----------------------------------- *** procedure xRecover ? "File length= " xF= xFiles(xEl,2) ?? xF xR=0 xP=0 xL=0 do xRPL ? "Number of records= " ?? alltrim(str(xR)) ? "Position of the first data record= " ?? alltrim(str(xP)) ? "Length of one record= " ?? alltrim(str(xL)) ? if xL=0 ? "File could not be recovered" wait window return endif xR1= (xF-1-xP) / xL if xR1<>int(xR1) ? xR1 ? "Figures do not balance out" else ? "Figures balance out" endif xR1= int(xR1) ?? " - Lost records= " ?? alltrim(str(xR-xR1)) wait "Press Escape if you do not want to recover this file" if lastkey()=27 ? "This database has not been recovered" return endif do xAdjust if xDiagnose() ? "Recovered" else ? "Could not recover this database" endif ?