From ddd2f09972f1c67ee562a3ccf5c22c92890b4eaa Mon Sep 17 00:00:00 2001 From: PradeepKiruvale Date: Wed, 29 Jun 2022 16:46:40 +0530 Subject: c8y_configuration_plugin --init and c8y_log_plugin --init are overwriting exiting files (#1217) --init should not overwrite the existing files Signed-off-by: Pradeep Kumar K J --- crates/common/tedge_utils/src/file.rs | 83 +++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 22 deletions(-) (limited to 'crates/common') diff --git a/crates/common/tedge_utils/src/file.rs b/crates/common/tedge_utils/src/file.rs index 6b714750..902d10c0 100644 --- a/crates/common/tedge_utils/src/file.rs +++ b/crates/common/tedge_utils/src/file.rs @@ -1,5 +1,5 @@ use nix::unistd::*; -use std::fs::File; +use std::io::Write; use std::os::linux::fs::MetadataExt; use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; @@ -28,6 +28,9 @@ pub enum FileError { #[error("The path is not accessible. {path:?}")] PathNotAccessible { path: PathBuf }, + + #[error("Writing the content to the file failed: {file:?}.")] + WriteContentFailed { file: String, from: std::io::Error }, } pub fn create_directory_with_user_group( @@ -37,14 +40,12 @@ pub fn create_directory_with_user_group( mode: u32, ) -> Result<(), FileError> { let perm_entry = PermissionEntry::new(Some(user.into()), Some(group.into()), Some(mode)); - let () = perm_entry.create_directory(Path::new(dir))?; - Ok(()) + perm_entry.create_directory(Path::new(dir)) } pub fn create_directory_with_mode(dir: &str, mode: u32) -> Result<(), FileError> { let perm_entry = PermissionEntry::new(None, None, Some(mode)); - let () = perm_entry.create_directory(Path::new(dir))?; - Ok(()) + perm_entry.create_directory(Path::new(dir)) } pub fn create_file_with_user_group( @@ -52,16 +53,10 @@ pub fn create_file_with_user_group( user: &str, group: &str, mode: u32, + default_content: Option<&str>, ) -> Result<(), FileError> { let perm_entry = PermissionEntry::new(Some(user.into()), Some(group.into()), Some(mode)); - let () = perm_entry.create_file(Path::new(file))?; - Ok(()) -} - -pub fn create_file_with_mode(file: &str, mode: u32) -> Result<(), FileError> { - let perm_entry = PermissionEntry::new(None, None, Some(mode)); - let () = perm_entry.create_file(Path::new(file))?; - Ok(()) + perm_entry.create_file(Path::new(file), default_content) } #[derive(Debug, PartialEq, Eq, Default, Clone)] @@ -111,12 +106,31 @@ impl PermissionEntry { } } - fn create_file(&self, file: &Path) -> Result<(), FileError> { - match File::create(file) { - Ok(_) => { + /// This function creates a file with a given path, specific access privileges and with the given content. + /// If the file already exists, then it will not be re-created and it will not overwrite/append the contents of the file. + /// This method returns + /// Ok() when file is created and the content is written successfully into the file. + /// Ok() when the file aleady exists + /// Err(_) When it can not create the file with the appropriate owner and access permissions. + fn create_file(&self, file: &Path, default_content: Option<&str>) -> Result<(), FileError> { + match fs::OpenOptions::new() + .create_new(true) + .write(true) + .open(file) + { + Ok(mut f) => { let () = self.apply(file)?; + if let Some(default_content) = default_content { + f.write(default_content.as_bytes()).map_err(|e| { + FileError::WriteContentFailed { + file: file.display().to_string(), + from: e, + } + })?; + } Ok(()) } + Err(e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()), Err(e) => Err(FileError::FileCreateFailed { file: file.display().to_string(), @@ -229,7 +243,7 @@ mod tests { let file_path = temp_dir.path().join("file").display().to_string(); let user = whoami::username(); - let _ = create_file_with_user_group(file_path.as_str(), &user, &user, 0o644).unwrap(); + let _ = create_file_with_user_group(file_path.as_str(), &user, &user, 0o644, None).unwrap(); assert!(Path::new(file_path.as_str()).exists()); let meta = std::fs::metadata(file_path.as_str()).unwrap(); let perm = meta.permissions(); @@ -237,14 +251,39 @@ mod tests { assert!(format!("{:o}", perm.mode()).contains("644")); } + #[test] + fn create_file_with_default_content() { + let temp_dir = TempDir::new().unwrap(); + let file_path = temp_dir.path().join("file").display().to_string(); + let user = whoami::username(); + + let example_config = r#"# Add the configurations to be managed by c8y-configuration-plugin + files = [ + # { path = '/etc/tedge/tedge.toml' }, + ]"#; + + // Create a new file with default content + create_file_with_user_group( + file_path.as_str(), + &user, + &user, + 0o775, + Some(&example_config.to_string()), + ) + .unwrap(); + + let content = fs::read(file_path).unwrap(); + assert_eq!(example_config.as_bytes(), content); + } + #[test] fn create_file_wrong_user() { let temp_dir = TempDir::new().unwrap(); let file_path = temp_dir.path().join("file").display().to_string(); let user = whoami::username(); - let err = - create_file_with_user_group(file_path.as_str(), "test", &user, 0o775).unwrap_err(); + let err = create_file_with_user_group(file_path.as_str(), "test", &user, 0o775, None) + .unwrap_err(); assert!(err.to_string().contains("User not found")); } @@ -255,8 +294,8 @@ mod tests { let file_path = temp_dir.path().join("file").display().to_string(); let user = whoami::username(); - let err = - create_file_with_user_group(file_path.as_str(), &user, "test", 0o775).unwrap_err(); + let err = create_file_with_user_group(file_path.as_str(), &user, "test", 0o775, None) + .unwrap_err(); assert!(err.to_string().contains("Group not found")); fs::remove_file(file_path.as_str()).unwrap(); @@ -309,7 +348,7 @@ mod tests { let file_path = temp_dir.path().join("file").display().to_string(); let user = whoami::username(); - let _ = create_file_with_user_group(file_path.as_str(), &user, &user, 0o644).unwrap(); + let _ = create_file_with_user_group(file_path.as_str(), &user, &user, 0o644, None).unwrap(); assert!(Path::new(file_path.as_str()).exists()); let meta = fs::metadata(file_path.as_str()).unwrap(); -- cgit v1.2.3