home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 18 REXX
/
18-REXX.zip
/
dirtools.zip
/
copydir.cmd
next >
Wrap
OS/2 REXX Batch file
|
1999-12-13
|
19KB
|
696 lines
/* CopyDir.CMD -- A utility to robustly copy a directory tree.
Created by: Daniel Hellerstein (danielh@econ.ag.gov), 08 Nov 1998
Requires: The REXXLIB library (which may be included in the distribution
file)
Usage. From an OS/2 command prompt:
COPYDIR source_dir dest_dir [-opt]
where:
source_dir -- source directory
dest_dir -- destination directory
[-opt ] -- list of options.
Options include:
-8 -- Always convert "long" (HPFS) style file names to unique
8.3 (FAT) names; even if destination drive can support
long file names.
-Q -- Quiet mode
-QQ -- Very quite mode
-R -- Replace mode. If /R not specified, then newer files will
not be overwritten.
-NOCHECK -- Do not check if destination drive has enough space
-CHECK -- Check if destination drive has enough space
-ZIP=filename -- Create directory specific filename.ZIP files on the
the destination drive, with each of these ZIP files
containing the contents of the source directory.
Notes:
* these options can override the user changable parameters
discussed below.
* if the destination drive is FAT, the 8.3 conversion of filenames
will always be done (if necessary).
* when an 8.3 conversion occurs, a name of the form XXXXXnnn.EXT is
used; where XXXXX is the first 5 characters of the source file's name,
nnn is an integer from 001 to 999, and EXT is the first 3 characters
of the source file's extension.
* If a long directory name is encountered, the directory's contents will NOT
be copied.
* If a bad sector (or some other form of error) prevents copying
a file, the file will be skipped (that is, COPYDIR will try and
copy the other files).
* By default, if any problems occur a file with the name COPYDIR.ERR is
created. This file (located in the directory containing COPYDIR.CMD)
signifies the problems -- such as a "failure to copy a file" or
"longname converted".
* If there is not enough room on the destination drive, you will
be asked to "continue anyways". Note that this "not enough room"
calculation is made without accounting for the possiblitiy of
overwriting a file, hence is conservative.
* If the source and target directory may contain spaces, be sure to place the
directory name between " characters.
* If you do not include =filename after a -ZIP option,
a name derived from today's date is used. For example, 20NOV98.ZIP
(corresponding to 20 Nov 1998)
* Note that when the -ZIP option is used, a ZIP file will be created
on the destination drive, and will be filled with files from
the corresponding source drive. The same filename
is used in each destination directory (though, of course, each of
these .ZIP files will contain unique content).
Examples:
COPYDIR E:\DOCS G:\DOCS
COPYDIR F:\GAMES\NEW E:\FUN -8 -CHECK -R
COPYDIR "My Docs" "F:\archive\Old Docs" -NOCHECK
COPYDIR F:\DOCS\CURRENT I:\ARCHIVE\Y1998 -ZIP
*/
/* ------------ USER changeable Parameters ---------- */
/* Check if there is enough room on destination drive
=1 : Check
=0 : Do NOT check */
testsize=1
/* Verbosity:
0 = Minimal
1 = Average
2 = Lots (displays all problems) */
verbose=1
/* Fully qualified name of file to write "errors" to.
If blank, then COPYDIR.ERR, in the directory containing COPYDIR.CMD,
is used. */
errfile=''
/* ------------ END of USER changeable Parameters ---------- */
/*--- Load REXX libraries ----- */
/* Load up advanced REXX functions */
foo=rxfuncquery('sysloadfuncs')
if foo=1 then do
foo=RxFuncAdd('SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs')
if foo=0 then call SysLoadFuncs
end
foo=rxfuncquery('rexxlibregister')
if foo=1 then do
foo=rxfuncadd('rexxlibregister','rexxlib', 'rexxlibregister')
if foo=0 then call rexxlibregister
end
foo=rxfuncquery('rexxlibregister')
if foo=1 then do
say "Sorry, this utility requires the REXXLIB library "
exit
end
/* doscopy error list */
doscopys.2='source file not found '
doscopys.3=' source or target path not found '
doscopys.5 =' target file exists but 'A' or 'R' mode not specified '
doscopys.32 =' sharing violation for source or target file '
doscopys.108 =' source or target drive locked '
doscopys.112 = 'disk full '
doscopys.206 = 'invalid source or target file name '
doscopys.267 = 'source name is a directory '
doscopys.282 = 'extended attributes not supported for target '
nowdir=directory()
nowdrive=filespec('d',nowdir)
nowpath=filespec('p',nowdir)
fromkeyb=0
parse arg bax
if bax='' then say "Copy a directory tree (? for help)."
qq=pos('"',bax)
if qq>0 then do
newbax=''
do forever
if bax='' then leave
parse var bax p1 '"' p2 '"' bax
if p2='' then do
newbax=newbax' 'p1
iterate
end /* do */
p2=translate(p2,'01'x,' ')
newbax=newbax' 'p1' 'p2
end /* do */
parse var newbax in1 in2 astuff2
in1=translate(in1,' ','01'x)
in2=translate(in2,' ','01'x)
end /* do */
else do
parse arg in1 in2 astuff2
end
astuff2=translate(astuff2)
call getopts
if in1='?' then do
Say "Utility to copy a directory tree "
say "Usage: x:>COPYDIR fromdir todir [-opt] "
say " Where: fromdir= source directory "
say " todir = target directory "
say " [-opt]= one or more options. "
call showhelp 0
exit
end /* do */
a1:
if in1='' then do
fromkeyb=1 /* keyboard io */
do forever
call charout, " From what directory: "
pull fromdir
if fromdir='?' then do
say "Enter a source directory from which to copy files "
iterate
end /* do */
leave
end
say
end
else do
fromdir=in1
end /* do */
in1=''
fromdir=fixdir(fromdir,nowdrive)
if dir_exists(fromdir)=0 then do
say "No such directory: " fromdir
signal a1
end
else do
say " >>> Copying from: "fromdir
end /* do */
fromdrive=filespec('d',fromdir)
say
a2: if fromkeyb=1 then do
do forever
call charout, "To what directory: "
pull todir
if todir='?' then do
say "Enter a destination directory, into which files will be copied."
iterate
end /* do */
say
leave
end
end /* do */
else do
todir=in2
end /* do */
in2=''
todir=fixdir(todir,nowdrive)
todrive=filespec('d',todir)
if dir_exists(strip(todir,,'\'))=0 then do
say "No such destination directory: "todir
call charout,' Create it? (Y=yes) '
pull mkit ; mkit=left(strip(mkit),1)
say
if mkit<>1 & mkit<>'Y' then signal a2
foo=sysmkdir2(todir)
end /* do */
if fromkeyb=1 then do
do forever
say
call charout, " Enter -options: "
pull astuff2
if astuff2='?' then do
call showhelp 1
iterate
end /* do */
call getopts
leave
end
say
end /* do */
if dozip=0 then
say " >>> Writing to: " todir
else
say " >>> Archiving to " zipfile " files in " todir
say " .... using Options: " astuff2
say
todrivetype=dosfilesys(strip(todrive,,':'))
fromdrivetype=dosfilesys(strip(fromdrive,,':'))
if trunc8=1 then do
select
when todrivetype='FAT' & fromdrivetype<>'FAT' then
say " Caution: copying from non-FAT to FAT drive ."
when todrivetype<>'FAT' & fromdrivetype<>'FAT' then
say "Caution: copying from non-FAT to non-FAT, with 8.3 truncation "
otherwise
say "Copying from FAT drive; 8.3 truncation not required "
end
end
else do
if todrivetype='FAT' & fromdrivetype<>'FAT' then do
say " ** Warning: writing to a FAT drive from a non-FAT drive "
if fromkeyb=1 then do
call charout,' Continue (long names will be truncated). 1=Yes ?'
pull aa ;aa=left(strip(aa),1)
if aa<>1 & aa<>'Y' then exit
end /* do */
trunc8=1
end /* do */
end
getit=strip(fromdir,,'\')'\*.*'
wow=sysfiletree(getit,'stuff','DOS')
j1=stuff.0+1
stuff.j1=fromdir
ieelen=length(stuff.j1)
stuff.0=j1
if testsize=1 then do /* get size of this, see if enough room on target */
arf=sysdriveinfo(todrive)
parse var arf . todrivefree .
if verbose>0 then say todrive" has "||addcomma(todrivefree)||' bytes free.',
" Checking if this is sufficient ..."
ssize1=0 ;ssize2=0
wow=sysfiletree(getit,'stuff3','FS')
do ii=1 to stuff3.0
parse var stuff3.ii d1 d2 jsize d3 aname
ssize1=ssize1+dosfileinfo(strip(aname),'s')
ssize2=ssize2+jsize
end /* do */
say " Bytes to copy: "||addcomma(ssize2)||' ('||addcomma(ssize1)||')'
if ssize1>todrivefree then do
say "Warning: ignoring overwrites, there is not enough free space on "||todrive
if verbose<1 then exit
call charout,' Copy anyways (Y=yes)? '
pull ans; ans=left(strip(ans),1)
if ans<>'Y' & ans<>1 then exit
end /* do */
end
trunc8s.0=0
badcopies.0=0
nfiles=0
nbytes=0 ;badbytes=0 ;nbytes0=0
nfiles2=0
llen=0
gotlong1=0
do mm=1 to stuff.0
thisdir=strip(stuff.mm,,'\')
mkit=strip(todir'\'||strip(substr(thisdir,ieelen+1),,'\'),,'\')
foo=1
if trunc8=1 then foo=checkdir8(mkit)
if foo=0 then do /* unable to write to this directory */
nk=badcopies.0+1
badcopies.nk=stuff.mm
badcopies.nk.2=mkit
badcopies.nk.1='*.*'
badcopies.0=nk
iterate
end /* do */
yeep=left(mm 'of 'stuff.0||") "thisdir " to " mkit '..... ',79)
if verbose>0 then say yeep
yow=sysmkdir2(mkit)
wow=sysfiletree(thisdir'\*.*','stuff2','fo')
llen=0
igoo=0
if dozip=1 then do
if stuff2.0=0 then iterate /* nothing to zip */
say " ZIPping "stuff2.0 " files."
azipfile=mkit||'\'zipfile
if trunc8=1 then azipfile=fix8(azipfile)
address cmd '@ZIP -j -q 'azipfile ' 'thisdir'\*.*'
foo=rc
nfiles=nfiles+stuff2.0
iterate
end
/* else, copy each file */
do mmm=1 to stuff2.0
nfiles=nfiles+1
yee1=filespec('N',stuff2.mmm)
targfile=mkit||'\'||yee1
targfile0=targfile
if trunc8=1 then targfile=fix8(targfile)
s1=stream(stuff2.mmm,'c','query datetime')
s2=stream(targfile,'c','query datetime')
if s1==s2 & replaceit<>1 then iterate
nfiles2=nfiles2+1
fsize=stream(stuff2.mmm,'c','query size')
if datatype(fsize)<>'NUM' then do
foo=-1
fsize=0
end /* do */
else do
nbytes0=nbytes0+fsize
foo=doscopy(stuff2.mmm,targfile,'R')
fsize=dosfileinfo(stuff2.mmm,'s')
nbytes=nbytes+fsize
end
if foo<>0 then do
say
errname=doscopys.foo
if errname='DOSCOPYS.'FOO then errname='unknown error'
if verbose>0 then say " Error copying: "yee1 '(' foo'='errname
if verbose=0 then say " Error copying: "yee1 '(' foo
llen=80
nk=badcopies.0+1
badcopies.nk=stuff2.mmm
badcopies.nk.2=targfile
badcopies.nk.1=foo
badcopies.0=nk
badbytes=badbytes+fsize
end /* error */
else do
if verbose>0 then do
if targfile<>targfile0 then do
yee1=yee1' as '||filespec('n',targfile)||','
oi=trunc8s.0+1
trunc8s.oi=stuff2.mmm
trunc8s.oi.1=filespec('n',targfile)
trunc8s.oi.2=targfile
trunc8s.0=oi
end /* do */
if igoo=0 & verbose>0 then call charout,' : '
igoo=1
lyee1=length(yee1)
lrem=lyee1//14
yee2=yee1
if lrem>0 then do
yee2=yee1||copies(' ',14-lrem)
end /* do */
if (llen+length(yee2))>75 then do
if llen<>80 then say
llen=0; if verbose>0 then call charout ,' : '
end /* do */
if verbose>0 then call charout,yee2' '
llen=length(yee2)+llen+2
end
end
end /* all files */
if verbose>0 & igoo=1 then say
end
say ' ----------------- '
if verbose>0 then do
say " Total of " nfiles " files in " stuff.0 " directories: "
if dozip=0 then do
say " files / bytes (allocated) copied = " nfiles2' / '||addcomma(nbytes0) ' ('|| ,
addcomma(nbytes)||')'
if badcopies.0+badbytes>0 then
say ' .... of which ' badcopies.0' / 'badbytes' failed '
end
end
do ii=1 to badcopies.0
if verbose>1 then say badcopies.ii '( 'badcopies.ii.1
if badcopies.ii.1='*.*' then
arf.ii='COPY 'badcopies.ii||'\*.* 'badcopies.ii.2
else
arf.ii='COPY 'badcopies.ii ' 'badcopies.ii.2
end
do ii=1 to trunc8s.0
if verbose>1 then say trunc8s.ii '(' trunc8s.ii.1
ii2=ii+badcopies.0
arf.ii2='REN 'trunc8s.ii.2 ' 'trunc8s.ii
end /* do */
arf.0=badcopies.0+trunc8s.0
if arf.0>0 & verbose>0 then do
if errfile<>'' then do
goog=errfile
end /* do */
else do
parse source os type name
oo=lastpos('.',name)
if oo>0 then
goog=left(name,oo)||'ERR'
else
goog=goog||'.ERR'
end
ii=arf.0
ii=ii+1
arf.ii='Rem COPY entries indicate files, or directories, that could not be copied '
ii=ii+1
arf.ii='Rem REN entries indicate files with shortened file names '
arf.0=ii
foo=filewrite(goog,'arf','R')
say " Writing failures and renames to " goog
end
exit
/*************/
fixdir:procedure /* fix up directory string */
parse arg fromdir,nowdrive
fromdir=strip(fromdir)
if left(fromdir,1)='\' then fromdir=nowdrive||fromdir /* \foobar */
fromdir=strip(strip(fromdir,'t','\'))
sspos=pos(':',fromdir)
if sspos=0 then fromdir=nowdrive||fromdir /* no : in dir, so add X: */
sspos=pos(':',fromdir)
if substr(fromdir,sspos+1,1)<>'\' then do /* x:d1\d2 */
foo=directory()
yy=left(fromdir,sspos)
woo=directory(yy)
goo=directory(foo)
parse var fromdir a1 ':' a2
fromdir=woo'\'a2
end /* do */
fromdir=strip(fromdir,'t','\')
if right(fromdir,1)=':' then fromdir=fromdir'\'
return fromdir
/* ------------------------------------- */
sysmkdir2:procedure
parse arg adir
adir=strip(adir,'t','\')
ff=sysmkdir(adir)
if ff=0 then return ff
/* make the tree */
f2=adir'\'
dd=filespec('d',f2)
pp=filespec('p',f2)
if pp='\' | pp='' then return -1
pp2=strip(translate(pp,' ','\'))
do mm=1 to words(pp2)
a1=subword(pp2,1,mm)
a1=translate(a1,'\',' ')
dd2=dd'\'a1
hoo=sysmkdir(dd2)
if hoo=0 then say ' ... creating: 'dd2
end /* do */
return hoo
/************/
/* ADD COMMAS TO A NUMBER */
addcomma:procedure
parse arg aval,ndec
parse var aval p1 '.' p2
if ndec='' then do
p2=''
end
else do
p2='.'||left(p2,ndec,'0')
end /* do */
plen=length(p1)
p1new=''
do i=1 to 10000 while plen>3
p1new=','right(p1,3)||p1new
p1=delstr(p1,plen-2)
plen=plen-3
end /* do */
return p1||p1new||p2
/**********/
/* convert hpfs long file names to some kind of fat name */
fix8:procedure
parse arg aname
t1=filespec('d',aname)
t2=filespec('p',aname)
t3=filespec('n',aname)
parse var t3 t3a '.' t3b
select
when pos(' ',t3)>0 then not8=1
when pos('.',t3b)>0 then not8=1
when length(t3a)>8 then not8=1
when length(t3b)>3 then not8=1
otherwise not8=0
end
if not8=0 then return aname
/* else, it's a non-fat allowable name --- create a new name */
/* first, replace ' ' with _ */
t3a=translate(t3a,'_',' ')
t3b=translate(t3b,'__','. ')
if length(t3a)>8 | length(t3b)>3 then do
t3a=left(t3a,min(length(t3a),5))'???'
end /* do */
if length(t3b)>3 then t3b=left(t3b,3)
t3=t3a
if t3b<>'' then t3=t3a'.'t3b
newname=dostempname(t1||t2||t3)
return newname
/**********/
/* check for 8 character max in directory names */
checkdir8:procedure
parse arg aa
aa0=aa
if (pos(' ',aa)+pos('.',aa))>0 then do
say "Caution:ERROR: converting . or space to _ in directory: " aa0
aa=translate(aa,'__',' .')
end /* do */
aa=translate(aa,' ',':\')
do mm=1 to words(aa)
if length(word(aa,mm))>8 then do
say "ERROR: Unable to create longname directory on FAT drive: " aa0
return 0
end /* do */
end
return 1
/**********/
getopts:
if pos('-Q',astuff2)>0 then verbose=0
if pos('-QQ',astuff2)>0 then verbose=-1
replaceit=0
if pos('-R',astuff2)>0 then replaceit=1
trunc8=0
if pos('-8',astuff2)>0 then trunc8=1
if pos('-CHECK',astuff2)>0 then testsize=1
if pos('-NOCHECK',astuff2)>0 then testsize=0
dozip=0
zz=pos('-ZIP',astuff2)
if zz>0 then do
dozip=1
parse upper var astuff2 . '-ZIP=' zipfile '.' .
if zipfile=' ' then do
zipfile=date('n')
parse var zipfile a1 a2 a3
zipfile=a1||a2||right(a3,2)
end
/* check for ZIP.exe */
foo=doscommandfind('ZIP')
if foo='' then do
say "Sorry, can not find ZIP program in your OS/2 PATH. "
exit
end
end /* do */
return 0
/***************/
showhelp:
parse arg iii
say
say " Available options are:"
say " -Q = quite mode "
say " -R = always replace "
say " -8 = copy to FAT style (8.3) file names "
say " -CHECK = check dest. drive for free space "
say " -NOCHECK = do NOT check dest. drive for free space "
say " -ZIP=filename = store files in zip files on dest. drive"
if iii=0 then say " Or, COPYDIR with no arguments to be prompted. "
say
return 0
/*************************************************/
/* Check for the existence of a directory. Correctly identifies
empty directories.
Usage:
flag=dir_exists(a_directory)
where
flag=1 if a_directory exists (it might be an empty directory )
flag=0 if it doesn't exist
*/
dir_exists:procedure
parse arg adir
adir=strip(adir)
adir=strip(adir,'t','\')
nowdir=directory()
nowdrive=filespec('d',nowdir'\')
nowpath=filespec('p',nowdir'\')
adr=filespec('d',adir)
if adr='' then do
if abbrev(adir,'\')=0 then
adir=nowdrive||nowpath||adir
else
adir=nowdrive||adir
end /* do */
foo=sysfiletree(adir,goo,'D')
if goo.0>0 then return 1
return 0