1*37da2899SCharles.Forsythimplement FSproto; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsythinclude "sys.m"; 4*37da2899SCharles.Forsyth sys: Sys; 5*37da2899SCharles.Forsyth Dir: import Sys; 6*37da2899SCharles.Forsythinclude "draw.m"; 7*37da2899SCharles.Forsythinclude "bufio.m"; 8*37da2899SCharles.Forsyth bufio: Bufio; 9*37da2899SCharles.Forsyth Iobuf: import bufio; 10*37da2899SCharles.Forsythinclude "string.m"; 11*37da2899SCharles.Forsyth str: String; 12*37da2899SCharles.Forsythinclude "readdir.m"; 13*37da2899SCharles.Forsyth readdir: Readdir; 14*37da2899SCharles.Forsythinclude "fsproto.m"; 15*37da2899SCharles.Forsyth 16*37da2899SCharles.ForsythFile: adt { 17*37da2899SCharles.Forsyth new: string; 18*37da2899SCharles.Forsyth elem: string; 19*37da2899SCharles.Forsyth old: string; 20*37da2899SCharles.Forsyth uid: string; 21*37da2899SCharles.Forsyth gid: string; 22*37da2899SCharles.Forsyth mode: int; 23*37da2899SCharles.Forsyth}; 24*37da2899SCharles.Forsyth 25*37da2899SCharles.ForsythProto: adt { 26*37da2899SCharles.Forsyth b: ref Iobuf; 27*37da2899SCharles.Forsyth doquote: int; 28*37da2899SCharles.Forsyth indent: int; 29*37da2899SCharles.Forsyth lineno: int; 30*37da2899SCharles.Forsyth newfile: string; 31*37da2899SCharles.Forsyth oldfile: string; 32*37da2899SCharles.Forsyth oldroot: string; 33*37da2899SCharles.Forsyth ec: chan of Direntry; 34*37da2899SCharles.Forsyth wc: chan of (string, string); 35*37da2899SCharles.Forsyth 36*37da2899SCharles.Forsyth walk: fn(w: self ref Proto, f: ref File, level: int); 37*37da2899SCharles.Forsyth entry: fn(w: self ref Proto, old: string, new: string, d: ref Sys->Dir); 38*37da2899SCharles.Forsyth warn: fn(w: self ref Proto, s: string); 39*37da2899SCharles.Forsyth fatal: fn(w: self ref Proto, s: string); 40*37da2899SCharles.Forsyth}; 41*37da2899SCharles.Forsyth 42*37da2899SCharles.Forsythinit(): string 43*37da2899SCharles.Forsyth{ 44*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 45*37da2899SCharles.Forsyth bufio = load Bufio Bufio->PATH; 46*37da2899SCharles.Forsyth if(bufio == nil) 47*37da2899SCharles.Forsyth return sys->sprint("%r"); 48*37da2899SCharles.Forsyth str = load String String->PATH; 49*37da2899SCharles.Forsyth if(str == nil) 50*37da2899SCharles.Forsyth return sys->sprint("%r"); 51*37da2899SCharles.Forsyth readdir = load Readdir Readdir->PATH; 52*37da2899SCharles.Forsyth if(readdir == nil) 53*37da2899SCharles.Forsyth return sys->sprint("%r"); 54*37da2899SCharles.Forsyth return nil; 55*37da2899SCharles.Forsyth} 56*37da2899SCharles.Forsyth 57*37da2899SCharles.Forsythreadprotofile(proto: string, root: string, entries: chan of Direntry, warnings: chan of (string, string)): string 58*37da2899SCharles.Forsyth{ 59*37da2899SCharles.Forsyth b := bufio->open(proto, Sys->OREAD); 60*37da2899SCharles.Forsyth if(b == nil) 61*37da2899SCharles.Forsyth return sys->sprint("%r"); 62*37da2899SCharles.Forsyth rdproto(b, root, entries, warnings); 63*37da2899SCharles.Forsyth return nil; 64*37da2899SCharles.Forsyth} 65*37da2899SCharles.Forsyth 66*37da2899SCharles.Forsythreadprotostring(proto: string, root: string, entries: chan of Direntry, warnings: chan of (string, string)) 67*37da2899SCharles.Forsyth{ 68*37da2899SCharles.Forsyth rdproto(bufio->sopen(proto), root, entries, warnings); 69*37da2899SCharles.Forsyth} 70*37da2899SCharles.Forsyth 71*37da2899SCharles.Forsythrdproto(b: ref Iobuf, root: string, entries: chan of Direntry, warnings: chan of (string, string)): string 72*37da2899SCharles.Forsyth{ 73*37da2899SCharles.Forsyth w := ref Proto; 74*37da2899SCharles.Forsyth w.b = b; 75*37da2899SCharles.Forsyth w.doquote = 1; 76*37da2899SCharles.Forsyth w.ec = entries; 77*37da2899SCharles.Forsyth w.wc = warnings; 78*37da2899SCharles.Forsyth w.oldroot = root; 79*37da2899SCharles.Forsyth w.lineno = 0; 80*37da2899SCharles.Forsyth w.indent = 0; 81*37da2899SCharles.Forsyth file := ref File; 82*37da2899SCharles.Forsyth file.mode = 0; 83*37da2899SCharles.Forsyth spawn walker(w, file); 84*37da2899SCharles.Forsyth return nil; 85*37da2899SCharles.Forsyth} 86*37da2899SCharles.Forsyth 87*37da2899SCharles.Forsythwalker(w: ref Proto, file: ref File) 88*37da2899SCharles.Forsyth{ 89*37da2899SCharles.Forsyth w.walk(file, -1); 90*37da2899SCharles.Forsyth w.entry(nil, nil, nil); 91*37da2899SCharles.Forsyth} 92*37da2899SCharles.Forsyth 93*37da2899SCharles.ForsythProto.entry(w: self ref Proto, old: string, new: string, d: ref Sys->Dir) 94*37da2899SCharles.Forsyth{ 95*37da2899SCharles.Forsyth if(w.ec != nil) 96*37da2899SCharles.Forsyth w.ec <-= (old, new, d); 97*37da2899SCharles.Forsyth} 98*37da2899SCharles.Forsyth 99*37da2899SCharles.ForsythProto.warn(w: self ref Proto, s: string) 100*37da2899SCharles.Forsyth{ 101*37da2899SCharles.Forsyth if(w.wc != nil) 102*37da2899SCharles.Forsyth w.wc <-= (w.oldfile, s); 103*37da2899SCharles.Forsyth else 104*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "warning: %s\n", s); 105*37da2899SCharles.Forsyth} 106*37da2899SCharles.Forsyth 107*37da2899SCharles.ForsythProto.fatal(w: self ref Proto, s: string) 108*37da2899SCharles.Forsyth{ 109*37da2899SCharles.Forsyth if(w.wc != nil) 110*37da2899SCharles.Forsyth w.wc <-= (w.oldfile, s); 111*37da2899SCharles.Forsyth else 112*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "fatal error: %s\n", s); 113*37da2899SCharles.Forsyth w.ec <-= (nil, nil, nil); 114*37da2899SCharles.Forsyth exit; 115*37da2899SCharles.Forsyth} 116*37da2899SCharles.Forsyth 117*37da2899SCharles.ForsythProto.walk(w: self ref Proto, me: ref File, level: int) 118*37da2899SCharles.Forsyth{ 119*37da2899SCharles.Forsyth (child, fp) := getfile(w, me); 120*37da2899SCharles.Forsyth if(child == nil) 121*37da2899SCharles.Forsyth return; 122*37da2899SCharles.Forsyth if(child.elem == "+" || child.elem == "*" || child.elem == "%"){ 123*37da2899SCharles.Forsyth rec := child.elem[0] == '+'; 124*37da2899SCharles.Forsyth filesonly := child.elem[0] == '%'; 125*37da2899SCharles.Forsyth child.new = me.new; 126*37da2899SCharles.Forsyth setnames(w, child); 127*37da2899SCharles.Forsyth mktree(w, child, rec, filesonly); 128*37da2899SCharles.Forsyth (child, fp) = getfile(w, me); 129*37da2899SCharles.Forsyth } 130*37da2899SCharles.Forsyth while(child != nil && w.indent > level){ 131*37da2899SCharles.Forsyth if(mkfile(w, child)) 132*37da2899SCharles.Forsyth w.walk(child, w.indent); 133*37da2899SCharles.Forsyth (child, fp) = getfile(w, me); 134*37da2899SCharles.Forsyth } 135*37da2899SCharles.Forsyth if(child != nil){ 136*37da2899SCharles.Forsyth w.b.seek(big fp, 0); 137*37da2899SCharles.Forsyth w.lineno--; 138*37da2899SCharles.Forsyth } 139*37da2899SCharles.Forsyth} 140*37da2899SCharles.Forsyth 141*37da2899SCharles.Forsythmktree(w: ref Proto, me: ref File, rec: int, filesonly: int) 142*37da2899SCharles.Forsyth{ 143*37da2899SCharles.Forsyth fd := sys->open(w.oldfile, Sys->OREAD); 144*37da2899SCharles.Forsyth if(fd == nil){ 145*37da2899SCharles.Forsyth w.warn(sys->sprint("can't open %s: %r", w.oldfile)); 146*37da2899SCharles.Forsyth return; 147*37da2899SCharles.Forsyth } 148*37da2899SCharles.Forsyth child := ref *me; 149*37da2899SCharles.Forsyth (d, n) := readdir->init(w.oldfile, Readdir->NAME|Readdir->COMPACT); 150*37da2899SCharles.Forsyth for(i := 0; i < n; i++) { 151*37da2899SCharles.Forsyth if(filesonly && (d[i].mode & Sys->DMDIR)) 152*37da2899SCharles.Forsyth continue; 153*37da2899SCharles.Forsyth child.new = mkpath(me.new, d[i].name); 154*37da2899SCharles.Forsyth if(me.old != nil) 155*37da2899SCharles.Forsyth child.old = mkpath(me.old, d[i].name); 156*37da2899SCharles.Forsyth child.elem = d[i].name; 157*37da2899SCharles.Forsyth setnames(w, child); 158*37da2899SCharles.Forsyth if(copyfile(w, child, d[i]) && rec) 159*37da2899SCharles.Forsyth mktree(w, child, rec, filesonly); 160*37da2899SCharles.Forsyth } 161*37da2899SCharles.Forsyth} 162*37da2899SCharles.Forsyth 163*37da2899SCharles.Forsythmkfile(w: ref Proto, f: ref File): int 164*37da2899SCharles.Forsyth{ 165*37da2899SCharles.Forsyth (i, dir) := sys->stat(w.oldfile); 166*37da2899SCharles.Forsyth if(i < 0){ 167*37da2899SCharles.Forsyth w.warn(sys->sprint("can't stat file %s: %r", w.oldfile)); 168*37da2899SCharles.Forsyth skipdir(w); 169*37da2899SCharles.Forsyth return 0; 170*37da2899SCharles.Forsyth } 171*37da2899SCharles.Forsyth return copyfile(w, f, ref dir); 172*37da2899SCharles.Forsyth} 173*37da2899SCharles.Forsyth 174*37da2899SCharles.Forsythcopyfile(w: ref Proto, f: ref File, d: ref Dir): int 175*37da2899SCharles.Forsyth{ 176*37da2899SCharles.Forsyth d.name = f.elem; 177*37da2899SCharles.Forsyth if(f.mode != ~0){ 178*37da2899SCharles.Forsyth if((d.mode&Sys->DMDIR) != (f.mode&Sys->DMDIR)) 179*37da2899SCharles.Forsyth w.warn(sys->sprint("inconsistent mode for %s", f.new)); 180*37da2899SCharles.Forsyth else 181*37da2899SCharles.Forsyth d.mode = f.mode; 182*37da2899SCharles.Forsyth } 183*37da2899SCharles.Forsyth w.entry(w.oldfile, w.newfile, d); 184*37da2899SCharles.Forsyth return (d.mode & Sys->DMDIR) != 0; 185*37da2899SCharles.Forsyth} 186*37da2899SCharles.Forsyth 187*37da2899SCharles.Forsythsetnames(w: ref Proto, f: ref File) 188*37da2899SCharles.Forsyth{ 189*37da2899SCharles.Forsyth w.newfile = f.new; 190*37da2899SCharles.Forsyth if(f.old != nil){ 191*37da2899SCharles.Forsyth if(f.old[0] == '/') 192*37da2899SCharles.Forsyth w.oldfile = mkpath(w.oldroot, f.old); 193*37da2899SCharles.Forsyth else 194*37da2899SCharles.Forsyth w.oldfile = f.old; 195*37da2899SCharles.Forsyth }else 196*37da2899SCharles.Forsyth w.oldfile = mkpath(w.oldroot, f.new); 197*37da2899SCharles.Forsyth} 198*37da2899SCharles.Forsyth 199*37da2899SCharles.Forsyth# 200*37da2899SCharles.Forsyth# skip all files in the proto that 201*37da2899SCharles.Forsyth# could be in the current dir 202*37da2899SCharles.Forsyth# 203*37da2899SCharles.Forsythskipdir(w: ref Proto) 204*37da2899SCharles.Forsyth{ 205*37da2899SCharles.Forsyth if(w.indent < 0) 206*37da2899SCharles.Forsyth return; 207*37da2899SCharles.Forsyth b := w.b; 208*37da2899SCharles.Forsyth level := w.indent; 209*37da2899SCharles.Forsyth for(;;){ 210*37da2899SCharles.Forsyth w.indent = 0; 211*37da2899SCharles.Forsyth fp := b.offset(); 212*37da2899SCharles.Forsyth p := b.gets('\n'); 213*37da2899SCharles.Forsyth if(p != nil && p[len p - 1] != '\n') 214*37da2899SCharles.Forsyth p += "\n"; 215*37da2899SCharles.Forsyth w.lineno++; 216*37da2899SCharles.Forsyth if(p == nil){ 217*37da2899SCharles.Forsyth w.indent = -1; 218*37da2899SCharles.Forsyth return; 219*37da2899SCharles.Forsyth } 220*37da2899SCharles.Forsyth for(j := 0; (c := p[j++]) != '\n';) 221*37da2899SCharles.Forsyth if(c == ' ') 222*37da2899SCharles.Forsyth w.indent++; 223*37da2899SCharles.Forsyth else if(c == '\t') 224*37da2899SCharles.Forsyth w.indent += 8; 225*37da2899SCharles.Forsyth else 226*37da2899SCharles.Forsyth break; 227*37da2899SCharles.Forsyth if(w.indent <= level){ 228*37da2899SCharles.Forsyth b.seek(fp, 0); 229*37da2899SCharles.Forsyth w.lineno--; 230*37da2899SCharles.Forsyth return; 231*37da2899SCharles.Forsyth } 232*37da2899SCharles.Forsyth } 233*37da2899SCharles.Forsyth} 234*37da2899SCharles.Forsyth 235*37da2899SCharles.Forsythgetfile(w: ref Proto, old: ref File): (ref File, int) 236*37da2899SCharles.Forsyth{ 237*37da2899SCharles.Forsyth p, elem: string; 238*37da2899SCharles.Forsyth c: int; 239*37da2899SCharles.Forsyth 240*37da2899SCharles.Forsyth if(w.indent < 0) 241*37da2899SCharles.Forsyth return (nil, 0); 242*37da2899SCharles.Forsyth b := w.b; 243*37da2899SCharles.Forsyth fp := int b.offset(); 244*37da2899SCharles.Forsyth do { 245*37da2899SCharles.Forsyth w.indent = 0; 246*37da2899SCharles.Forsyth p = b.gets('\n'); 247*37da2899SCharles.Forsyth if(p != nil && p[len p - 1] != '\n') 248*37da2899SCharles.Forsyth p += "\n"; 249*37da2899SCharles.Forsyth w.lineno++; 250*37da2899SCharles.Forsyth if(p == nil){ 251*37da2899SCharles.Forsyth w.indent = -1; 252*37da2899SCharles.Forsyth return (nil, 0); 253*37da2899SCharles.Forsyth } 254*37da2899SCharles.Forsyth for(; (c = p[0]) != '\n'; p = p[1:]) 255*37da2899SCharles.Forsyth if(c == ' ') 256*37da2899SCharles.Forsyth w.indent++; 257*37da2899SCharles.Forsyth else if(c == '\t') 258*37da2899SCharles.Forsyth w.indent += 8; 259*37da2899SCharles.Forsyth else 260*37da2899SCharles.Forsyth break; 261*37da2899SCharles.Forsyth } while(c == '\n' || c == '#'); 262*37da2899SCharles.Forsyth (elem, p) = getname(w, p); 263*37da2899SCharles.Forsyth if(p == nil) 264*37da2899SCharles.Forsyth return (nil, 0); 265*37da2899SCharles.Forsyth f := ref File; 266*37da2899SCharles.Forsyth f.new = mkpath(old.new, elem); 267*37da2899SCharles.Forsyth (nil, f.elem) = str->splitr(f.new, "/"); 268*37da2899SCharles.Forsyth if(f.elem == nil) 269*37da2899SCharles.Forsyth w.fatal(sys->sprint("can't find file name component of %s", f.new)); 270*37da2899SCharles.Forsyth (f.mode, p) = getmode(w, p); 271*37da2899SCharles.Forsyth if(p == nil) 272*37da2899SCharles.Forsyth return (nil, 0); 273*37da2899SCharles.Forsyth (f.uid, p) = getname(w, p); 274*37da2899SCharles.Forsyth if(p == nil) 275*37da2899SCharles.Forsyth return (nil, 0); 276*37da2899SCharles.Forsyth if(f.uid == nil) 277*37da2899SCharles.Forsyth f.uid = "-"; 278*37da2899SCharles.Forsyth (f.gid, p) = getname(w, p); 279*37da2899SCharles.Forsyth if(p == nil) 280*37da2899SCharles.Forsyth return (nil, 0); 281*37da2899SCharles.Forsyth if(f.gid == nil) 282*37da2899SCharles.Forsyth f.gid = "-"; 283*37da2899SCharles.Forsyth f.old = getpath(p); 284*37da2899SCharles.Forsyth if(f.old == "-") 285*37da2899SCharles.Forsyth f.old = nil; 286*37da2899SCharles.Forsyth if(f.old == nil && old.old != nil) 287*37da2899SCharles.Forsyth f.old = mkpath(old.old, elem); 288*37da2899SCharles.Forsyth setnames(w, f); 289*37da2899SCharles.Forsyth return (f, fp); 290*37da2899SCharles.Forsyth} 291*37da2899SCharles.Forsyth 292*37da2899SCharles.Forsythgetpath(p: string): string 293*37da2899SCharles.Forsyth{ 294*37da2899SCharles.Forsyth for(; (c := p[0]) == ' ' || c == '\t'; p = p[1:]) 295*37da2899SCharles.Forsyth ; 296*37da2899SCharles.Forsyth for(n := 0; (c = p[n]) != '\n' && c != ' ' && c != '\t'; n++) 297*37da2899SCharles.Forsyth ; 298*37da2899SCharles.Forsyth return p[0:n]; 299*37da2899SCharles.Forsyth} 300*37da2899SCharles.Forsyth 301*37da2899SCharles.Forsythgetname(w: ref Proto, p: string): (string, string) 302*37da2899SCharles.Forsyth{ 303*37da2899SCharles.Forsyth for(; (c := p[0]) == ' ' || c == '\t'; p = p[1:]) 304*37da2899SCharles.Forsyth ; 305*37da2899SCharles.Forsyth i := 0; 306*37da2899SCharles.Forsyth s := ""; 307*37da2899SCharles.Forsyth quoted := 0; 308*37da2899SCharles.Forsyth for(; (c = p[0]) != '\n' && (c != ' ' && c != '\t' || quoted); p = p[1:]){ 309*37da2899SCharles.Forsyth if(quoted && c == '\'' && p[1] == '\'') 310*37da2899SCharles.Forsyth p = p[1:]; 311*37da2899SCharles.Forsyth else if(c == '\'' && w.doquote){ 312*37da2899SCharles.Forsyth quoted = !quoted; 313*37da2899SCharles.Forsyth continue; 314*37da2899SCharles.Forsyth } 315*37da2899SCharles.Forsyth s[i++] = c; 316*37da2899SCharles.Forsyth } 317*37da2899SCharles.Forsyth if(len s > 0 && s[0] == '$'){ 318*37da2899SCharles.Forsyth s = getenv(s[1:]); 319*37da2899SCharles.Forsyth if(s == nil) 320*37da2899SCharles.Forsyth w.warn(sys->sprint("can't read environment variable %s", s)); 321*37da2899SCharles.Forsyth } 322*37da2899SCharles.Forsyth return (s, p); 323*37da2899SCharles.Forsyth} 324*37da2899SCharles.Forsyth 325*37da2899SCharles.Forsythgetenv(s: string): string 326*37da2899SCharles.Forsyth{ 327*37da2899SCharles.Forsyth if(s == "user") 328*37da2899SCharles.Forsyth return readfile("/dev/user"); # more accurate? 329*37da2899SCharles.Forsyth return readfile("/env/"+s); 330*37da2899SCharles.Forsyth} 331*37da2899SCharles.Forsyth 332*37da2899SCharles.Forsythreadfile(f: string): string 333*37da2899SCharles.Forsyth{ 334*37da2899SCharles.Forsyth fd := sys->open(f, Sys->OREAD); 335*37da2899SCharles.Forsyth if(fd != nil){ 336*37da2899SCharles.Forsyth a := array[256] of byte; 337*37da2899SCharles.Forsyth n := sys->read(fd, a, len a); 338*37da2899SCharles.Forsyth if(n > 0) 339*37da2899SCharles.Forsyth return string a[0:n]; 340*37da2899SCharles.Forsyth } 341*37da2899SCharles.Forsyth return nil; 342*37da2899SCharles.Forsyth} 343*37da2899SCharles.Forsyth 344*37da2899SCharles.Forsythgetmode(w: ref Proto, p: string): (int, string) 345*37da2899SCharles.Forsyth{ 346*37da2899SCharles.Forsyth s: string; 347*37da2899SCharles.Forsyth 348*37da2899SCharles.Forsyth (s, p) = getname(w, p); 349*37da2899SCharles.Forsyth if(s == nil || s == "-") 350*37da2899SCharles.Forsyth return (~0, p); 351*37da2899SCharles.Forsyth m := 0; 352*37da2899SCharles.Forsyth if(s[0] == 'd'){ 353*37da2899SCharles.Forsyth m |= Sys->DMDIR; 354*37da2899SCharles.Forsyth s = s[1:]; 355*37da2899SCharles.Forsyth } 356*37da2899SCharles.Forsyth if(s[0] == 'a'){ 357*37da2899SCharles.Forsyth m |= Sys->DMAPPEND; 358*37da2899SCharles.Forsyth s = s[1:]; 359*37da2899SCharles.Forsyth } 360*37da2899SCharles.Forsyth if(s[0] == 'l'){ 361*37da2899SCharles.Forsyth m |= Sys->DMEXCL; 362*37da2899SCharles.Forsyth s = s[1:]; 363*37da2899SCharles.Forsyth } 364*37da2899SCharles.Forsyth for(i:=0; i<len s || i < 3; i++) 365*37da2899SCharles.Forsyth if(i >= len s || !(s[i]>='0' && s[i]<='7')){ 366*37da2899SCharles.Forsyth w.warn(sys->sprint("bad mode specification %s", s)); 367*37da2899SCharles.Forsyth return (~0, p); 368*37da2899SCharles.Forsyth } 369*37da2899SCharles.Forsyth (v, nil) := str->toint(s, 8); 370*37da2899SCharles.Forsyth return (m|v, p); 371*37da2899SCharles.Forsyth} 372*37da2899SCharles.Forsyth 373*37da2899SCharles.Forsythmkpath(prefix, elem: string): string 374*37da2899SCharles.Forsyth{ 375*37da2899SCharles.Forsyth slash1 := slash2 := 0; 376*37da2899SCharles.Forsyth if(len prefix > 0) 377*37da2899SCharles.Forsyth slash1 = prefix[len prefix - 1] == '/'; 378*37da2899SCharles.Forsyth if(len elem > 0) 379*37da2899SCharles.Forsyth slash2 = elem[0] == '/'; 380*37da2899SCharles.Forsyth if(slash1 && slash2) 381*37da2899SCharles.Forsyth return prefix+elem[1:]; 382*37da2899SCharles.Forsyth if(!slash1 && !slash2) 383*37da2899SCharles.Forsyth return prefix+"/"+elem; 384*37da2899SCharles.Forsyth return prefix+elem; 385*37da2899SCharles.Forsyth} 386