.title Files Program to Read Index Header File  .ident /2.X/ ; 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. '; (; 19-Nov-1985 Mark Oakley Added capability to handle character ); uic's on command line. *; +; 20-Dec-1985 Mark Oakley Experimental version to program ,; around XQP bug. -; .;-- / 0 .sbttl Symbols 1 2 .library /SYS$LIBRARY:LIB.MLB/ 3 4 $dvidef ; Device definitions. 5 $fabdef ; File access block definitions. 6 $fh2def ; File-header definitions. 7 $fi2def ; File-header-id definitions. 8 $fibdef ; File-information-block definitions. 9 $jpidef ; Job/process definitions. : $hm2def ; Home block definitions. ; $secdef ; Mapping section definitions. < $ssdef ; Termination definitions. = $tpadef ; LIB$TPARSE definitions. > ? @; A; Note that $fh2def lacks the following definitions: B; Cfh2$t_fname = ^x50 Dfh2$l_alloc = ^x18 ; Offset to blocks allocated. Efh2$l_used = ^x1c ; Offset to blocks used. F G H; I; Macro to help set up fabs for each volume in a volume set. J; K .macro mfab ?desc,?start Ldesc: .long fib$k_length M .address start Nstart: O. = . + fib$w_fid P .word 1 Q .word 1 R. = start + fib$k_length S .endm mfab T U; V; Macro to handle return codes. W; X .macro on_err there,?here Y blbs r0,here Z brw there [here: .endm on_err \ ] ^ .sbttl Command line, prompts data _ ` .psect files_data,rd,wrt,noexe,long,shr,pic a bcommand_line_desc: c .word command_line_buf_siz d .word 0 e .address command_line_buf f gcommand_line_buf: ; Store the command line here. h .blkb 80 icommand_line_buf_siz = . - command_line_buf j kcommand_line_len: ; Store the command line length here. l .blkl 1 m nparse_blk: ; Parse block for LIB$TPARSE to o .long tpa$k_count0 ; parse command line. p .long tpa$m_abbrev ; Permit unambiguous abbreviations. q .blkb tpa$k_length0-8 r smin_file_size: ; Search for files larger than t .blkl 1 ; this size. u vgrp_uic: ; Search for files with this group w .long -1 ; uic. x ymem_uic: ; Search for files with this group z .long -1 ; uic. { | .sbttl Device data } ~default_disk: ; Use default if no disk given.  .ascid /SYS$DISK/ init_dvi_itmlst: ; Item list to get the root device .word devnam_buf_siz ; name of a volume set. .word dvi$_rootdevnam .address devnam_buf .address devnam_len .word 4 .word dvi$_volcount .address volset_cnt .long 0 .long 0 next_dvi_itmlst: ; Item list to get succeeding .word next_devnam_buf_siz ; device names of a volume set, .word dvi$_nextdevnam ; disk cluster size, and maximum .address next_devnam_buf ; number of files allowed on .address next_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 next_devnam_buf: .blkb 50 next_devnam_buf_siz = . - next_devnam_buf next_devnam_len: .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. 0 $tran '/' ; Another qualifier detected. 1 $tran tpa$_symbol,tpa$_exit,- ; 2 ,,devnam_desc 3 4 5 $state ; Determine which qualifier. 6 $tran 'SIZE',get_size 7 $tran 'UIC',get_uic 8 9 $state get_uic ; Parse for getting the uic. : $tran '=' ; $state < $tran '[' = > $state ? $tran '*',comma_check,,-1,grp_uic ; Check for [* @ $tran tpa$_octal,get_mem_uic,,,grp_uic ; Check for [n A $tran tpa$_symbol,end_uic,cvt_chr_uic ; Check for [x B C $state comma_check D $tran ']',start,,-1,mem_uic ; Check for [*] E $tran <','>,have_comma ; Check for [*, F G $state get_mem_uic H $tran <','> ; Check for [n, I $state have_comma J $tran tpa$_octal,,,,mem_uic ; Check for [*,n or [n,n K $tran '*',,,-1,mem_uic ; Check for [*,* or [n,* L M $state end_uic N $tran ']',start O P Q $state get_size ; Parse for getting the minimum R $tran '=' ; file size S $state T $tran tpa$_decimal,start,,,min_file_size U V $end_state W X .sbttl LIB$TPARSE Action Routine for Character UIC. Y Z; [; This action routine processes a character uic. $ASCTOID is called to \; perform the conversion. If the system service fails, or a non-uic id ]; is detected, then an error status is returned. ^; _ ` .entry cvt_chr_uic,^m a b $asctoid_s - ; Convert character uic to numeric. c name=parse_blk+tpa$l_tokencnt,- d id=grp_uic e on_err cvt_chr_uic_exit f g bicl3 #^x3fffffff,grp_uic,r5 ; Did we get a non-uic id? h beqlu 20$ i pushal parse_blk+- ; Yes, capture the string and j tpa$l_tokencnt ; signal the error. k pushl #1 l pushl #fls_notuicid m calls #3,g^lib$signal n o20$: p movzwl grp_uic,mem_uic ; Put the group and member uic's into q ashl #<-16>,grp_uic,grp_uic ; separate longwords. r s movl #ss$_normal,r0 t ucvt_chr_uic_exit: v ret w x .sbttl Main program y .psect files_code,rd,nowrt,exe,long,shr,pic z .entry files,^m { | jsb parse_comm_line ; Override default values as necessary. } on_err main_exit ~  jsb compute_offsets ; Compute offsets to 1st file header  on_err main_exit ; and other info.   jsb search_bitmap ; Search for valid headers, output  on_err main_exit ; results.  main_exit:  ret   .sbttl Parse Command Line ; ; This routine scans the command line for uic, file size, ; and a device name. ;  parse_comm_line:   movq default_disk,- ; Assume device is default device  devnam_desc ; until we find otherwise.   pushl #0 ; See what's on the command line.  pushal command_line_len  pushl #0  pushal command_line_desc  calls #4,g^lib$get_foreign  on_err parse_comm_line_exit   movzwl command_line_len,- ; Set up for LIB$TPARSE.  parse_blk+tpa$l_stringcnt  moval command_line_buf,-  parse_blk+tpa$l_stringptr  pushal files_key  pushal files_state  pushal parse_blk  calls #3,g^lib$tparse  cmpl #lib$_syntaxerr,r0 ; Did we get a syntax error?  bneq 30$  pushal parse_blk+- ; Yes, capture the string and  tpa$l_tokencnt ; signal the error.  pushl #1  pushl #fls_syntaxerr  calls #3,g^lib$signal  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.  next_vol:  $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]  exp: $assign_s -  devnam=devnam_desc,-  chan=ifb_channel[r5]  on_err compute_header_exit   $qiow_s func=#,-  chan=ifb_channel[r5],-  iosb=ifb_iosb,-  p1=(r4)  on_err compute_header_exit  movzwl ifb_iosb,r0  on_err compute_header_exit   cmpl r5,volset_cnt ; End of volumes?  bgeq 10$  pushr #^m ; Save reg for doing a movc3 op.  movc3 next_devnam_len,- ; Set up for doing $getdvi on next  next_devnam_buf,- ; volume in set.  devnam_buf  popr #^m  movl next_devnam_len,- ; Make sure device name length is ok.  devnam_desc  movl next_devnam_len,-  devnam_len  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. /; 0 1search_bitmap: 2 3 movl #1,r5 ; r5 is volume pointer. 4 510$: 6 jsb read_bitmap 7 on_err search_bitmap_exit 8 9 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 A B20$: C movl (r11)[r10],r9 ; Get next entry in ifb. D clrl r8 ; Bit pointer into entry. E movl #32,r7 ; Size of entry to search, in bits. F G30$: H ffs r8,r7,r9,r8 ; Look for a set bit. I beql 40$ ; Is there a bit set? J K jsb read_write_header ; Yes, get information on this header. L on_err search_bitmap_exit M N subl3 r8,#32,r7 ; Any more bits to check O bgtr 30$ ; in this entry? P Q40$: R aobleq r6,r10,20$ ; Get next entry if max not reached. S T aobleq volset_cnt,r5,10$ ; Next volume U V calls #0,g^write_totals ; Write total blocks allocated and W on_err search_bitmap_exit ; used. X Ysearch_bitmap_exit: Z rsb [ \ .sbttl Read and Write Header Information ]; ^; This routine reads a file header from disk and outputs selected _; information about the header. `; aread_write_header: b c; d; Compute page offset in memory of where the header is mapped. e; f incl r8 ; Compute file id as (bit pos +1) + g movl r10,r2 ; 32 * (number of bitmap long word). h ashl #5,r2,r2 ; i addl2 r8,r2 ; r2 has file number. j cmpl r4,r2 ; Is this file header in memory? k blss 40$ l brw in_memory ; Yes. m n40$: o tstl return_addr ; No, see if we need to perform p beql 60$ ; any "unmapping" first. q $deltva_s - r inadr=return_addr s on_err read_write_header_exit t u60$: v addl3 header_offset[r5],r2,r1 ; Get where to start read from disk. w x $crmpsc_s - ; Bring the headers into memory. y inadr=input_addr,- z retadr=return_addr,- { flags=#sect_flag,- | chan=ifb_channel[r5],- } pagcnt=mapped_pages,- ~ vbn=r1,-  pfc=pf_cluster  cmpl #ss$_endoffile,r0 ; Did we reach end-of-file?  bneq 80$  movl #32,r8 ; Yes, fix things up so that  addl3 #1,r6,r10 ; we move on to the next volume  clrq return_addr ; (if there is one).  movl #ss$_normal,r0  brw read_write_header_exit  80$:  on_err read_write_header_exit   subl3 #511,return_addr+4,r3 ; r3 has start addr of max hdr.  subl3 return_addr,- ; Compute highest numbered file number  return_addr+4,r4 ; in memory.  ashl #-9,r4,r4  addl3 r2,r4,r4  in_memory:  subl3 r2,r4,r2 ; Header location in memory is:  ashl #9,r2,r2 ; loc = r3 - 512 * (max_files - r2)  subl3 r2,r3,r2  ; ; Check for a valid header. ;  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?  beql 30$  brw read_write_header_exit ; No, this is not a valid header.  30$:  tstw fh2$w_checksum(r2) ; Is the checksum 0?  bneq 40$  brw read_write_header_exit ; Yes, this is not a valid header.  40$:  ; ; Header is valid, does file meet our criteria for reporting? ;  rotl #16,fh2$l_alloc(r2),r1 ; Is file large enough?  cmpl min_file_size,r1  bleq 50$  brw read_write_header_exit  50$:  tstl grp_uic ; Should we test file group uic?  blss 60$  cmpw grp_uic,- ; Yes, do the group uic's match?  fh2$w_uicgroup(r2)  beql 60$ ; Yes, keep on checking.  brw read_write_header_exit ; No, don't report.  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$: 0 movl (sp)+,r6 1 movc3 r6,(sp),@4(r7) ; Adjust descriptor. 2 addl2 r6,sp 3 addl2 r6,(r7) 4 addl2 r6,4(r7) 5 6 movl #ss$_normal,r0 ; Indicate success. 7 8bk_link_exit: 9 ret : ; .end files