[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[info-sather] Recursive copy (was: How's Sather coming along?)
From: |
Sather User |
Subject: |
[info-sather] Recursive copy (was: How's Sather coming along?) |
Date: |
Thu, 13 Dec 2012 17:23:30 +1030 (CST) |
On Fri, 7 Dec 2012, Duke Normandin wrote:
> Whatever you do, don't rush it! There's Christmas shopping to do,
> etc etc. Priorities man!! Priorities!!
Okay, I think you're right, it's time to knock off for a while. But
here is a little example of a Sather program, a cp -aR in Sather.
Dart (directory and rest to...) does not have different options, but
always copies a directory tree to a directory and always preserves
atimes and mtimes.
Unfortunately its runtime is 125% as long as that of cp when copying
the Linux kernel source. On the other hand it preserves the mtimes of
symlinks. I haven't seen a cp option that does that. Result of
"dart i j" followed by "find -type l | ls ... --full-time":
lrwxrwxrwx 1 33 2012-12-13 16:21:13.992247352 +1030
./i/linux-3.6.9/arch/microblaze/boot/dts/system.dts ->
../../platform/generic/system.dts
lrwxrwxrwx 1 33 2012-12-13 16:21:13.992247352 +1030
./j/i/linux-3.6.9/arch/microblaze/boot/dts/system.dts ->
../../platform/generic/system.dts
lrwxrwxrwx 1 33 2012-12-13 16:13:31.720854961 +1030
./linux/linux-3.6.9/arch/microblaze/boot/dts/system.dts ->
../../platform/generic/system.dts
All the LSTAT attributes have to be shareds because they are populated
by a C callback provoked by LSTAT::get_stat(name:STR) (overloads with
and without a return value). SEMILSTAT::create copies some of the
LSTAT shareds into SEMILSTAT object attributes.
I hope you are not irritated by the quirky terminology likening a file
path to a spear with shaft and tip in place of dirname and basename.
-- directory and rest to ...
--
-- Only 2 args, so simple processing.
-- Only copy files.
-- Anything else, symlinks, directories, fifos etc., create anew in the
-- dest location.
-- But in the case of a directory, after creating it, recurse into the
-- subject src directory, and after leaving it set the mtime and atime
-- of the dest directory.
class DART is
include PATH;
const noerr, helped, few_args, src_not_dir, dst_shaft_not_dir,
dst_exists, no_src, no_dst, bad_mkdir;
const base_mode:INT:=0o777;
const path_separator:CHAR:='/';
shared me:STR;
shared src_stub, dst_stub:STR;
err(retval:INT, s:STR):INT is
#ERR+me+": "+s.nl;
return retval
end;
mkdir(s:STR, mode:INT) is
RUNTIME::mkdir(s,mode);
e::=ERRNO::errno;
if e = noerr then return end;
msg ::= "mkdir("+s+", ...) failed: ";
case e
when ERRNO::enoent then raise msg+"missing path component or dangle"
when ERRNO::eacces then raise msg+"access denied"
when ERRNO::eexist then raise msg+"file or directory exists"
when ERRNO::enospc then raise msg+"no space for this directory"
when ERRNO::erofs then raise msg+"read-only file system"
else
raise e
end
end;
make_symlink(oldpath,newpath:STR) is
ERRNO::reset;
i::=SYMLINK::make_symlink(oldpath,newpath);
if i = 0 then return end;
msg::="write_symlink("+oldpath+","+newpath+"): ";
e::=ERRNO::errno;
case e
when ERRNO::eacces then raise msg+"access denied"
when ERRNO::eexist then raise msg+newpath+" already exists"
when ERRNO::enoent then raise msg+"empty oldpath or missing path
component or dangle"
when ERRNO::enospc then raise msg+"no space to write link"
when ERRNO::enotdir then raise msg+"non-directory component in "+newpath
when ERRNO::erofs then raise msg+newpath+"is on a read-only file system"
else
raise e
end
end;
main(args:ARRAY{STR}):INT is
me:=pathchew(args[0]).tip;
if args.size /= 3 then
return err(few_args,"Need 2 args, src fullpath"
" (not a symlink) and dest shaft")
end;
dst:STR:=args[2];
if LSTAT::get_stat(dst) = -1 then
return err(no_dst, "dest shaft does not exist")
end;
if LSTAT::st_mode.band(LSTAT::s_fmt) /= LSTAT::s_ifdir then
return err(src_not_dir, "second arg must be directory")
end;
src:STR:=args[1];
if LSTAT::get_stat(src) = -1 then
return err(no_src, "first arg (src) does not exist")
end;
if LSTAT::st_mode.band(LSTAT::s_fmt) /= LSTAT::s_ifdir then
return err(src_not_dir, "first arg must be directory")
end;
src_dir_stat::=#SEMILSTAT;
if LSTAT::get_stat(dst+path_separator+pathchew(src).tip) /= -1 then
return err(dst_exists, "dest tip must not exist")
end;
ERRNO::reset;
newdir::=dst+path_separator+pathchew(src).tip;
protect
mkdir(newdir,base_mode);
when INT then
msg::="mkdir("+newdir+", ...) failed: ";
return err(bad_mkdir, msg+"ERRNO::errno="+exception.str)
when STR then
return err(bad_mkdir, exception)
end;
src_stub:=pathchew(src).shaft;
dst_stub:=dst;
protect
delve(src);
when $STR then
#OUT+"delve exception "+exception.str+"\n";
return 0
end;
src_dir_stat.store_times(dst, pathchew(src).tip);
return noerr
end;
delve(s:STR) is
src_stub:=src_stub+path_separator+s;
dst_stub:=dst_stub+path_separator+s;
dd::=#DIR(src_stub, false); --whether to sort is false
loop
n::=dd.elt!;
if n /= "." and n /= ".." then
newdest::=dst_stub+path_separator+n;
LSTAT::get_stat(src_stub+path_separator+n);
case LSTAT::st_mode.band(LSTAT::s_fmt)
when LSTAT::s_ifreg then
-- regular file. copy it.
f1::=FILE::open_for_read(src_stub+path_separator+n);
if f1.error then
emsg ::= newdest+": open_for_read failed, errno="
+ERRNO::errno.str;
raise emsg
end;
f2::=FILE::open_for_write(newdest);
if f2.error then
emsg ::= newdest+": open_for_write failed, errno="
+ERRNO::errno.str;
raise emsg
end;
f2+f1.fstr;
f1.close;
f2.close;
times_dest::=pathchew(newdest);
LSTAT::store_times(times_dest.shaft,times_dest.tip)
when LSTAT::s_ifdir then
-- directory. create it, then call this routine with
thisstat::=#SEMILSTAT;
mkdir(newdest, base_mode);
old_src_stub::=src_stub;
old_dst_stub::=dst_stub;
delve(n);
times_dest::=pathchew(newdest);
thisstat.store_times(times_dest.shaft,times_dest.tip);
src_stub := old_src_stub;
dst_stub := old_dst_stub;
when LSTAT::s_iflnk then
-- symlink.
SYMLINK::read_symlink(src_stub+path_separator+n,
LSTAT::st_size_lobits);
make_symlink(SYMLINK::val, dst_stub+path_separator+n);
spear::=pathchew(dst_stub+path_separator+n);
LSTAT::store_times(spear.shaft, spear.tip)
else
#ERR+src_stub+path_separator+n
+": unhandled file type "
+LSTAT::st_mode.band(LSTAT::s_fmt).nl
end
end
end;
dd.close
end
end;
--
Michael Talbot-Wilson