.title Files Program to Read Index Header File  .ident /2.3/ ; 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. *; +;-- , - .sbttl Symbols . / .library /SYS$LIBRARY:LIB.MLB/ 0 1 $dvidef ; Device definitions. 2 $fabdef ; File access block definitions. 3 $fh2def ; File-header definitions. 4 $fi2def ; File-header-id definitions. 5 $jpidef ; Job/process definitions. 6 $hm2def ; Home block definitions. 7 $secdef ; Mapping section definitions. 8 $ssdef ; Termination definitions. 9 $tpadef ; LIB$TPARSE definitions. : ; <; =; Note that $fh2def lacks the following definitions: >; ?fh2$t_fname = ^x50 @fh2$l_alloc = ^x18 ; Offset to blocks allocated. Afh2$l_used = ^x1c ; Offset to blocks used. B C D; E; Macro to help set up fabs for each volume in a volume set. F; G .macro mfab H $fab dnm=<[000000]INDEXF.SYS>,- I fna=devnam_buf,- J fop= K .endm mfab L M; N; Macro to handle return codes. O; P .macro on_err there,?here Q blbs r0,here R brw there Shere: .endm on_err T U V .sbttl Command line, prompts data W X .psect files_data,rd,wrt,noexe,long,shr,pic Y Zcommand_line_desc: [ .word command_line_buf_siz \ .word 0 ] .address command_line_buf ^ _command_line_buf: ; Store the command line here. ` .blkb 80 acommand_line_buf_siz = . - command_line_buf b ccommand_line_len: ; Store the command line length here. d .blkl 1 e fparse_blk: ; Parse block for LIB$TPARSE to g .long tpa$k_count0 ; parse command line. h .long tpa$m_abbrev ; Permit unambiguous abbreviations. i .blkb tpa$k_length0-8 j kmin_file_size: ; Search for files larger than l .blkl 1 ; this size. m ngrp_uic: ; Search for files with this group o .long -1 ; uic. p qmem_uic: ; Search for files with this group r .long -1 ; uic. s t .sbttl Device data u vdefault_disk: ; Use default if no disk given. w .ascid /SYS$DISK/ x yinit_dvi_itmlst: ; Item list to get the root device z .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. ( $tran '/' ; Another qualifier detected. ) $tran tpa$_symbol,tpa$_exit,- ; * ,,devnam_desc + , - $state ; Determine which qualifier. . $tran 'SIZE',get_size / $tran 'UIC',get_uic 0 1 $state get_uic ; Parse for getting the uic. 2 $tran '=' 3 $state 4 $tran '[' 5 6 $state 7 $tran '*',comma_check,,-1,grp_uic ; Check for [* 8 $tran tpa$_octal,get_mem_uic,,,grp_uic ; Check for [n 9 $tran tpa$_symbol,end_uic,cvt_chr_uic ; Check for [x : ; $state comma_check < $tran ']',start,,-1,mem_uic ; Check for [*] = $tran <','>,have_comma ; Check for [*, > ? $state get_mem_uic @ $tran <','> ; Check for [n, A $state have_comma B $tran tpa$_octal,,,,mem_uic ; Check for [*,n or [n,n C $tran '*',,,-1,mem_uic ; Check for [*,* or [n,* D E $state end_uic F $tran ']',start G H I $state get_size ; Parse for getting the minimum J $tran '=' ; file size K $state L $tran tpa$_decimal,start,,,min_file_size M N $end_state O P .sbttl LIB$TPARSE Action Routine for Character UIC. Q R; S; This action routine processes a character uic. $ASCTOID is called to T; perform the conversion. If the system service fails, or a non-uic id U; is detected, then an error status is returned. V; W X .entry cvt_chr_uic,^m Y Z $asctoid_s - ; Convert character uic to numeric. [ name=parse_blk+tpa$l_tokencnt,- \ id=grp_uic ] on_err cvt_chr_uic_exit ^ _ bicl3 #^x3fffffff,grp_uic,r5 ; Did we get a non-uic id? ` beqlu 20$ a pushal parse_blk+- ; Yes, capture the string and b tpa$l_tokencnt ; signal the error. c pushl #1 d pushl #fls_notuicid e calls #3,g^lib$signal f g20$: h movzwl grp_uic,mem_uic ; Put the group and member uic's into i ashl #<-16>,grp_uic,grp_uic ; separate longwords. j k movl #ss$_normal,r0 l mcvt_chr_uic_exit: n ret o p .sbttl Main program q .psect files_code,rd,nowrt,exe,long,shr,pic r .entry files,^m s t jsb parse_comm_line ; Override default values as necessary. u on_err main_exit v w jsb compute_offsets ; Compute offsets to 1st file header x on_err main_exit ; and other info. y z 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]   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. ;  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. 0 movl #32,r7 ; Size of entry to search, in bits. 1 230$: 3 ffs r8,r7,r9,r8 ; Look for a set bit. 4 beql 40$ ; Is there a bit set? 5 6 jsb read_write_header ; Yes, get information on this header. 7 on_err search_bitmap_exit 8 9 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 @ A calls #0,g^write_totals ; Write total blocks allocated and B on_err search_bitmap_exit ; used. C Dsearch_bitmap_exit: E rsb F G .sbttl Read and Write Header Information H; I; This routine reads a file header from disk and outputs selected J; information about the header. K; Lread_write_header: M N; O; Compute page offset in memory of where the header is mapped. P; Q incl r8 ; Compute file id as (bit pos +1) + R movl r10,r2 ; 32 * (number of bitmap long word). S ashl #5,r2,r2 ; T addl2 r8,r2 ; r2 has file number. U cmpl r4,r2 ; Is this file header in memory? V blss 40$ W brw in_memory ; Yes. X Y40$: Z tstl return_addr ; No, see if we need to perform [ beql 60$ ; any "unmapping" first. \ $deltva_s - ] inadr=return_addr ^ on_err read_write_header_exit _ `60$: a addl3 header_offset[r5],r2,r1 ; Get where to start read from disk. b c $crmpsc_s - ; Bring the headers into memory. d inadr=input_addr,- e retadr=return_addr,- f flags=#sect_flag,- g chan=ifb_channel[r5],- h pagcnt=mapped_pages,- i vbn=r1,- j pfc=pf_cluster k cmpl #ss$_endoffile,r0 ; Did we reach end-of-file? l bneq 80$ m movl #32,r8 ; Yes, fix things up so that n addl3 #1,r6,r10 ; we move on to the next volume o clrq return_addr ; (if there is one). p movl #ss$_normal,r0 q brw read_write_header_exit r s80$: t on_err read_write_header_exit u v subl3 #511,return_addr+4,r3 ; r3 has start addr of max hdr. w subl3 return_addr,- ; Compute highest numbered file number x return_addr+4,r4 ; in memory. y ashl #-9,r4,r4 z 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$:  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