Bad remote file systems can change mtime unexpectedly, and then there is the problem that git rebase and similar operations like to change the files and then change them back, modifying the mtimes but not the content. Avoid spurious Put errors on both of those by checking file content. (False positive "modified since last read" make the real ones difficult to notice.)
133 lines
2.2 KiB
C
133 lines
2.2 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <draw.h>
|
|
#include <thread.h>
|
|
#include <cursor.h>
|
|
#include <mouse.h>
|
|
#include <keyboard.h>
|
|
#include <frame.h>
|
|
#include <fcall.h>
|
|
#include <plumb.h>
|
|
#include <libsec.h>
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
|
|
static Block *blist;
|
|
|
|
int
|
|
tempfile(void)
|
|
{
|
|
char buf[128];
|
|
int i, fd;
|
|
|
|
snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", 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;
|
|
}
|
|
|
|
Disk*
|
|
diskinit()
|
|
{
|
|
Disk *d;
|
|
|
|
d = emalloc(sizeof(Disk));
|
|
d->fd = tempfile();
|
|
if(d->fd < 0){
|
|
fprint(2, "acme: can't create temp file: %r\n");
|
|
threadexitsall("diskinit");
|
|
}
|
|
return d;
|
|
}
|
|
|
|
static
|
|
uint
|
|
ntosize(uint n, uint *ip)
|
|
{
|
|
uint size;
|
|
|
|
if(n > Maxblock)
|
|
error("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->u.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].u.next = &blist[j+1];
|
|
}
|
|
b = blist;
|
|
blist = b->u.next;
|
|
b->addr = d->addr;
|
|
if(d->addr+size < d->addr){
|
|
error("temp file overflow");
|
|
}
|
|
d->addr += size;
|
|
}
|
|
b->u.n = n;
|
|
return b;
|
|
}
|
|
|
|
void
|
|
diskrelease(Disk *d, Block *b)
|
|
{
|
|
uint i;
|
|
|
|
ntosize(b->u.n, &i);
|
|
b->u.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->u.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))
|
|
error("write error to temp file");
|
|
b->u.n = n;
|
|
}
|
|
|
|
void
|
|
diskread(Disk *d, Block *b, Rune *r, uint n)
|
|
{
|
|
if(n > b->u.n)
|
|
error("internal error: diskread");
|
|
|
|
ntosize(b->u.n, nil);
|
|
if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
|
|
error("read error from temp file");
|
|
}
|