commit 67dbeee5fe9e2a855384048615bafe100e876f4c from: Russ Cox date: Tue Oct 10 17:51:24 2017 UTC acme: check file content before declaring file "modified since last read" 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.) commit - 680c57a15c51c302d89aec134e25f08820d3f30d commit + 67dbeee5fe9e2a855384048615bafe100e876f4c blob - 2f4fe3ab40eac3470ea2d40347dcc2e87fc5db6d blob + 10dcdcc85a291ebcaa9aeb5eee8590f18b46cbbf --- src/cmd/acme/acme.c +++ src/cmd/acme/acme.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" /* for generating syms in mkfile only: */ blob - f09688dc61526d3adfd949531fe6c1a2bff8e98c blob + 861e5e01f0d7c4c13d31d1d89e565088179f155a --- src/cmd/acme/addr.c +++ src/cmd/acme/addr.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - 875bb0b0402839847a186f5ab294ea77e0672866 blob + bb938ca4cfab4132fc0540d1505ae4e2da3b1f34 --- src/cmd/acme/buff.c +++ src/cmd/acme/buff.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -231,7 +232,7 @@ bufloader(void *v, uint q0, Rune *r, int nr) } uint -loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *arg) +loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *arg, DigestState *h) { char *p; Rune *r; @@ -253,6 +254,8 @@ loadfile(int fd, uint q0, int *nulls, int(*f)(void*, u warning(nil, "read error in Buffer.load"); break; } + if(h != nil) + sha1((uchar*)p+m, n, nil, h); m += n; p[m] = 0; l = m; @@ -269,11 +272,11 @@ loadfile(int fd, uint q0, int *nulls, int(*f)(void*, u } uint -bufload(Buffer *b, uint q0, int fd, int *nulls) +bufload(Buffer *b, uint q0, int fd, int *nulls, DigestState *h) { if(q0 > b->nc) error("internal error: bufload"); - return loadfile(fd, q0, nulls, bufloader, b); + return loadfile(fd, q0, nulls, bufloader, b, h); } void blob - 5e16c21aa3319b1c1281a1ed4c77abd04f5f35ac blob + 10e014eea40583686201e3cccdc3d89bf3344c4f --- src/cmd/acme/cols.c +++ src/cmd/acme/cols.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - df1a6422a7ff9f270551f8f31eef6b75edc34904 blob + 8c4b14ee2388146308abc3732eb178578f78c069 --- src/cmd/acme/dat.h +++ src/cmd/acme/dat.h @@ -105,7 +105,7 @@ struct Buffer }; void bufinsert(Buffer*, uint, Rune*, uint); void bufdelete(Buffer*, uint, uint); -uint bufload(Buffer*, uint, int, int*); +uint bufload(Buffer*, uint, int, int*, DigestState*); void bufread(Buffer*, uint, Rune*, uint); void bufclose(Buffer*); void bufreset(Buffer*); @@ -135,8 +135,9 @@ struct File Rune *name; /* name of associated file */ int nname; /* size of name */ uvlong qidpath; /* of file when read */ - ulong mtime; /* of file when read */ + ulong mtime; /* of file when read */ int dev; /* of file when read */ + uchar sha1[20]; /* of file when read */ int unread; /* file has not been read from disk */ int editclean; /* mark clean after edit command */ @@ -152,7 +153,7 @@ void fileclose(File*); void filedelete(File*, uint, uint); void filedeltext(File*, Text*); void fileinsert(File*, uint, Rune*, uint); -uint fileload(File*, uint, int, int*); +uint fileload(File*, uint, int, int*, DigestState*); void filemark(File*); void filereset(File*); void filesetname(File*, Rune*, int); blob - 8d95fa1d519f88ffd9d0e1999ad4214982480c05 blob + c3ada9c3c0b037bf4992f449eec81046934bf10f --- src/cmd/acme/disk.c +++ src/cmd/acme/disk.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - bdcaf9f5a72d5a08c21b0e3d3e3616e9444da61a blob + 9bedae4ca39fa20069b7459fa576a3e573868192 --- src/cmd/acme/ecmd.c +++ src/cmd/acme/ecmd.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "edit.h" #include "fns.h" @@ -336,7 +337,7 @@ e_cmd(Text *t, Cmd *cp) } elogdelete(f, q0, q1); nulls = 0; - loadfile(fd, q1, &nulls, readloader, f); + loadfile(fd, q1, &nulls, readloader, f, nil); free(s); close(fd); if(nulls) blob - 4495bf6976cddc6757224157871e72c1465ebc99 blob + d3f820593ea00d1e52229b00bcd847bb62affd58 --- src/cmd/acme/edit.c +++ src/cmd/acme/edit.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "edit.h" #include "fns.h" blob - 4ec3e3b29d89a57ed4a6f057c1273659ed138ac3 blob + c5650f03f9934aaba9d8a20aa1741b0725c24d18 --- src/cmd/acme/elog.c +++ src/cmd/acme/elog.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" #include "edit.h" blob - 2a259533313dbf503634ac57273db722d80d1a35 blob + 75737d80b768bd81dba3f230cfda71d563e45866 --- src/cmd/acme/exec.c +++ src/cmd/acme/exec.c @@ -9,6 +9,7 @@ #include #include #include +#include #include <9pclient.h> #include "dat.h" #include "fns.h" @@ -635,6 +636,30 @@ get(Text *et, Text *t, Text *argt, int flag1, int _0, xfidlog(w, "get"); } +static void +checksha1(char *name, File *f, Dir *d) +{ + int fd, n; + DigestState *h; + uchar out[20]; + uchar *buf; + + fd = open(name, OREAD); + if(fd < 0) + return; + h = sha1(nil, 0, nil, nil); + buf = emalloc(8192); + while((n = read(fd, buf, 8192)) > 0) + sha1(buf, n, nil, h); + close(fd); + sha1(nil, 0, out, h); + if(memcmp(out, f->sha1, sizeof out) == 0) { + f->dev = d->dev; + f->qidpath = d->qid.path; + f->mtime = d->mtime; + } +} + void putfile(File *f, int q0, int q1, Rune *namer, int nname) { @@ -646,13 +671,15 @@ putfile(File *f, int q0, int q1, Rune *namer, int nnam Dir *d, *d1; Window *w; int isapp; + DigestState *h; w = f->curtext->w; name = runetobyte(namer, nname); d = dirstat(name); if(d!=nil && runeeq(namer, nname, f->name, f->nname)){ - /* f->mtime+1 because when talking over NFS it's often off by a second */ - if(f->dev!=d->dev || f->qidpath!=d->qid.path || labs((long)(f->mtime-d->mtime)) > 1){ + if(f->dev!=d->dev || f->qidpath!=d->qid.path || f->mtime != d->mtime) + checksha1(name, f, d); + if(f->dev!=d->dev || f->qidpath!=d->qid.path || f->mtime != d->mtime) { if(f->unread) warning(nil, "%s not written; file already exists\n", name); else @@ -679,6 +706,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nnam s = fbufalloc(); free(d); d = dirfstat(fd); + h = sha1(nil, 0, nil, nil); isapp = (d!=nil && d->length>0 && (d->qid.type&QTAPPEND)); if(isapp){ warning(nil, "%s not written; file is append only\n", name); @@ -691,6 +719,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nnam n = BUFSIZE/UTFmax; bufread(&f->b, q, r, n); m = snprint(s, BUFSIZE+1, "%.*S", n, r); + sha1((uchar*)s, m, nil, h); if(Bwrite(b, s, m) != m){ warning(nil, "can't write file %s: %r\n", name); goto Rescue2; @@ -730,6 +759,8 @@ putfile(File *f, int q0, int q1, Rune *namer, int nnam f->qidpath = d->qid.path; f->dev = d->dev; f->mtime = d->mtime; + sha1(nil, 0, f->sha1, h); + h = nil; f->mod = FALSE; w->dirty = FALSE; f->unread = FALSE; @@ -741,6 +772,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nnam } fbuffree(s); fbuffree(r); + free(h); free(d); free(namer); free(name); @@ -753,6 +785,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nnam Bterm(b); free(b); } + free(h); fbuffree(s); fbuffree(r); close(fd); blob - 00d5d54ccd7ca38c67746298d1c61da92820cca1 blob + e1eddc462abbcb70198471736124e1446ebb1286 --- src/cmd/acme/file.c +++ src/cmd/acme/file.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -163,11 +164,11 @@ fileunsetname(File *f, Buffer *delta) } uint -fileload(File *f, uint p0, int fd, int *nulls) +fileload(File *f, uint p0, int fd, int *nulls, DigestState *h) { if(f->seq > 0) error("undo in file.load unimplemented"); - return bufload(&f->b, p0, fd, nulls); + return bufload(&f->b, p0, fd, nulls, h); } /* return sequence number of pending redo */ blob - af06344544d625631f5f241aa1ff9e357c2186bd blob + 1cd352578f9646ff920f0a46e5306de89f75980a --- src/cmd/acme/fns.h +++ src/cmd/acme/fns.h @@ -25,7 +25,7 @@ void savemouse(Window*); int restoremouse(Window*); void clearmouse(void); void allwindows(void(*)(Window*, void*), void*); -uint loadfile(int, uint, int*, int(*)(void*, uint, Rune*, int), void*); +uint loadfile(int, uint, int*, int(*)(void*, uint, Rune*, int), void*, DigestState*); void movetodel(Window*); Window* errorwin(Mntdir*, int); blob - 549213d73d54fe443951834dd5171ff59e33764b blob + 4c395eb2bf2090d8b432466d75979c1f47197cc1 --- src/cmd/acme/fsys.c +++ src/cmd/acme/fsys.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - 82b3d80c97469d408a752d3937fbc3c62a45b9e3 blob + 567b83839e653505a5ede655d12ef057ce56637a --- src/cmd/acme/logf.c +++ src/cmd/acme/logf.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - 3c5765a8c5afbd1c6ba773f575211a84eac06423 blob + cbbc71bf5faf907167d57a7017bbb8c65b231cbf --- src/cmd/acme/look.c +++ src/cmd/acme/look.c @@ -10,6 +10,7 @@ #include #include <9pclient.h> #include +#include #include "dat.h" #include "fns.h" blob - 9ad07d3cbbd62b220277e44de0f3e4ea1f48ee45 blob + 56ea900c654bb27914fa8f4cf9c7ec7d25fb5c2a --- src/cmd/acme/regx.c +++ src/cmd/acme/regx.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - 965088e1ec6dbd8c220c5cf28ad12acc3d3d8c21 blob + 2d6cbccaa6ba055265cea571f81620de9c5806a0 --- src/cmd/acme/rows.c +++ src/cmd/acme/rows.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - baf7ec79cb30d5d773994e388fb342a68ef051f2 blob + 6504699da15fb6b736ee420c15824c81b3e7d867 --- src/cmd/acme/scrl.c +++ src/cmd/acme/scrl.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - c53694c6ffe17e84db33786b505daec39e0e68a6 blob + 4832de8ecefd00aa99e5c29d49138b961ed32b87 --- src/cmd/acme/text.c +++ src/cmd/acme/text.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "dat.h" #include "fns.h" @@ -198,6 +199,7 @@ textload(Text *t, uint q0, char *file, int setqid) Dir *d, *dbuf; char *tmp; Text *u; + DigestState *h; if(t->ncache!=0 || t->file->b.nc || t->w==nil || t!=&t->w->body) error("text.load"); @@ -220,6 +222,7 @@ textload(Text *t, uint q0, char *file, int setqid) goto Rescue; } nulls = FALSE; + h = nil; if(d->qid.type & QTDIR){ /* this is checked in get() but it's possible the file changed underfoot */ if(t->file->ntext > 1){ @@ -264,9 +267,17 @@ textload(Text *t, uint q0, char *file, int setqid) }else{ t->w->isdir = FALSE; t->w->filemenu = TRUE; - q1 = q0 + fileload(t->file, q0, fd, &nulls); + if(q0 == 0) + h = sha1(nil, 0, nil, nil); + q1 = q0 + fileload(t->file, q0, fd, &nulls, h); } if(setqid){ + if(h != nil) { + sha1(nil, 0, t->file->sha1, h); + h = nil; + } else { + memset(t->file->sha1, 0, sizeof t->file->sha1); + } t->file->dev = d->dev; t->file->mtime = d->mtime; t->file->qidpath = d->qid.path; blob - e177713173baf1f9962d0c5966cd01853dccf6bd blob + 38d70579d87fea40cf94873ae4f158e62fee4a49 --- src/cmd/acme/time.c +++ src/cmd/acme/time.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - 28c99ad3fc83f99d4fdeb67b26b5a8e53c575be7 blob + d694634f2bc0f03bb6041315a8e01327002b022c --- src/cmd/acme/util.c +++ src/cmd/acme/util.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - 712eb1dcabdf71ee7625ad0602cb48a8162a93f7 blob + 19b52f5c184b42f52bc4ffd433637cf834ba671c --- src/cmd/acme/wind.c +++ src/cmd/acme/wind.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" blob - 33732def0a9b664eee2202012beae718ebf99120 blob + 5aa4a1804d50a970733ba27d4fd0ba162484030e --- src/cmd/acme/xfid.c +++ src/cmd/acme/xfid.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h"