!*************************************************************************** !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'file,S,10,"" ! file containing yesterdays files MAP1 new'file,S,10,"" ! file containing todays files MAP1 del'file,S,10,"" ! file containing deleted files MAP1 added'file,S,10,"" ! file containing added files MAP1 hash'file,S,10,"" ! file containing hash-differences MAP1 old'mfd'account,S,20 ! old MFD account spec MAP1 new'mfd'account,S,20 ! new MFD account spec MAP1 filespec,S,50 ! individual filespec MAP1 old'list(800),S,50 ! array holding yesterday's PPN files MAP1 new'list(800),S,50 ! array holding today's PPN files 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