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; } } }