master disk.c
ohmu  ·  2026-09-13
  1#include <u.h>
  2#include <libc.h>
  3#include <draw.h>
  4#include <thread.h>
  5#include <cursor.h>
  6#include <mouse.h>
  7#include <keyboard.h>
  8#include <frame.h>
  9#include <fcall.h>
 10#include <plumb.h>
 11#include <libsec.h>
 12#include "dat.h"
 13#include "fns.h"
 14
 15static	Block	*blist;
 16
 17int
 18tempfile(void)
 19{
 20	char buf[128];
 21	int i, fd;
 22
 23	snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", PID, getuser());
 24	for(i='A'; i<='Z'; i++){
 25		buf[5] = i;
 26		if(access(buf, AEXIST) == 0)
 27			continue;
 28		fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600);
 29		if(fd >= 0)
 30			return fd;
 31	}
 32	return -1;
 33}
 34
 35Disk*
 36diskinit()
 37{
 38	Disk *d;
 39
 40	d = emalloc(sizeof(Disk));
 41	d->fd = tempfile();
 42	if(d->fd < 0){
 43		fprint(2, "acme: can't create temp file: %r\n");
 44		threadexitsall("diskinit");
 45	}
 46	return d;
 47}
 48
 49static
 50uint
 51ntosize(uint n, uint *ip)
 52{
 53	uint size;
 54
 55	if(n > Maxblock)
 56		error("internal error: ntosize");
 57	size = n;
 58	if(size & (Blockincr-1))
 59		size += Blockincr - (size & (Blockincr-1));
 60	/* last bucket holds blocks of exactly Maxblock */
 61	if(ip)
 62		*ip = size/Blockincr;
 63	return size * sizeof(Rune);
 64}
 65
 66Block*
 67disknewblock(Disk *d, uint n)
 68{
 69	uint i, j, size;
 70	Block *b;
 71
 72	size = ntosize(n, &i);
 73	b = d->free[i];
 74	if(b)
 75		d->free[i] = b->u.next;
 76	else{
 77		/* allocate in chunks to reduce malloc overhead */
 78		if(blist == nil){
 79			blist = emalloc(100*sizeof(Block));
 80			for(j=0; j<100-1; j++)
 81				blist[j].u.next = &blist[j+1];
 82		}
 83		b = blist;
 84		blist = b->u.next;
 85		b->addr = d->addr;
 86		if(d->addr+size < d->addr){
 87			error("temp file overflow");
 88		}
 89		d->addr += size;
 90	}
 91	b->u.n = n;
 92	return b;
 93}
 94
 95void
 96diskrelease(Disk *d, Block *b)
 97{
 98	uint i;
 99
100	ntosize(b->u.n, &i);
101	b->u.next = d->free[i];
102	d->free[i] = b;
103}
104
105void
106diskwrite(Disk *d, Block **bp, Rune *r, uint n)
107{
108	int size, nsize;
109	Block *b;
110
111	b = *bp;
112	size = ntosize(b->u.n, nil);
113	nsize = ntosize(n, nil);
114	if(size != nsize){
115		diskrelease(d, b);
116		b = disknewblock(d, n);
117		*bp = b;
118	}
119	if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
120		error("write error to temp file");
121	b->u.n = n;
122}
123
124void
125diskread(Disk *d, Block *b, Rune *r, uint n)
126{
127	if(n > b->u.n)
128		error("internal error: diskread");
129
130	ntosize(b->u.n, nil);
131	if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
132		error("read error from temp file");
133}