.title scan2 scan ODS-2 for file headers .ident /v01/ ;+ ; Scan2 scans all of the blocks in an ODS-2 disk volume for potential ; file headers and writes candidates out to a sequential file. This ; is the first step in recovering a disk that should not have been ; initialized. ; ; Anthony E. Scandora, Jr. ; Science Applications International Corp. ; October 5, 1984 ;- .psect data,noexe,long ; ; Parameters unique to the disk being recovered ; These should be determined at run time, but I'm in a hurry ; dsksiz = 891072 ; size of an RA81 innam: .ascid /DUK1:/ ; name of volume to be scanned .align long ; ; Register usage: ; ; r10 number of blocks left to process in current buffer ; r9 current block in buffer ; r8 id area in current block ; r7 map area in current block ; r6 access control area in current block ; r0-5 scratched by movc3 and used for temps ; ; Definitions that do not have to be changed for every disk ; .library /fhdo2/ ; define file header offsets .mcall fhdo2$ fhdo2$ iniosb: .blkw 4 ; I/O status block for input channel outfab: $fab fac=put,fnm=,org=seq,rat=cr,rfm=var outrab: $rab fab=outfab,rbf=outrec,rsz=outsiz assin: $assign devnam=innam,chan=rdqio+qiow$_chan rdefn = 1 ; efn for reading input disk rdqio: $qiow rdefn,,io$_readlblk,iniosb,,,blocks msgdsc: .blkl ; actual size of message buffer .address msgbuf msgds0: .long 132 ; msgbuf size for $fao input .address msgbuf msgbuf: .blkb 132 ; output message buffer ; ; record for indexf.seq ; outrec: hdlbn: .blkl ; LBN of current header hdfnum: .blkl ; file number of current header hdfseq: .blkw ; sequence number of current header hdfseg: .blkw ; file segment number hdefnu: .blkl ; file number of extension header hdefsq: .blkw ; sequence number of extension header delete: .blkb ; blank or '-' if deleted direct: .blkb ; blank or 'D' if directory file hdbfnu: .blkl ; file number of back pointer hdbfsq: .blkw ; file sequence number of back pointer hdfnam: .blkb 20 ; file name hdcrdt: .blkw 4 ; file creation date hdefbk: .blkl ; logical end of file block hdhibk: .blkl ; high allocated block number outsiz = .-outrec ; indexf.seq record size rdmsg: .ascid /Read !UL bytes (!UL blocks) from block !UL/ .psect buffer,noexe,page bufsiz = 1000 ; do bufsiz blocks at a time blocks: .blkb bufsiz*512 ; buffer for those blocks .page .sbttl the main program .psect scan2,nowrt,nord .entry scan2,^m callg assin,g^sys$assign ; assign channel to input disk blbs r0,20$ pushl r0 ; complain if no good calls #1,g^lib$stop 20$: $create outfab ; create output file blbs r0,30$ pushl r0 ; complain if can't create output file calls #1,g^lib$stop 30$: $connect outrab ; connect rab to output file blbs r0,40$ pushl r0 ; complain if can't connect ;40$: movl #445746,rdqio+qiow$_p3 ; start at block zero 40$: clrl rdqio+qiow$_p3 ; start at block zero 100$: movl rdqio+qiow$_p3,r0 ; get number of next block to read addl3 #bufsiz,r0,r10 ; compute last block to read + 1 cmpl r10,#dsksiz ; off the end of the disk? blss 110$ movl #dsksiz,r10 ; if so, stop at the end 110$: subl r0,r10 ; compute number of blocks to read bgtr 115$ brw 900$ ; done if none left 115$: mull3 #512,r10,rdqio+qiow$_p2 ; compute transfer size callg rdqio,g^sys$qiow ; read the blocks blbc r0,117$ ; complain if system error movzwl iniosb,r0 ; check I/O status blbs r0,120$ ; complain if read error 117$: pushl r0 calls #1,g^lib$stop 120$: pushl rdqio+qiow$_p3 ; push first block just read pushl r10 ; push number of blocks just read pushl iniosb+2 ; push actual number of bytes read pushaq msgds0 ; push full size message buffer pushaw msgdsc ; push pointer to actual size pushaq rdmsg ; push format string calls #6,g^sys$fao ; format what was just read blbs r0,130$ pushl r0 ; complain if $fao failed calls #1,g^lib$stop 130$: pushaq msgdsc ; push actual message descriptor calls #1,g^lib$put_output ; tell operator what was just read movab blocks,r9 ; pointer to current block 200$: decl r10 ; any blocks left in this buffer? bgeq 210$ brw 100$ ; get next buffer if done 210$: jsb check ; check the block addl #512,r9 ; point to next block in buffer incl rdqio+qiow$_p3 ; bump current block number brw 200$ ; and get next block 900$: $close outfab ; done, close output file movl #1,r0 ; exit ret .page .sbttl check a block to see if it is a header .psect check,nowrt,nord ; so debug will be same as listing check: cmpw 6(r9),#^x0201 ; is it structure 2 level 1? beqlu 310$ ; if so, take it rsb ; if not, forget it 310$: movzbl (r9),r8 ; word offset to ID area cmpb r8,#hdr2$l_fown/2 ; is header area big enough? blssu 390$ ; if not, forget it movzbl 1(r9),r7 ; word offset to map area subl3 r8,r7,r0 ; word length of ID area cmpw r0,#id2$q_exdt/2 ; is ID area big enough? blssu 390$ ; if not, forget it movzbl 2(r9),r6 ; word offset to access control area subl3 r7,r6,r0 ; word length of map area movzbl hdr2$b_use(r9),r1 ; actual number of map words in use cmpb r0,r1 ; is map area big enough? blssu 390$ ; if not, forget it bisw3 hdr2$w_fnum(r9),hdr2$w_frvn(r9),r0 ; file number & relative volume zero? bisw2 510(r9),r0 ; and checksum zero? beqlu 350$ ; if so, it's a deleted header ; ; got a possible file header ; movaw (r9),r6 ; compute checksum of header movzbl #255,r1 ; add up first 255 words clrl r0 320$: addw2 (r6)+,r0 ; add in next word sobgtr r1,320$ cmpw (r6),r0 ; is checksum right? bneq 390$ ; if not, forget it movw hdr2$w_fnum(r9),hdfnum ; good header, get file number low word movzbw hdr2$w_frvn+1(r9),hdfnum+2 ; get file number high byte movb #^a/ /,delete ; mark the file not deleted brb 400$ ; continue processing the header ; ; got a possible deleted file header ; 350$: bitb #hdr2$m_scha_mdl,hdr2$b_scha(r9) ; is file marked for delete? beqlu 390$ ; if not, forget it subl3 hdlbn,rdqio+qiow$_p3,r0 ; number of LBNs after previous header addl2 r0,hdfnum ; compute deleted file number movb #^a/-/,delete ; mark the file deleted brb 400$ ; continue processing the header ; ; block is not a header, return ; 390$: rsb .page .sbttl write out a header 400$: movl rdqio+qiow$_p3,hdlbn ; save header's LBN movw hdr2$w_fseq(r9),hdfseq ; file sequence number movw hdr2$w_fseg(r9),hdfseg ; file segment number movw hdr2$w_efnu(r9),hdefnu ; extension file number movzbw hdr2$w_ervn+1(r9),hdefnu+2 ; rest of extension file number movw hdr2$w_efsq(r9),hdefsq ; extension sequence number movb #^a/ /,direct ; assume it's not a directory bitb #hdr2$m_scha_dir,hdr2$b_scha(r9) ; is it a directory file? beqlu 420$ movb #^a/D/,direct ; if so, mark it 420$: movw hdr2$w_bfnu(r9),hdbfnu ; back link file number movzbw hdr2$w_brvn+1(r9),hdbfnu+2 ; rest of back link file number movw hdr2$w_bfsq(r9),hdbfsq ; back link sequence number movaw (r9)[r8],r8 ; point to ID field movc3 #20,(r8),hdfnam ; copy filename movq id2$q_crdt(r8),hdcrdt ; copy creation date and time movw hdr2$_ufat+6(r9),hdhibk ; copy low word of high block movw hdr2$_ufat+4(r9),hdhibk+2 ; copy high word of high block movw hdr2$_ufat+10(r9),hdefbk ; copy low word of eof block movw hdr2$_ufat+8(r9),hdefbk+2 ; copy high word of eof block $put outrab ; write record blbs r0,450$ pushl r0 ; complain if write error calls #1,g^lib$stop ; ; tell the operator about it ; 450$: pushab (r8) ; build filename string descriptor pushl #20 movaq (sp),r0 pushaq (r0) ; filename string calls #1,g^lib$put_output ; print filename string for operator addl #8,sp ; pop descriptor off stack rsb .end scan2