mirror of
https://github.com/storytold/soundcraft.git
synced 2026-11-11 16:35:42 -06:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f96843a24 |
@@ -454,6 +454,21 @@ pub fn create_folder(dir: &Path) -> std::io::Result<()> {
|
||||
builder.create(dir)
|
||||
}
|
||||
|
||||
/// [`create_folder`] for a folder at a predictable place in a shared folder (the system's temporary
|
||||
/// folder): refused when it already exists with any access for group or other, as another account
|
||||
/// could have made it first and read, or replace, what is written into it.
|
||||
pub fn create_private_folder(dir: &Path) -> std::io::Result<()> {
|
||||
create_folder(dir)?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
if std::fs::metadata(dir)?.mode() & 0o077 != 0 {
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "the folder already exists and is open to other accounts"));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_synced(path: &Path, bytes: &[u8]) -> std::io::Result<()> {
|
||||
let mut f = std::fs::File::create(path)?;
|
||||
f.write_all(bytes)?;
|
||||
@@ -663,6 +678,19 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(&base);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn a_private_folder_is_refused_when_it_already_exists_open() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let base = folder("private-folder");
|
||||
let dir = base.join("soundcraft-recordings-1");
|
||||
create_private_folder(&dir).unwrap();
|
||||
create_private_folder(&dir).unwrap();
|
||||
std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||
assert!(create_private_folder(&dir).is_err());
|
||||
let _ = std::fs::remove_dir_all(&base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_take_still_recording_at_a_crash_is_placed_on_recovery() {
|
||||
use crate::io::Take;
|
||||
|
||||
@@ -155,7 +155,13 @@ impl SoundApp {
|
||||
/// autosave folder. Returns the takes it records.
|
||||
fn arm_recorder(&mut self) -> Result<Vec<soundcraft_engine::io::Take>, String> {
|
||||
let name = soundcraft_engine::io::sanitize_name(&self.engine.session().name);
|
||||
let unsaved_dir = self.autosave_dir.as_ref().map_or_else(std::env::temp_dir, |d| d.join(name));
|
||||
// Without autosave storage the takes of a session never saved go to a folder of their own under
|
||||
// the shared temporary folder, made private below, not into the shared folder itself.
|
||||
let shared_temp = self.autosave_dir.is_none();
|
||||
let unsaved_dir = self
|
||||
.autosave_dir
|
||||
.as_ref()
|
||||
.map_or_else(|| std::env::temp_dir().join(format!("soundcraft-recordings-{}", std::process::id())), |d| d.join(name));
|
||||
let Some(r) = &mut self.recorder else { return Err("no audio input device".into()) };
|
||||
let plan = soundcraft_engine::io::plan_takes(&self.engine, &unsaved_dir, r.channels);
|
||||
if plan.is_empty() {
|
||||
@@ -163,9 +169,17 @@ impl SoundApp {
|
||||
}
|
||||
// The takes are unsaved work: the folder they go into under the autosave root is
|
||||
// owner-only, like the autosaves, before the recorder makes anything in it.
|
||||
if self.engine.path.is_none() && self.autosave_dir.is_some() {
|
||||
if self.engine.path.is_none() {
|
||||
if shared_temp {
|
||||
soundcraft_engine::autosave::create_private_folder(&unsaved_dir).map_err(|e| format!("{}: {e}", unsaved_dir.display()))?;
|
||||
}
|
||||
for dir in plan.iter().filter_map(|(_, _, path)| path.parent()) {
|
||||
soundcraft_engine::autosave::create_folder(dir).map_err(|e| format!("{}: {e}", dir.display()))?;
|
||||
let made = if shared_temp {
|
||||
soundcraft_engine::autosave::create_private_folder(dir)
|
||||
} else {
|
||||
soundcraft_engine::autosave::create_folder(dir)
|
||||
};
|
||||
made.map_err(|e| format!("{}: {e}", dir.display()))?;
|
||||
}
|
||||
}
|
||||
let takes = plan
|
||||
|
||||
Reference in New Issue
Block a user