!***************************************************************************
!DSKACT.BAS - DISK ACCOUNTING (a "Verify Plus" program)
! by Dave Heyliger - AMUS Staf
!
! DSKACT was created to discover file differences over a given time. These
! file differences include: new PPNs, new files, deleted PPNs, deleted files,
! and hash code differences (if any) of existing files. DSKACT will produce
! three user-defined output filespecs that contain the following:
! 1) A list of all deleted files in full filespec format.
! 2) A list of all added files in full filespec format.
! 3) A list of all files whose hash codes have changed.
!
! This program was originally created to discover what files were added/
! changed to the AM3000 when software testing was performed. The output file-
! specs make it easy to discover what needs to be deleted/restored, etc...
! to get the computer "back to normal". However, there are many uses for this
! program. For example, if you are nervous about a VIRUS, well, this is great
! protection. In addition, the output files are easily modified to be used
! with a .CMD file etc, for ERASING or what-have-you.
!
! To execute DSKACT, the following must be true:
! 1) You have an "old" file containing a logical device's files + hashes
! that was created with the AMOS command
! ".DIR/D/H/K file.ext=Dev#:[]"
! executed from the OPR: account.
! 2) You have created a "new" file containing the same as in (1) above
! created in the same fashion as (1) above (usually the next day,
! week, or what-have-you). The name of this file is different, of
! course.
!
! Note: you do NOT need to do the entire device. For example, to just
! check certain PPNs on a logical, you could use the following:
! ".DIR/D/H/K file.ext = Dev#:[P,PN]"
! Also, as a rule of thumb, the directory file size in blocks will
! be the "Grand total" number of files divided by 10.
!
! As an example run of DSKACT, let's use the AMUS DAILY BACKUP command file.
! For example, in AMUS' DAILY BACKUP I do the following for DSK2: from the
! OPR: account.
! 1) Make a "new" directory file with ".DIR/D/H/K DISK2.NEW = DSK2:[]".
! The "/K" option will erase DISK2.NEW if already present before
! creating DISK2.NEW (just in case). DISK2.OLD is assumed to already
! exist.
! 2) .RUN DSKACT, which requires the following input:
! "old" file list: DISK2.OLD
! "new" file list: DISK2.NEW
! filename to contain deleted files: DISK2.DEL
! filename to contain added files: DISK2.ADD
! filename to contain hash differences: DISK2.HSH
! Once DSKACT is complete, DISK2.DEL, DISK2.ADD, and DISK2.HSH contain all
! of the disk's activity in full filespec format.
! 3) Finally, I ".RENAME DISK2.OLD=DISK2.NEW/D" to first delete the
! "old" file listing and then rename the "new" file list to ".OLD".
! The output files are then examined, saved, or whatever you want!
!
!***************************************************************************
MAP1 old'count,F,6 ! number of files in a yesterday's PPN
MAP1 new'count,F,6 ! number of files in today's PPN
MAP1 old'index,F,6 ! index into old'list array
MAP1 new'index,F,6 ! index into new'list array
MAP1 old'next'list,S,50 ! filename of "next PPN" - yesterday
MAP1 new'next'list,S,50 ! filename of "next PPN" - today
MAP1 files'dsk,S,10 ! the "Dev#:" of the filespec
MAP1 files'ppn,S,10 ! the "PPN" of the filepsec
MAP1 files'account,S,20 ! the "Dev#:[PPN] of the filespec"
MAP1 old'project,S,3 ! the P in Ppn of an old filespec
MAP1 old'prg'number,S,3 ! the PN in pPN of an old filespec
MAP1 new'project,S,3 ! similar as above, but for new files
MAP1 new'prg'number,S,3
MAP1 temp,F,6 ! a stupid floating point number
BEGIN:
! Get the files necessary for operation
INPUT "Enter old FILE master list file: ", old'file
INPUT "Enter new FILE master list file: ", new'file
INPUT "Enter filespec which will contain DELETED files: ", del'file
INPUT "Enter filespec which will contain ADDED files: ", added'file
INPUT "Enter filepsec which will contain HASH differences: ", hash'file
! Open both MFD files, plus the DIR/D files (OLD and NEW).
! Also create an output file which will contain the stats
OPEN #1,old'file,INPUT ! open yesterdays file list
OPEN #2,new'file,INPUT ! open todays file list
OPEN #3,del'file,OUTPUT ! create new report file
OPEN #4,added'file,OUTPUT ! create new report file
OPEN #5,hash'file,OUTPUT ! create new report file
! Clear the screen, and initialize for first time through
? TAB(-1,0); TAB(-1,29);
old'next'list = ""
new'next'list = ""
! Get one file from ".OLD" list, including the file's account
INPUT LINE #1, filespec
IF EOF(1) &
THEN old'next'list = "." &
ELSE CALL GET'FILES'ACCOUNT : &
old'next'list = filespec : &
old'mfd'account = files'account
! Get one file from ".NEW" list, including the file's account
INPUT LINE #2, filespec
IF EOF(2) &
THEN new'next'list = "." &
ELSE CALL GET'FILES'ACCOUNT : &
new'next'list = filespec : &
new'mfd'account = files'account
! The following LOOP is repeated and is the main body of the prg.
! It analyses each PPN, discovering an ADDED, DELETED, or HASH change
!
! Test condition: If both files EOF, time to exit to dot
LOOP: IF old'next'list = "." &
THEN IF new'next'list = "." &
THEN ? TAB(-1,28) : &
END
! Test condition: If ".OLD" at EOF, ".NEW" must have new files
IF old'next'list = "." &
THEN CALL LIST'NEW'PPN : &
GOTO L2
! Test condition: If ".NEW" at EOF, ".OLD" must have deleted files
IF new'next'list = "." &
THEN CALL LIST'DELETED'PPN : &
GOTO L1
! Final test condition: if accounts the same, look for account file
! differences ELSE the accounts are different, so report account
! addition or deletion.
IF old'mfd'account = new'mfd'account &
THEN CALL FIND'DIFFERENCES &
ELSE CALL ADDED'OR'DELETED'PPN
! Once an account has been analysed, set new account specifications
! and get the file's account for both ".OLD" and ".NEW" filespecs
L1: IF old'next'list = "." &
THEN GOTO L2
filespec = old'next'list
CALL GET'FILES'ACCOUNT
old'mfd'account = files'account
L2:
IF new'next'list = "." &
THEN GOTO LOOP
filespec = new'next'list
CALL GET'FILES'ACCOUNT
new'mfd'account = files'account
! Finally, check the new PPN listing as before
GOTO LOOP
!SUBROUTINE FIND'DIFFERENCES
! On entry: ".OLD" and ".NEW" files contain the same account
! On exit: Changes in the given account are recorded
!
!
FIND'DIFFERENCES:
? TAB(6,30) "Reading " old'mfd'account ! display current PPN
CALL GET'OLD'PPN'FILES ! get old files for the PPN
CALL GET'NEW'PPN'FILES ! get new files for the PPN
? TAB(6,30) " "; ! clear out above message
CALL COMPARE'PPN'FILES ! compare files in the PPN
CALL OUTPUT'DIFFERENCES ! display the differences
RETURN ! and return
!SUBROUTINE GET'OLD'PPN'FILES
! On entry: ".OLD" file has 1 or more files in the current account
! being analysed.
! On exit: All files in the current account are in the old'list array.
! In addition, old'next'list contains next filespec in ".OLD"
GET'OLD'PPN'FILES:
! Establish first member of the array with old'next'list
old'count = 1
old'list(old'count) = old'next'list
! Get another file from ".OLD" If EOF, then mark end of list with "."
! and return
GOPF10: INPUT LINE #1,filespec
IF EOF(1) &
THEN old'next'list = "." : &
old'list(old'count+1) = "." : &
RETURN
! If NOT EOF, then get the files account and make sure it is the same
! as the current Dev#:[PPN]. If different, save the filespec just
! read in old'next'list, and return
CALL GET'FILES'ACCOUNT
IF files'account # old'mfd'account &
THEN old'next'list = filespec : RETURN
! Filespec read in is in the current PPN - place filespec into array
! and read another filespec
old'count = old'count + 1
old'list(old'count) = filespec
GOTO GOPF10
!SUBROUTINE GET'NEW'PPN'FILES
! On entry: ".NEW" file has 1 or more files in the current account
! being analysed.
! On exit: All files in the current account are in the new'list array.
! In addition, new'next'list contains next filespec in ".NEW"
!
GET'NEW'PPN'FILES:
! Establish first member of the array with new'next'list
new'count = 1
new'list(new'count) = new'next'list
! Get another file from ".NEW" If EOF, then mark end of list with "."
! and return
GNPF1: INPUT LINE #2,filespec
IF EOF(2) &
THEN new'next'list = "." : &
new'list(new'count+1) = "." : &
RETURN
! If NOT EOF, then get the files account and make sure it is the same
! as the current Dev#:[PPN]. If different, save the filespec just
! read in new'next'list, and return
CALL GET'FILES'ACCOUNT
IF files'account # new'mfd'account &
THEN new'next'list = filespec : RETURN
! Filespec read in is in the current PPN - place filespec into array
! and read another filespec
new'count = new'count + 1
new'list(new'count) = filespec
GOTO GNPF1
!SUBROUTINE GET'FILES'ACCOUNT
! On entry: filespec contains a "Dev#:filename.ext[P,PN]"
! On exit: files'account contains the "Dev#:[P,PN]"
!
GET'FILES'ACCOUNT:
files'dsk = LEFT(filespec,INSTR(1,filespec,":"))
files'ppn = MID(filespec,INSTR(1,filespec,"["),INSTR(1,filespec,"]"))
files'account = files'dsk + files'ppn
RETURN
!SUBROUTINE COMPARE'PPN'FILES
! On entry: both arrays called old'list() and new'list() contains
! files from a given account
! On exit: Differences are recorded in output files
!
COMPARE'PPN'FILES:
! Display the header message to the screen, and initialize the array
! index to "1".
? TAB(5,19); "Currently working on: ";
i = 1
! Scan the "new'list" array for the current file in the "old'list"
! array. If and when they match, make both array elements null
! strings (""). To speed things up, bypass all elements in the
! new'list array if they have already been nulled. Display the
! old'list element while scanning.
CPF10: FOR j = 1 to new'count
IF new'list(j) = "" THEN NEXT j
? TAB(5,41); : ? LEFT(old'list(i),30);
! If the new'list element is "", then get the next element. Then,
! if we are at the end of the new'list array, the old'list element
! will NOT be nulled to "". Then, if not at the end of the old'list,
! get the next file in the old'list and restart at CPF10
CPF20: IF new'list(j) = "" &
THEN j = j + 1 : &
IF j > new'count &
THEN i = i + 1 : &
IF i <= old'count &
THEN GOTO CPF10 &
ELSE RETURN
! However, if the new'list element is NOT "", see if the old'list &
! new'list element filenames match. If they match, record hash code
! changes if necessary, null both strings to "", and check end cond.
! And, (finally) if the new'list element is NOT "" and it DOESN'T
! match, then get the next new'list element, check end cond. & act
IF LEFT(old'list(i),30) = LEFT(new'list(j),30) &
THEN CALL COMPARE'HASH'TOTALS : &
old'list(i) = "" : &
new'list(j) = "" : &
i = i + 1 : &
IF i <= old'count &
THEN GOTO CPF10 &
ELSE RETURN &
ELSE j = j + 1 : &
IF j > new'count &
THEN i = i + 1 : &
IF i <= old'count &
THEN GOTO CPF10 &
ELSE RETURN &
ELSE GOTO CPF20
!SUBROUTINE OUTPUT'DIFFERENCES
! On entry: both arrays old'list() and new'list() contain filenames
! if and only if the filenames were added/deleted
! On exit: these files will be placed in the correct list output file
!
OUTPUT'DIFFERENCES:
? " "
! Output all non-null strings in old'list to DELETED filespec
FOR i = 1 to old'count
IF old'list(i) # "" &
THEN ? #3, LEFT(old'list(i),30)
NEXT i
! Output all non-null strings in new'list to ADDED filespec
FOR i = 1 to new'count
IF new'list(i) # "" &
THEN ? #4, LEFT(new'list(i),30)
NEXT i
RETURN
!SUBROUTINE COMPARE'HASH'TOTALS
! On entry: ".OLD" filespec matched a ".NEW" filespec
! On exit: If hash code totals are different, this difference is
! recorded in the proper output filespec
!
COMPARE'HASH'TOTALS:
IF MID(old'list(i),31,15) # MID(new'list(j),31,15) &
THEN ? #5, LEFT(old'list(i),30)
RETURN
!SUBROUTINE ADDED'OR'DELETED'PPN
! On entry: file accounts didn't match between ".OLD" and ".NEW"
! On exit: depending on the P and PN values, either deleted or
! added files listed in proper output filespec.
!
ADDED'OR'DELETED'PPN:
! Get the P and PN of the old MFD account
temp = INSTR(1,old'mfd'account,",")
old'project = MID(old'mfd'account,7,temp-7)
old'prg'number = MID(old'mfd'account, &
temp+1,LEN(old'mfd'account)-temp-1)
! Get the P and PN of the new MFD account
temp = INSTR(1,new'mfd'account,",")
new'project = MID(new'mfd'account,7,temp-7)
new'prg'number = MID(new'mfd'account, &
temp+1,LEN(new'mfd'account)-temp-1)
! If the old P is larger than the new P, must be a new PPN
IF VAL(old'project) > VAL(new'project) &
THEN CALL LIST'NEW'PPN : &
RETURN
! If the old P is less than the new P, must be a deleted PPN
IF VAL(old'project) < VAL(new'project) &
THEN CALL LIST'DELETED'PPN : &
RETURN
! Else, the PN will give it away as to new or old PPN
IF VAL(new'prg'number) < VAL(old'prg'number) &
THEN CALL LIST'NEW'PPN &
ELSE CALL LIST'DELETED'PPN
RETURN
!SUBROUTINE LIST'NEW'PPN
! On entry: A new PPN has been found in ".NEW"
! On exit: The contents of this PPN are listed in added output filespec
! and the next filespec is contained in new'next'list
!
LIST'NEW'PPN:
! Output what's been new
? TAB(6,30); "New PPN Addition - ";
? new'mfd'account;
! Then output all new files as long as the PPN doesn't change
! If it changes, record the changes and return
? #4, LEFT(new'next'list,30)
LNP1: INPUT LINE #2,filespec
IF EOF(2) &
THEN new'next'list = "." : &
? TAB(6,30); " "; : &
RETURN
CALL GET'FILES'ACCOUNT
IF files'account # new'mfd'account &
THEN new'next'list = filespec : &
CALL GET'FILES'ACCOUNT : &
new'mfd'account = files'account : &
? TAB(6,30); " "; : &
RETURN
? #4, LEFT(filespec,30)
GOTO LNP1
!SUBROUTINE LIST'DELETED'PPN
! On entry: An old PPN has been deleted
! On exit: The contents of this PPN are listed in deleted output file
! and the next filespec is contained in old'next'list
!
LIST'DELETED'PPN:
! Output the PPN that was deleted
? TAB (6,30); "PPN Deletion - ";
? old'mfd'account;
? #3, LEFT(old'next'list,30)
! Output each file in the PPN until the PPN changes. When it does
! change, record the change and return
LDP1: INPUT LINE #1,filespec
IF EOF(1) &
THEN old'next'list = "." : &
? TAB(6,30); " "; : &
RETURN
CALL GET'FILES'ACCOUNT
IF files'account # old'mfd'account &
THEN old'next'list = filespec : &
CALL GET'FILES'ACCOUNT : &
old'mfd'account = files'account : &
? TAB(6,30); " "; : &
RETURN
? #3,LEFT(filespec,30)
GOTO LDP1