blob: 6f755b6e144d9715bdb12d9b4e19ab31648e38e5 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
package invalid.lena.scrcpy;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
// Crash-atomic whole-file write: stage the bytes into a sibling temp file,
// fsync it, then rename it over the destination. The rename is the only
// mutation a concurrent reader can observe, so a reader sees either the old
// file or the new file in full, never a truncated mix. A crash mid-write
// leaves at most a stale ".tmp", never a damaged destination.
//
// Deliberately no fsync of the parent directory: the rename itself may be
// lost on power failure (the old content survives intact). Callers store
// re-creatable state, so atomicity matters here and durability does not.
//
// android-free (java.io/java.nio only) so it is unit-testable on the JVM.
final class AtomicFiles {
private AtomicFiles() {}
static void write(File dest, byte[] data) throws IOException {
File parent = dest.getAbsoluteFile().getParentFile();
File tmp = new File(parent, dest.getName() + ".tmp");
try (FileOutputStream os = new FileOutputStream(tmp)) {
os.write(data);
os.flush();
os.getFD().sync();
}
try {
Files.move(tmp.toPath(), dest.toPath(),
StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
tmp.delete();
throw e;
}
}
}
|