.title Files Program to Read Index Header File  .ident /2.2/ ; File: FILES.MAR  ;++ ; Facility: ; Utility to collect information about the size and ownership ; of files. ; ; Abstract: ; This program examines the file header file (INDEXF.SYS) ; to retrieve information about the largest files strored ; on disk and who owns them. Back link pointers in the ; INDESF.SYS file are followed to obtain a complete ; directory specification. ; ; Environment: ; Needs SYSPRV. ; ; Author: ; Mark Oakley, Battelle Columbus Labs, 11-Feb-1984 ; ; Modifications: ; ; 11-Mar-1984 Mark Oakley Revised to use mapping routines ; to access file headers. ; ; 15-Mar-1984 Mark Oakley Fixed bug in check of member uic. ; ; 22-Mar-1984 Mark Oakley Added signalling for command line ; syntax errors. ; ; 7-Apr-1984 Mark Oakley Fixed to print files equal to or !; greater that minimum size. Only "; files greater than minimum were #; printed previously. $; %; 17-Feb-1985 Mark Oakley Revised to work with V4 file &; headers. '; (;-- ) * .sbttl Symbols + , .library /SYS$LIBRARY:LIB.MLB/ - . $dvidef ; Device definitions. / $fabdef ; File access block definitions. 0 $fh2def ; File-header definitions. 1 $fi2def ; File-header-id definitions. 2 $jpidef ; Job/process definitions. 3 $hm2def ; Home block definitions. 4 $secdef ; Mapping section definitions. 5 $ssdef ; Termination definitions. 6 $tpadef ; LIB$TPARSE definitions. 7 8 9; :; Note that $fh2def lacks the following definitions: ;; <fh2$t_fname = ^x50 =fh2$l_alloc = ^x18 ; Offset to blocks allocated. >fh2$l_used = ^x1c ; Offset to blocks used. ? @ A; B; Macro to help set up fabs for each volume in a volume set. C; D .macro mfab E $fab dnm=<[000000]INDEXF.SYS>,- F fna=devnam_buf,- G fop= H .endm mfab I J; K; Macro to handle return codes. L; M .macro on_err there,?here N blbs r0,here O brw there Phere: .endm on_err Q R S .sbttl Command line, prompts data T U .psect files_data,rd,wrt,noexe,long,shr,pic V Wcommand_line_desc: X .word command_line_buf_siz Y .word 0 Z .address command_line_buf [ \command_line_buf: ; Store the command line here. ] .blkb 80 ^command_line_buf_siz = . - command_line_buf _ `command_line_len: ; Store the command line length here. a .blkl 1 b cparse_blk: ; Parse block for LIB$TPARSE to d .long tpa$k_count0 ; parse command line. e .long tpa$m_abbrev ; Permit unambiguous abbreviations. f .blkb tpa$k_length0-8 g hmin_file_size: ; Search for files larger than i .blkl 1 ; this size. j kgrp_uic: ; Search for files with this group l .long -1 ; uic. m nmem_uic: ; Search for files with this group o .long -1 ; uic. p q .sbttl Device data r sdefault_disk: ; Use default if no disk given. t .ascid /SYS$DISK/ u vinit_dvi_itmlst: ; Item list to get the root device w .word devnam_buf_siz ; name of a volume set. x .word dvi$_rootdevnam y .address devnam_buf z .address devnam_len { .long 0 | }root_dvi_itmlst: ; Item list used just for first ~ .word 4 ; volume in set.  .word dvi$_cluster .address cluster_size .long 0 .word 4 .word dvi$_maxfiles .address max_files .long 0 .word 4 .word dvi$_volcount .address volset_cnt .long 0 .long 0 next_dvi_itmlst: ; Item list to get succeeding .word devnam_buf_siz ; device names of a volume set, .word dvi$_nextdevnam ; disk cluster size, and maximum .address devnam_buf ; number of files allowed on .address devnam_len ; device. .word 4 .word dvi$_cluster .address cluster_size .long 0 .word 4 .word dvi$_maxfiles .address max_files .long 0 .long 0 devnam_desc: .word devnam_buf_siz .word 0 .address devnam_buf devnam_buf: ; Store the device name here. .blkb 50 devnam_buf_siz = . - devnam_buf devnam_len: ; Store the device name length here. .blkl 1 cluster_size: ; Disk cluster factor. .blkl 1 max_files: ; Maximum number of files .blkl 1 ; on disk. ifb_channel: ; Table of channels to each INDEXF.SYS .blkw 10 ; on each volume in set. ifb_iosb: ; Status for INDEXF.SYS operations. .blkq 1 volset_cnt: ; Number of volumes in a volume set. .blkl 1 directory_desc: ; Directory spec will be .word 0 ; stored here. .word 0 .address directory_buf directory_buf: .blkb 255 directory_buf_size = . - directory_buf file_desc: .word 0 .word 0 .address file_buf file_buf: .blkb fi2$s_filename+fi2$s_filenamext file_buf_siz = . - file_buf .sbttl Table of Fab's for Volume Set .psect fab_table,,rd,wrt,noexe,page,shr,pic ; ; Allow up to 10 volumes in a volume set. ; indexf_fab_1: mfab indexf_fab_2: mfab indexf_fab_3: mfab indexf_fab_4: mfab indexf_fab_5: mfab indexf_fab_6: mfab indexf_fab_7: mfab indexf_fab_8: mfab indexf_fab_9: mfab indexf_fab_10: mfab fab_index_table: .address indexf_fab_1 .address indexf_fab_2 .address indexf_fab_3 .address indexf_fab_4 .address indexf_fab_5 .address indexf_fab_6 .address indexf_fab_7 .address indexf_fab_8 .address indexf_fab_9 .address indexf_fab_10 .sbttl Index File Bitmap Buffer .psect indexf_file_bitmap,rd,wrt,noexe,page,shr,pic index_file_bitmap: .blkb <60*512> ; Allow for bitmap sizes up to 60 blocks ; (29760 files) per volume. first_ifb_vbn: ; Table of vbn's which are the start of .blkl 10 ; bitmap in each INDEXF.SYS for each volume. header_offset: ; Table of offset's to get to the start of ; headers in each INDEXF.SYS for each volume. last_ifb_vbn: ; Table of vbn's which are the end of bitmap  .blkl 10 ; in each INDEXF.SYS for each volume.   .psect directory_header,rd,wrt,noexe,page,shr,pic  ; ; Store file header for directory here. This is used to follow ; directiry back-links to obtain a complete directory spec for ; the file. ;  dir_hd_buf: .blkb 512   .sbttl Mapped Section Data Structures  input_addr: ; sec$m_expreg will be set, so setting  .long ^x20000 ; both address's equal guarantees that  .long ^x20000 ; no more memory is mapped than needed.  return_addr: ; Address of mapped area. This area  .blkl 2 ; will hold up to 4000 file headers.  mapped_pages: ; Max number of pages mapped at once.  .long 4000  pf_cluster: ; Number of pages to bring into memory  .long 128 ; if a page fault occurs.  sect_flag = ; Section is copy-on-reference and  ; expand memory region as needed.   .sbttl Parse Tables ; ; State and transition instructions on how to parse command line. !; " # .psect files_parse,rd,nowrt,exe,long,shr,pic $ % $init_state files_state,files_key & ' $state start ( $tran tpa$_eos,tpa$_exit ; End of string here is success. ) $tran '/' ; Another qualifier detected. * $tran tpa$_symbol,tpa$_exit,- ; + ,,devnam_desc , - . $state ; Determine which qualifier. / $tran 'SIZE',get_size 0 $tran 'UIC',get_uic 1 2 $state get_uic ; Parse for getting the uic. 3 $tran '=' 4 $state 5 $tran '[' 6 $state 7 $tran '*',,,-1,grp_uic 8 $tran tpa$_octal,,,,grp_uic 9 $state comma : $tran <','> ; $state < $tran '*',,,-1,mem_uic = $tran tpa$_octal,,,,mem_uic > $state ? $tran ']',start @ A B $state get_size ; Parse for getting the minimum C $tran '=' ; file size D $state E $tran tpa$_decimal,start,,,min_file_size F G $end_state H I .sbttl Main program J .psect files_code,rd,nowrt,exe,long,shr,pic K .entry files,^m L M jsb parse_comm_line ; Override default values as necessary. N on_err main_exit O P jsb compute_offsets ; Compute offsets to 1st file header Q on_err main_exit ; and other info. R S jsb search_bitmap ; Search for valid headers, output T on_err main_exit ; results. U Vmain_exit: W ret X Y .sbttl Parse Command Line Z; [; This routine scans the command line for uic, file size, \; and a device name. ]; ^ _parse_comm_line: ` a movq default_disk,- ; Assume device is default device b devnam_desc ; until we find otherwise. c d pushl #0 ; See what's on the command line. e pushal command_line_len f pushl #0 g pushal command_line_desc h calls #4,g^lib$get_foreign i on_err parse_comm_line_exit j k movzwl command_line_len,- ; Set up for LIB$TPARSE. l parse_blk+tpa$l_stringcnt m moval command_line_buf,- n parse_blk+tpa$l_stringptr o pushal files_key p pushal files_state q pushal parse_blk r calls #3,g^lib$tparse s cmpl #lib$_syntaxerr,r0 ; Did we get a syntax error? t bneq 30$ u pushal parse_blk+- ; Yes, capture the string and v tpa$l_tokencnt ; signal the error. w pushl #1 x pushl #fls_syntaxerr y calls #3,g^lib$signal z {30$: | on_err parse_comm_line_exit } ~ $getdvi_s - ; Get root volume name.  devnam=devnam_desc,-  itmlst=init_dvi_itmlst  on_err parse_comm_line_exit   movw devnam_len,devnam_desc ; Must restore what we or LIB$TPARSE  moval devnam_buf,- ; did to this descriptor.  devnam_desc+4  parse_comm_line_exit:  rsb   .sbttl Compute offsets ; ; This routine computes the first block in INDEXF.SYS which contains ; a header. ;  compute_offsets:   clrl r5 ; r5 holds volume number.   $getdvi_s - ; Get the root name of this  devnam=devnam_desc,- ; volume set.  itmlst=root_dvi_itmlst  on_err compute_header_exit  brw skip_on_first ; Skip past next $GETDVI on first loop.  next_vol:  movw devnam_len,devnam_desc ; Make sure device name length is ok.  $getdvi_s - ; Get infomation about maximum files,  devnam=devnam_desc,- ; cluster size, and next volume in set.  itmlst=next_dvi_itmlst  on_err compute_header_exit  skip_on_first:  movl r5,r4  incl r5 ; Set r5 to point to next volume.  movl fab_index_table[r4],r4 ; Compute fab address.  movb devnam_len,- ; Remember to set the length of the  fab$b_fns(r4) ; device name in the fab.  ; ; Compute the start of the file headers, which is ; 4 * disk cluster factor + bit map file size. ;  divl3 #4096,max_files,r2 ; Bitmap file size is max files / 4096  incl r2 ; + 1.  mull3 #4,cluster_size,r3  addl2 r2,r3 ; File header offset in r3.  ; ; Save start and end vbn's of index bit file map. ;  movl r3,last_ifb_vbn[r5]  subl2 r2,r3  incl r3  movl r3,first_ifb_vbn[r5]   $open fab=(r4) ; Open the file for "user" file  on_err read_bitmap_exit ; processing.   movw fab$l_stv(r4),- ; Remember the channel number.  ifb_channel[r5]   cmpl r5,volset_cnt ; End of volumes?  bgeq 10$  brw next_vol   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 ifb_channel+2,ifb_channel  movl first_ifb_vbn+4,first_ifb_vbn  compute_header_exit:  rsb   .sbttl Read Index Bitfile Map  ; ; Read the index bitfile map in INDEXF.SYS. ;  read_bitmap:   movl last_ifb_vbn[r5],r3 ; Number of bytes to read is:  subl2 first_ifb_vbn[r5],r3 ; (last vbn - first vbn + 1) * 512.  incl r3  mull2 #512,r3   $qiow_s chan=ifb_channel[r5],- ; Read the bitmap.  func=#io$_readvblk,-  iosb=ifb_iosb,-  p1=index_file_bitmap,- ; Read buffer.  p2=r3,- ; Number of bytes to read.  p3=first_ifb_vbn[r5] ; Where to start reading.   on_err read_bitmap_exit  movzwl ifb_iosb,r0  on_err read_bitmap_exit  read_bitmap_exit:  rsb   .sbttl Search the Index Bitmap File ; ; This routine searches the index header bitmap for valid headers. ; When a valid header is found, it is read from disk. Selected ; fields are printed. ;  search_bitmap:   movl #1,r5 ; r5 is volume pointer.  10$:  jsb read_bitmap  on_err search_bitmap_exit   clrl r4 ; Initialize max header number.  clrl r10 ; Pointer into ifb.  moval index_file_bitmap,r11 ; Get base addr of ifb.  subl3 first_ifb_vbn[r5],- ; r6 will hold the size  last_ifb_vbn[r5],r6 ; (in long words) of the  decl r6 ; index bitmap file.  mull2 #<4096/32>,r6  incl r6  20$:  movl (r11)[r10],r9 ; Get next entry in ifb.  clrl r8 ; Bit pointer into entry.  movl #32,r7 ; Size of entry to search, in bits.  30$:  ffs r8,r7,r9,r8 ; Look for a set bit.  beql 40$ ; Is there a bit set?   jsb read_write_header ; Yes, get information on this header.  on_err search_bitmap_exit   subl3 r8,#32,r7 ; Any more bits to check  bgtr 30$ ; in this entry?  40$:  aobleq r6,r10,20$ ; Get next entry if max not reached.   aobleq volset_cnt,r5,10$ ; Next volume   calls #0,g^write_totals ; Write total blocks allocated and  on_err search_bitmap_exit ; used.  search_bitmap_exit:  rsb   .sbttl Read and Write Header Information ; ; This routine reads a file header from disk and outputs selected !; information about the header. "; #read_write_header: $ %; &; Compute page offset in memory of where the header is mapped. '; ( incl r8 ; Compute file id as (bit pos +1) + ) movl r10,r2 ; 32 * (number of bitmap long word). * ashl #5,r2,r2 ; + addl2 r8,r2 ; r2 has file number. , cmpl r4,r2 ; Is this file header in memory? - blss 40$ . brw in_memory ; Yes. / 040$: 1 tstl return_addr ; No, see if we need to perform 2 beql 60$ ; any "unmapping" first. 3 $deltva_s - 4 inadr=return_addr 5 on_err read_write_header_exit 6 760$: 8 addl3 header_offset[r5],r2,r1 ; Get where to start read from disk. 9 : $crmpsc_s - ; Bring the headers into memory. ; inadr=input_addr,- < retadr=return_addr,- = flags=#sect_flag,- > chan=ifb_channel[r5],- ? pagcnt=mapped_pages,- @ vbn=r1,- A pfc=pf_cluster B cmpl #ss$_endoffile,r0 ; Did we reach end-of-file? C bneq 80$ D movl #32,r8 ; Yes, fix things up so that E addl3 #1,r6,r10 ; we move on to the next volume F clrq return_addr ; (if there is one). G movl #ss$_normal,r0 H brw read_write_header_exit I J80$: K on_err read_write_header_exit L M subl3 #511,return_addr+4,r3 ; r3 has start addr of max hdr. N subl3 return_addr,- ; Compute highest numbered file number O return_addr+4,r4 ; in memory. P ashl #-9,r4,r4 Q addl3 r2,r4,r4 R Sin_memory: T subl3 r2,r4,r2 ; Header location in memory is: U ashl #9,r2,r2 ; loc = r3 - 512 * (max_files - r2) V subl3 r2,r3,r2 W X; Y; Check for a valid header. Z; [ tstw fh2$w_fid(r2) ; Is the file number 0? \ bneq 20$ ] brw read_write_header_exit ; Yes, this is not a valid header. ^ _20$: ` tstw fh2$w_seg_num(r2) ; Is the extension segment number 0? a beql 30$ b brw read_write_header_exit ; No, this is not a valid header. c d30$: e tstw fh2$w_checksum(r2) ; Is the checksum 0? f bneq 40$ g brw read_write_header_exit ; Yes, this is not a valid header. h i40$: j k; l; Header is valid, does file meet our criteria for reporting? m; n rotl #16,fh2$l_alloc(r2),r1 ; Is file large enough? o cmpl min_file_size,r1 p bleq 50$ q brw read_write_header_exit r s50$: t tstl grp_uic ; Should we test file group uic? u blss 60$ v cmpw grp_uic,- ; Yes, do the group uic's match? w fh2$w_uicgroup(r2) x beql 60$ ; Yes, keep on checking. y brw read_write_header_exit ; No, don't report. z {60$: | tstl mem_uic ; Should we test member uic? } blss 70$ ~ cmpw mem_uic,- ; Yes, do the member uic's match?  fh2$w_uicmember(r2)  beql 70$ ; Yes.  brw read_write_header_exit ; No, don't report.  70$:  ; ; Get back-link of file to determine complete directory spec. ;  dir_bkl:   pushr #^m   movzwl fh2$w_bk_fidrvn(r2),r10 ; If the file and directory are  tstl r10 ; on the same volume, then the  bgtr 10$ ; fh2$w_bk_fidrvn field will be  movl r5,r10 ; zero. Thus, use the file rvn.  10$:  moval dir_hd_buf,r8  movw #1,directory_desc  movb #^a/[/,directory_buf ; Start dir spec with a "[".  moval directory_desc,r7  addl2 #1,4(r7)  movzwl fh2$w_backlink(r2),-(sp) ; Trace backlinks to see which  calls #1,g^bk_link ; directory the file is in.   moval directory_buf,4(r7)  addl3 (r7),4(r7),r6  cmpw directory_desc,#1  bgtr 20$  incl r6  incw directory_desc  20$:  decl r6  movb #^a/]/,(r6) ; End dir spec with a "]".  write_header_info:   pushal directory_desc  movl r2,r6 ; Will need R2 for MOVC3.  pushaw fh2$w_fid(r6)   movzbl fh2$b_idoffset(r6),r7 ; Get word offset to file name.  mull2 #2,r7 ; Convert to byte offset.  addl2 r6,r7 ; Add in header address.  movc3 #fi2$s_filename,- ; Move first part of filename  fi2$t_filename(r7),- ; to file name buffer.  file_buf  movc3 #fi2$s_filenamext,- ; Move last part of filename  fi2$t_filenamext(r7),- ; to file name buffer.  (r3) ; R3 got set by previous MOVC3.   pushab file_buf  pushal fh2$l_alloc(r6)  pushal fh2$l_used(r6)  pushaw fh2$w_uicmember(r6)  pushaw fh2$w_uicgroup(r6)  calls #7,write_it  on_err read_write_header_exit  popr #^m  read_write_header_exit:  rsb   .sbttl Follow Backlinks ; ; Recursive routine to follow directory backlinks. ;   .entry bk_link,^m   addl3 header_offset[r10],- ; Compute block which contains  4(ap),r9 ; the file header for the dir.  $qiow_s chan=ifb_channel[r10],- ; Read a block.  func=#io$_readvblk,-  p1=(r8),-  p2=#512,-  p3=r9  on_err bk_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 filename  fi2$t_filename(r11),- ; into buffer.  file_buf  movc3 #fi2$s_filenamext,- ; Move last part of filename,  fi2$t_filenamext(r11),- ; this instruction MUST  (r3) ; IMMEDIATELY follow prev instr.   locc #^a/./,#,-  file_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,file_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^bk_link  on_err bk_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.  bk_link_exit:  ret   .end files