From: fairfield@slacvx.slac.stanford.edu
Subject: COPYTREE.COM (Was: Need: Multi dir copy between nodes.)
Organization: Stanford Linear Accelerator Center
Date: Wed, 13 Jan 1993 01:18:54 GMT

In article <01GTFHS4SK4Y95OOX3@wl.aecl.ca>, LITWINK@WL.AECL.CA (Keith Litwin) writes:
> Does anyone know of a utility to copy entire directory trees and contents
> between nodes without using a saveset?

    Yes :-)   I cooked this up a couple years ago when I had to move 
a set of users from one cluster to another at our site.  Backup wasn't
an option for most (I would've had to do it for them).

    I've included COPYTREE.COM below by sig.  It works locally, but was
designed to work between nodes using DECnet syntax.  I made sure my users
had proxy access to the remote node (the "source" node in our case) so that
passwords weren't slung about freely over the network, but it will work fine
with the usual NODE"username password":: specification.

    Two key features to this command file: (1) the "source" and "destination"
directories may be subdirectories themselves, and (2) I've tried to 
reestablish the VMS default protection on .MAI files and MAIL.DIR (if
you have one) and its subdirectories.

    I think the comments in the header describe things well enough, but
if need be, drop me a note and I'll try to answer questions.

	Use and enjoy!  Ken
-- 
 Dr. Kenneth H. Fairfield    |  Internet: Fairfield@Slac.Stanford.Edu
 SLAC, P.O.Box 4349, MS 98   |  DECnet:   45537::FAIRFIELD (45537=SLACVX)
 Stanford, CA   94309        |  BITNET    Fairfield@Slacvx
 ----------------------------------------------------------------------------
 These opinions are mine, not SLAC's, Stanford's, nor the DOE's...

---------------cut/here---------COPYTREE.COM-----------cut/here--------------
$!
$!		C O P Y T R E E . C O M
$!		=======================
$!
$!	Command procedure copies a complete directory tree from one "root"
$!	to another, including between VAXes.
$!
$!	File and directory protection masks are taken from the source
$!	directory and its subdirectories.  The destination root directory
$!	protection mask (only) made be specified on the command line if
$!	it is to be different than the source directory root.
$!
$! Input Parameters:
$!
$!	p1 - Source root directory.  This should include the full
$!	     directory specification, e.g. NODE::DEV:[DIRECTORY],
$!	     where NODE:: is optional.  The source root may include
$!	     one or more subdirectories.
$!
$!	p2 - Destination root directory.  Specify in the same way as p1.
$!
$!	p3 - File protection string for creating p2 (optional)
$!
$	If p1 .Eqs. "" Then Inquire p1 "Input root"
$	If p2 .Eqs. "" Then Inquire p2 "Output root"
$	If p3 .Nes. ""
$	Then
$	   dirprot = "/Prot=(" + p3 + ")"
$	   fprot   = "/Prot=(" + F$Element(0, ",", p3) + "D," -
			       + F$Element(1, ",", p3) + "D," -
			       + F$Element(2, ",", p3) + ","  -
			       + F$Element(3, ",", p3) + ")"
$	Else
$	   lastdir = ""
$	   n=0
$ DIRLOOP:
$	   thisdir = F$Element (n, ".", p1)
$	   If (thisdir .Nes. ".")
$	   Then
$	      lastdir = "." + thisdir
$	      n=n+1
$	      Goto DIRLOOP
$	   Else
$	      If (lastdir .Nes. "")
$	      Then
$		 bclose = F$Extract (F$Length(p1)-1, 1, p1)
$		 thisdir = lastdir - "." - bclose
$		 parent  = p1 - lastdir + bclose + thisdir + ".DIR;1"
$		 dirprot = "/Prot=(" + -
		    F$Edit (F$File_Attributes (parent, "PRO"), "COLLAPSE") -
				+ ")"
$	      Else
$		 dirprot = " "
$	      Endif
$	   Endif
$	   fprot   = " "
$	Endif
$
$!
$	Set Noon
$	Create/Dire/Log'dirprot' 'p2'
$	crestat = $Status
$	If .Not.crestat
$	Then
$	Else
$	   If crestat .Eq. %X10911293
$	   Then
$	      Inquire yn "Do you wish to continue? (y/n)"
$	      If yn Then Goto OK
$	   Else
$	      Goto OK
$	   Endif
$	Endif
$	Exit 'crestat'
$!
$ OK:
$	Write Sys$output " Copying " + p1 + "*.*;*  -->  " + p2 + "*.*;*"
$	Copy 'p1'*.*;*/Exclude=(*.DIR;1,NETSERVER.LOG;*) 'p2'*.*;*'fprot'
$	Set On
$!
$!  Re-establish correct (VMS default) protections on MAIL files.
$!
$	If F$Search("''p2'*.mai;*") .Nes. "" Then -
	    Set Prot=(SYSTEM:RW, OWNER:RW, GROUP, WORLD) 'p2'*.MAI;*
$!
$ LOOP: next = F$Search(p1+"*.DIR;1")
$	If next .Eqs. "" Then Exit 1
$!
$!!!	Set Message/Nofacil/Noiden/Notext/Nosev
$!!!	newprot = ""
$	newprot = F$Edit (F$File_Attrbutes (next, "PRO"), "COLLAPSE")
$!!!	Set Message/Facil/Iden/Text/Sev
$!
$	next = F$Parse(next,,,"NAME")
$	input_dir  = p1 - "]" + "." + next + "]"
$	output_dir = p2 - "]" + "." + next + "]"
$	@'F$Environment("PROCEDURE") 'input_dir' 'output_dir' 'newprot'
$	Goto LOOP