diff --git a/crates/font-store/src/language_packs/tests.rs b/crates/font-store/src/language_packs/tests.rs index f9ef14e8..1107e719 100644 --- a/crates/font-store/src/language_packs/tests.rs +++ b/crates/font-store/src/language_packs/tests.rs @@ -318,3 +318,18 @@ fn hostile_archives_are_refused() { unpack(&pack_archive("nl", "x"), &dest).unwrap(); assert!(dest.join("LICENCES/COPYING").is_file()); } + +/// A staging folder an earlier process with the same id left behind is cleared, so an unpack +/// (`create_new`) can't fail on, or mix in, its files. +#[test] +fn a_stale_stage_folder_is_cleared() { + let store = temp("stale-stage"); + let staging = store.join(".staging"); + for n in 0..512 { + let d = staging.join(format!("{}-{n}", std::process::id())); + std::fs::create_dir_all(d.join("nl")).unwrap(); + std::fs::write(d.join("nl/pack.toml"), b"old").unwrap(); + } + let stage = Stage::new(&store).unwrap(); + assert_eq!(std::fs::read_dir(&stage.dir).unwrap().count(), 0, "{}", stage.dir.display()); +} diff --git a/crates/font-store/src/store.rs b/crates/font-store/src/store.rs index e2cd1161..7c3ed0f3 100644 --- a/crates/font-store/src/store.rs +++ b/crates/font-store/src/store.rs @@ -840,6 +840,10 @@ impl Stage { pub(crate) fn new(store: &Path) -> Result { static N: AtomicU64 = AtomicU64::new(0); let dir = store.join(STAGING).join(format!("{}-{}", std::process::id(), N.fetch_add(1, Ordering::Relaxed))); + // A folder left by an earlier process with the same id is cleared, not mixed in. + if std::fs::symlink_metadata(&dir).is_ok() { + std::fs::remove_dir_all(&dir).map_err(io("clearing an old download folder"))?; + } std::fs::create_dir_all(&dir).map_err(io("creating a download folder"))?; Ok(Self { dir }) }