This was copied fro u9fs, with the issue filed in: https://github.com/golang/go/issues/39238
Unified · Split
| @@ -397,6 +397,13 @@ fswstat(Chan *c, uchar *buf, int n) · 396 unmodified lines | ||
| 397 | 397 | char strs[NAME_MAX*3]; |
| 398 | 398 | Ufsinfo *uif; |
| 399 | 399 | |
| 400 | + /* | |
| 401 | + * wstat is supposed to be atomic. | |
| 402 | + * we check all the things we can before trying anything. | |
| 403 | + * still, if we are told to truncate a file and rename it and only | |
| 404 | + * one works, we're screwed. in such cases we leave things | |
| 405 | + * half broken and return an error. it's hardly perfect. | |
| 406 | + */ | |
| 400 | 407 | if(convM2D(buf, n, &d, strs) != n) |
| 401 | 408 | error(Ebadstat); |
| 402 | 409 | |
| @@ -404,6 +411,13 @@ fswstat(Chan *c, uchar *buf, int n) · 1 unmodified line | ||
| 404 | 411 | if(stat(uif->path, &stbuf) < 0) |
| 405 | 412 | error(strerror(errno)); |
| 406 | 413 | |
| 414 | + /* | |
| 415 | + * try things in increasing order of harm to the file. | |
| 416 | + * mtime should come after truncate so that if you | |
| 417 | + * do both the mtime actually takes effect, but i'd rather | |
| 418 | + * leave truncate until last. | |
| 419 | + * (see above comment about atomicity). | |
| 420 | + */ | |
| 407 | 421 | if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) { |
| 408 | 422 | if(chmod(uif->path, d.mode&0777) < 0) |
| 409 | 423 | error(strerror(errno)); |
| @@ -450,6 +464,10 @@ fswstat(Chan *c, uchar *buf, int n) · 40 unmodified lines | ||
| 450 | 464 | uif->gid = p->id; |
| 451 | 465 | } |
| 452 | 466 | */ |
| 467 | + | |
| 468 | + if((uvlong)d.length != (uvlong)~0 && truncate(uif->path, d.length) < 0) | |
| 469 | + error(strerror(errno)); | |
| 470 | + | |
| 453 | 471 | return n; |
| 454 | 472 | } |
| 455 | 473 | |