tacme: use buffered i/o to write file - plan9port - [fork] Plan 9 from user spa… | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 1d2c3c3945a229f896640b615b84f3d9a78e8b5a | |
parent d213189122bb3cd509cfe706240ffea528fee5f2 | |
Author: Russ Cox <[email protected]> | |
Date: Sat, 19 Apr 2014 10:09:22 -0400 | |
acme: use buffered i/o to write file | |
Bakul Shah has observed corrupted files being written | |
when acme writes over osxfuse to sshfs to a remote file system. | |
In one example we examined, acme is writing an 0xf03-byte | |
file in two system calls, first an 0x806-byte write and then a 0x6fd-byte | |
write. (0x806 is BUFSIZE/sizeof(Rune); this file has no multibyte UTF-8.) | |
What actually ends up happening is that an 0x806-byte file is written: | |
0x000-0x6fd contains what should be 0x806-0xf03 | |
0x6fd-0x7fa contains zeros | |
0x7fa-0x806 contains what should be 0x7fa-0x806 (correct!) | |
The theory is that fuse or sshfs or perhaps the remote file server is | |
mishandling the unaligned writes. acme does not seem to be at fault. | |
Using bio here will make the writes align to 8K boundaries, | |
avoiding the bugs in whatever underlying piece is broken. | |
TBR=r | |
https://codereview.appspot.com/89550043 | |
Diffstat: | |
M src/cmd/acme/exec.c | 17 ++++++++++++++++- | |
1 file changed, 16 insertions(+), 1 deletion(-) | |
--- | |
diff --git a/src/cmd/acme/exec.c b/src/cmd/acme/exec.c | |
t@@ -1,5 +1,6 @@ | |
#include <u.h> | |
#include <libc.h> | |
+#include <bio.h> | |
#include <draw.h> | |
#include <thread.h> | |
#include <cursor.h> | |
t@@ -633,6 +634,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname) | |
{ | |
uint n, m; | |
Rune *r; | |
+ Biobuf *b; | |
char *s, *name; | |
int i, fd, q; | |
Dir *d, *d1; | |
t@@ -660,6 +662,8 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname) | |
warning(nil, "can't create file %s: %r\n", name); | |
goto Rescue1; | |
} | |
+ b = emalloc(sizeof *b); | |
+ Binit(b, fd, OWRITE); | |
r = fbufalloc(); | |
s = fbufalloc(); | |
free(d); | |
t@@ -676,11 +680,18 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname) | |
n = BUFSIZE/UTFmax; | |
bufread(&f->b, q, r, n); | |
m = snprint(s, BUFSIZE+1, "%.*S", n, r); | |
- if(write(fd, s, m) != m){ | |
+ if(Bwrite(b, s, m) != m){ | |
warning(nil, "can't write file %s: %r\n", name); | |
goto Rescue2; | |
} | |
} | |
+ if(Bflush(b) < 0) { | |
+ warning(nil, "can't write file %s: %r\n", name); | |
+ goto Rescue2; | |
+ } | |
+ Bterm(b); | |
+ free(b); | |
+ b = nil; | |
if(runeeq(namer, nname, f->name, f->nname)){ | |
if(q0!=0 || q1!=f->b.nc){ | |
f->mod = TRUE; | |
t@@ -727,6 +738,10 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname) | |
return; | |
Rescue2: | |
+ if(b != nil) { | |
+ Bterm(b); | |
+ free(b); | |
+ } | |
fbuffree(s); | |
fbuffree(r); | |
close(fd); |