From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  5-JUL-1989 20:22
To:	MRGATE::"ARISIA::EVERHART"
Subj:	backup journal file format

Message-Id:  <8907060016.AA07096@crdgw1.ge.com>
Received: From KL.SRI.COM ([0.0.0.0]) by CRVAX.SRI.COM with TCP; Wed,  5 JUL 89 16:35:08 PDT
Received: from CUNYVM.CUNY.EDU by KL.SRI.COM with TCP; Wed, 5 Jul 89 16:26:21 PDT
Received: from DGOGWDG5.BITNET by CUNYVM.CUNY.EDU (IBM VM SMTP R1.1) with BSMTP id 7981; Wed, 05 Jul 89 19:20:40 EDT
Date:    Wed,  5 Jul 1989 14:19:42  +0200
From: "GWDGV1::MOELLER"  <U0012%DGOGWDG5.BITNET@CUNYVM.CUNY.EDU>
To: info-vax@kl.sri.COM
Subject: backup journal file format

Greg Orman (Tigger <GREG%HMCVAX.BITNET@CUNYVM.CUNY.EDU>) asked:
> Does anyone out there still have VMS V3 docs?  Or some other source for the
> information that I need?  What I'm looking for is the BACKUP journal file
> format.
> ...

I probably have the old doc's around somewhere,
but maybe the following program will also help.
It displays the contents (all that's to it) of a BACKUP journal file
and it does handle the small extension that has been introduced
in VMS V4.

At the low level, a BACKUP journal file is just a stream of bytes,
and has traditionally been processed by BACKUP in block mode.
Its 'record structure' is foreign to RMS, but interesting since
it can be processed forward & backward:

        .byte   L1
        .blkb   L1              ; 1st 'record' (size = L1 bytes)
        .byte   L1.xor.L2
        .blkb   L2              ; 2nd 'record' (size = L2 bytes)
        .byte   L2.xor.L3
        ...
        .blkb   Ln              ; last 'record' (size = Ln bytes)
        .byte   Ln

(In fact, a journal file can consist of more than 1 such 'section'.)

At the higher level, the 'records' have a first byte that classifies
the record type, as can be seen from the comments in ZB1.FOR
(symbolic definitions were never available, so I did not care
to use them).
The directory name records are compressed, in that their 2nd byte
indicates an offset into the 'previous' directory name, up to which
the names are equal, and that is followed by the XOR (again) of the
remainder of the 'current' and the 'previous' directory name.

To build:
        $ FOR ZB1
        $ MACRO BJLR+SYS$LIBRARY:LIB/LIB
        $ LINK ZB1,BJLR

(If you change the line
        k=bjl_r_open(fn(1:lfn))
into
        k=bjl_r_open(fn(1:lfn),.TRUE.)
the journal file will be dumped backwards!)

I also have a few simple program which manipulate journal files, like
append two of them (as BACKUP does when it 'updates' an old journal),
and delete a piece from a file. If there is sufficient interest ...

Enjoy,

Wolfgang J. Moeller, GWDG, D-3400 Goettingen, F.R.Germany | Disclaimer ...
Bitnet/Earn: U0012@DGOGWDG5         Phone: +49 551 201516 | No claim intended

$! ................... Cut between dotted lines and save. ...................
$!...........................................................................
$! VAX/VMS archive file created by VMS_SHARE V06.10 7-FEB-1989.
$!
$! VMS_SHARE was written by James Gray (Gray:OSBUSouth@Xerox.COM) from
$! VMS_SHAR by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au).
$!
$! To unpack, simply save, concatinate all parts into one file and
$! execute (@) that file.
$!
$! This archive was created by user MOELLER
$! on  5-JUL-1989 13:44:50.82.
$!
$! It contains the following 2 files:
$!        BJLR.MAR
$!        ZB1.FOR
$!
$!============================================================================
$ SET SYMBOL/SCOPE=( NOLOCAL, NOGLOBAL )
$ VERSION = F$GETSYI( "VERSION" )
$ IF VERSION .GES "V4.4" THEN GOTO VERSION_OK
$ WRITE SYS$OUTPUT "You are running VMS ''VERSION'; ", -
    "VMS_SHARE V06.10 7-FEB-1989 requires VMS V4.4 or higher."
$ EXIT 44 ! SS$_ABORT
$VERSION_OK:
$ GOTO START
$!
$UNPACK_FILE:
$ WRITE SYS$OUTPUT "Creating ''FILE_IS'"
$ DEFINE/USER_MODE SYS$OUTPUT NL:
$ EDIT/TPU/COMMAND=SYS$INPUT/NODISPLAY/OUTPUT='FILE_IS'/NOSECTION -
    VMS_SHARE_DUMMY.DUMMY
b_part := CREATE_BUFFER( "{Part}", GET_INFO( COMMAND_LINE, "file_name" ) )
; s_file_spec := GET_INFO( COMMAND_LINE, "output_file" ); SET( OUTPUT_FILE
, b_part, s_file_spec ); b_errors := CREATE_BUFFER( "{Errors}" ); i_errors
:= 0; pat_beg_1 := ANCHOR & "-+-+-+ Beginning"; pat_beg_2 := LINE_BEGIN
& "+-+-+-+ Beginning"; pat_end := ANCHOR & "+-+-+-+-+ End"; POSITION
( BEGINNING_OF( b_part ) ); LOOP EXITIF SEARCH( SPAN( ' ' )@r_trail
& LINE_END, FORWARD) = 0; POSITION( r_trail ); ERASE( r_trail ); ENDLOOP
; POSITION( BEGINNING_OF( b_part ) ); i_append_line := 0; LOOP EXITIF MARK
( NONE ) = END_OF( b_part ); s_x := ERASE_CHARACTER( 1 )
; IF s_x = '+' THEN r_skip := SEARCH( pat_beg_1, FORWARD, EXACT ); IF r_skip
<> 0 THEN s_x := ''; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ERASE_LINE; ENDIF
; ENDIF; IF s_x = '-' THEN r_skip := SEARCH( pat_end, FORWARD, EXACT )
; IF r_skip <> 0 THEN s_x := ''; MOVE_HORIZONTAL( -CURRENT_OFFSET ); m_skip
:= MARK( NONE ); r_skip := SEARCH( pat_beg_2, FORWARD, EXACT ); IF r_skip
<> 0 THEN POSITION( END_OF( r_skip ) ); MOVE_HORIZONTAL( -CURRENT_OFFSET )
; MOVE_VERTICAL( 1 ); MOVE_HORIZONTAL( -1 ); ELSE POSITION( END_OF( b_part
) ); ENDIF; ERASE( CREATE_RANGE( m_skip, MARK( NONE ), NONE ) ); ENDIF; ENDIF
; IF s_x = 'V' THEN s_x := ''; IF i_append_line <> 0 THEN APPEND_LINE
; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF; i_append_line := 1
; MOVE_VERTICAL( 1 ); ENDIF; IF s_x = 'X' THEN s_x := ''; IF i_append_line
<> 0 THEN APPEND_LINE; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF
; i_append_line := 0; MOVE_VERTICAL( 1 ); ENDIF; IF s_x <> '' THEN i_errors
:= i_errors + 1; s_text := CURRENT_LINE; POSITION( b_errors ); COPY_TEXT
( "The following line could not be unpacked properly:" ); SPLIT_LINE
; COPY_TEXT( s_x ); COPY_TEXT( s_text ); POSITION( b_part ); MOVE_VERTICAL
( 1 ); ENDIF; ENDLOOP; POSITION( BEGINNING_OF( b_part ) ); LOOP r_x := SEARCH
( "`", FORWARD, EXACT ); EXITIF r_x = 0; POSITION( r_x ); ERASE_CHARACTER
( 1 ); COPY_TEXT( ASCII( INT( ERASE_CHARACTER( 3 ) ) ) ); ENDLOOP
; IF i_errors = 0 THEN SET( NO_WRITE, b_errors, ON ); ELSE POSITION
( BEGINNING_OF( b_errors ) ); COPY_TEXT( FAO
( "The following !UL errors were detected while unpacking !AS", i_errors
, s_file_spec ) ); SPLIT_LINE; SET( OUTPUT_FILE, b_errors, "SYS$COMMAND" )
; ENDIF; EXIT;
$ DELETE VMS_SHARE_DUMMY.DUMMY;*
$ CHECKSUM 'FILE_IS
$ WRITE SYS$OUTPUT " CHECKSUM ", -
  F$ELEMENT( CHECKSUM_IS .EQ. CHECKSUM$CHECKSUM, ",", "failed!!,passed." )
$ RETURN
$!
$START:
$ FILE_IS = "BJLR.MAR"
$ CHECKSUM_IS = 673215675
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X`009.title`009bjl_r`009subroutines for reading a BACKUP JOURNAL file
X;
X;`009w.j.m. dec 84
X;`009change apr 85: use multiblock i/o
X;`009update jun 85: edits, set nblk=9
X;
X;`009note: event flag #0 is used for $qiow
X;
X; entries:
X;
X;`009integer*4 function bjl_r_open(filespec[,reverse]) = status
X;`009character*(*) filespec`009! in
X;`009[logical*1 reverse]`009! in, def=.false.
X;`009... open for input, in either forward or reverse direction
X;
X;
X;`009integer*4 function bjl_r_byte(byte) = status
X;`009logical*1 byte`009`009! out
X;`009... get next byte (in specified direction)
X;
X;
X;`009integer*4 function bjl_r_bytes(array,count) = status
X;`009logical*1 array(count)`009! out
X;`009integer count`009`009! in
X;`009... get next "count" bytes (supposedly a record)
X;`009`009When reading backward, array is filled in reverse order,
X;`009`009therefore direction does not matter.
X;
X;
X;`009integer*4 function bjl_r_close() = status
X;`009... close input
X;
X;`009`009
X;*****
X;
Xnblk=9`009`009;buffer size (blocks)
X;
X`009$atrdef
X`009$fatdef`009`009; LIB.MLB
X;
X;
X`009.psect
X;
Xfab:`009$fab`009fna=0-0,fns=0-0,dnm=<.BJL>,-
X`009`009rfm=fix,mrs=1,fop=ufo,shr=<upi>
X;
Xrecattr:`009.blkb`009fat$c_length
X;
Xacc_dsc:`009.word`009atr$s_recattr,atr$c_recattr
X`009`009.address`009recattr
X`009`009.long`0090
X;
Xiosb:`009`009.blkw`0094
X;
Xl_hiblk:`009.blkl
Xl_efblk:`009.blkl
Xw_ffbyte:`009.blkw
X;
Xl_blkno:`009.blkl
Xl_bufpoi:`009.blka`009`009`009;point to block "l_blkno" w/i buffer
Xl_bufno:`009.blkl`009`009`009;blkno of 1st block in buffer
Xw_byteoff:`009.blkw
Xbuf:`009`009.blkb`009512*nblk
Xb_reverse:`009.blkb
X;
X;
X;*****
X;
X`009.entry`009bjl_r_open,`094m<>
X;
X`009clrb`009b_reverse`009`009`009;assume forward
X`009cmpb`009(ap),#2`009`009`009`009;2 args?
X`009blssu`0095$`009`009`009`009;br if yes
X`009movb`009@2*4(ap),b_reverse
X5$:
X;
X`009movq`009@1*4(ap),r0`009`009`009;set filespec from arg#1
X`009movl`009r1,fab+fab$l_fna
X`009movb`009r0,fab+fab$b_fns
X`009$open`009fab=fab
X`009blbs`009r0,19$
X`009ret
X19$:
X;
X`009$qiow_s`009func=#io$_access,-
X`009`009chan=fab+fab$l_stv,-
X`009`009iosb=iosb,-
X`009`009p5=#acc_dsc
X`009blbc`009r0,28$
X`009movzwl`009iosb,r0
X`009blbs`009r0,29$
X28$:`009ret
X29$:
X;
X`009rotl`009#16,recattr+fat$l_hiblk,l_hiblk
X`009rotl`009#16,recattr+fat$l_efblk,l_efblk
X`009movw`009recattr+fat$w_ffbyte,w_ffbyte
X;
X`009mnegl`009#1,l_bufno`009`009`009;set buffer invalid
X;
X`009blbc`009b_reverse,35$`009`009`009;br if forward direction
X;
X`009movl`009l_efblk,l_blkno
X`009movw`009w_ffbyte,w_byteoff`009`009;assumed 0..512-1
X`009brb`00938$
X35$:
X`009clrl`009l_blkno
X`009movw`009#512-1,w_byteoff
X38$:
X;
X`009tstl`009l_blkno
X`009beql`00949$
X`009cmpl`009l_blkno,l_hiblk
X`009bgtru`00949$
X`009bsbw`009read_block_r1
X`009blbc`009r0,99$
X49$:
X;
X`009movzbl`009#ss$_normal,r0
X;
X99$:
X`009ret
X;
X;
X;*****`009subroutine: read block given by l_blkno
X;`009`009returns status in r0
X;
Xread_block_r1:
X;
X`009clrl`009r1
X`009subl3`009#1,l_blkno,r0
X`009ediv`009#nblk,r0,r0,r1
X`009mull3`009#512,r1,-(sp)`009`009;compute offset in buffer
X`009movab`009buf,-(sp)
X`009addl3`009(sp)+,(sp)+,l_bufpoi
X`009cmpl`009r0,l_bufno`009`009;block in buffer?
X`009bneq`00921$`009`009`009;br if no
X`009movzbl`009#ss$_normal,r0`009`009;else all done
X`009rsb
X;
X21$:
X`009movl`009r0,l_bufno
X`009subl3`009r1,l_blkno,r1`009`009;r1 = start block
X`009addl3`009#nblk-1,r1,r0`009`009;r0 = end block
X`009cmpl`009r0,l_hiblk`009`009;beyond eof?
X`009blequ`00923$`009`009`009;br if no
X`009movl`009l_hiblk,r0
X23$:
X`009subl`009r1,r0
X`009incl`009r0`009`009`009;r0 = #blocks to be read
X`009bgtr`00924$`009`009`009;br if >0
X`009movzwl`009#ss$_endoffile,r0`009;return eof status
X`009rsb
X24$:
X`009mull`009#512,r0
X`009$qiow_s`009func=#io$_readvblk,-
X`009`009chan=fab+fab$l_stv,-
X`009`009iosb=iosb,-
X`009`009p1=buf,p2=r0,p3=r1
X`009blbc`009r0,99$
X`009movzwl`009iosb,r0
X;
X99$:
X`009rsb
X;
X;
X;*****`009subroutine: get next byte (ggf. updates w_byteoff & l_blkno)
X;`009`009returns r0=status, r1=byte
X;
Xget_byte_r1:
X;
X`009blbc`009b_reverse,20$`009`009`009;br if forward direction
X;
X10$:`009`009`009`009`009`009;reverse
X`009cvtwl`009w_byteoff,r1
X;
X`009tstl`009r1
X`009bgtr`00918$
X`009decl`009l_blkno
X`009bgtru`00913$
X`009movzwl`009#ss$_endoffile,r0
X`009rsb
X13$:
X`009addw3`009#512,r1,w_byteoff
X`009bsbw`009read_block_r1`009`009`009;read previous block
X`009blbs`009r0,10$`009`009`009`009;& try again
X`009rsb
X;
X18$:
X`009decl`009r1
X`009brb`00940$
X;
X20$:
X`009cvtwl`009w_byteoff,r1`009`009`009;forward
X;
X`009cmpl`009l_blkno,l_efblk
X`009blssu`00924$
X`009bgtru`00923$
X`009incl`009r1
X`009cmpw`009r1,w_ffbyte`009`009`009;w/i last block
X`009blss`00940$
X23$:`009`009`009`009`009`009;at eof
X`009movzwl`009#ss$_endoffile,r0
X`009rsb
X24$:
X`009cmpl`009r1,#512-1
X`009blss`00928$
X;
X`009cmpl`009l_blkno,l_hiblk
X`009beql`00923$`009`009`009`009;don't read beyond hiblk
X`009incl`009l_blkno
X`009subw3`009#512,r1,w_byteoff
X`009bsbw`009read_block_r1`009`009`009;read next block
X`009blbs`009r0,20$`009`009`009`009;& try again
X`009rsb
X;
X28$:
X`009incl`009r1
X;
X40$:
X`009movw`009r1,w_byteoff
X`009movzbl`009@l_bufpoi[r1],r1
X`009movzbl`009#ss$_normal,r0
X`009rsb
X;
X;
X;*****
X;
X`009.entry`009bjl_r_byte,`094m<>
X;
X`009bsbw`009get_byte_r1
X`009blbc`009r0,99$
X;
X`009movb`009r1,@1*4(ap)
X99$:
X`009ret
X;
X;
X;*****
X;
X`009.entry`009bjl_r_bytes,`094m<r2,r3>
X;
X`009movab`009@1*4(ap),r2`009`009`009;start of array
X`009movl`009@2*4(ap),r3`009`009`009;count
X`009blbc`009b_reverse,28$
X`009addl`009r3,r2`009`009`009`009;if reverse, point to end
X`009brb`00928$
X;
X20$:
X`009bsbw`009get_byte_r1
X`009blbc`009r0,99$
X;
X`009blbc`009b_reverse,25$
X`009movb`009r1,-(r2)`009`009`009;reverse: decrement addr.
X`009brb`00928$
X25$:
X`009movb`009r1,(r2)+`009`009`009;forward: increment addr.
X;
X28$:
X`009sobgeq`009r3,20$
X;
X`009movzbl`009#ss$_normal,r0
X99$:
X`009ret
X;
X;
X;*****
X;
X`009.entry`009bjl_r_close,`094m<>
X;
X`009$dassgn_s`009chan=fab+fab$l_stv
X;
X`009ret
X;
X;
X`009.end
$ GOSUB UNPACK_FILE

$ FILE_IS = "ZB1.FOR"
$ CHECKSUM_IS = 1010377049
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
Xc`009dump BACKUP .BJL file
Xc
Xc`009w.j.m. dec 1984 (vms v3, struclev=0101)
Xc`009mod oct 1985 wjm: file flag longword with vms v4 (struclev=0201),
Xc`009`009`009  support long output
Xc
Xc
X`009character fn*255
X`009integer k,lfn,l1,l2
X`009logical*1 l1b,l2b
Xc
X`009external ss$_endoffile
X`009integer bjl_r_open,bjl_r_byte,bjl_r_close
Xc
Xc
Xc***
Xc
X`009k=lib$get_input(fn,'Journal file: ',lfn)
X`009if(.not.k) stop
Xc
X`009k=bjl_r_open(fn(1:lfn))
X`009if(.not.k) then
X`009`009call lib$stop(%val(k))
X`009endif
Xc
X`009open(unit=6,file='SYS$OUTPUT:',status='new',
X     1`009     recl=260,carriagecontrol='fortran',
X     2`009     access='sequential',form='formatted')
Xc
Xc
X30`009continue`009! new .BJL file
Xc
X`009k=bjl_r_byte(l1b)
X`009if(.not.k) then
X`009`009if(k.eq.%loc(ss$_endoffile)) goto 80`009! eof
X`009`009call lib$stop(%val(k))
X`009endif
Xd`009type *,'input: ',zext(l1b)
Xc
X`009l1=zext(l1b)
Xd`009type *,'l1=',l1
X`009call lib$put_output('%ZBJL-I-Start of BACKUP Journal section')
X`009if(l1.eq.0) goto 49
Xc
X40`009continue
X`009call bjldump(l1)
Xc
X`009k=bjl_r_byte(l2b)
X`009if(.not.k) then
X`009`009call lib$stop(%val(k))
X`009endif
Xd`009type *,'input: ',zext(l2b)
Xc
X`009l2=zext(l2b)
X`009l1=l1.xor.l2
X`009if(l1.ne.0) goto 40
Xc
X49`009continue
X`009call lib$put_output('%ZBJL-I-End of BACKUP Journal section')
Xc
X`009goto 30
Xc
Xc
X80`009continue
X`009k=bjl_r_close()
X`009if(.not.k) then
X`009`009call lib$stop(%val(k))
X`009endif
Xc
X`009call lib$put_output('%ZBJL-I-End of BACKUP Journal file')
X`009call exit
X`009end
Xc
Xc+++++
Xc
X`009subroutine bjldump(l)`009! dump .BJL record
X`009integer l`009! in, record length
Xc
Xc`009called when record length (=l) has been read
Xc`009returns after reading the given number of bytes
Xc
X`009character*255 buf
X`009character*24 timbuf
X`009integer*2 timlen
X`009integer i,k,jrtyp,ll,ld,ioff,relvol
X`009logical*1 dirnam(255)/255*0/
X`009integer*4 fflag
X`009logical*1 str1,str2
Xc
X`009integer bjl_r_bytes
Xc
Xc
Xc***
Xc
X`009k=bjl_r_bytes(%ref(buf(1:l)),l)
X`009if(.not.k) then
X`009`009call lib$stop(%val(k))
X`009endif
Xc
X`009jrtyp=ichar(buf(1:1))
Xc
X`009goto(30,31,32,33,34),jrtyp+1
X`009write(6,129) jrtyp
X129`009format(' %ZBJL-E-Unexpected record type %x',z2.2)
X`009ll=0
X`009goto 40
Xc
Xc
X30`009continue`009!`009STRUCLEV = 0
Xc
X`009str1=ichar(buf(2:2))
X`009str2=ichar(buf(3:3))
X`009write(6,1301) str1,str2
X1301`009format(' BACKUP Journal Structure level %x',2z2.2)
X`009ll=2
X`009goto 40
Xc
Xc
X31`009continue`009!`009SSNAME = 1
Xc
X`009call sys$asctim(timlen,timbuf,%ref(buf(2:9)),%val(0))
X`009write(6,1311) buf(10:l),timbuf(1:timlen)
X1311`009format(' Save set ',a,' dated ',a)
X`009goto 50
Xc
Xc
X32`009continue`009!`009VOLUME = 2
Xc
X`009relvol=ichar(buf(14:14))+ichar(buf(15:15))*256
X`009write(6,1321) relvol,buf(2:13)
X1321`009format(' Volume number',i6.5,' labelled "',a,'"')
X`009ll=12+2
X`009goto 40
Xc
Xc
X33`009continue`009!`009DIRECTORY = 3
Xc
X`009ioff=ichar(buf(2:2))
X`009do i=3,l
X`009`009dirnam(i-2+ioff)=dirnam(i-2+ioff).xor.ichar(buf(i:i))
X`009enddo
X`009ld=255
X`009do i=1,255
X`009`009if(dirnam(i).eq.0) then
X`009`009`009ld=i-1
X`009`009`009goto 333
X`009`009endif
X`009enddo
X333`009continue
X`009write(6,1331) (dirnam(i),i=1,ld)
X1331`009format(' [',<ld>a1,']')
X`009goto 50
Xc
Xc
X34`009continue`009!`009FILE = 4
Xc
X`009if(str1.eq.1) then
X`009`009write(6,1341) buf(2:l)
X`009else
X`009`009call lib$movc3(4,%ref(buf(l-3:l)),fflag)
X`009`009if(fflag.eq.0) then
X`009`009`009write(6,1341) buf(2:l-4)
X`009`009elseif(fflag.eq.1) then
X`009`009`009write(6,1341) buf(2:l-4)//' file header only'
X`009`009else
X`009`009`009write(6,1341) buf(2:l-4)
X`009`009`009write(6,1342) fflag
X`009`009endif
X`009endif
X1341`009format(' `009',a)`009`009`009!!! 'blank tab'
X1342`009format(' %ZBJL-W-Unknown file flags %x',z8.8,' for above file')
X`009goto 50
Xc
Xc
X40`009continue
X`009if(ll+1.ge.l) goto 50
X`009write(6,141) (ichar(buf(i:i)),i=1+ll+1,l)
X141`009format(' %ZBJL-W-Extra bytes (hex):',20(1x,z2))
Xc
X50`009continue
X`009return
X`009end
$ GOSUB UNPACK_FILE
$ EXIT

