summaryrefslogtreecommitdiff
path: root/appl/cmd/install/proto.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/install/proto.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/install/proto.b')
-rw-r--r--appl/cmd/install/proto.b320
1 files changed, 320 insertions, 0 deletions
diff --git a/appl/cmd/install/proto.b b/appl/cmd/install/proto.b
new file mode 100644
index 00000000..c25ee220
--- /dev/null
+++ b/appl/cmd/install/proto.b
@@ -0,0 +1,320 @@
+implement Proto;
+
+include "sys.m";
+ sys: Sys;
+ Dir : import Sys;
+include "draw.m";
+include "bufio.m";
+ bufio : Bufio;
+ Iobuf : import bufio;
+include "string.m";
+ str: String;
+include "readdir.m";
+ readdir : Readdir;
+include "proto.m";
+include "protocaller.m";
+
+NAMELEN: con 8192;
+
+WARN, ERROR, FATAL : import Protocaller;
+
+File: adt {
+ new: string;
+ elem: string;
+ old: string;
+ uid: string;
+ gid: string;
+ mode: int;
+};
+
+indent: int;
+lineno := 0;
+newfile: string;
+oldfile: string;
+oldroot : string;
+b: ref Iobuf;
+cmod : Protocaller;
+
+rdproto(proto : string, root : string, pcmod : Protocaller) : int
+{
+ if (sys == nil) {
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+ str = load String String->PATH;
+ readdir = load Readdir Readdir->PATH;
+ }
+ cmod = pcmod;
+ oldroot = root;
+ b = bufio->open(proto, Sys->OREAD);
+ if(b == nil){
+ cmod->protoerr(FATAL, lineno, sys->sprint("can't open %s: %r: skipping\n", proto));
+ b.close();
+ return -1;
+ }
+ lineno = 0;
+ indent = 0;
+ file := ref File;
+ file.mode = 0;
+ mkfs(file, -1);
+ b.close();
+ return 0;
+}
+
+mkfs(me: ref File, level: int)
+{
+ (child, fp) := getfile(me);
+ if(child == nil)
+ return;
+ if(child.elem == "+" || child.elem == "*" || child.elem == "%"){
+ rec := child.elem[0] == '+';
+ filesonly := child.elem[0] == '%';
+ child.new = me.new;
+ setnames(child);
+ mktree(child, rec, filesonly);
+ (child, fp) = getfile(me);
+ }
+ while(child != nil && indent > level){
+ if(mkfile(child))
+ mkfs(child, indent);
+ (child, fp) = getfile(me);
+ }
+ if(child != nil){
+ b.seek(big fp, 0);
+ lineno--;
+ }
+}
+
+mktree(me: ref File, rec: int, filesonly: int)
+{
+ fd := sys->open(oldfile, Sys->OREAD);
+ if(fd == nil){
+ cmod->protoerr(WARN, lineno, sys->sprint("can't open %s: %r", oldfile));
+ return;
+ }
+ child := ref *me;
+ (d, n) := readdir->init(oldfile, Readdir->NAME|Readdir->COMPACT);
+ for (i := 0; i < n; i++) {
+ if (filesonly && (d[i].mode & Sys->DMDIR))
+ continue;
+ child.new = mkpath(me.new, d[i].name);
+ if(me.old != nil)
+ child.old = mkpath(me.old, d[i].name);
+ child.elem = d[i].name;
+ setnames(child);
+ if(copyfile(child, d[i]) && rec)
+ mktree(child, rec, filesonly);
+ }
+}
+
+mkfile(f: ref File): int
+{
+ (i, dir) := sys->stat(oldfile);
+ if(i < 0){
+ cmod->protoerr(WARN, lineno, sys->sprint("can't stat file %s: %r", oldfile));
+ skipdir();
+ return 0;
+ }
+ return copyfile(f, ref dir);
+}
+
+copyfile(f: ref File, d: ref Dir): int
+{
+ d.name = f.elem;
+ if(f.mode != ~0){
+ if((d.mode&Sys->DMDIR) != (f.mode&Sys->DMDIR))
+ cmod->protoerr(WARN, lineno, sys->sprint("inconsistent mode for %s", f.new));
+ else
+ d.mode = f.mode;
+ }
+ cmod->protofile(newfile, oldfile, d);
+ return (d.mode & Sys->DMDIR) != 0;
+}
+
+setnames(f: ref File)
+{
+ newfile = f.new;
+ if(f.old != nil){
+ if(f.old[0] == '/')
+ oldfile = mkpath(oldroot, f.old);
+ else
+ oldfile = f.old;
+ }else
+ oldfile = mkpath(oldroot, f.new);
+}
+
+#
+# skip all files in the proto that
+# could be in the current dir
+#
+skipdir()
+{
+ if(indent < 0)
+ return;
+ level := indent;
+ for(;;){
+ indent = 0;
+ fp := b.offset();
+ p := b.gets('\n');
+ if (p != nil && p[len p - 1] != '\n')
+ p += "\n";
+ lineno++;
+ if(p == nil){
+ indent = -1;
+ return;
+ }
+ for(j := 0; (c := p[j++]) != '\n';)
+ if(c == ' ')
+ indent++;
+ else if(c == '\t')
+ indent += 8;
+ else
+ break;
+ if(indent <= level){
+ b.seek(fp, 0);
+ lineno--;
+ return;
+ }
+ }
+}
+
+getfile(old: ref File): (ref File, int)
+{
+ f: ref File;
+ p, elem: string;
+ c: int;
+
+ if(indent < 0)
+ return (nil, 0);
+ fp := int b.offset();
+ do {
+ indent = 0;
+ p = b.gets('\n');
+ if (p != nil && p[len p - 1] != '\n')
+ p += "\n";
+ lineno++;
+ if(p == nil){
+ indent = -1;
+ return (nil, 0);
+ }
+ for(; (c = p[0]) != '\n'; p = p[1:])
+ if(c == ' ')
+ indent++;
+ else if(c == '\t')
+ indent += 8;
+ else
+ break;
+ } while(c == '\n' || c == '#');
+ f = ref File;
+ (elem, p) = getname(p, NAMELEN);
+ f.new = mkpath(old.new, elem);
+ (nil, f.elem) = str->splitr(f.new, "/");
+ if(f.elem == nil)
+ cmod->protoerr(ERROR, lineno, sys->sprint("can't find file name component of %s", f.new));
+ (f.mode, p) = getmode(p);
+ (f.uid, p) = getname(p, NAMELEN);
+ if(f.uid == nil)
+ f.uid = "-";
+ (f.gid, p) = getname(p, NAMELEN);
+ if(f.gid == nil)
+ f.gid = "-";
+ f.old = getpath(p);
+ if(f.old == "-")
+ f.old = nil;
+ if(f.old == nil && old.old != nil)
+ f.old = mkpath(old.old, elem);
+ setnames(f);
+ return (f, fp);
+}
+
+getpath(p: string): string
+{
+ for(; (c := p[0]) == ' ' || c == '\t'; p = p[1:])
+ ;
+ for(n := 0; (c = p[n]) != '\n' && c != ' ' && c != '\t'; n++)
+ ;
+ return p[0:n];
+}
+
+getname(p: string, lim: int): (string, string)
+{
+ for(; (c := p[0]) == ' ' || c == '\t'; p = p[1:])
+ ;
+ i := 0;
+ s := "";
+ for(; (c = p[0]) != '\n' && c != ' ' && c != '\t'; p = p[1:])
+ s[i++] = c;
+ if(len s >= lim){
+ cmod->protoerr(WARN, lineno, sys->sprint("name %s too long; truncated", s));
+ s = s[0:lim-1];
+ }
+ if(len s > 0 && s[0] == '$'){
+ s = getenv(s[1:]);
+ if(s == nil)
+ cmod->protoerr(ERROR, lineno, sys->sprint("can't read environment variable %s", s));
+ if(len s >= NAMELEN)
+ s = s[0:NAMELEN-1];
+ }
+ return (s, p);
+}
+
+getenv(s: string): string
+{
+ if(s == "user")
+ return getuser();
+ return nil;
+}
+
+getuser(): string
+{
+ fd := sys->open("/dev/user", Sys->OREAD);
+ if(fd != nil){
+ u := array [100] of byte;
+ n := sys->read(fd, u, len u);
+ if(n > 0)
+ return string u[0:n];
+ }
+ return nil;
+}
+
+getmode(p: string): (int, string)
+{
+ s: string;
+
+ (s, p) = getname(p, 7);
+ if(s == nil || s == "-")
+ return (~0, p);
+ m := 0;
+ if(s[0] == 'd'){
+ m |= Sys->DMDIR;
+ s = s[1:];
+ }
+ if(s[0] == 'a'){
+ #m |= CHAPPEND;
+ s = s[1:];
+ }
+ if(s[0] == 'l'){
+ #m |= CHEXCL;
+ s = s[1:];
+ }
+ for(i:=0; i<len s || i < 3; i++)
+ if(i >= len s || !(s[i]>='0' && s[i]<='7')){
+ cmod->protoerr(WARN, lineno, sys->sprint("bad mode specification %s", s));
+ return (~0, p);
+ }
+ (v, nil) := str->toint(s, 8);
+ return (m|v, p);
+}
+
+mkpath(prefix, elem: string): string
+{
+ slash1 := slash2 := 0;
+ if (len prefix > 0)
+ slash1 = prefix[len prefix - 1] == '/';
+ if (len elem > 0)
+ slash2 = elem[0] == '/';
+ if (slash1 && slash2)
+ return prefix+elem[1:];
+ if (!slash1 && !slash2)
+ return prefix+"/"+elem;
+ return prefix+elem;
+}