xref: /inferno-os/appl/cmd/ndb/mkhash.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Mkhash;
2
3#
4# for compatibility, this is closely modelled on Plan 9's ndb/mkhash
5#
6
7include "sys.m";
8	sys: Sys;
9
10include "draw.m";
11
12include "bufio.m";
13include "attrdb.m";
14	attrdb: Attrdb;
15	Db, Dbf, Dbentry, Tuples, Attr: import attrdb;
16	attrhash: Attrhash;
17	NDBPLEN, NDBHLEN, NDBCHAIN, NDBNAP: import Attrhash;
18
19Mkhash: module
20{
21	init:	fn(nil: ref Draw->Context, nil: list of string);
22};
23
24init(nil: ref Draw->Context, args: list of string)
25{
26	sys = load Sys Sys->PATH;
27	attrdb = load Attrdb Attrdb->PATH;
28	if(attrdb == nil)
29		error(sys->sprint("can't load %s: %r", Attrdb->PATH));
30	attrdb->init();
31	attrhash = load Attrhash Attrhash->PATH;
32	if(attrhash == nil)
33		error(sys->sprint("can't load %s: %r", Attrhash->PATH));
34
35	if(len args != 3)
36		error("usage: mkhash file attr");
37	args = tl args;
38	dbname := hd args;
39	args = tl args;
40	attr := hd args;
41	dbf := Dbf.open(dbname);
42	if(dbf == nil)
43		error(sys->sprint("can't open %s: %r", dbname));
44	offset := 0;
45	n := 0;
46	for(;;){
47		(e, nil, next) := dbf.readentry(offset, nil, nil, 0);
48		if(e == nil)
49			break;
50		m := len e.find(attr);
51		if(0 && m != 0)
52			sys->fprint(sys->fildes(2), "%ud [%d]\n", offset, m);
53		n += m;
54		offset = next;
55	}
56	hlen := 2*n+1;
57	chains := n*2*NDBPLEN;
58	file := array[NDBHLEN + hlen*NDBPLEN + chains] of byte;
59	tab := file[NDBHLEN:];
60	for(i:=0; i<len tab; i+=NDBPLEN)
61		put3(tab[i:], NDBNAP);
62	offset = 0;
63	chain := hlen*NDBPLEN;
64	for(;;){
65		(e, nil, next) := dbf.readentry(offset, nil, nil, 0);
66		if(e == nil)
67			break;
68		for(l := e.find(attr); l != nil; l = tl l)
69			for((nil, al) := hd l; al != nil; al = tl al)
70				chain = enter(tab, hd al, hlen, chain, offset);
71		offset = next;
72	}
73	hashfile := dbname+"."+attr;
74	hfd := sys->create(hashfile, Sys->OWRITE, 8r666);
75	if(hfd == nil)
76		error(sys->sprint("can't create %s: %r", hashfile));
77	mtime := 0;
78	if(dbf.dir != nil)
79		mtime = dbf.dir.mtime;
80	put4(file, mtime);
81	put4(file[4:], hlen);
82	if(sys->write(hfd, file, NDBHLEN+chain) != NDBHLEN+chain)
83		error(sys->sprint("error writing %s: %r", hashfile));
84}
85
86error(s: string)
87{
88	sys->fprint(sys->fildes(2), "mkhash: %s\n", s);
89	raise "fail:error";
90}
91
92enter(tab: array of byte, a: ref Attr, hlen: int, chain: int, offset: int): int
93{
94	o := attrhash->hash(a.val, hlen)*NDBPLEN;
95	for(; (p := attrhash->get3(tab[o:])) != NDBNAP; o = p & ~NDBCHAIN)
96		if((p & NDBCHAIN) == 0){
97			put3(tab[o:], chain | NDBCHAIN);
98			put3(tab[chain:], p);
99			put3(tab[chain+NDBPLEN:], offset);
100			return chain+2*NDBPLEN;
101		}
102	put3(tab[o:], offset);
103	return chain;
104}
105
106put3(a: array of byte, v: int)
107{
108	a[0] = byte v;
109	a[1] = byte (v>>8);
110	a[2] = byte (v>>16);
111}
112
113put4(a: array of byte, v: int)
114{
115	a[0] = byte v;
116	a[1] = byte (v>>8);
117	a[2] = byte (v>>16);
118	a[3] = byte (v>>24);
119}
120