At work, we’re developing a FUSE filesystem which uses IMAP as a data-store. Everything’s fine, ’till we change something and try this:
$ echo 'hello' > hello.txt
This should make a new mail, with only content ‘hello’. And it works, BUT create also an empty mail message before. Why?
Our policy is to commit the mail to the IMAP server only in front of a flush. So, we look at syscalls given by fuse to us:
...
open
fgetattr
flush
write
flush
...
Oh, nice. nice? not at all. What’s that first “flush” in the sequence?! Well, simple; let’s strace the bash’s echo:
...
open("hello.txt", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
fcntl64(1, F_GETFD) = 0
fcntl64(1, F_DUPFD, 10) = 10
fcntl64(1, F_GETFD) = 0
fcntl64(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 1) = 1
close(3) = 0
write(1, "ciao\n", 5) = 5
dup2(10, 1) = 1
fcntl64(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
...
Try to guess now… yes, it’s the dup2. Evidently, the dup2, before making the file descriptor duplication, flush them so to be sure they’re in sync, and this causes the extra flush() at the beginning, just after the open. What a nice world…
