Read a Save File
February 3, 2010 Hey, Ted
I had an unusual experience recently and thought other readers of Four Hundred Guru might also find it of interest. A physical file had no active records and three deleted records. We were trouble-shooting a problem and needed to know what data was in the three deleted records. We have two third-party products that are supposed to retrieve deleted records, but they failed us. Here’s what we did. First, we saved the file to a save file that we keep on hand. SAVOBJ OBJ(IBLOCK) LIB($$DATA) DEV(*SAVF) OBJTYPE(*FILE) SAVF(MYLIB/MYSAVF) Next, we ran Display File Description to find the save file’s record length. DSPFD FILE(MYLIB/MYSAVF) DSPFD told us that the record length of our save file was 528 bytes, so we created a program-described file of the same record length. CRTPF FILE(QTEMP/MYFILEDELS) RCDLEN(528) We tried to copy the save file to the physical file, but that was no good. CPYF FROMFILE(MYLIB/MYSAVF) TOFILE(QTEMP/MYFILEDELS) FMTOPT(*NOCHK) So we wrote RPG program CPY528R and a CL driver, CPY528C, to duplicate the save file into the physical file. FInput IF F 528 Disk FOutput O F 528 Disk DRec DS 528 /Free Read Input Rec; DoW not %eof(Input); Write Output Rec; Read Input Rec; EndDo; *inLR = *On; Return; /End-Free PGM OVRDBF FILE(INPUT) TOFILE(MYLIB/MYSAVF) OVRDBF FILE(OUTPUT) TOFILE(QTEMP/MYFILEDELS) CALL PGM(CPY528R) DLTOVR FILE(INPUT) DLTOVR FILE(OUTPUT) ENDPGM Calling the CL program copied the save file into physical file MYFILEDELS, where we could use the Display Physical File Member command to view the data in the three deleted records. DSPPFM FILE(MYFILEDELS) It was not long until our mystery was solved. Later I got curious and decided to go a step farther. As I studied the data in the physical file, I came to realize that first 512 bytes of each record of the save file contained database data and other things, and that bytes 513 – 528 of each record were devoted to a sequence number and something else that was unrelated to my purposes. I also determined that each deleted database record’s data was preceded by a left brace. So I threw together the following RPG program (PRTMYFILER) and CL driver PRTMYFILEC. H DftActGrp(*No) ActGrp(*New) Option(*SrcStmt:*NoDebugIO) FInput IF F 528 Disk FQSysPrt O F 132 Printer D InputStruc DS 528 Qualified D Data 1 512A D MyFileRec E DS ExtName(MYFILE) Inz D Buffer S 1024A Varying D EOF S N D Offset S 10I 0 D Get PR D Buffer 1024A Varying D EOF N /Free DoU *inLR = *On; If %Len(Buffer) < %Len(MyFileRec) + 1; Get(Buffer: EOF); EndIf; Offset = %Scan ('{' : Buffer); If Offset > *zero; Buffer = %SubSt(Buffer:Offset); If %Len(Buffer) < %Len(MyFileRec) + 1; Get(Buffer: EOF); EndIf; Buffer = %SubSt(Buffer : 2); MyFileRec = %SubSt(Buffer : 1: %Len(MyFileRec)); Monitor; Except PrintLine; Buffer = %SubSt(Buffer : %Len(MyFileRec) + 1); On-Error; EndMon; Else; Clear Buffer; EndIf; If EOF; Leave; EndIf; EndDo; *inLR = *On; Return; /End-Free OQSysPrt e PrintLine 1 O mf_field1 O mf_field2 +0001 O mf_field3 +0001 O mf_field4 M +0001 O mf_field5 J +0001 P Get B D PI D Buffer 1024A Varying D EOF N /Free Read Input InputStruc; If %EOF(); EOF = *On; Else; Buffer += InputStruc.Data; EndIf; /End-Free P E PGM OVRDBF FILE(INPUT) TOFILE(MYLIB/MYSAVF) CALL PGM(PRTMYFILER) DLTOVR FILE(INPUT) ENDPGM The fields in the output specs are the database fields, which are defined in data structure MyFileRec. These are the fields in the saved database file, MYFILE. Calling the CL program produced a report of the three deleted records. I am not recommending the mining of save files as standard operating procedure, and we have taken measures to make sure that the third-party utilities won’t fail us the next time we need them. But in this instance, reading a save file helped us resolve a problem, and I offer our experience in case it may be of benefit to someone else someday. –Name withheld by request
|