diff options
Diffstat (limited to 'appl/cmd/install/logs.b')
| -rw-r--r-- | appl/cmd/install/logs.b | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/appl/cmd/install/logs.b b/appl/cmd/install/logs.b new file mode 100644 index 00000000..20135622 --- /dev/null +++ b/appl/cmd/install/logs.b @@ -0,0 +1,287 @@ +implement Logs; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; + +include "string.m"; + str: String; + +include "logs.m"; + +Hashsize: con 1024; +Incr: con 500; + +init(bio: Bufio): string +{ + sys = load Sys Sys->PATH; + bufio = bio; + str = load String String->PATH; + if(str == nil) + return sys->sprint("can't load %s: %r", String->PATH); + return nil; +} + +Entry.read(in: ref Iobuf): (ref Entry, string) +{ + if((s := in.gets('\n')) == nil) + return (nil, nil); + if(s[len s-1] == '\n') + s = s[0:len s-1]; + + e := ref Entry; + e.x = -1; + + l := str->unquoted(s); + fields := array[11] of string; + for(i := 0; l != nil; l = tl l) + fields[i++] = S(hd l); + + # time gen verb path serverpath mode uid gid mtime length + # 1064889121 4 a sys/src/cmd/ip/httpd/webls.denied - 664 sys sys 1064887847 3 + # time[0] gen[1] op[2] path[3] (serverpath|"-")[4] mode[5] uid[6] gid[7] mtime[8] length[9] + + if(i < 10 || len fields[2] != 1) + return (nil, sys->sprint("bad log entry: %q", s)); + e.action = fields[2][0]; + case e.action { + 'a' or 'c' or 'd' or 'm' => + ; + * => + return (nil, sys->sprint("bad log entry: %q", s)); + } + + time := bigof(fields[0], 10); + sgen := bigof(fields[1], 10); + e.seq = (time << 32) | sgen; # for easier comparison + + # time/gen check + # name check + + if(fields[4] == "-") # undocumented + fields[4] = fields[3]; + e.path = fields[3]; + e.serverpath = fields[4]; + e.d = sys->nulldir; + { + e.d.mode = intof(fields[5], 8); + e.d.qid.qtype = e.d.mode>>24; + e.d.uid = fields[6]; + if(e.d.uid == "-") + e.d.uid = ""; + e.d.gid = fields[7]; + if(e.d.gid == "-") + e.d.gid = ""; + e.d.mtime = intof(fields[8], 10); + e.d.length = bigof(fields[9], 10); + }exception ex { + "log format:*" => + return (nil, sys->sprint("%s in log entry %q", ex, s)); + } + e.contents = fields[10] :: nil; # optional + return (e, nil); +} + +rev[T](l: list of T): list of T +{ + rl: list of T; + for(; l != nil; l = tl l) + rl = hd l :: rl; + return rl; +} + +bigof(s: string, base: int): big +{ + (b, r) := str->tobig(s, base); + if(r != nil) + raise "invalid integer field"; + return b; +} + +intof(s: string, base: int): int +{ + return int bigof(s, base); +} + +mkpath(root: string, name: string): string +{ + if(len root > 0 && root[len root-1] != '/' && (len name == 0 || name[0] != '/')) + return root+"/"+name; + return root+name; +} + +contents(e: ref Entry): string +{ + if(e.contents == nil) + return ""; + s := ""; + for(cl := e.contents; cl != nil; cl = tl cl) + s += " " + hd cl; + return s[1:]; +} + +Entry.text(e: self ref Entry): string +{ + a := e.action; + if(a == 0) + a = '?'; + return sys->sprint("%bd %bd %q [%d] %c m=%uo l=%bd t=%ud c=%q", e.seq>>32, e.seq & 16rFFFFFFFF, e.path, e.x, a, e.d.mode, e.d.length, e.d.mtime, contents(e)); +} + +Entry.sumtext(e: self ref Entry): string +{ + case e.action { + 'a' or 'm' => + return sys->sprint("%c %q %uo %q %q %ud", e.action, e.path, e.d.mode, e.d.uid, e.d.gid, e.d.mtime); + 'd' or 'c' => + return sys->sprint("%c %q", e.action, e.path); + * => + return sys->sprint("? %q", e.path); + } +} + +Entry.dbtext(e: self ref Entry): string +{ + # path dpath|"-" mode uid gid mtime length + return sys->sprint("%bd %bd %q - %uo %q %q %ud %bd%s", e.seq>>32, e.seq & 16rFFFFFFFF, e.path, e.d.mode, e.d.uid, e.d.gid, e.d.mtime, e.d.length, contents(e)); +} + +Entry.logtext(e: self ref Entry): string +{ + # gen n act path spath|"-" dpath|"-" mode uid gid mtime length + a := e.action; + if(a == 0) + a = '?'; + sf := e.serverpath; + if(sf == nil || sf == e.path) + sf = "-"; + return sys->sprint("%bd %bd %c %q %q %uo %q %q %ud %bd%s", e.seq>>32, e.seq & 16rFFFFFFFF, a, e.path, sf, e.d.mode, e.d.uid, e.d.gid, e.d.mtime, e.d.length, contents(e)); +} + +Entry.remove(e: self ref Entry) +{ + e.action = 'd'; +} + +Entry.removed(e: self ref Entry): int +{ + return e.action == 'd'; +} + +Entry.update(e: self ref Entry, n: ref Entry) +{ + if(n == nil) + return; + if(n.action == 'd') + e.contents = nil; + else + e.d = n.d; + if(n.action != 'm' || e.action == 'd') + e.action = n.action; + e.serverpath = S(n.serverpath); + for(nl := rev(n.contents); nl != nil; nl = tl nl) + e.contents = hd nl :: e.contents; + if(n.seq > e.seq) + e.seq = n.seq; +} + +Db.new(name: string): ref Db +{ + db := ref Db; + db.name = name; + db.stateht = array[Hashsize] of list of ref Entry; + db.nstate = 0; + db.state = array[50] of ref Entry; + return db; +} + +Db.look(db: self ref Db, name: string): ref Entry +{ + (b, nil) := hash(name, len db.stateht); + for(l := db.stateht[b]; l != nil; l = tl l) + if((hd l).path == name) + return hd l; + return nil; +} + +Db.entry(db: self ref Db, seq: big, name: string, d: Sys->Dir): ref Entry +{ + e := ref Entry; + e.action = 'a'; + e.seq = seq; + e.path = name; + e.d = d; + e.x = db.nstate++; + if(e.x >= len db.state){ + a := array[len db.state + Incr] of ref Entry; + a[0:] = db.state; + db.state = a; + } + db.state[e.x] = e; + (b, nil) := hash(name, len db.stateht); + db.stateht[b] = e :: db.stateht[b]; + return e; +} + +Db.sort(db: self ref Db, key: int) +{ + sortentries(db.state[0:db.nstate], key); +} + +sortentries(a: array of ref Entry, key: int): (array of ref Entry, int) +{ + mergesort(a, array[len a] of ref Entry, key); + return (a, len a); +} + +mergesort(a, b: array of ref Entry, key: int) +{ + r := len a; + if(r > 1) { + m := (r-1)/2 + 1; + mergesort(a[0:m], b[0:m], key); + mergesort(a[m:], b[m:], key); + b[0:] = a; + for((i, j, k) := (0, m, 0); i < m && j < r; k++) { + if(key==Byname && b[i].path > b[j].path || key==Byseq && b[i].seq > b[j].seq) + a[k] = b[j++]; + else + a[k] = b[i++]; + } + if(i < m) + a[k:] = b[i:m]; + else if(j < r) + a[k:] = b[j:r]; + } +} + +strings: array of list of string; + +S(s: string): string +{ + if(strings == nil) + strings = array[257] of list of string; + h := hash(s, len strings).t0; + for(sl := strings[h]; sl != nil; sl = tl sl) + if(hd sl == s) + return hd sl; + strings[h] = s :: strings[h]; + return s; +} + +hash(s: string, n: int): (int, int) +{ + # hashpjw + h := 0; + for(i:=0; i<len s; i++){ + h = (h<<4) + s[i]; + if((g := h & int 16rF0000000) != 0) + h ^= ((g>>24) & 16rFF) | g; + } + return ((h&~(1<<31))%n, h); +} |
