aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/invalid/lena/scrcpy/AtomicFiles.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/invalid/lena/scrcpy/AtomicFiles.java')
-rw-r--r--app/src/main/java/invalid/lena/scrcpy/AtomicFiles.java30
1 files changed, 20 insertions, 10 deletions
diff --git a/app/src/main/java/invalid/lena/scrcpy/AtomicFiles.java b/app/src/main/java/invalid/lena/scrcpy/AtomicFiles.java
index 6f755b6..77235f6 100644
--- a/app/src/main/java/invalid/lena/scrcpy/AtomicFiles.java
+++ b/app/src/main/java/invalid/lena/scrcpy/AtomicFiles.java
@@ -10,7 +10,8 @@ import java.nio.file.StandardCopyOption;
// 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.
+// may leave a stale staging file, never a damaged destination. The next
+// write removes stale staging files before creating its own.
//
// Deliberately no fsync of the parent directory: the rename itself may be
// lost on power failure (the old content survives intact). Callers store
@@ -21,20 +22,29 @@ final class AtomicFiles {
private AtomicFiles() {}
- static void write(File dest, byte[] data) throws IOException {
+ static synchronized 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();
+ if (parent == null || !parent.isDirectory()) {
+ throw new IOException("destination parent is not a directory: " + parent);
}
+ String prefix = dest.getName() + ".tmp";
+ File[] stale = parent.listFiles((dir, name) ->
+ name.equals(prefix) || name.startsWith(prefix + "-"));
+ if (stale == null) throw new IOException("cannot list destination parent: " + parent);
+ for (File file : stale) Files.deleteIfExists(file.toPath());
+ File tmp = Files.createTempFile(parent.toPath(), dest.getName() + ".tmp-", null).toFile();
+ boolean moved = false;
try {
+ try (FileOutputStream os = new FileOutputStream(tmp)) {
+ os.write(data);
+ os.flush();
+ os.getFD().sync();
+ }
Files.move(tmp.toPath(), dest.toPath(),
StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
- } catch (IOException e) {
- tmp.delete();
- throw e;
+ moved = true;
+ } finally {
+ if (!moved) Files.deleteIfExists(tmp.toPath());
}
}
}