home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 18 REXX
/
18-REXX.zip
/
rxrsync.zip
/
rxrsync.rex
< prev
next >
Wrap
OS/2 REXX Batch file
|
1999-11-10
|
11KB
|
386 lines
/* 10 November 1999. Daniel Hellerstein (danielh@crosslink.net)
Rexx procedures to implement the rsync differencing protocol
These OS/2 "classic" REXX callable procedures implement the Rsync
"client/server differencing" protocol. They require the RxRsync.DLL
(version 1.1).
Basically, rsync is used to form a "difference" between an "old" and a
"new" version of two files; one can then combine the "old" version
and the "difference" to construct an exact copy of the "new" version.
The following outlines there use (for details on rsync, and how to use
these procedures, please see rsync.doc).
I) Installation
1) Make sure that RxRsync.DLL is in your LIBPATH (say, copy it
to x:\OS2\DLL, or make sure it's in your current directory).
You will also need a copy of REXXUTIL, but that's part of
most OS/2 installations.
2) Write a REXX program, and include a copy of this file (say,
put it at the end of your file)
3) Call the procedures.
II) Description of procedures
There are three procedures:
rsync_client: creates a synopsis of an old version.
status=rsync_client(oldver_file,synopsis_file,comment,quiet,blocksize)
quiet, blocksize, and comment are optional parameters
Note that rsync_client has a few user changeable parameters
rsync_server: uses this synopsis, and the new version, to create
and rsync difference file
status=rsync_server(synopsis_string,newver_file,diff_file,quiet)
quiet is an optional parameter
rsync_undiff: uses the difference file, and the old version, to
build a copy of the new version
status=rsync_undiff(oldver_file,diff_file,newver_file_dup,quiet)
quiet is an optional parameters
Note that rsync_undiff has a few user changeable parameters
See RSYNCTST.CMD for an example of how to use RxRsync.cmd
*/
/*******************************************************************/
/* rsync_client: creates a synopsis of an old version.
status=rsync_client(oldver_file,synopsis_file,comment,quiet,blocksize)
quiet, blocksize, and comment are optional parameters
*/
rsync_client:procedure
/********* USER changeable parameters ************/
/* (larger blocksizes means smaller synopsis, but possibly larger difference */
blocksize=500
quiet=0 /* default status messages: 1-terse, 0=normal */
/**** END of USER changeable parameters ************/
parse arg afile,outfile,comment,verbo,bsize
a=rsync_load_dlls()
if a<>0 then return a
if afile='' then return "ERROR no old-version file specified"
if outfile='' then return "ERROR no synopsis-file specified "
if verbo<>'' then verbose=verbo
if bsize<>'' then do
if datatype(bsize)='NUM' then blocksize=bsize
end /* do */
select
when verbose=0 then verbose=1
when verbose=1 then verbose=0
otherwise nop
end
reportat=verbose
if verbose<2 then reportat=250000
crlf='0d0a'x
a=time('r')
if comment='' then comment=date('n')||' '||time('n')
/* read "Afile" */
aa=translate(stream(afile,'c','open read'))
if abbrev(aa,'READY')=0 then return "ERROR could not open "afile
isize=stream(afile,'c','query size')
if isize='' | isize=0 then do
return 'ERROR 'afile " is unaccessible"
exit
end
astuff=charin(afile,1,isize)
aa=stream(afile,'c','close')
amd4=rx_md4(astuff)
if verbose>0 then do
say "Rsync Client: read "isize" bytes from "afile
end
/* break into chunks of size blocksize, and compute "adler" and md4 checksums */
ifoo=trunc(isize/blocksize+0.999999)
/* Structure of client request file
Comment -- 80 characters (i.e.; requested file name)
1 space
Blocksize -- 6 digit integer
1 space
#Blocks -- 8 digit character
1 space
md4 -- 32 digit md4
3 spaces
rsync1||md41||..||rsyncN||md4||N -- rsync and md4 values (machine format)
*/
ac1=left(comment,80)||' '||left(blocksize,6)||' '||left(ifoo,8)||' '||amd4||' '
iat=1
do mm=1 to ifoo
if mm=ifoo then
ablock=substr(astuff,iat)
else
ablock=substr(astuff,iat,blocksize)
ac1=ac1||x2c(rx_rsync32_md4(ablock))
iat=iat+blocksize
end
foo=time('e')
if verbose>0 then say ' Done creating hashes for 'ifoo' blocks'
foo=sysfiledelete(outfile)
foo=charout(outfile,ac1,1) /* create the message the client send to the server*/
if foo<>0 then do
foo=stream(outfile,'c','close')
return "ERROR problem writing synopsis file "outfile
end /* do */
foo=stream(outfile,'c','close')
b=time('e')
if verbose>0 then
say ' Saving synopsis file to 'outfile' [elapsed time='||strip(b,'t','0')
nn=length(ac1)
drop ac1
return 'OK 'nn ' bytes written to synopsis file 'outfile
/*******************************************************************/
/* rsync_server: uses this synopsis, and the new version, to create
and rsync difference file
status=rsync_server(synopsis_string,newver_file,diff_file,quiet)
quiet is an optional parameter
*****************************************/
rsync_server: procedure
parse arg sfile,newverfile,outfile,verbo
a=rsync_load_dlls()
if a<>0 then return a
if sfile='' then return "ERROR no synopsis file specified "
if newverfile='' then return "ERROR no new_version file specified"
if outfile='' then return "ERROR no difference file specified "
if verbo<>'' then verbose=verbo
select
when verbose=0 then verbose=1
when verbose=1 then verbose=0
otherwise nop
end
crlf='0d0a'x
a=time('r')
b=time('r')
/* read "synopsis file" */
aa=translate(stream(sfile,'c','open read'))
if abbrev(aa,'READY')=0 then return "ERROR could not open "sfile
issize=stream(sfile,'c','query size')
if issize='' | issize=0 then do
return 'ERROR 'sfile " is unaccessible"
exit
end
synopsis=charin(sfile,1,issize)
aa=stream(sfile,'c','close')
if verbose>0 then do
say "Rsync server: read "issize" bytes in the synopsis file"
end
in1=left(synopsis,132)
parse var in1 comment +80 iblock numblocks amd4 gotcts .
if datatype(iblock)<>'NUM' | datatype(numblocks)<>'NUM' then do
return 'ERROR not a proper synopsis 'iblock numblocks
end
if verbose>0 then do
say " Comment: "||left(comment,64)
say " (client used blocksize=" iblock ', and sent 'numblocks' blocks '
end
if stream(newverfile,'c','query exists')='' then do
say " sss "newverfile
return 'ERROR no such new_version file '||newverfile
end
if verbose>0 then do
nn=stream(newverfile,'c','query size')
say " Read "nn" bytes in "newverfile
end
/* call the integrated rsync_server procedure */
foo=sysfiledelete(outfile)
if foo>2 then return "ERROR could not delete old version of "outfile
status=rx_rsync_server(newverfile,synopsis,outfile)
b=time('e')
if verbose>0 then do
nn=stream(outfile,'c','query size')
say ' Saving difference file to 'outfile '[elapsed time='||strip(b,'t','0')
end
return status
/***************************************************/
/* rsync_undiff: uses the difference file, and the old version, to
build a copy of the new version
status=rsync_undiff(oldver_file,diff_file,newfile,quiet)
**************************************/
rsync_undiff:procedure
parse arg afile,dfile,outfile,verbo
a=rsync_load_dlls()
if a<>0 then return a
if afile='' then return "ERROR no old_version file specified"
if dfile='' then return "ERROR no difference-file specified "
if newfile='' then return "ERROR no new_version file specified "
if verbo<>'' then verbose=verbo
select
when verbose=0 then verbose=1
when verbose=1 then verbose=0
otherwise nop
end
crlf='0d0a'x
a=time('r')
/* read "diff Afile" */
aa=translate(stream(dfile,'c','open read'))
if abbrev(aa,'READY')=0 then return "ERROR could not open "dfile
idsize=stream(dfile,'c','query size')
if idsize='' | idsize=0 then do
return 'ERROR 'dfile " is unaccessible"
exit
end
s1=charin(dfile,1,idsize)
aa=stream(dfile,'c','close')
if verbose>0 then do
say "Rsync undiff: read "idsize" bytes in the difference file"
end
/* read "Afile" */
aa=translate(stream(afile,'c','open read'))
if abbrev(aa,'READY')=0 then return "ERROR could not open "afile
iasize=stream(afile,'c','query size')
if iasize='' | iasize=0 then do
return 'ERROR 'afile " is unaccessible"
exit
end
astuff=charin(afile,1,iasize)
aa=stream(afile,'c','close')
if verbose>0 then do
say " "iasize" bytes in the old_version file"
end
amd4=rx_md4(astuff) /* md4 of old version */
/* get md4 and blocksize from s1 */
parse var s1 smd4 bsize (crlf) s1
if strip(translate(amd4))=strip(translate(smd4)) then do
if verbose>0 then
say " File has not changed! "
bstuff=astuff
signal writeme1
end
/* start building. Each records starts with a single character identifier,
either a B or a C. Following the identifier is:
B: a block start: block end number, and then a crlf
C: a count of bytes (nnn), a ":", a string of length nnn, and a crlf
*/
bstuff=''
noted=0
do forever
if length(s1)=0 | s1='' then leave
mbl=lengtH(bstuff)
if mbl-noted> reportat then do
if verbose>0 then say "... Rsync client: # characters recovered "mbl
noted=mbl
end /* do */
parse var s1 atype +1 s1 ; atype=translate(atype)
select
when atype='C' then do
parse var s1 nnn ':' s1
parse var s1 ccs +(nnn) (crlf) s1
bstuff=bstuff||ccs
end /* do */
when atype='B' then do
parse var s1 idb1 ':' idb2 (crlf) s1
i1=((idb1-1)*bsize)+1
i2=idb2*bsize
i2=min(i2,iasize)
bstuff=bstuff||substr(astuff,i1,1+i2-i1)
end /* do */
otherwise do
return "ERROR in differnce file: unknown type= "atype
end
end /* select */
end /* do */
/* compute md4 of this constructed file */
b2md4=rx_md4(bstuff)
if strip(translate(b2md4)) <> strip(translate(smd4)) then do
return "ERROR md4 does not match: "b2md4', 'smd4
end /* do */
writeme1: nop /* jump here if no change */
foo=sysfiledelete(outfile)
if foo>2 then return 'ERROR unable to delete output file 'outfile
foo=charout(outfile,bstuff,1) /* save the computed new file */
foo=stream(outfile,'c','close')
b=time('e')
if verbose>0 then
say ' Saving duplicate to 'outfile ' [elapsed time='||strip(b,'t','0')
nn=length(bstuff)
drop bstuff; drop astuff
return 'OK 'nn ' bytes written to 'outfile
/****************************************************************/
/* read in some useful procedures */
rsync_load_dlls:procedure
if rxfuncquery('rx_md4')=1 then do
call RXFuncAdd 'RXRsyncLoad', 'RXRSYNC', 'RxRsyncLoad'
call RxRsyncLoad
end
if rxfuncquery('rx_md4')=1 then do
return "ERROR could not load RxRsync.DLL"
end
/* Load up advanced REXX functions */
foo=rxfuncquery('sysloadfuncs')
if foo=1 then do
call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
call SysLoadFuncs
end
if rxfuncquery('sysfiledelete')=1 then do
return "ERROR could not load REXXUTIL.DLL"
end
return 0