              <<< VAXAXP::NOTES$:[NOTES$LIBRARY]VMSNOTES.NOTE;1 >>>
               -< VAX and Alpha VMS - Digital Internal Use Only >-
================================================================================
Note 223.11      VMS directory, how to repair or perhaps delete?        11 of 20
GIDDAY::GILLINGS "a crucible of informative mistak" 203 lines   1-FEB-1995 22:03
                             -< V2.0 - now tested >-
--------------------------------------------------------------------------------
  The program in .4 doesn't quite do the right thing. It seems that there
  *is* an entry in the directory which points to itself. Clearing the
  backlink therefore makes ANALYZE/DISK work, but on /REPAIR, ANALYZE
  notices that there is a directory entry which should point to the file
  and helpfully restores the backlink to point to the directory containing
  the entry - itself!. This puts us back at square 1. 

  re .5: The trouble with DUMP/IDENT is that it doesn't always work! Indeed,
  the example in .0 is only really circumstantial evidence that we have a
  looped directory. It fails to dump the header because there is no directory
  entry pointing to it. DUMP/FILE with the appropriate start block will always
  show the header, regardless of the existence of a directory entry. With the
  dump you can positively identify that the directory is looped.

  re DFU: As I've said before, DFU is a fine tool for internal use, but I
  cannot send it to customers, and I certainly can't drop it in an Internet
  message and have it received by the customer while I have them on the phone.
  A MACRO program might not be as elegant as DFU, but I can guarantee that
  it can be used by any customer (in worst case I could FAX it!)

  Now, here's V2.0. In this version, instead of just blanking out the backlink,
  it's set to (4,4,0) (the MFD). The program then creates a directory entry in
  [000000] for the directory, using its original name. This recovers the file
  without needing to run ANALYZE/DISK. Since the name and backlink match the
  [000000] entry, it is considered the primary entry. That means the bad entry
  within the directory can be safely SET FILE/REMOVEd.

  There are also some minor edits to make it work on Alpha. Code has now been
  tested on Alpha and VAX under OpenVMS V6.1. The only wrinkle on Alpha is
  finding the FID from the looping process. It's NOT in R11. It seems that it
  sometimes pops up in R0. Perhaps someone knows a surefire way to identify
  the FID?

        .TITLE BlastBacklink
;;;
;;;
;!!!WARNING!!!!WARNING!!!!!!!WARNING!!!!!WARNING!!!!!!!!WARNING!!!!!!!
;!!                                                                 !!
;!! ALL STATEMENTS WITH A COMMENT OF '****' MUST BE MODIFIED        !!
;!! BY THE USER TO POINT TO THE APPROPRIATE DISK AND FILE.          !!
;!!    There are 4 statements that need to be modified.             !!
;!!                                                                 !!
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;
; This program changes directory backlink in the header of a file (specified
; by file ID) to point to the MFD, [000000] and create an appropriate
; directory entry. The primary purpose is to correct directory files which
; have become entered into themselves, thereby causing ANALYZE/DISK into a
; COM loop for systems running OpenVMS V6.1 and lower.
;
; Problem reference: VMSNOTES 830.0
;
; Diagnostic is to check the looping ANALYZE/DISK process from SDA and
; examine R6 (VAX) or R0? (AXP) to determine the suspect file ID. From
; there dump the header of the file in INDEXF.SYS to verify that the
; backlink is the same as the file ID.
;
; This program can then be used to adjust the backlink and create a directory
; entry in [000000]. The directory will then contain an entry pointing to
; itself which should then be removed. The repaired directrory can then be
; RENAMEd back to where it belongs
;
; For example, suppose the original directory were DISK1:[PC_SERVICE.MYDIR]
; with file ID (132,5,0). To recover, edit this program to contain the
; correct device and file ID information, then:
;	$ MACRO FIX_BACKLINK
;	$ LINK FIX_BACKLINK 
; 	$ RUN FIX_BACKLINK
;	$ SET FILE/REMOVE DISK1:[MYDIR]MYDIR.DIR;
;	$ RENAME DISK1:[000000]MYDIR.DIR DISK1:[PC_SERVICE]
;
        .LIBRARY /SYS$SHARE:LIB/
        $FIBDEF
        $ATRDEF
;
	.psect $DATA,RD,WRT,NOEXE
; *** THE FOLLOWING 4 LINES MUST BE MODIFIED TO SPECIFY THE FILE TO FIX
dev:            .ASCID  /NOSUCHDEV:/	;**** disk name where file resides
FILE_FID=				;**** First number in FID
FILE_SEQ=				;**** Second number in FID
FILE_RVN=				;**** Third number in FID
iosb:           .QUAD                      ;IOSB for QIO
dev_chan:       .BLKW 1                    ;IO channel for output file
fib_block:      .BLKB FIB$K_LENGTH         ;FIB to open file
fib_descr:      .LONG FIB$K_LENGTH
                .LONG fib_block
newfib:		.BLKB FIB$K_LENGTH         ;FIB for new entry
newfib_descr:	.LONG FIB$K_LENGTH
                .LONG newfib
namdesc:	.LONG ATR$S_FILE_SPEC	   ;descriptor for filespec
		.ADDRESS oldnam_blk
oldatr_block:	.WORD ATR$S_FILE_SPEC	   ;ATR block to get filespec
		.WORD ATR$C_FILE_SPEC
		.ADDRESS oldnam_blk
                .LONG 0
oldnam_blk:	.BLKB ATR$S_FILE_SPEC	   ;buffer for filespec
atr_block:      .WORD ATR$S_BACKLINK       ;File attributes block
                .WORD ATR$C_BACKLINK       ; used to write the file id
                .ADDRESS atr_bklk_buf      ; of the directory file.
                .LONG 0
atr_bklk_buf:   .WORD 4			   ; file ID (4,4,0)
		.WORD 4
		.WORD 0

	.psect $code,exe,nowrt,rd

        .ENTRY BEGIN, ^M<>
;
; Store the file id for the corrupt file in the FIB.
;
        MOVW #FILE_FID, fib_block+FIB$W_FID_NUM
        MOVW #FILE_SEQ, fib_block+FIB$W_FID_SEQ
        MOVW #FILE_RVN, fib_block+FIB$W_FID_RVN
;
; Set the access control bits and name string control bits
; in the FIB.
;
        MOVL #FIB$M_WRITE!FIB$M_WRITETHRU,fib_block+FIB$L_ACCTL
        MOVL #FIB$M_FINDFID,fib_block+FIB$W_NMCTL
;
; Assign a channel to the disk containing the file to be deleted
;
        $ASSIGN_S devnam=dev, chan=dev_chan
        BLBS R0,1$
	BRW bye
;
; Open file via file-id
;
1$:     $QIOW_S chan=dev_chan,-
		func=#IO$_ACCESS!IO$M_ACCESS,-
                iosb=iosb,-
                p1=fib_descr,-
		p5=#oldatr_block
        BLBS R0,2$
	BRW bye
2$:     MOVZWL iosb,R0
        BLBS R0,3$
	BRW bye
3$:
;
; Set backlink to (4,4,0)
;
        $QIOW_S chan=dev_chan,-
                func=#IO$_MODIFY,-
                iosb=iosb,-
                p1=fib_descr,-
                p5=#atr_block
        BLBS R0,4$
	BRW bye
4$:     MOVZWL iosb,R0
        BLBS R0,5$
	BRW bye
5$:
; 
; Create entry for file in [000000]
;
	MOVC5 #0,#0,#0,#FIB$K_LENGTH,newfib	; clear FIB
        MOVW #FILE_FID, newfib+FIB$W_FID_NUM	; set FID
        MOVW #FILE_SEQ, newfib+FIB$W_FID_SEQ
        MOVW #FILE_RVN, newfib+FIB$W_FID_RVN
        MOVW #4,	newfib+FIB$W_DID_NUM	; set DID
        MOVW #4,	newfib+FIB$W_DID_SEQ
        MOVW #0,	newfib+FIB$W_DID_RVN
;
; oldnam_blk contains a (word) counted ASCII string containing the complete
; filespec, including device name. The following loop strips off all characters
; up to the first "]".

	MOVZWL oldnam_blk,namdesc		; build filename descriptor
	MOVAB  oldnam_blk+2,R0
10$:	DECL   namdesc				; strip directory spec
	CMPB   (R0)+,#^A/]/
	BNEQ   10$
	MOVL	R0,namdesc+4

        $QIOW_S chan=dev_chan,-
                func=#IO$_CREATE,-
                iosb=iosb,-
                p1=newfib_descr,-
		p2=#namdesc
        BLBS R0,6$
	BRW bye
6$:     MOVZWL iosb,R0
        BLBS R0,7$
	BRW bye
7$:
;
; Close file
;
        $QIOW_S chan=dev_chan,-
                func=#IO$_DEACCESS, -
                iosb=iosb, -
                p1=fib_descr
        BLBS R0,8$
	BRW bye
8$:     MOVZWL iosb,R0
        BLBS R0,9$
	BRW bye
9$:
        
bye:    $EXIT_S R0
        .END begin

