mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-18 12:48:07 +00:00
add context to all fs calls (#423)
Adds additional context in error handling to all `std::fs` and `tokio::fs` calls. Fixes #309
This commit is contained in:
@ -36,7 +36,7 @@ use crate::tasks::{
|
|||||||
coverage::{recorder::CoverageRecorder, total::TotalCoverage},
|
coverage::{recorder::CoverageRecorder, total::TotalCoverage},
|
||||||
utils::default_bool_true,
|
utils::default_bool_true,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use onefuzz::{
|
use onefuzz::{
|
||||||
@ -124,7 +124,9 @@ impl CoverageTask {
|
|||||||
seen_inputs = true;
|
seen_inputs = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::remove_dir_all(&dir.path).await?;
|
fs::remove_dir_all(&dir.path).await.with_context(|| {
|
||||||
|
format!("unable to remove readonly_inputs: {}", dir.path.display())
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if seen_inputs {
|
if seen_inputs {
|
||||||
@ -154,7 +156,12 @@ impl CoverageTask {
|
|||||||
processor: &mut CoverageProcessor,
|
processor: &mut CoverageProcessor,
|
||||||
corpus_dir: &SyncedDir,
|
corpus_dir: &SyncedDir,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let mut corpus = fs::read_dir(&corpus_dir.path).await?;
|
let mut corpus = fs::read_dir(&corpus_dir.path).await.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to read corpus coverage directory: {}",
|
||||||
|
corpus_dir.path.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
let mut seen_inputs = false;
|
let mut seen_inputs = false;
|
||||||
|
|
||||||
while let Some(input) = corpus.next().await {
|
while let Some(input) = corpus.next().await {
|
||||||
@ -208,7 +215,12 @@ impl CoverageProcessor {
|
|||||||
|
|
||||||
if !self.module_totals.contains_key(&module) {
|
if !self.module_totals.contains_key(&module) {
|
||||||
let parent = &self.config.coverage.path.join("by-module");
|
let parent = &self.config.coverage.path.join("by-module");
|
||||||
fs::create_dir_all(parent).await?;
|
fs::create_dir_all(parent).await.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to create by-module coverage directory: {}",
|
||||||
|
parent.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
let module_total = parent.join(&module);
|
let module_total = parent.join(&module);
|
||||||
let total = TotalCoverage::new(module_total);
|
let total = TotalCoverage::new(module_total);
|
||||||
self.module_totals.insert(module.clone(), total);
|
self.module_totals.insert(module.clone(), total);
|
||||||
@ -226,7 +238,9 @@ impl CoverageProcessor {
|
|||||||
|
|
||||||
for file in &files {
|
for file in &files {
|
||||||
verbose!("checking {:?}", file);
|
verbose!("checking {:?}", file);
|
||||||
let mut content = fs::read(file).await?;
|
let mut content = fs::read(file)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to read module coverage: {}", file.display()))?;
|
||||||
self.update_module_total(file, &content).await?;
|
self.update_module_total(file, &content).await?;
|
||||||
sum.append(&mut content);
|
sum.append(&mut content);
|
||||||
}
|
}
|
||||||
@ -234,7 +248,9 @@ impl CoverageProcessor {
|
|||||||
let mut combined = path.as_os_str().to_owned();
|
let mut combined = path.as_os_str().to_owned();
|
||||||
combined.push(".cov");
|
combined.push(".cov");
|
||||||
|
|
||||||
fs::write(&combined, sum).await?;
|
fs::write(&combined, sum)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to write combined coverage file: {:?}", combined))?;
|
||||||
|
|
||||||
Ok(combined.into())
|
Ok(combined.into())
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use onefuzz::{
|
use onefuzz::{
|
||||||
fs::{has_files, OwnedDir},
|
fs::{has_files, OwnedDir},
|
||||||
sha256::digest_file,
|
sha256::digest_file,
|
||||||
@ -47,7 +47,12 @@ impl CoverageRecorder {
|
|||||||
self.config.coverage.path.join("inputs").join(digest)
|
self.config.coverage.path.join("inputs").join(digest)
|
||||||
};
|
};
|
||||||
|
|
||||||
fs::create_dir_all(&coverage_path).await?;
|
fs::create_dir_all(&coverage_path).await.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to create coverage path: {}",
|
||||||
|
coverage_path.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
let script = self.invoke_debugger_script(test_input, &coverage_path)?;
|
let script = self.invoke_debugger_script(test_input, &coverage_path)?;
|
||||||
let output = script.wait_with_output().await?;
|
let output = script.wait_with_output().await?;
|
||||||
@ -77,7 +82,14 @@ impl CoverageRecorder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !has_files(&coverage_path).await? {
|
if !has_files(&coverage_path).await? {
|
||||||
tokio::fs::remove_dir(&coverage_path).await?;
|
tokio::fs::remove_dir(&coverage_path)
|
||||||
|
.await
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to remove coverage path: {}",
|
||||||
|
coverage_path.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
bail!("no coverage files for input: {}", test_input.display());
|
bail!("no coverage files for input: {}", test_input.display());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
use crate::tasks::{config::CommonConfig, heartbeat::HeartbeatSender, utils::default_bool_true};
|
use crate::tasks::{config::CommonConfig, heartbeat::HeartbeatSender, utils::default_bool_true};
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use futures::{future::try_join_all, stream::StreamExt};
|
use futures::{future::try_join_all, stream::StreamExt};
|
||||||
use onefuzz::{
|
use onefuzz::{
|
||||||
fs::list_files,
|
fs::list_files,
|
||||||
@ -120,7 +120,15 @@ impl LibFuzzerFuzzTask {
|
|||||||
let mut entries = tokio::fs::read_dir(local_input_dir.path()).await?;
|
let mut entries = tokio::fs::read_dir(local_input_dir.path()).await?;
|
||||||
while let Some(Ok(entry)) = entries.next().await {
|
while let Some(Ok(entry)) = entries.next().await {
|
||||||
let destination_path = self.config.inputs.path.clone().join(entry.file_name());
|
let destination_path = self.config.inputs.path.clone().join(entry.file_name());
|
||||||
tokio::fs::rename(entry.path(), destination_path).await?;
|
tokio::fs::rename(&entry.path(), &destination_path)
|
||||||
|
.await
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to move crashing input into results directory: {} - {}?",
|
||||||
|
entry.path().display(),
|
||||||
|
destination_path.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Context, Error, Result};
|
||||||
use onefuzz::telemetry::EventData;
|
use onefuzz::telemetry::EventData;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tokio::io::AsyncBufReadExt;
|
use tokio::io::AsyncBufReadExt;
|
||||||
|
|
||||||
pub async fn read_stats(output_path: impl AsRef<Path>) -> Result<Vec<EventData>, Error> {
|
pub async fn read_stats(output_path: impl AsRef<Path>) -> Result<Vec<EventData>, Error> {
|
||||||
let f = tokio::fs::File::open(output_path).await?;
|
let output_path = output_path.as_ref();
|
||||||
|
let f = tokio::fs::File::open(&output_path).await.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to open AFL stats for read: {}",
|
||||||
|
output_path.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
let mut stats = Vec::new();
|
let mut stats = Vec::new();
|
||||||
|
|
||||||
let reader = tokio::io::BufReader::new(f);
|
let reader = tokio::io::BufReader::new(f);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use onefuzz::{
|
use onefuzz::{
|
||||||
http::{is_auth_error_code, ResponseExt},
|
http::{is_auth_error_code, ResponseExt},
|
||||||
jitter::delay_with_jitter,
|
jitter::delay_with_jitter,
|
||||||
@ -83,7 +83,9 @@ impl StaticConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_file(config_path: impl AsRef<Path>) -> Result<Self> {
|
pub fn from_file(config_path: impl AsRef<Path>) -> Result<Self> {
|
||||||
let data = std::fs::read(config_path)?;
|
let config_path = config_path.as_ref();
|
||||||
|
let data = std::fs::read(config_path)
|
||||||
|
.with_context(|| format!("unable to read config file: {}", config_path.display()))?;
|
||||||
Self::new(&data)
|
Self::new(&data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,14 +153,18 @@ impl DynamicConfig {
|
|||||||
pub async fn save(&self) -> Result<()> {
|
pub async fn save(&self) -> Result<()> {
|
||||||
let path = Self::save_path()?;
|
let path = Self::save_path()?;
|
||||||
let data = serde_json::to_vec(&self)?;
|
let data = serde_json::to_vec(&self)?;
|
||||||
fs::write(&path, &data).await?;
|
fs::write(&path, &data)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to save dynamic config: {}", path.display()))?;
|
||||||
info!("saved dynamic-config: {}", path.display());
|
info!("saved dynamic-config: {}", path.display());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load() -> Result<Self> {
|
pub async fn load() -> Result<Self> {
|
||||||
let path = Self::save_path()?;
|
let path = Self::save_path()?;
|
||||||
let data = fs::read(&path).await?;
|
let data = fs::read(&path)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to load dynamic config: {}", path.display()))?;
|
||||||
let ctx: Self = serde_json::from_slice(&data)?;
|
let ctx: Self = serde_json::from_slice(&data)?;
|
||||||
info!("loaded dynamic-config: {}", path.display());
|
info!("loaded dynamic-config: {}", path.display());
|
||||||
Ok(ctx)
|
Ok(ctx)
|
||||||
|
@ -4,12 +4,15 @@
|
|||||||
use std::fs::metadata;
|
use std::fs::metadata;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use onefuzz::fs::onefuzz_root;
|
use onefuzz::fs::onefuzz_root;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
pub async fn set_done_lock() -> Result<()> {
|
pub async fn set_done_lock() -> Result<()> {
|
||||||
fs::write(done_path()?, "").await?;
|
let path = done_path()?;
|
||||||
|
fs::write(&path, "")
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to write done lock: {}", path.display()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use downcast_rs::Downcast;
|
use downcast_rs::Downcast;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
@ -40,13 +40,14 @@ pub struct Reboot;
|
|||||||
|
|
||||||
impl Reboot {
|
impl Reboot {
|
||||||
pub async fn save_context(&mut self, ctx: RebootContext) -> Result<()> {
|
pub async fn save_context(&mut self, ctx: RebootContext) -> Result<()> {
|
||||||
info!(
|
let path = reboot_context_path()?;
|
||||||
"saving reboot context to: {}",
|
|
||||||
reboot_context_path()?.display()
|
info!("saving reboot context to: {}", path.display());
|
||||||
);
|
|
||||||
|
|
||||||
let data = serde_json::to_vec(&ctx)?;
|
let data = serde_json::to_vec(&ctx)?;
|
||||||
fs::write(reboot_context_path()?, &data).await?;
|
fs::write(&path, &data)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to save reboot context: {}", path.display()))?;
|
||||||
|
|
||||||
verbose!("reboot context saved");
|
verbose!("reboot context saved");
|
||||||
|
|
||||||
@ -72,7 +73,9 @@ impl Reboot {
|
|||||||
let data = data?;
|
let data = data?;
|
||||||
let ctx = serde_json::from_slice(&data)?;
|
let ctx = serde_json::from_slice(&data)?;
|
||||||
|
|
||||||
fs::remove_file(&path).await?;
|
fs::remove_file(&path)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to remove reboot context: {}", path.display()))?;
|
||||||
|
|
||||||
info!("loaded reboot context");
|
info!("loaded reboot context");
|
||||||
Ok(Some(ctx))
|
Ok(Some(ctx))
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use downcast_rs::Downcast;
|
use downcast_rs::Downcast;
|
||||||
use onefuzz::az_copy;
|
use onefuzz::az_copy;
|
||||||
use onefuzz::process::Output;
|
use onefuzz::process::Output;
|
||||||
@ -48,7 +48,9 @@ impl SetupRunner {
|
|||||||
.join(setup_dir);
|
.join(setup_dir);
|
||||||
|
|
||||||
// `azcopy sync` requires the local dir to exist.
|
// `azcopy sync` requires the local dir to exist.
|
||||||
fs::create_dir_all(&setup_dir).await?;
|
fs::create_dir_all(&setup_dir).await.with_context(|| {
|
||||||
|
format!("unable to create setup container: {}", setup_dir.display())
|
||||||
|
})?;
|
||||||
az_copy::sync(setup_url.to_string(), &setup_dir, false).await?;
|
az_copy::sync(setup_url.to_string(), &setup_dir, false).await?;
|
||||||
|
|
||||||
verbose!(
|
verbose!(
|
||||||
@ -106,8 +108,15 @@ async fn create_setup_symlink(setup_dir: &Path, work_unit: &WorkUnit) -> Result<
|
|||||||
use std::os::windows::fs::symlink_dir;
|
use std::os::windows::fs::symlink_dir;
|
||||||
use tokio::task::spawn_blocking;
|
use tokio::task::spawn_blocking;
|
||||||
|
|
||||||
fs::create_dir(&work_unit.working_dir()?).await?;
|
let working_dir = work_unit.working_dir()?;
|
||||||
let task_setup_dir = work_unit.working_dir()?.join("setup");
|
|
||||||
|
fs::create_dir(&working_dir).await.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to create working directory: {}",
|
||||||
|
working_dir.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let task_setup_dir = working_dir.join("setup");
|
||||||
|
|
||||||
// Tokio does not ship async versions of the `std::fs::os` symlink
|
// Tokio does not ship async versions of the `std::fs::os` symlink
|
||||||
// functions (unlike the Unix equivalents).
|
// functions (unlike the Unix equivalents).
|
||||||
@ -129,10 +138,27 @@ async fn create_setup_symlink(setup_dir: &Path, work_unit: &WorkUnit) -> Result<
|
|||||||
async fn create_setup_symlink(setup_dir: &Path, work_unit: &WorkUnit) -> Result<()> {
|
async fn create_setup_symlink(setup_dir: &Path, work_unit: &WorkUnit) -> Result<()> {
|
||||||
use tokio::fs::os::unix::symlink;
|
use tokio::fs::os::unix::symlink;
|
||||||
|
|
||||||
tokio::fs::create_dir_all(work_unit.working_dir()?).await?;
|
let working_dir = work_unit.working_dir()?;
|
||||||
|
|
||||||
let task_setup_dir = work_unit.working_dir()?.join("setup");
|
tokio::fs::create_dir_all(&working_dir)
|
||||||
symlink(&setup_dir, &task_setup_dir).await?;
|
.await
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to create working directory: {}",
|
||||||
|
working_dir.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let task_setup_dir = working_dir.join("setup");
|
||||||
|
symlink(&setup_dir, &task_setup_dir)
|
||||||
|
.await
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to create symlink from {} to {}",
|
||||||
|
setup_dir.display(),
|
||||||
|
task_setup_dir.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
verbose!(
|
verbose!(
|
||||||
"created symlink from {} to {}",
|
"created symlink from {} to {}",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use downcast_rs::Downcast;
|
use downcast_rs::Downcast;
|
||||||
use onefuzz::{blob::BlobContainerUrl, http::is_auth_error};
|
use onefuzz::{blob::BlobContainerUrl, http::is_auth_error};
|
||||||
use storage_queue::QueueClient;
|
use storage_queue::QueueClient;
|
||||||
@ -63,7 +63,9 @@ impl WorkSet {
|
|||||||
info!("saving workset context: {}", path.display());
|
info!("saving workset context: {}", path.display());
|
||||||
|
|
||||||
let data = serde_json::to_vec(&self)?;
|
let data = serde_json::to_vec(&self)?;
|
||||||
fs::write(path, &data).await?;
|
fs::write(&path, &data)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to save WorkSet context: {}", path.display()))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use std::process::{Child, Command, Stdio};
|
use std::process::{Child, Command, Stdio};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context as AnyhowContext, Result};
|
||||||
use downcast_rs::Downcast;
|
use downcast_rs::Downcast;
|
||||||
use onefuzz::process::{ExitStatus, Output};
|
use onefuzz::process::{ExitStatus, Output};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
@ -189,13 +189,20 @@ impl IWorkerRunner for WorkerRunner {
|
|||||||
|
|
||||||
verbose!("worker working dir = {}", working_dir.display());
|
verbose!("worker working dir = {}", working_dir.display());
|
||||||
|
|
||||||
fs::create_dir_all(&working_dir).await?;
|
fs::create_dir_all(&working_dir).await.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"unable to create working directory: {}",
|
||||||
|
working_dir.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
verbose!("created worker working dir: {}", working_dir.display());
|
verbose!("created worker working dir: {}", working_dir.display());
|
||||||
|
|
||||||
let config_path = work.config_path()?;
|
let config_path = work.config_path()?;
|
||||||
|
|
||||||
fs::write(&config_path, work.config.expose_ref()).await?;
|
fs::write(&config_path, work.config.expose_ref())
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to save task config: {}", config_path.display()))?;
|
||||||
|
|
||||||
verbose!(
|
verbose!(
|
||||||
"wrote worker config to config_path = {}",
|
"wrote worker config to config_path = {}",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@ -25,13 +25,19 @@ pub fn onefuzz_etc() -> Result<PathBuf> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn has_files(path: impl AsRef<Path>) -> Result<bool> {
|
pub async fn has_files(path: impl AsRef<Path>) -> Result<bool> {
|
||||||
let mut paths = fs::read_dir(&path).await?;
|
let path = path.as_ref();
|
||||||
|
let mut paths = fs::read_dir(&path)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to check if directory has files: {}", path.display()))?;
|
||||||
let result = paths.next_entry().await?.is_some();
|
let result = paths.next_entry().await?.is_some();
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_files(path: impl AsRef<Path>) -> Result<Vec<PathBuf>> {
|
pub async fn list_files(path: impl AsRef<Path>) -> Result<Vec<PathBuf>> {
|
||||||
let paths = fs::read_dir(&path).await?;
|
let path = path.as_ref();
|
||||||
|
let paths = fs::read_dir(&path)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to list files: {}", path.display()))?;
|
||||||
|
|
||||||
let mut files = paths
|
let mut files = paths
|
||||||
.filter_map(|x| async {
|
.filter_map(|x| async {
|
||||||
@ -106,8 +112,12 @@ pub async fn write_file(path: impl AsRef<Path>, content: &str) -> Result<()> {
|
|||||||
let parent = path
|
let parent = path
|
||||||
.parent()
|
.parent()
|
||||||
.ok_or_else(|| format_err!("no parent for: {}", path.display()))?;
|
.ok_or_else(|| format_err!("no parent for: {}", path.display()))?;
|
||||||
fs::create_dir_all(parent).await?;
|
fs::create_dir_all(parent)
|
||||||
fs::write(path, content).await?;
|
.await
|
||||||
|
.with_context(|| format!("unable to create nested path: {}", parent.display()))?;
|
||||||
|
fs::write(path, content)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to write file: {}", path.display()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,10 +125,14 @@ pub async fn reset_dir(dir: impl AsRef<Path>) -> Result<()> {
|
|||||||
let dir = dir.as_ref();
|
let dir = dir.as_ref();
|
||||||
|
|
||||||
if exists(dir).await? {
|
if exists(dir).await? {
|
||||||
fs::remove_dir_all(dir).await?;
|
fs::remove_dir_all(dir).await.with_context(|| {
|
||||||
|
format!("unable to remove directory and contents: {}", dir.display())
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::create_dir_all(dir).await?;
|
fs::create_dir_all(dir)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to create directory: {}", dir.display()))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -143,7 +157,9 @@ impl OwnedDir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_if_missing(&self) -> Result<()> {
|
pub async fn create_if_missing(&self) -> Result<()> {
|
||||||
fs::create_dir_all(self.path()).await?;
|
fs::create_dir_all(self.path())
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to create directory: {}", self.path().display()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
use crate::fs::{onefuzz_etc, write_file};
|
use crate::fs::{onefuzz_etc, write_file};
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use reqwest_retry::SendRetry;
|
use reqwest_retry::SendRetry;
|
||||||
|
use std::path::Path;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -83,7 +84,10 @@ pub async fn get_scaleset_name() -> Result<Option<String>> {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub async fn get_os_machine_id() -> Result<Uuid> {
|
pub async fn get_os_machine_id() -> Result<Uuid> {
|
||||||
let contents = fs::read_to_string("/etc/machine-id").await?;
|
let path = Path::new("/etc/machine-id");
|
||||||
|
let contents = fs::read_to_string(&path)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to read machine_id: {}", path.display()))?;
|
||||||
let uuid = Uuid::parse_str(contents.trim())?;
|
let uuid = Uuid::parse_str(contents.trim())?;
|
||||||
Ok(uuid)
|
Ok(uuid)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
@ -22,7 +22,10 @@ pub fn digest_iter(data: impl IntoIterator<Item = impl AsRef<[u8]>>) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn digest_file(file: impl AsRef<Path>) -> Result<String> {
|
pub async fn digest_file(file: impl AsRef<Path>) -> Result<String> {
|
||||||
let data = fs::read(file).await?;
|
let file = file.as_ref();
|
||||||
|
let data = fs::read(file)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("unable to read file to generate digest: {}", file.display()))?;
|
||||||
|
|
||||||
Ok(hex::encode(Sha256::digest(&data)))
|
Ok(hex::encode(Sha256::digest(&data)))
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
telemetry::{Event, EventData},
|
telemetry::{Event, EventData},
|
||||||
uploader::BlobUploader,
|
uploader::BlobUploader,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use std::{path::PathBuf, str, time::Duration};
|
use std::{path::PathBuf, str, time::Duration};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
@ -55,7 +55,9 @@ impl SyncedDir {
|
|||||||
anyhow::bail!("File with name '{}' already exists", self.path.display());
|
anyhow::bail!("File with name '{}' already exists", self.path.display());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => fs::create_dir(&self.path).await.map_err(|e| e.into()),
|
Err(_) => fs::create_dir(&self.path).await.with_context(|| {
|
||||||
|
format!("unable to create local SyncedDir: {}", self.path.display())
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user