Skip to content

Commit

Permalink
Use read_link to cope with broken symlinks
Browse files Browse the repository at this point in the history
Signed-off-by: James Rhodes <[email protected]>
  • Loading branch information
jarhodes314 committed Jan 13, 2025
1 parent a3403b4 commit 67a7a9a
Showing 1 changed file with 35 additions and 12 deletions.
47 changes: 35 additions & 12 deletions crates/common/tedge_utils/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,11 @@ pub fn atomically_write_file_sync(
dest: impl AsRef<Path>,
mut reader: impl Read,
) -> Result<(), AtomFileError> {
// resolve path (including valid symlinks that point to an existing file)
let dest = dest
.as_ref()
.canonicalize()
.unwrap_or_else(|_| dest.as_ref().to_path_buf());
let dest_dir = parent_dir(dest.as_ref());
let dest = dest.as_ref();
// resolve path (including symlinks)
// if the symlink doesn't exist, (attempt to) create the file it points to
let dest = std::fs::read_link(dest).unwrap_or_else(|_| dest.to_path_buf());
let dest_dir = parent_dir(&dest);

// removed on drop
let mut file = tempfile::Builder::new()
Expand Down Expand Up @@ -94,15 +93,21 @@ pub fn atomically_write_file_sync(
)?;

// Move the temp file to its destination
file.persist(&dest)
.with_context(|| "could not write to destination file".to_string(), &dest)?;
file.persist(&dest).with_context(
|| "could not write to destination file".to_string(),
&dest,
)?;

// Ensure the new name reach the disk
let dir = std::fs::File::open(dest_dir)
.with_context(|| "could not open the directory".to_string(), &dest)?;
let dir = std::fs::File::open(dest_dir).with_context(
|| "could not open the directory".to_string(),
&dest,
)?;

dir.sync_all()
.with_context(|| "could not save the file to disk".to_string(), &dest)?;
dir.sync_all().with_context(
|| "could not save the file to disk".to_string(),
&dest,
)?;

Ok(())
}
Expand Down Expand Up @@ -257,4 +262,22 @@ mod tests {
panic!("failed to read the new file");
}
}

#[test]
fn atomically_write_file_file_sync_with_broken_symlink() {
let temp_dir = tempdir().unwrap();
let link_path = temp_dir.path().join("test-link");
let destination_path = temp_dir.path().join("test-orig");
let _ = std::os::unix::fs::symlink(destination_path.clone(), link_path.clone());

let content = "test_data";

let () = atomically_write_file_sync(link_path.clone(), content.as_bytes()).unwrap();

if let Ok(destination_content) = std::fs::read(destination_path) {
assert_eq!(destination_content, content.as_bytes());
} else {
panic!("failed to read the new file");
}
}
}

0 comments on commit 67a7a9a

Please sign in to comment.