Blob
- Date:
- Message:
- 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.)
- Actions:
- History | Blame | Raw File
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"15 enum16 {17 Slop = 100 /* room to grow with reallocation */18 };20 static21 void22 sizecache(Buffer *b, uint n)23 {24 if(n <= b->cmax)25 return;26 b->cmax = n+Slop;27 b->c = runerealloc(b->c, b->cmax);28 }30 static31 void32 addblock(Buffer *b, uint i, uint n)33 {34 if(i > b->nbl)35 error("internal error: addblock");37 b->bl = realloc(b->bl, (b->nbl+1)*sizeof b->bl[0]);38 if(i < b->nbl)39 memmove(b->bl+i+1, b->bl+i, (b->nbl-i)*sizeof(Block*));40 b->bl[i] = disknewblock(disk, n);41 b->nbl++;42 }44 static45 void46 delblock(Buffer *b, uint i)47 {48 if(i >= b->nbl)49 error("internal error: delblock");51 diskrelease(disk, b->bl[i]);52 b->nbl--;53 if(i < b->nbl)54 memmove(b->bl+i, b->bl+i+1, (b->nbl-i)*sizeof(Block*));55 b->bl = realloc(b->bl, b->nbl*sizeof b->bl[0]);56 }58 /*59 * Move cache so b->cq <= q0 < b->cq+b->cnc.60 * If at very end, q0 will fall on end of cache block.61 */63 static64 void65 flush(Buffer *b)66 {67 if(b->cdirty || b->cnc==0){68 if(b->cnc == 0)69 delblock(b, b->cbi);70 else71 diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);72 b->cdirty = FALSE;73 }74 }76 static77 void78 setcache(Buffer *b, uint q0)79 {80 Block **blp, *bl;81 uint i, q;83 if(q0 > b->nc)84 error("internal error: setcache");85 /*86 * flush and reload if q0 is not in cache.87 */88 if(b->nc == 0 || (b->cq<=q0 && q0<b->cq+b->cnc))89 return;90 /*91 * if q0 is at end of file and end of cache, continue to grow this block92 */93 if(q0==b->nc && q0==b->cq+b->cnc && b->cnc<Maxblock)94 return;95 flush(b);96 /* find block */97 if(q0 < b->cq){98 q = 0;99 i = 0;100 }else{101 q = b->cq;102 i = b->cbi;103 }104 blp = &b->bl[i];105 while(q+(*blp)->u.n <= q0 && q+(*blp)->u.n < b->nc){106 q += (*blp)->u.n;107 i++;108 blp++;109 if(i >= b->nbl)110 error("block not found");111 }112 bl = *blp;113 /* remember position */114 b->cbi = i;115 b->cq = q;116 sizecache(b, bl->u.n);117 b->cnc = bl->u.n;118 /*read block*/119 diskread(disk, bl, b->c, b->cnc);120 }122 void123 bufinsert(Buffer *b, uint q0, Rune *s, uint n)124 {125 uint i, m, t, off;127 if(q0 > b->nc)128 error("internal error: bufinsert");130 while(n > 0){131 setcache(b, q0);132 off = q0-b->cq;133 if(b->cnc+n <= Maxblock){134 /* Everything fits in one block. */135 t = b->cnc+n;136 m = n;137 if(b->bl == nil){ /* allocate */138 if(b->cnc != 0)139 error("internal error: bufinsert1 cnc!=0");140 addblock(b, 0, t);141 b->cbi = 0;142 }143 sizecache(b, t);144 runemove(b->c+off+m, b->c+off, b->cnc-off);145 runemove(b->c+off, s, m);146 b->cnc = t;147 goto Tail;148 }149 /*150 * We must make a new block. If q0 is at151 * the very beginning or end of this block,152 * just make a new block and fill it.153 */154 if(q0==b->cq || q0==b->cq+b->cnc){155 if(b->cdirty)156 flush(b);157 m = min(n, Maxblock);158 if(b->bl == nil){ /* allocate */159 if(b->cnc != 0)160 error("internal error: bufinsert2 cnc!=0");161 i = 0;162 }else{163 i = b->cbi;164 if(q0 > b->cq)165 i++;166 }167 addblock(b, i, m);168 sizecache(b, m);169 runemove(b->c, s, m);170 b->cq = q0;171 b->cbi = i;172 b->cnc = m;173 goto Tail;174 }175 /*176 * Split the block; cut off the right side and177 * let go of it.178 */179 m = b->cnc-off;180 if(m > 0){181 i = b->cbi+1;182 addblock(b, i, m);183 diskwrite(disk, &b->bl[i], b->c+off, m);184 b->cnc -= m;185 }186 /*187 * Now at end of block. Take as much input188 * as possible and tack it on end of block.189 */190 m = min(n, Maxblock-b->cnc);191 sizecache(b, b->cnc+m);192 runemove(b->c+b->cnc, s, m);193 b->cnc += m;194 Tail:195 b->nc += m;196 q0 += m;197 s += m;198 n -= m;199 b->cdirty = TRUE;200 }201 }203 void204 bufdelete(Buffer *b, uint q0, uint q1)205 {206 uint m, n, off;208 if(!(q0<=q1 && q0<=b->nc && q1<=b->nc))209 error("internal error: bufdelete");210 while(q1 > q0){211 setcache(b, q0);212 off = q0-b->cq;213 if(q1 > b->cq+b->cnc)214 n = b->cnc - off;215 else216 n = q1-q0;217 m = b->cnc - (off+n);218 if(m > 0)219 runemove(b->c+off, b->c+off+n, m);220 b->cnc -= n;221 b->cdirty = TRUE;222 q1 -= n;223 b->nc -= n;224 }225 }227 static int228 bufloader(void *v, uint q0, Rune *r, int nr)229 {230 bufinsert(v, q0, r, nr);231 return nr;232 }234 uint235 loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *arg, DigestState *h)236 {237 char *p;238 Rune *r;239 int l, m, n, nb, nr;240 uint q1;242 p = emalloc((Maxblock+UTFmax+1)*sizeof p[0]);243 r = runemalloc(Maxblock);244 m = 0;245 n = 1;246 q1 = q0;247 /*248 * At top of loop, may have m bytes left over from249 * last pass, possibly representing a partial rune.250 */251 while(n > 0){252 n = read(fd, p+m, Maxblock);253 if(n < 0){254 warning(nil, "read error in Buffer.load");255 break;256 }257 if(h != nil)258 sha1((uchar*)p+m, n, nil, h);259 m += n;260 p[m] = 0;261 l = m;262 if(n > 0)263 l -= UTFmax;264 cvttorunes(p, l, r, &nb, &nr, nulls);265 memmove(p, p+nb, m-nb);266 m -= nb;267 q1 += (*f)(arg, q1, r, nr);268 }269 free(p);270 free(r);271 return q1-q0;272 }274 uint275 bufload(Buffer *b, uint q0, int fd, int *nulls, DigestState *h)276 {277 if(q0 > b->nc)278 error("internal error: bufload");279 return loadfile(fd, q0, nulls, bufloader, b, h);280 }282 void283 bufread(Buffer *b, uint q0, Rune *s, uint n)284 {285 uint m;287 if(!(q0<=b->nc && q0+n<=b->nc))288 error("bufread: internal error");290 while(n > 0){291 setcache(b, q0);292 m = min(n, b->cnc-(q0-b->cq));293 runemove(s, b->c+(q0-b->cq), m);294 q0 += m;295 s += m;296 n -= m;297 }298 }300 void301 bufreset(Buffer *b)302 {303 int i;305 b->nc = 0;306 b->cnc = 0;307 b->cq = 0;308 b->cdirty = 0;309 b->cbi = 0;310 /* delete backwards to avoid n² behavior */311 for(i=b->nbl-1; --i>=0; )312 delblock(b, i);313 }315 void316 bufclose(Buffer *b)317 {318 bufreset(b);319 free(b->c);320 b->c = nil;321 b->cnc = 0;322 free(b->bl);323 b->bl = nil;324 b->nbl = 0;325 }