Initial revision
diff --git a/src/cmd/sam/disk.c b/src/cmd/sam/disk.c
new file mode 100644
index 0000000..83b2553
--- /dev/null
+++ b/src/cmd/sam/disk.c
@@ -0,0 +1,122 @@
+#include "sam.h"
+
+static	Block	*blist;
+
+#if 0
+static int
+tempdisk(void)
+{
+	char buf[128];
+	int i, fd;
+
+	snprint(buf, sizeof buf, "/tmp/X%d.%.4ssam", getpid(), getuser());
+	for(i='A'; i<='Z'; i++){
+		buf[5] = i;
+		if(access(buf, AEXIST) == 0)
+			continue;
+		fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600);
+		if(fd >= 0)
+			return fd;
+	}
+	return -1;
+}
+#else
+extern int tempdisk(void);
+#endif
+
+Disk*
+diskinit()
+{
+	Disk *d;
+
+	d = emalloc(sizeof(Disk));
+	d->fd = tempdisk();
+	if(d->fd < 0){
+		fprint(2, "sam: can't create temp file: %r\n");
+		exits("diskinit");
+	}
+	return d;
+}
+
+static
+uint
+ntosize(uint n, uint *ip)
+{
+	uint size;
+
+	if(n > Maxblock)
+		panic("internal error: ntosize");
+	size = n;
+	if(size & (Blockincr-1))
+		size += Blockincr - (size & (Blockincr-1));
+	/* last bucket holds blocks of exactly Maxblock */
+	if(ip)
+		*ip = size/Blockincr;
+	return size * sizeof(Rune);
+}
+
+Block*
+disknewblock(Disk *d, uint n)
+{
+	uint i, j, size;
+	Block *b;
+
+	size = ntosize(n, &i);
+	b = d->free[i];
+	if(b)
+		d->free[i] = b->_.next;
+	else{
+		/* allocate in chunks to reduce malloc overhead */
+		if(blist == nil){
+			blist = emalloc(100*sizeof(Block));
+			for(j=0; j<100-1; j++)
+				blist[j]._.next = &blist[j+1];
+		}
+		b = blist;
+		blist = b->_.next;
+		b->addr = d->addr;
+		d->addr += size;
+	}
+	b->_.n = n;
+	return b;
+}
+
+void
+diskrelease(Disk *d, Block *b)
+{
+	uint i;
+
+	ntosize(b->_.n, &i);
+	b->_.next = d->free[i];
+	d->free[i] = b;
+}
+
+void
+diskwrite(Disk *d, Block **bp, Rune *r, uint n)
+{
+	int size, nsize;
+	Block *b;
+
+	b = *bp;
+	size = ntosize(b->_.n, nil);
+	nsize = ntosize(n, nil);
+	if(size != nsize){
+		diskrelease(d, b);
+		b = disknewblock(d, n);
+		*bp = b;
+	}
+	if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
+		panic("write error to temp file");
+	b->_.n = n;
+}
+
+void
+diskread(Disk *d, Block *b, Rune *r, uint n)
+{
+	if(n > b->_.n)
+		panic("internal error: diskread");
+
+	ntosize(b->_.n, nil);	/* called only for sanity check on Maxblock */
+	if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
+		panic("read error from temp file");
+}