!*************************** AMUS Program Label ******************************
! Filename: UFDSAV.RUN (d/basic) Date: 06/12/89
! Category: DISK Hash Code: 146-144-030-164 Version: 1.0(105)
! Initials: AMI Name: AMI BAR-YADIN
! Company: UNITED FASHIONS OF TEXAS Telephone #: 5126312277
! Related Files: SBR'S: DISKIO,DEVCHR,WRTREC,HASH,DATES
! Min. Op. Sys.: na Expertise Level: NOV
! Special: requires d/basic (but could be converted :-)
! Description: Writes the system structure (label,mfd,ufd) of a disk to a file
!
!
!*****************************************************************************
!* Updated on 12-Jun-89 at 8:08 PM by Ami Bar-Yadin; edit time: 3:55:07 *!
PROGRAM UFDSAV,1.0(105) ! save disk system structure (label,mfd,ufd)
!
! (c) 1989 by Ami Bar-Yadin
!
! usage:
! .run ufdsav file=disk {/O} {/S}
!ie .run ufdsav dsk0.ufd=dsk0
!
! The 2nd backup fields in the disk label block are updated
! (after the label is saved) with today's date and the output
! file name.
!
! UFD save file format:
! The save file is mostly in binary format, however it may have
! an ASCII header, so long as each line has a ";" in column 1.
!
! There are four sections: ID, Label, MFD and UFD.
!
! The ID is a binary image as follows:
MAP1 ID
MAP2 ID'DEVNAM,S,8 ! null padded ASCII device name
MAP2 ID'BLKSIZ,B,4 ! size of each disk block
MAP2 ID'MFDBLKS,B,4 ! number of MFD blocks
MAP2 ID'UFDBLKS,B,4 ! number of UFD blocks
MAP2 ID'SAVDATE,B,4 ! system internal format
! The ID is followed by a 32-bit hash code for the ID data.
!
! Following the ID is a stream of disk blocks each preceeded by
! a block ID header and followed by a 32-bit hash code which
! includes the block ID data.
MAP1 BLOCK'ID ! (all zeros for disk label block)
MAP2 BID'BLKNUM,B,4 ! original disk block number
MAP2 BID'PPN,B,2 ! =0,0 for MFD blocks
MAP2 BID'RELBLK,B,2 ! relative to MFD/UFD (1st=1)
MAP2 BID'BUF,X,512 ! (buffer for IO and hash code)
!
! The Label is always one block long.
! The MFD blocks are saved one after the other and then
! the UFD blocks are saved, one PPN at a time, block after block.
!
! disk block formats
MAP1 LABEL,X,512
MAP1 LABELX,@LABEL
MAP2 LBL'OKFLAG,B,4
MAP2 LBL'VOLNAM,S,40
MAP2 LBL'VOLID,S,10
MAP2 LBL'CREATOR,S,30
MAP2 LBL'INSTALATION,S,30
MAP2 LBL'SYSNAM,S,30
MAP2 LBL'CREATED,B,4 ! D,M,W,Y separated,word swapped
MAP2 LBL'ACCESSED,B,4
MAP2 LBL'BACKUP1,B,4
MAP2 LBL'BACKVOL1,S,10
MAP2 LBL'BACKUP2,B,4
MAP2 LBL'BACKVOL2,S,10
! save file ID debug info format
MAP1 FH$,S,80, &
"Save file ID: \2345\ block=### MFDs=\-\ UFDs=\---\ \234567\ hash=\234567\"
! block ID debug info format
MAP1 BH$,S,80, &
"Block ID: block=###### PPN=\23456\ relative=#### hash=\234567\"
MAP1 SILENT'FLAG,F
MAP1 OUTFIL,S,30
MAP1 HASHCODE,B,4
MAP1 I,F
MAP1 J,F
MAP1 A$,S,15
!
!=======
!
UFDSAV:
++INCLUDE USMAC:MTMCSN
GOSUB SETUP
GOSUB SHOW'LABEL ! read label and display some fields
GOSUB WRITE'ID
GOSUB SAVE'LABEL
GOSUB SAVE'MFD
GOSUB SAVE'UFD
GOSUB UPDATE'LABEL
EXIT:
IF OUTFIL<>SPACE CLOSE #1
END
SETUP:
PRINT .pgmname;" v";.pgmversion
IF INSTR(1,.options,"/S") SILENT'FLAG=-1
I=INSTR(1,.options,"=")
WHEN I=0
! PRINT "?Command line error" : END
PRINT "%No file output; DEBUG ONLY run."
OUTFIL=SPACE
ELSE
OUTFIL=.options[1,I-1]
WEND
ID'DEVNAM=parse(.options[I+1,-1])
XCALL DEVCHR,ID'DEVNAM,DEVCHR'MAP,ID'DEVNAM
IF (DEVCHR'FLAGS AND DCF'NODEVICE) &
PRINT "?No such device" : END
IF (DEVCHR'FLAGS AND DCF'FILSTRUC)=0 &
PRINT "?Device not file structured" : END
IF (DEVCHR'FLAGS AND DCF'MOUNTED)=0 &
PRINT "?Device not mounted." : END
XCALL DISKIO,0,DDB,BID'BUF,ID'DEVNAM
DFLG=DFLG AND (NOT (DFERC OR DFBYP)) ! enable systm error trapping
WHEN OUTFIL<>SPACE
LOOKUP OUTFIL,I
WHEN I<>0
IF INSTR(1,.options,"/O")=0 &
PRINT "?Output file exists." : END
KILL OUTFIL
WEND
OPEN #1,OUTFIL,OUTPUT
PRINT #1 ";";STAMP$()
WEND
RETURN
WRITE'ID:
ID'BLKSIZ=DEVCHR'BLKSIZE ! set block size
XCALL DATES,1,0,0,ID'SAVDATE ! set save date
GOSUB COUNT'MFD'BLOCKS
GOSUB COUNT'UFD'BLOCKS
XCALL HASH,ID,HASHCODE,0,1 ! one pass, all of id
WHEN OUTFIL<>SPACE
XCALL WRTREC,1,ID ! write ID
XCALL WRTREC,1,HASHCODE ! write ID hash code
ELSE
XCALL DATES,1,0,ID'SAVDATE,A$
PRINT USING FH$;ID'DEVNAM,ID'BLKSIZ,STR(ID'MFDBLKS), &
STR(ID'UFDBLKS),A$,HEX(HASHCODE)
WEND
RETURN
SAVE'MFD:
MFD'NEXT=1 ! start with MFD root block
IF OUTFIL<>SPACE AND SILENT'FLAG=0 PRINT "Saving MFD block ";
BID'RELBLK=0
WHILE MFD'NEXT
IF OUTFIL<>SPACE AND SILENT'FLAG=0 PRINT HEX(MFD'NEXT);" ";
MB=MFD'NEXT
XCALL DISKIO,1,DDB,MB,MFD
BID'BLKNUM=MB
BID'PPN=0
BID'RELBLK+=1
BID'BUF=MFD
GOSUB SAVE'BLOCK
WEND
IF SILENT'FLAG=0 PRINT
RETURN
SAVE'UFD:
IF OUTFIL<>SPACE AND SILENT'FLAG=0 PRINT "Saving UFD blocks: "
MFD'NEXT=1 ! start with MFD root block
WHILE MFD'NEXT
IF OUTFIL<>SPACE AND SILENT'FLAG=0 &
PRINT " MFD block ";HEX(MFD'NEXT)
MB=MFD'NEXT
XCALL DISKIO,1,DDB,MB,MFD ! read MFD block
FOR I=1 TO MFD'ENTRIES
WHEN MFD'PPN(I)
PPN=MFD'PPN(I)
A$=OCT(PPN'PROJ)+","+OCT(PPN'PROG)
UFD'NEXT=MFD'UFDLINK(I)
IF UFD'NEXT GOSUB SAVE'UFDS
WEND
NEXT
WEND
RETURN
SAVE'UFDS:
IF OUTFIL<>SPACE AND SILENT'FLAG=0 PRINT " ";A$;": ";
BID'RELBLK=0
WHILE UFD'NEXT
IF OUTFIL<>SPACE AND SILENT'FLAG=0 PRINT HEX(UFD'NEXT);" ";
UB=UFD'NEXT
XCALL DISKIO,1,DDB,UB,UFD
BID'BLKNUM=UB
BID'PPN=PPN
BID'RELBLK+=1
BID'BUF=UFD
GOSUB SAVE'BLOCK
WEND
IF SILENT'FLAG=0 PRINT
RETURN
LBLDATE=LBL'BACKUP1
XCALL DATES,1,0,LBLDATEX,A$
PRINT "Last backed up ";A$;" on ";LBL'BACKVOL1
LBLDATE=LBL'BACKUP2
XCALL DATES,1,0,LBLDATEX,A$
PRINT "Last UFD save ";A$;" on ";LBL'BACKVOL2
RETURN
UPDATE'LABEL:
WHEN OUTFIL=SPACE
PRINT "%Disk label not updated."
ELSE
XCALL DATES,1,0,ID'SAVDATE,LBLDATEX
LBL'BACKUP2=LBLDATE
LBL'BACKVOL2=OUTFIL
XCALL DATES,1,0,LBLDATEX,A$
PRINT "UFD saved ";A$;" on ";LBL'BACKVOL2
DOPN=0 !enable write
XCALL DISKIO,2,DDB,0,LABEL ! update disk label
DOPN=1 !disable write
WEND
RETURN
COUNT'MFD'BLOCKS:
IF SILENT'FLAG=0 PRINT "Counting MFD blocks: ";
ID'MFDBLKS=0
MFD'NEXT=1 ! start with MFD root block
WHILE MFD'NEXT
IF SILENT'FLAG=0 PRINT HEX(MFD'NEXT);" ";
ID'MFDBLKS+=1 ! count MFD block
MB=MFD'NEXT
XCALL DISKIO,1,DDB,MB,MFD ! read MFD block
WHEN MFD'NEXT>DEVCHR'BLOCKS ! check link to next block
PRINT &
"?Invalid next block link in MFD block ";HEX(MB)
BREAK
WEND
WEND
IF SILENT'FLAG=0 PRINT
RETURN
COUNT'UFD'BLOCKS:
ID'UFDBLKS=0
IF SILENT'FLAG=0 PRINT "Counting UFD blocks: "
MFD'NEXT=1 ! start with MFD root block
WHILE MFD'NEXT
IF SILENT'FLAG=0 PRINT " MFD block ";HEX(MFD'NEXT)
MB=MFD'NEXT
XCALL DISKIO,1,DDB,MB,MFD ! read MFD block
FOR I=1 TO MFD'ENTRIES
WHEN MFD'PPN(I)
PPN=MFD'PPN(I)
A$=OCT(PPN'PROJ)+","+OCT(PPN'PROG)
UFD'NEXT=MFD'UFDLINK(I)
WHEN UFD'NEXT
WHEN UFD'NEXT>DEVCHR'BLOCKS
PRINT &
"%Invalid UFD block link in entry";I;"of MFD block ";HEX(MB);" for ";A$
ELSE
GOSUB COUNT'UFDS
WEND
WEND
ELSE
IF MFD'UFDLINK(I) PRINT &
"%Non-zero block link for zero PPN in entry";I;"of MFD block ";HEX(MB)
WEND
NEXT
WEND
RETURN
COUNT'UFDS:
IF SILENT'FLAG=0 PRINT " ";A$;": ";
J=0
WHILE UFD'NEXT
IF SILENT'FLAG=0 PRINT HEX(UFD'NEXT);" ";
ID'UFDBLKS+=1
J+=1
UB=UFD'NEXT
XCALL DISKIO,1,DDB,UB,UFD ! read MFD block
WHEN UFD'NEXT>DEVCHR'BLOCKS
PRINT &
"?Invalid next block link in UFD block ";HEX(UB);", block";J;" of ";A$
BREAK
WEND
WEND
IF SILENT'FLAG=0 PRINT
RETURN
SAVE'BLOCK:
XCALL HASH,BLOCK'ID,HASHCODE,0,1
WHEN OUTFIL<>SPACE
XCALL WRTREC,1,BLOCK'ID
XCALL WRTREC,1,HASHCODE
ELSE
PPN=BID'PPN
A$=OCT(PPN'PROJ)+","+OCT(PPN'PROG)
PRINT USING BH$;BID'BLKNUM,A$,BID'RELBLK,HEX(HASHCODE)
WEND
RETURN