Skip to content

Commit 58f0071

Browse files
untitakerwgreenberg
authored andcommitted
Fix malformed QMDL store writes
Fix #199 Fix #151 rayhunter updates manifest files using write **without truncation**. This means that if the new manifest is shorter than the old one, trailing bytes of the old data will persist in the new file. Switch over to atomic file writes so that this bug is fixed + rayhunter behaves correctly if it is killed mid-write. #182 could be reverted as it seems to mostly be a workaround.
1 parent 3c0716c commit 58f0071

File tree

1 file changed

+18
-16
lines changed

1 file changed

+18
-16
lines changed

bin/src/qmdl_store.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -120,19 +120,17 @@ impl RecordingStore {
120120
fs::create_dir_all(&path)
121121
.await
122122
.map_err(RecordingStoreError::OpenDirError)?;
123-
let mut manifest_file = File::create(&manifest_path)
124-
.await
125-
.map_err(RecordingStoreError::WriteManifestError)?;
126-
let empty_manifest = Manifest {
127-
entries: Vec::new(),
123+
124+
let mut store = RecordingStore {
125+
path: manifest_path,
126+
manifest: Manifest {
127+
entries: Vec::new()
128+
},
129+
current_entry: None,
128130
};
129-
let empty_manifest_contents =
130-
toml::to_string_pretty(&empty_manifest).expect("failed to serialize manifest");
131-
manifest_file
132-
.write_all(empty_manifest_contents.as_bytes())
133-
.await
134-
.map_err(RecordingStoreError::WriteManifestError)?;
135-
RecordingStore::load(path).await
131+
132+
store.write_manifest().await?;
133+
Ok(store)
136134
}
137135

138136
async fn read_manifest<P>(path: P) -> Result<Manifest, RecordingStoreError>
@@ -240,17 +238,21 @@ impl RecordingStore {
240238
}
241239

242240
async fn write_manifest(&mut self) -> Result<(), RecordingStoreError> {
243-
let mut manifest_file = File::options()
244-
.write(true)
245-
.open(self.path.join("manifest.toml"))
241+
let tmp_path = self.path.join("manifest.toml.new");
242+
let mut manifest_tmp_file = File::create(&tmp_path)
246243
.await
247244
.map_err(RecordingStoreError::WriteManifestError)?;
245+
248246
let manifest_contents =
249247
toml::to_string_pretty(&self.manifest).expect("failed to serialize manifest");
250-
manifest_file
248+
manifest_tmp_file
251249
.write_all(manifest_contents.as_bytes())
252250
.await
253251
.map_err(RecordingStoreError::WriteManifestError)?;
252+
253+
fs::rename(tmp_path, self.path.join("manifest.toml")).await
254+
.map_err(RecordingStoreError::WriteManifestError)?;
255+
254256
Ok(())
255257
}
256258

0 commit comments

Comments
 (0)