code: plan9front

Download patch

ref: e8242918f4073dfff640da6b4a01287664ccb9f0
parent: 970d3b7eb7dc56aa84924dd68c4c39fd1df5d1f5
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Nov 25 14:04:01 EST 2023

ndb/mkhash: handle database= reordering, check offset overflow, remove file

when opening /lib/ndb/local, the db returned is the first entry
in the database= tuple, not the file passed to ndbopen(),
so search for the file in question.

make sure the file-offset doesnt exceed the NDBSPEC bit (23-bit).

remove the created hash file on error, and set TMP bit.

--- a/sys/src/cmd/ndb/mkhash.c
+++ b/sys/src/cmd/ndb/mkhash.c
@@ -11,16 +11,8 @@
 ulong hlen;
 Ndb *db;
 ulong nextchain;
+char err[ERRMAX];
 
-char*
-syserr(void)
-{
-	static char buf[ERRMAX];
-
-	errstr(buf, sizeof buf);
-	return buf;
-}
-
 void
 enter(char *val, ulong dboff)
 {
@@ -28,6 +20,8 @@
 	uchar *last;
 	ulong ptr;
 
+	assert(dboff < NDBSPEC);
+
 	h = ndbhash(val, hlen);
 	h *= NDBPLEN;
 	last = &ht[h];
@@ -37,6 +31,8 @@
 		return;
 	}
 
+	assert(nextchain < NDBSPEC);
+
 	if(ptr & NDBCHAIN){
 		/* walk the chain to the last entry */
 		for(;;){
@@ -61,16 +57,14 @@
 	nextchain += 2*NDBPLEN;
 }
 
-uchar nbuf[16*1024];
-
 void
 main(int argc, char **argv)
 {
 	Ndbtuple *t, *nt;
 	int n;
-	Dir *d;	
-	uchar buf[8];
-	char file[128];
+	Dir *d;
+	uchar buf[NDBHLEN];
+	char *file;
 	int fd;
 	ulong off;
 	uchar *p;
@@ -80,14 +74,14 @@
 		exits("usage");
 	}
 	db = ndbopen(argv[1]);
-	if(db == 0){
+	while(db != nil && strcmp(db->file, argv[1]) != 0)
+		db = db->next;
+	if(db == nil){
+		errstr(err, sizeof(err));
 		fprint(2, "mkhash: can't open %s\n", argv[1]);
-		exits(syserr());
+		exits(err);
 	}
 
-	/* try a bigger than normal buffer */
-	Binits(&db->b, Bfildes(&db->b), OREAD, nbuf, sizeof(nbuf));
-
 	/* count entries to calculate hash size */
 	n = 0;
 
@@ -99,13 +93,18 @@
 		ndbfree(nt);
 	}
 
+	if(Boffset(&db->b) >= NDBSPEC){
+		fprint(2, "mkhash: db file offset overflow\n");
+		exits("overflow");
+	}
+
 	/* allocate an array large enough for worst case */
 	hlen = 2*n+1;
 	n = hlen*NDBPLEN + hlen*2*NDBPLEN;
 	ht = mallocz(n, 1);
-	if(ht == 0){
+	if(ht == nil){
 		fprint(2, "mkhash: not enough memory\n");
-		exits(syserr());
+		exits("not enougth memory");
 	}
 	for(p = ht; p < &ht[n]; p += NDBPLEN)
 		NDBPUTP(NDBNAP, p);
@@ -124,32 +123,36 @@
 	}
 
 	/* create the hash file */
-	snprint(file, sizeof(file), "%s.%s", argv[1], argv[2]);
-	fd = create(file, ORDWR, 0664);
+	file = smprint("%s.%s", argv[1], argv[2]);
+	fd = create(file, OWRITE, DMTMP|0664);
 	if(fd < 0){
-		fprint(2, "mkhash: can't create %s\n", file);
-		exits(syserr());
+		errstr(err, sizeof(err));
+		fprint(2, "mkhash: can't create %s: %s\n", file, err);
+		exits(err);
 	}
 	NDBPUTUL(db->mtime, buf);
 	NDBPUTUL(hlen, buf+NDBULLEN);
 	if(write(fd, buf, NDBHLEN) != NDBHLEN){
-		fprint(2, "mkhash: writing %s\n", file);
-		exits(syserr());
+		errstr(err, sizeof(err));
+		fprint(2, "mkhash: writing %s: %s\n", file, err);
+		remove(file);
+		exits(err);
 	}
 	if(write(fd, ht, nextchain) != nextchain){
-		fprint(2, "mkhash: writing %s\n", file);
-		exits(syserr());
+		errstr(err, sizeof(err));
+		fprint(2, "mkhash: writing %s: %s\n", file, err);
+		remove(file);
+		exits(err);
 	}
 	close(fd);
 
 	/* make sure file didn't change while we were making the hash */
 	d = dirstat(argv[1]);
-	if(d == nil || d->qid.path != db->qid.path
-	   || d->qid.vers != db->qid.vers){
+	if(d == nil || d->qid.path != db->qid.path || d->qid.vers != db->qid.vers){
 		fprint(2, "mkhash: %s changed underfoot\n", argv[1]);
 		remove(file);
 		exits("changed");
 	}
 
-	exits(0);
+	exits(nil);
 }