.TITLE FINDFILE Find a File Given a Disk Address .IDENT /2.0/ ;++ ; ; Title: ; FINDFILE.MAR - Find a file given a disk address. ; ; Version: ; 1-001 ; ; Facility: ; System management tool. ; ; Abstract: ; This program returns the name of a file given a disk address ; (lbn or cylinder/track/sector address) and a device name. This ; tools is quite useful when you know where a bad spot is on a ; disk, but you don't know who occupies it. ; ; Environment: ; Native mode, need access to file header index file. ; ; Author: ; Mark Oakley Battelle Columbus Laboratories 28-Mar-1984 ; ; Modifications: ; ; 09-Jan-1986 Mark Oakley Modified to work properly with V4, replace ; FAB's with FIB's as workaround to RMS bug, ; supply more file info on output. ; ; 11-Jan-1986 Mark Oakley Fixed to compute file spec length. ; ;-- .SBTTL Definitions and Macros .LIBRARY /SYS$LIBRARY:LIB.MLB/ $DVIDEF ; Device information symbols. $FABDEF ; RMS FAB symbols. $FIBDEF ; File information block definitions. $FI2DEF ; File header id symbols. $FH2DEF ; File header symbols. $SECDEF ; Section (mapping) symbols. $SSDEF ; Status definitions. $TPADEF ; LIB$TPARSE symbols. FH2$L_ALLOC = ^X18 ; Offset to blocks allocated. FH2$L_USED = ^X1C ; Offset to blocks used. ; ; Macro to help set up fibs for each volume in a volume set. ; .MACRO MFIB ?DESC,?FIB DESC: .LONG FIB$K_LENGTH .ADDRESS FIB FIB: . = . + FIB$W_FID .WORD 1 ; INDEXF.SYS always has .WORD 1 ; (1,1,n) file id. . = FIB + FIB$K_LENGTH .ENDM MFIB ; ; Macro to handle return codes. ; .MACRO ON_ERR THERE,?HERE BLBS R0,HERE BRW THERE HERE: .ENDM ON_ERR ; ; Macro to create table for a SPANC instruction. We ; will need this table to skip over an ascii number ; field. ; .MACRO NUMBER_TABLE .BYTE 0[48] .BYTE 1[10] ; "0" to "9" are Ascii 48 to 57. .BYTE 0[198] .ENDM NUMBER_TABLE .SBTTL Command Line Data Structures .PSECT FINDFILE_DATA,RD,WRT,NOEXE,PAGE,PIC,SHR COMM_LINE_BUF: ; Store command line here. .BLKB 80 COMM_LINE_BUF_SIZ = . - COMM_LINE_BUF COMM_LINE_DESC: .LONG COMM_LINE_BUF_SIZ .ADDRESS COMM_LINE_BUF COMM_LINE_LEN: .BLKL 1 PARSE_BLK: ; Parse block for LIB$TPARSE. .LONG TPA$K_COUNT0 .LONG TPA$M_ABBREV ; Permit abbreviations. . = PARSE_BLK + TPA$K_LENGTH0 QUAL_MASK: ; Used to determine if logical or .LONG 0 ; physical address specified. LBN: ; Desired lbn. .BLKL 1 SECTOR: ; Desired sector. .BLKL 1 TRACK: ; Desired track. .BLKL 1 CYLINDER: ; Desired cylinder. .BLKL 1 .SBTTL Device Information DEVICE_ITM_LIST: ; Item list to return: .WORD 4 ; 1) Sectors per track. .WORD DVI$_SECTORS ; 2) Tracks per cylinder. .ADDRESS SEC_PER_TRK ; 3) Cylinders on volume. .ADDRESS 0 ; 4) Maximum files that .WORD 4 ; can be on volume. .WORD DVI$_TRACKS ; 5) Physical device name. .ADDRESS TRK_PER_CYL ; 6) Maximum number of .ADDRESS 0 ; blocks on volume. .WORD 4 ; 7) Root device name. .WORD DVI$_CYLINDERS ; 8) Number of volumes in set. .ADDRESS CYL_PER_VOL ; 9) Number of this volume. .ADDRESS 0 .WORD 4 .WORD DVI$_CLUSTER .ADDRESS CLUSTER_FACTOR .ADDRESS 0 .WORD 4 .WORD DVI$_MAXFILES .ADDRESS MAX_FILES .ADDRESS 0 .WORD DEVICE_BUF_SIZ .WORD DVI$_DEVNAM .ADDRESS DEVICE_BUF .ADDRESS DEVICE_BUF_LEN .WORD 4 .WORD DVI$_MAXBLOCK .ADDRESS MAX_LBN .ADDRESS 0 .WORD NEXT_BUF_SIZ .WORD DVI$_ROOTDEVNAM .ADDRESS NEXT_BUF .ADDRESS NEXT_LEN .WORD 4 .WORD DVI$_VOLCOUNT .ADDRESS VOLCOUNT .ADDRESS 0 .WORD 4 .WORD DVI$_VOLNUMBER .ADDRESS VOLNUMBER .ADDRESS 0 .LONG 0 ; End of list. DEFAULT_DEVICE: .ASCID /SYS$DISK/ DEVICE_BUF: ; Physical device name. .BLKB 40 DEVICE_BUF_SIZ = . - DEVICE_BUF DEVICE_DESC: .LONG DEVICE_BUF_SIZ .ADDRESS DEVICE_BUF DEVICE_BUF_LEN: ; Length of physical device .BLKL 1 ; name. SEC_PER_TRK: ; Sectors per track. .BLKL 1 TRK_PER_CYL: ; Tracks per cylinder. .BLKL 1 CYL_PER_VOL: ; Cylinders on volume .BLKL 1 MAX_FILES: ; Maximum number of files that .BLKL 1 ; can be stored on device. CLUSTER_FACTOR: ; Allocation unit for device. .BLKL 1 HEADER_OFFSET: ; Pointer to start of headers .BLKL 10 ; INDEXF.SYS. MAX_LBN: ; Maxmium number of blocks on .BLKL 1 ; volume. VOLCOUNT: ; Number of volumes in set. .BLKL 1 VOLNUMBER: ; Number of current volume .BLKL 1 ; in set. DVI_IOSB: ; Return status. .BLKQ 1 .SBTTL Mapping Data Structures .ALIGN 4 ; Long word align for fib. IDX_FIB: . = . + FIB$W_FID .WORD 1 ; INDEXF.SYS always has .WORD 1 ; (1,1,n) file id. . = IDX_FIB + FIB$K_LENGTH IDX_FIB_DESC: ; For an index header file .LONG FIB$K_LENGTH ; we will map. .ADDRESS IDX_FIB CHANNEL: ; Need channels for mapping, .BLKW 10 ; and tracing backlinks. QIO_IOSB: ; Return status. .BLKQ 1 INPUT_ADDR: ; Let system service allocate .LONG ^X20000 ; memory as needed. .LONG ^X20000 RETURN_ADDR: ; Need to know exactly where .BLKQ 1 ; memory was allocated. MAPPED_PAGES: ; Maximum number of pages to .LONG 4000 ; map at once. PF_CLUSTER: ; Number of pages to bring into .LONG 128 ; physical memory at once. SECT_FLAG = ; Section is copy-on-reference ; and expand memory allocation ; as needed. .SBTTL Table of Fib's for Volume Set .PSECT FIB_TABLE,,RD,WRT,NOEXE,PAGE,SHR,PIC ; ; Allow up to 10 volumes in a volume set. ; INDEXF_FIB_1: MFIB INDEXF_FIB_2: MFIB INDEXF_FIB_3: MFIB INDEXF_FIB_4: MFIB INDEXF_FIB_5: MFIB INDEXF_FIB_6: MFIB INDEXF_FIB_7: MFIB INDEXF_FIB_8: MFIB INDEXF_FIB_9: MFIB INDEXF_FIB_10: MFIB FIB_INDEX_TABLE: .ADDRESS INDEXF_FIB_1 .ADDRESS INDEXF_FIB_2 .ADDRESS INDEXF_FIB_3 .ADDRESS INDEXF_FIB_4 .ADDRESS INDEXF_FIB_5 .ADDRESS INDEXF_FIB_6 .ADDRESS INDEXF_FIB_7 .ADDRESS INDEXF_FIB_8 .ADDRESS INDEXF_FIB_9 .ADDRESS INDEXF_FIB_10 .SBTTL Data Structures for Tracing Backlinks NEXT_DVI_ITMLST: ; Item list to find: .WORD NEXT_BUF_SIZ ; 1) Next volume in set. .WORD DVI$_NEXTDEVNAM ; 2) Cluster factor of .ADDRESS NEXT_BUF ; current volume. .ADDRESS NEXT_LEN ; 3) Maximum number of .WORD 4 ; files that can be .WORD DVI$_CLUSTER ; stored on current .ADDRESS CLUSTER_FACTOR ; volume. .ADDRESS 0 .WORD 4 .WORD DVI$_MAXFILES .ADDRESS MAX_FILES .ADDRESS 0 .LONG 0 NEXT_DESC: ; Then "NEXT" data structures .LONG NEXT_BUF_SIZ ; are used to obtain cluster .ADDRESS NEXT_BUF ; factors and maximum file ; information about each NEXT_BUF: ; volume in the set. .BLKB 30 NEXT_BUF_SIZ = . - NEXT_BUF NEXT_LEN: .BLKL 1 .SBTTL Data Structures for Printing Results DIR_DESC: ; Descriptor for directory .LONG DIR_BUF_SIZ ; spec. .ADDRESS DIR_BUF DIR_BUF: ; Directory spec will be .BLKB 255 ; stored here. DIR_BUF_SIZ = . - DIR_BUF DIR_BUF_LEN: ; Length of directory spec. .BLKL 1 FILE_NAME_DESC: .LONG FILE_NAME_BUF_SIZ .ADDRESS FILE_NAME_BUF FILE_NAME_BUF: ; Store file name here. .BLKB FILE_NAME_BUF_SIZ = . - FILE_NAME_BUF FILE_NAME_LEN: .BLKL 1 NUM_TBL: ; Used to find the end of the NUMBER_TABLE ; version number field. DIR_NAME_DESC: .LONG DIR_NAME_BUF_SIZ .ADDRESS DIR_NAME_BUF DIR_NAME_BUF: ; Store a directory name here. .BLKB DIR_NAME_BUF_SIZ = . - DIR_NAME_BUF DIR_NAME_LEN: .BLKL 1 FILE_ID: ; File id, seq are here. FILE_ID_NUM: .BLKW 1 FILE_ID_SEQ: .BLKW 1 FILE_UIC: ; Owner of file. FILE_MEM_UIC: .BLKW 1 FILE_GRP_UIC: .BLKW 1 NAME_DESC: ; Ascii id owner of file. .LONG NAME_BUF_SIZ .ADDRESS NAME_BUF NAME_BUF: .BLKB 20 NAME_BUF_SIZ = . - NAME_BUF BLKS_ALLOC: ; Blocks allocated to file. .BLKL 1 BLKS_USED: ; Blocks used by file. .BLKL 1 CTRL_STG: ; Control string for $FAO. .ASCID #!/!_Disk file is !AS!AS # CTRL_STG2: .ASCID #!_File owner is [!6OW,!6OW] !AS# CTRL_STG3: .ASCID #!_File id is (!ZW,!ZW,!ZW)# CTRL_STG4: .ASCID #!_Blocks allocated/used: !ZL/!ZL !/# OUTPUT_DESC: .LONG OUTPUT_BUF_SIZ .ADDRESS OUTPUT_BUF OUTPUT_BUF: ; Output line will be .BLKB 80 ; stored here. OUTPUT_BUF_SIZ = . - OUTPUT_BUF OUTPUT_LEN: .BLKL 1 .SBTTL Header Buffers and File ID's. .PSECT BL_HDR_BUF,RD,WRT,NOEXE,PAGE,PIC,SHR FILE_HDR_BUF: ; File header buffer. .BLKB 512 EXT_HDR_BUF: ; Buffer for any file extension .BLKB 512 ; headers. DIR_HDR_BUF: ; Buffer for directory file .BLKB 512 ; headers. EXT_SEG_NUM: ; Extension number for this .BLKW 1 ; segment. FILE_EXT_NUM: ; File extension number. .BLKW 1 FILE_EXT_SEQ: ; File extension sequence .BLKW 1 ; number. FILE_EXT_RVN: ; File extension relative .BLKW 1 ; volume number. FILE_NUM: ; File ID for disk address we .BLKW 1 ; are looking for. FILE_SEQ: ; File sequence number for disk .BLKW 1 ; address we are looking for. FILE_RVN: ; File relative volume number .BLKW 1 ; for disk address we are ; looking for. .SBTTL Parse Intructions .PSECT FINDFILES_PARSE,RD,NOWRT,EXE,PAGE,PIC,SHR $INIT_STATE FILES_STATE,FILES_KEY $STATE START $TRAN TPA$_EOS,TPA$_EXIT ; End of string indicates success. $TRAN '/' ; Start of qualifier. $TRAN TPA$_SYMBOL,TPA$_EXIT,- ; Get device name (if there is one). ,,DEVICE_DESC $STATE $TRAN 'LBN',GET_LBN,,<<^B01>>,QUAL_MASK $TRAN 'CYLINDER',GET_CYL,,<<^B10>>,QUAL_MASK $TRAN 'TRACK',GET_TRK,,<<^B10>>,QUAL_MASK $TRAN 'TRK',GET_TRK,,<<^B10>>,QUAL_MASK $TRAN 'SECTOR',GET_SEC,,<<^B10>>,QUAL_MASK $STATE GET_LBN ; Get the LBN to look for. $TRAN '=' $STATE $TRAN TPA$_DECIMAL,START,- ,,LBN $STATE GET_CYL ; Get the cylinder to look for. $TRAN '=' $STATE $TRAN TPA$_DECIMAL,START,- ,,CYLINDER $STATE GET_TRK ; Get the track to look for. $TRAN '=' $STATE $TRAN TPA$_DECIMAL,START,- ,,TRACK $STATE GET_SEC ; Get the sector to look for. $TRAN '=' $STATE $TRAN TPA$_DECIMAL,START,- ,,SECTOR $END_STATE .SBTTL Main Program .PSECT FINDFILES_CODE,RD,NOWRT,EXE,PAGE,SHR,PIC .ENTRY FINDFILES,^M ; ; This main routine invokes routines to get the desired lbn to search ; for, and access the files headers to search for it. ; JSB PARSE_COMM_LINE ; Find what to look for. ON_ERR MAIN_EXIT JSB GET_DEV_INFO ; Get device-specific information. ON_ERR MAIN_EXIT JSB CHECK_QUALS ; Verify disk address is in range. ON_ERR MAIN_EXIT JSB SEARCH_HDRS ; Search file headers for desired lbn. ON_ERR MAIN_EXIT JSB GET_OFFSETS ; Setup for search of backlink ON_ERR MAIN_EXIT ; pointers. JSB FOLLOW_BACKLINKS ; Follow backlink pointers to get ON_ERR MAIN_EXIT ; complete file-spec. JSB OUTPUT_RESULTS ; Report file-spec. ON_ERR MAIN_EXIT MAIN_EXIT: RET .SBTTL Parse Command Line ;++ ; ; Functional Description: ; This routine inputs the command line, and parses it for ; a disk address and device name. ; ; Calling Sequence: ; JSB PARSE_COMM_LINE ; ; Formal Parameters: ; None. ; ; Implicit Inputs: ; Command line buffer, ; Parse block for LIB$TPARSE, ; Parse tables, ; Default device name, ; Device name buffer. ; ; Implicit Outputs: ; Device name buffer. ; ; Completion Status: ; Returned in R0. ; ; Side Effects: ; None. ; ;-- PARSE_COMM_LINE: MOVQ DEFAULT_DEVICE,- ; Assume the default device DEVICE_DESC ; until we find otherwise. PUSHL #0 ; Read the command line. PUSHAL COMM_LINE_LEN PUSHL #0 PUSHAL COMM_LINE_DESC CALLS #4,G^LIB$GET_FOREIGN ON_ERR PARSE_COMM_LINE_EXIT MOVL COMM_LINE_LEN,- ; Setup for LIB$TPARSE. PARSE_BLK+TPA$L_STRINGCNT MOVAL COMM_LINE_BUF,- PARSE_BLK+TPA$L_STRINGPTR PUSHAL FILES_KEY PUSHAL FILES_STATE PUSHAL PARSE_BLK CALLS #3,G^LIB$TPARSE ; Parse the command line. ON_ERR PARSE_COMM_LINE_EXIT PARSE_COMM_LINE_EXIT: RSB .SBTTL Get Device Information ;++ ; ; Functional Description: ; This routine invokes $GETDVI to get information on device ; geometry (cylinders, tracks, etc.) and computes the start ; of the file headers in INDEXF.SYS. ; ; Calling Sequence: ; JSB GET_DEV_INFO ; ; Formal Parameters: ; None. ; ; Implicit Inputs: ; Device name, ; Item list for getting disk geometry. ; ; Implicit Outputs: ; Device geometry (cylinders, tracks, etc.), ; Offset to start of file headers in INDEXF.SYS, ; Channel to INDEXF.SYS. ; ; Completion Status: ; Status returned in R0. ; ; Side Effects: ; None. ; ;-- GET_DEV_INFO: $GETDVI_S - ; Get info on disk geometry, DEVNAM=DEVICE_DESC,- ; max files, cluster factor, ITMLST=DEVICE_ITM_LIST,- ; etc. IOSB=DVI_IOSB ON_ERR GET_DEV_INFO_EXIT MOVZWL DVI_IOSB,R0 ON_ERR GET_DEV_INFO_EXIT MOVW DEVICE_BUF_LEN,- ; Must restore what we or DEVICE_DESC ; LIB$TPARSE did to this MOVAL DEVICE_BUF,- ; to this descriptor. DEVICE_DESC+4 ; ; Compute the offset to the first file header as: ; (MAX FILES / 4096) + 1 + (4 * CLUSTER FACTOR) ; DIVL3 #4096,MAX_FILES,R1 INCL R1 ; R1 = Bitmap size. MULL3 #4,CLUSTER_FACTOR,R2 ADDL3 R1,R2,HEADER_OFFSET ; ; Get a channel to the index header file stored on the device. ; $ASSIGN_S - DEVNAM=DEVICE_DESC,- CHAN=CHANNEL ON_ERR GET_DEV_INFO_EXIT $QIOW_S FUNC=#,- ; Channel will be to CHAN=CHANNEL,- ; INDEXF.SYS file. IOSB=QIO_IOSB,- P1=IDX_FIB_DESC ON_ERR GET_DEV_INFO_EXIT MOVZWL QIO_IOSB,R0 ON_ERR GET_DEV_INFO_EXIT GET_DEV_INFO_EXIT: RSB .SBTTL Check Qualifiers ;++ ; ; Functional Description: ; This routine validates the disk address specified on the ; command line to be sure it is in range. ; ; Calling Sequence: ; JSB CHECK_QUALS ; ; Formal Parameters: ; None. ; ; Implicit Inputs: ; Qualifier mask to determine if logical or physical address specified, ; Disk address, either LBN or cylinder, track, and sector, ; Maximum device values for blocks, cylinders, tracks, and sectors. ; ; Implicit Outputs: ; LBN. ; ; Completion Status: ; Errors are signaled, ; Status returned in R0. ; ; Side Effects: ; None. ; ;-- CHECK_QUALS: CASEB QUAL_MASK,#0,#3 ; Determine what qualifiers were 1$: .WORD NO_QUAL-1$ ; specified. .WORD LOG_QUAL-1$ .WORD PHYS_QUAL-1$ .WORD BOTH_QUAL-1$ NO_QUAL: ; No qualifier specified, signal PUSHAL FFS_NO_QUA ; error. CALLS #1,G^LIB$SIGNAL LOG_QUAL: ; Logical disk address specified. CMPL MAX_LBN,LBN ; Is it in range? BGEQ 10$ PUSHAL FFS_LBNTOOBIG ; No, signal error. CALLS #1,G^LIB$SIGNAL 10$: MOVL #SS$_NORMAL,R0 ; Yes, indicate success. BRW CHECK_QUALS_EXIT PHYS_QUAL: ; Physical address specified. CMPL CYL_PER_VOL,CYLINDER ; Is cylinder in range? BGEQ 20$ PUSHAL FFS_CYLTOOBIG ; No, signal error. CALLS #1,G^LIB$SIGNAL 20$: CMPL TRK_PER_CYL,TRACK ; Is track in range? BGEQ 30$ PUSHAL FFS_TRKTOOBIG ; No, signal error. CALLS #1,G^LIB$SIGNAL 30$: CMPL SEC_PER_TRK,SECTOR ; Is sector in range? BGEQ 40$ PUSHAL FFS_SECTOOBIG ; No, signal error. CALLS #1,G^LIB$SIGNAL 40$: MULL3 TRK_PER_CYL,- ; Compute logical address from CYLINDER,R2 ; physical address as: ADDL2 TRACK,R2 ; LBN = SECTOR + (SEC/TRK) * MULL2 SEC_PER_TRK,R2 ; (TRACK + CYLINDER * (TRK/CYL)) ADDL3 SECTOR,R2,LBN ; MOVL #SS$_NORMAL,R0 ; BRW CHECK_QUALS_EXIT BOTH_QUAL: ; Both logical and physical addresses PUSHAL FFS_TOOMANYQUA ; specified, signal error. CALLS #1,G^LIB$SIGNAL CHECK_QUALS_EXIT: RSB .SBTTL Search File Headers ;++ ; ; Functional Description: ; This routine controls the search for a file given a disk address. ; A linear search is performed, one retrieval pointer at a time, ; one file header at a time. The file headers are mapped into memory. ; ; Calling Sequence: ; JSB SEARCH_HDRS ; ; Formal Parameters: ; None. ; ; Implicit Inputs: ; Desired LBN, ; Channel to file header file, ; Information to control mapping of file headers. ; ; Implicit Outputs: ; File id of file with desired LBN. ; ; Completion Status: ; Status return in R0. ; ; Side Effects: ; Memory is allocated and deallocated in P0 space, ; INDEXF.SYS is accessed. ; ; Register Useage: ; R0 - Scratch and return status ; R1 - Disk address to start mapping ; R6 - Desired LBN ; R7 - File header pointer into header buffer ; R9 - Pointer to a retrieval poiner in header buffer ; R10 - File id number ; R11 - Maximum file id in memory ;-- SEARCH_HDRS: CLRL R11 ; Init maximum file id in memory. MOVL LBN,R6 ; Remember desired lbn. CLRL R10 ; Init file id. SEARCH_LOOP: INCL R10 ; Next header. CMPL R11,R10 ; Is it in memory? BGEQ IN_MEMORY ; Yes. JSB MAP_IDX ; No, map file into memory. ON_ERR SEARCH_HDRS_EXIT IN_MEMORY: ADDL2 #512,R7 ; Get to next header in buffer. ; ; Do we have a valid header? ; TSTW FH2$W_FID(R7) ; If file number is zero, then BNEQ 10$ ; header is not valid. BRW SEARCH_LOOP 10$: TSTW FH2$W_CHECKSUM(R7) ; If checksum is zero, then BNEQ 20$ ; header is not valid. BRW SEARCH_LOOP 20$: CMPW FH2$W_FID_NUM(R7),R10 ; If file id field does not equal BEQL 30$ ; file id, then header is not valid. BRW SEARCH_LOOP 30$: MOVZBL FH2$B_MPOFFSET(R7),R1 ; Remember map offset. Offset is in ASHL #1,R1,R1 ; words => must convert to bytes. ADDL3 R1,R7,R9 ; R9 points to first retrieval pointer. MOVZBL FH2$B_MAP_INUSE(R7),R8 ; Compute address for end of retrieval ASHL #1,R8,R8 ; pointers, and save address in R8. ADDL2 R9,R8 RETRIEVAL_LOOP: CMPL R8,R9 ; End of retrieval pointers? BGTR GET_ESCAPE_CODE BRW END_OF_RET_PTRS ; Yes GET_ESCAPE_CODE: ; No, see what kind of retrieval EXTZV #14,#2,(R9),R1 ; pointer we have. CASEB R1,#0,#3 1$: .WORD 000$-1$ .WORD 100$-1$ .WORD 200$-1$ .WORD 300$-1$ ; ; Format for placement control data is the following: ; ; ---------------- ; |00 | ; ---------------- ; 000$: ; Placement control data, ignor it ADDL2 #2,R9 ; and move onto the next retrieval BRW RETRIEVAL_LOOP ; pointer. ; ; Format for this retrieval pointer is the following: ; ; ---------------- ; |01 Hi LBN Count| ; ---------------- ; | Low LBN | ; ---------------- ; 100$: MOVZWL 2(R9),R2 ; Move start lbn into R3. EXTZV #8,#6,(R9),R0 INSV R0,#16,#6,R2 CMPL R2,R6 ; Could the desired lbn be in here? BGTR 190$ ; No way! BEQL 130$ ; Bingo! MOVZBL (R9),R3 ; Maybe, get count field. ADDL2 R3,R2 ; Compute end lbn. CMPL R6,R2 ; Could the desired lbn be in here? BGTR 190$ ; No. 130$: BRW LBN_FOUND ; Yes. 190$: ADDL2 #4,R9 ; Move on to the next retrieval BRW RETRIEVAL_LOOP ; pointer. ; ; Format for this retrieval pointer is the following: ; ; ---------------- ; |10 Count | ; ---------------- ; | Low LBN | ; ---------------- ; | Hi LBN | ; ---------------- ; 200$: MOVL 2(R9),R2 ; Move start lbn to R2. CMPL R2,R6 ; Could the desired lbn be in here? BGTR 290$ ; No way! BEQL 230$ ; Bingo! EXTZV #0,#14,(R9),R3 ; Maybe, get count field. ADDL2 R3,R2 ; Compute end lbn. CMPL R6,R2 ; Could the desired lbn be in here? BGTR 290$ ; No. 230$: BRW LBN_FOUND ; Yes. 290$: ADDL2 #6,R9 ; Move onto the next retrieval BRW RETRIEVAL_LOOP ; pointer. ; ; Format for this retrieval pointer is the following: ; ; ---------------- ; |11 Hi Count | ; ---------------- ; | Low Count | ; ---------------- ; | Low LBN | ; ---------------- ; | Hi LBN | ; ---------------- ; 300$: MOVL 4(R9),R2 ; Move start lbn to R2. CMPL R2,R6 ; Could the desired lbn be in here? BGTR 390$ ; No way! BEQL 330$ ; Bingo! MOVL (R9),R3 ; Maybe, get count field. BICL2 #^XC000,R3 ; Top 2 bits are escape code. ROTL #16,R3,R3 ; Swap low and hi words. ADDL2 R3,R2 ; Compute end lbn. CMPL R6,R2 ; Could the desired lbn be in here? BGTR 390$ ; No. 330$: BRW LBN_FOUND ; Yes. 390$: ADDL2 #8,R9 ; Move onto the next retrieval BRW RETRIEVAL_LOOP ; pointer. END_OF_RET_PTRS: BRW SEARCH_LOOP LBN_FOUND: MOVW FH2$W_SEG_NUM(R7),- ; See if we have an extension header, EXT_SEG_NUM ; or the file header. BEQL 20$ MOVC3 #512,(R7),EXT_HDR_BUF ; Got extension. BRB 40$ 20$: MOVC3 #512,(R7),FILE_HDR_BUF ; Got file header. 40$: $DELTVA_S - ; Get rid of memory we no longer need. INADR=RETURN_ADDR ON_ERR SEARCH_HDRS_EXIT SEARCH_HDRS_EXIT: RSB .SBTTL Map File Headers ;++ ; ; Functional Description: ; This routine maps all or a portion of the INDEXF.SYS ; file into memory. Any sections no longer used are ; "unmapped". ; ; Calling Sequence: ; JSB IDX ; ; Formal Parameters: ; None. ; ; Implicit Inputs: ; Header offset into INDEXF.SYS, ; Channel to INDEXF.SYS, ; Number of pages to map, ; Page fault cluster, ; Memory address of where to map in INDEXF.SYS, ; Flags to describe section, ; File id needed to be mapped, ; Maximum file id already in memory ; ; Implicit Outputs: ; Mapped file headers + 1 extra block at end, ; Addresses for mapped area. ; ; Completion Status: ; Status returned in R0. ; ; Side Effects: ; Virtual memory exapanded, ; INDEXF.SYS accessed. ; ;-- MAP_IDX: TSTL R11 ; Must we perform any "unmapping" first? BEQL 40$ $DELTVA_S - ; Yes. INADR=RETURN_ADDR ON_ERR MAP_IDX_EXIT 40$: ADDL3 HEADER_OFFSET,R10,R1 ; Determine where to start mapping. $CRMPSC_S - ; Bring the pages in. INADR=INPUT_ADDR,- RETADR=RETURN_ADDR,- FLAGS=#SECT_FLAG,- CHAN=CHANNEL,- PAGCNT=MAPPED_PAGES,- VBN=R1,- PFC=PF_CLUSTER CMPL #SS$_ENDOFFILE,R0 ; Did we reach the end of the headers? BNEQ 60$ PUSHAL FFS_FILNOTFOU ; Yes, signal file not found. CALLS #1,G^LIB$SIGNAL 60$: ON_ERR MAP_IDX_EXIT ; No, check for any other errors. SUBL3 RETURN_ADDR,- ; R11 has highest numbered file number RETURN_ADDR+4,R11 ; in memory. ASHL #-9,R11,R11 ADDL2 R10,R11 DECL R11 SUBL3 #512,RETURN_ADDR,R7 ; R7 is pointer to header in buffer. MAP_IDX_EXIT: RSB .SBTTL Get Offset Information ;++ ; ; Functional Description: ; This routine is invoked because a file has been found which contains ; the desired disk address. This routine is a setup for a subsequent ; routine that will follow backlink pointers to determine the complete ; file-spec. To perform this backlink search, this routine determines ; the offset to the first file header in INDEXF.SYS for each volume in ; the volume set. A channel is established to each INDEXF.SYS also. ; ; Calling Sequence: ; JSB GET_OFFSETS ; ; Formal Parameters: ; None. ; ; Implicit Inputs: ; File ID (file number, sequence number, relative volume number), ; Root device name. ; ; Implicit Outputs: ; Table of offsets into each INDEXF.SYS for start of file headers, ; Table of channel numbers for each INDEXF.SYS. ; ; Completion Status: ; Returned in R0. ; ; Side Effects: ; INDEXF.SYS files are open for reading. ; ;-- GET_OFFSETS: CLRL R5 ; R5 holds volume number. NEXT_VOLUME: MOVL R5,R4 ; Determine next fib address and INCL R5 ; store it in R4. MOVL FIB_INDEX_TABLE[R4],R4 MOVL NEXT_LEN,NEXT_DESC ; Set device name length. $ASSIGN_S - DEVNAM=NEXT_DESC,- ; Get a channel to the device. CHAN=CHANNEL[R5] ON_ERR GET_OFFSETS_EXIT $QIOW_S FUNC=#,- ; Associate the channel CHAN=CHANNEL[R5],- ; with INDEXF.SYS. IOSB=QIO_IOSB,- P1=(R4) ON_ERR GET_OFFSETS_EXIT MOVZWL QIO_IOSB,R0 ON_ERR GET_OFFSETS_EXIT MOVW NEXT_LEN,NEXT_DESC ; Fix descriptor for proper length. $GETDVI_S - ; Get information on cluster size, DEVNAM=NEXT_DESC,- ; maximum files that can be stored ITMLST=NEXT_DVI_ITMLST ; on volume, and next volume name. ON_ERR GET_OFFSETS_EXIT DIVL3 #4096,MAX_FILES,R2 ; Compute where the file headers INCL R2 ; start for this volume, and MULL3 #4,CLUSTER_FACTOR,R3 ; remember this value. ADDL3 R2,R3,HEADER_OFFSET[R5] CMPL R5,VOLCOUNT ; Any more volumes to process? BGEQ 10$ BRW NEXT_VOLUME ; Yes, loop again. 10$: ; ; Take care of case where we are processing just one device ; (that is, not a volume set). ; MOVL HEADER_OFFSET+4,HEADER_OFFSET MOVW CHANNEL+2,CHANNEL GET_OFFSETS_EXIT: RSB .SBTTL Follow Backlinks ;++ ; ; Functional Description: ; This routine follows the backlink pointers of the file extension ; headers (if this file has any file extension headers), file header, ; and directory headers to determine the complete file specification. ; ; Calling Sequence: ; JSB FOLLOW_BACKLINKS ; ; Formal Parameters: ; None. ; ; Implicit Inputs: ; File backlink pointers (number, sequence, volume), ; Table of Fibs to each INDEXF.SYS in volume set, ; Table of file header offsets to each INDEXF.SYS in volume set. ; ; Implicit Outputs: ; Complete directory specification. ; ; Completion Status: ; Returned in R0. ; ; Side Effects: ; INDEXF.SYS file(s) are read. ; ;-- FOLLOW_BACKLINKS: TSTW EXT_SEG_NUM ; Do we have a file header with BEQL 10$ ; directory pointers? JSB EXT_LINKS ; No, we have an extension header, ON_ERR FOLLOW_BACKLINKS_EXIT ; get the file header. 10$: MOVAL FILE_HDR_BUF,R6 ; Remember the file name. MOVZBL FH2$B_IDOFFSET(R6),R7 ; Determine start of file name in MULL2 #2,R7 ; file header. ADDL2 R6,R7 MOVC3 #FI2$S_FILENAME,- ; Save name in buffer. FI2$T_FILENAME(R7),- FILE_NAME_BUF MOVC3 #FI2$S_FILENAMEXT,- FI2$T_FILENAMEXT(R7),- (R3) LOCC #^A/;/,- ; Need to figure out the length of #FILE_NAME_BUF_SIZ,- ; file name. Find the start of the FILE_NAME_BUF ; version number. INCL R1 ; Start of version number (past ";"). DECL R0 SPANC R0,(R1),NUM_TBL,#1 ; Skip over version number. SUBL3 R0,#FILE_NAME_BUF_SIZ,- ; Compute length. FILE_NAME_DESC MOVL R6,R2 ; R2 points to desired file header. MOVZWL FH2$W_BK_FIDRVN(R2),R10 ; Get backlink rel. vol. number. TSTL R10 ; If it is zero, use volume number BGTR 20$ ; of volume we specified on command. MOVL VOLNUMBER,R10 20$: MOVL FH2$W_FID(R2),FILE_ID ; Save the file id. MOVL FH2$L_FILEOWNER(R2),- ; Save the owner field. FILE_UIC $IDTOASC_S - ; See if we have an Ascii ID=FILE_UIC,- ; id for this file. NAMLEN=NAME_DESC,- NAMBUF=NAME_DESC BLBS R0,25$ MOVL #1,NAME_DESC ; Set id to a blank if none found. MOVB #^A/ /,NAME_BUF 25$: ROTL #16,FH2$L_ALLOC(R2),- ; Save blocks allocated and used. BLKS_ALLOC ROTL #16,FH2$L_USED(R2),- BLKS_USED MOVAL DIR_HDR_BUF,R8 ; R8 has addr of buf to hold headers. MOVW #1,DIR_DESC ; Prefix dir-spec with "[" and adjust MOVB #^A/[/,DIR_BUF ; descriptor. MOVAL DIR_DESC,R7 ; R7 has dir-spec address. ADDL2 #1,4(R7) MOVZWL FH2$W_BACKLINK(R2),-(SP) CALLS #1,G^BACK_LINK ; Routine to recursively follow ON_ERR FOLLOW_BACKLINKS_EXIT ; backlinks. MOVAL DIR_BUF,4(R7) ; If file was not in MFD, then there ADDL3 (R7),4(R7),R6 ; will be a period at end of directory CMPW DIR_DESC,#1 ; spec. Adjust descriptor to get rid BGTR 30$ ; of period. INCL R6 INCW DIR_DESC 30$: DECL R6 ; Suffix directory-spec with "]". MOVB #^A/]/,(R6) MOVL #SS$_NORMAL,R0 FOLLOW_BACKLINKS_EXIT: RSB .SBTTL Trace File Extension Links ;++ ; ; Functional Description: ; This routine locates and reads the "0th" file extension ; header given the "nth". We need the "0th" for directory ; tracing and to get the correct file name. ; ; Calling Sequence: ; JSB EXT_LINKS ; ; Formal Parameters: ; None. ; ; Implicit Inputs: ; File extension buffer of "nth" extension, ; Channel number table, ; File header offset table, ; Number of volumes in set, ; Volume number for "nth" file extension header. ; ; Implicit Outputs: ; "0th" file extension header. ; ; Completion Status: ; Returned in R0. ; ; Side Effects: ; INDEXF.SYS file(s) are accessed. ; ;-- EXT_LINKS: MOVAL EXT_HDR_BUF,R7 ; Remember file ID of "nth" MOVW FH2$W_FID_NUM(R7),FILE_EXT_NUM ; file extension header. MOVW FH2$W_FID_SEQ(R7),FILE_EXT_SEQ MOVW VOLNUMBER,FILE_EXT_RVN MOVW FH2$W_BK_FIDNUM(R7),FILE_NUM ; Remember file ID of "0th" MOVW FH2$W_BK_FIDSEQ(R7),FILE_SEQ ; file extension header. CLRL R5 NEXT_VOL: INCL R5 ; R5 is volume counter for MOVAL FILE_HDR_BUF,R8 ; volume loop. MOVZWL FILE_NUM,R9 ADDL2 HEADER_OFFSET[R5],R9 ; Get offset into INDEXF.SYS. $QIOW_S CHAN=CHANNEL[R5],- ; Read file header. FUNC=#IO$_READVBLK,- P1=(R8),- P2=#512,- P3=R9 ON_ERR EXT_LINKS_EXIT CMPL VOLCOUNT,#1 ; If only 1 volume is in set, BGTR 20$ ; then we must have just read BRW GOT_0TH_HDR ; the "0th" file ext header. 20$: MOVZWL EXT_SEG_NUM,R11 ; R11 is ext segment count. NEXT_EXT: TSTW FH2$W_EX_FIDNUM(R8) ; See if this header has any BGTR 40$ ; extensions. BRW NEXT_VOL 40$: MOVW FH2$W_EX_FIDRVN(R8),R2 ; Get file id to next extension MOVZWL FH2$W_EX_FIDNUM(R8),R9 ; header. ADDL2 HEADER_OFFSET[R2],R9 $QIOW_S CHAN=CHANNEL[R2],- ; Read this header. FUNC=#IO$_READVBLK,- P1=(R7),- P2=#512,- P3=R9 ON_ERR EXT_LINKS_EXIT MOVAL EXT_HDR_BUF,R8 DECL R11 ; Have we reached the "nth" BEQL GOT_NTH_HDR ; extension header? BRW NEXT_EXT ; No, read next extension. GOT_NTH_HDR: ; We have reached an "nth" CMPW FILE_EXT_NUM,FH2$W_FID_NUM(R8) ; header. If file id number, BEQL 10$ ; sequence number, and relative BRW NEXT_VOL ; number match, then we know ; we have the "0th" header. 10$: CMPW FILE_EXT_SEQ,FH2$W_FID_SEQ(R8) BEQL 20$ BRW NEXT_VOL 20$: CMPW FILE_EXT_RVN,R2 BEQL GOT_0TH_HDR BRW NEXT_VOL GOT_0TH_HDR: MOVL R5,VOLNUMBER ; Need volume number for file id. MOVL #SS$_NORMAL,R0 EXT_LINKS_EXIT: RSB .SBTTL Recursively Follow Backlinks ;++ ; ; Functional Description: ; This routine performs the actual following of backlinks to ; get a complete directory specification. ; ; Calling Sequence: ; CALLS #1,BACK_LINK ; ; Formal Parameters: ; Backlink file number. ; ; Implicit Inputs: ; Backlink relative volume number (in R10), ; Buffer to store file headers (address in R8), ; Directory buffer (address in R7). ; ; Implicit Outputs: ; Complete directory spec. ; ; Completion Status: ; Returned in R0. ; ; Side Effects: ; Performs QIO virtual reads on INDEXF.SYS. ; ; Register Usage: ; R0 - Return status. ; R6 - Directory name length saved here. ; R7 - Address of directory descriptor. ; R8 - Address of header buffer. ; R9 - Specifies which vbn in INDESF.SYS to read. ; R10 - Volume number, used as index into header offset and ; channel tables. ;-- .ENTRY BACK_LINK,^M ADDL3 HEADER_OFFSET[R10],- ; Compute block which contains 4(AP),R9 ; the file header for the dir. $QIOW_S CHAN=CHANNEL[R10],- ; Read a block. FUNC=#IO$_READVBLK,- P1=(R8),- P2=#512,- P3=R9 ON_ERR BACK_LINK_EXIT MOVZBL FH2$B_IDOFFSET(R8),R11 ; Get word offset to id. MULL2 #2,R11 ; Compute to bytes. ADDL2 R8,R11 ; R11 points to start of id. MOVC3 #FI2$S_FILENAME,- ; Move first part of directory FI2$T_FILENAME(R11),- ; filename into buffer. DIR_NAME_BUF MOVC3 #FI2$S_FILENAMEXT,- ; Move last part of filename, FI2$T_FILENAMEXT(R11),- ; this instruction MUST (R3) ; IMMEDIATELY follow prev instr. LOCC #^A/./,#,- DIR_NAME_BUF ; Compute length of this SUBL2 #,- R0 ; portion of directory MNEGL R0,R6 ; string. CMPW FH2$W_BACKLINK(R8),4(AP) ; Are we at [000000] ? BEQL 20$ SUBL2 R6,SP ; Make room for directory MOVC3 R6,DIR_NAME_BUF,(SP) ; name and length. PUSHL R6 MOVZWL FH2$W_BACKLINK(R8),-(SP) ; No, keep tracing. TSTW FH2$W_BK_FIDRVN(R8) BEQL 10$ MOVZWL FH2$W_BK_FIDRVN(R8),R10 10$: CALLS #1,G^BACK_LINK ON_ERR BACK_LINK_EXIT 20$: MOVL (SP)+,R6 MOVC3 R6,(SP),@4(R7) ; Adjust descriptor. ADDL2 R6,SP ADDL2 R6,(R7) ADDL2 R6,4(R7) MOVL #SS$_NORMAL,R0 ; Indicate success. BACK_LINK_EXIT: RET .SBTTL Output Results ;++ ; ; Functional Description: ; This routine formats and outputs the file-spec and ; directory spec. ; ; Calling Sequence: ; JSB OUTPUT_RESULTS ; ; Formal Parameters: ; None. ; ; Implicit Inputs: ; Directory name, ; File name, ; Control (format) string. ; ; Implicit Outputs: ; None. ; ; Completion Status: ; Returned in R0. ; ; Side Effects: ; Writes to SYS$OUTPUT. ; ;-- OUTPUT_RESULTS: $FAO_S CTRSTR=CTRL_STG,- ; Format the string to OUTLEN=OUTPUT_LEN,- ; include directory-spec OUTBUF=OUTPUT_DESC,- ; and file name. P1=#DIR_DESC,- P2=#FILE_NAME_DESC ON_ERR OUTPUT_RESULTS_EXIT MOVW OUTPUT_LEN,OUTPUT_DESC ; Fix up the descriptor. PUSHAL OUTPUT_DESC CALLS #1,G^LIB$PUT_OUTPUT ON_ERR OUTPUT_RESULTS_EXIT MOVL #OUTPUT_BUF_SIZ,OUTPUT_DESC $FAO_S CTRSTR=CTRL_STG2,- ; Format the string to OUTLEN=OUTPUT_LEN,- ; include owner. OUTBUF=OUTPUT_DESC,- P1=FILE_GRP_UIC,- P2=FILE_MEM_UIC,- P3=#NAME_DESC ON_ERR OUTPUT_RESULTS_EXIT MOVW OUTPUT_LEN,OUTPUT_DESC ; Fix up the descriptor. PUSHAL OUTPUT_DESC CALLS #1,G^LIB$PUT_OUTPUT ON_ERR OUTPUT_RESULTS_EXIT MOVL #OUTPUT_BUF_SIZ,OUTPUT_DESC $FAO_S CTRSTR=CTRL_STG3,- ; Format the string to OUTLEN=OUTPUT_LEN,- ; include file-id. OUTBUF=OUTPUT_DESC,- P1=FILE_ID_NUM,- P2=FILE_ID_SEQ,- P3=VOLNUMBER ON_ERR OUTPUT_RESULTS_EXIT MOVW OUTPUT_LEN,OUTPUT_DESC ; Fix up the descriptor. PUSHAL OUTPUT_DESC CALLS #1,G^LIB$PUT_OUTPUT ON_ERR OUTPUT_RESULTS_EXIT MOVL #OUTPUT_BUF_SIZ,OUTPUT_DESC $FAO_S CTRSTR=CTRL_STG4,- ; Format the string to OUTLEN=OUTPUT_LEN,- ; include blocks allocated OUTBUF=OUTPUT_DESC,- ; and used. P1=BLKS_ALLOC,- P2=BLKS_USED ON_ERR OUTPUT_RESULTS_EXIT MOVW OUTPUT_LEN,OUTPUT_DESC ; Fix up the descriptor. PUSHAL OUTPUT_DESC CALLS #1,G^LIB$PUT_OUTPUT ON_ERR OUTPUT_RESULTS_EXIT OUTPUT_RESULTS_EXIT: RSB .END FINDFILES