max / audiofiles
1 file changed,
+15 insertions,
-0 deletions
| @@ -179,10 +179,25 @@ impl SampleStore { | |||
| 179 | 179 | if needs_write { | |
| 180 | 180 | let tmp = dest.with_file_name(format!("{hash}.{ext}.{}.tmp", std::process::id())); | |
| 181 | 181 | fs::copy(path, &tmp).map_err(|e| io_err(&tmp, e))?; | |
| 182 | + | // fsync the blob bytes to disk before the rename. Without this the | |
| 183 | + | // rename can be durable while the file contents are not, leaving a | |
| 184 | + | // canonical-path blob with garbage after a power loss — which a | |
| 185 | + | // content-addressed store would then trust forever. | |
| 186 | + | if let Ok(f) = fs::File::open(&tmp) { | |
| 187 | + | let _ = f.sync_all(); | |
| 188 | + | } | |
| 182 | 189 | if let Err(e) = fs::rename(&tmp, &dest) { | |
| 183 | 190 | let _ = fs::remove_file(&tmp); | |
| 184 | 191 | return Err(io_err(&dest, e)); | |
| 185 | 192 | } | |
| 193 | + | // Best-effort fsync of the directory so the rename itself is durable | |
| 194 | + | // (the new dirent survives a crash). Not all filesystems support | |
| 195 | + | // directory fsync; failure here only weakens durability, never the | |
| 196 | + | // import. | |
| 197 | + | if let Some(parent) = dest.parent() | |
| 198 | + | && let Ok(d) = fs::File::open(parent) { | |
| 199 | + | let _ = d.sync_all(); | |
| 200 | + | } | |
| 186 | 201 | // Mark the canonical blob read-only. The VFS mirror exposes store | |
| 187 | 202 | // blobs to DAWs/file managers via symlinks; a "save in place" would | |
| 188 | 203 | // otherwise write through and corrupt the SHA-256-named blob, |