mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-18 10:43:15 +00:00
ecstore update ec/disk/error
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use super::error::{Error, Result};
|
||||
use crate::utils::net;
|
||||
use common::error::{Error, Result};
|
||||
use path_absolutize::Absolutize;
|
||||
use rustfs_utils::is_local_host;
|
||||
use std::{fmt::Display, path::Path};
|
||||
use url::{ParseError, Url};
|
||||
|
||||
@@ -40,10 +41,10 @@ impl TryFrom<&str> for Endpoint {
|
||||
type Error = Error;
|
||||
|
||||
/// Performs the conversion.
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
// check whether given path is not empty.
|
||||
if ["", "/", "\\"].iter().any(|&v| v.eq(value)) {
|
||||
return Err(Error::from_string("empty or root endpoint is not supported"));
|
||||
return Err(Error::other("empty or root endpoint is not supported"));
|
||||
}
|
||||
|
||||
let mut is_local = false;
|
||||
@@ -59,7 +60,7 @@ impl TryFrom<&str> for Endpoint {
|
||||
&& url.fragment().is_none()
|
||||
&& url.query().is_none())
|
||||
{
|
||||
return Err(Error::from_string("invalid URL endpoint format"));
|
||||
return Err(Error::other("invalid URL endpoint format"));
|
||||
}
|
||||
|
||||
let path = url.path().to_string();
|
||||
@@ -76,12 +77,12 @@ impl TryFrom<&str> for Endpoint {
|
||||
let path = Path::new(&path[1..]).absolutize()?;
|
||||
|
||||
if path.parent().is_none() || Path::new("").eq(&path) {
|
||||
return Err(Error::from_string("empty or root path is not supported in URL endpoint"));
|
||||
return Err(Error::other("empty or root path is not supported in URL endpoint"));
|
||||
}
|
||||
|
||||
match path.to_str() {
|
||||
Some(v) => url.set_path(v),
|
||||
None => return Err(Error::from_string("invalid path")),
|
||||
None => return Err(Error::other("invalid path")),
|
||||
}
|
||||
|
||||
url
|
||||
@@ -93,15 +94,15 @@ impl TryFrom<&str> for Endpoint {
|
||||
}
|
||||
Err(e) => match e {
|
||||
ParseError::InvalidPort => {
|
||||
return Err(Error::from_string("invalid URL endpoint format: port number must be between 1 to 65535"))
|
||||
return Err(Error::other("invalid URL endpoint format: port number must be between 1 to 65535"))
|
||||
}
|
||||
ParseError::EmptyHost => return Err(Error::from_string("invalid URL endpoint format: empty host name")),
|
||||
ParseError::EmptyHost => return Err(Error::other("invalid URL endpoint format: empty host name")),
|
||||
ParseError::RelativeUrlWithoutBase => {
|
||||
// like /foo
|
||||
is_local = true;
|
||||
url_parse_from_file_path(value)?
|
||||
}
|
||||
_ => return Err(Error::from_string(format!("invalid URL endpoint format: {}", e))),
|
||||
_ => return Err(Error::other(format!("invalid URL endpoint format: {}", e))),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -144,7 +145,7 @@ impl Endpoint {
|
||||
pub fn update_is_local(&mut self, local_port: u16) -> Result<()> {
|
||||
match (self.url.scheme(), self.url.host()) {
|
||||
(v, Some(host)) if v != "file" => {
|
||||
self.is_local = net::is_local_host(host, self.url.port().unwrap_or_default(), local_port)?;
|
||||
self.is_local = is_local_host(host, self.url.port().unwrap_or_default(), local_port)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -186,17 +187,17 @@ fn url_parse_from_file_path(value: &str) -> Result<Url> {
|
||||
// /mnt/export1. So we go ahead and start the rustfs server in FS modes in these cases.
|
||||
let addr: Vec<&str> = value.splitn(2, '/').collect();
|
||||
if net::is_socket_addr(addr[0]) {
|
||||
return Err(Error::from_string("invalid URL endpoint format: missing scheme http or https"));
|
||||
return Err(Error::other("invalid URL endpoint format: missing scheme http or https"));
|
||||
}
|
||||
|
||||
let file_path = match Path::new(value).absolutize() {
|
||||
Ok(path) => path,
|
||||
Err(err) => return Err(Error::from_string(format!("absolute path failed: {}", err))),
|
||||
Err(err) => return Err(Error::other(format!("absolute path failed: {}", err))),
|
||||
};
|
||||
|
||||
match Url::from_file_path(file_path) {
|
||||
Ok(url) => Ok(url),
|
||||
Err(_) => Err(Error::from_string("Convert a file path into an URL failed")),
|
||||
Err(_) => Err(Error::other("Convert a file path into an URL failed")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,49 +261,49 @@ mod test {
|
||||
arg: "",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("empty or root endpoint is not supported")),
|
||||
expected_err: Some(Error::other("empty or root endpoint is not supported")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "/",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("empty or root endpoint is not supported")),
|
||||
expected_err: Some(Error::other("empty or root endpoint is not supported")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "\\",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("empty or root endpoint is not supported")),
|
||||
expected_err: Some(Error::other("empty or root endpoint is not supported")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "c://foo",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("invalid URL endpoint format")),
|
||||
expected_err: Some(Error::other("invalid URL endpoint format")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "ftp://foo",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("invalid URL endpoint format")),
|
||||
expected_err: Some(Error::other("invalid URL endpoint format")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "http://server/path?location",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("invalid URL endpoint format")),
|
||||
expected_err: Some(Error::other("invalid URL endpoint format")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "http://:/path",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("invalid URL endpoint format: empty host name")),
|
||||
expected_err: Some(Error::other("invalid URL endpoint format: empty host name")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "http://:8080/path",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("invalid URL endpoint format: empty host name")),
|
||||
expected_err: Some(Error::other("invalid URL endpoint format: empty host name")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "http://server:/path",
|
||||
@@ -320,25 +321,25 @@ mod test {
|
||||
arg: "https://93.184.216.34:808080/path",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("invalid URL endpoint format: port number must be between 1 to 65535")),
|
||||
expected_err: Some(Error::other("invalid URL endpoint format: port number must be between 1 to 65535")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "http://server:8080//",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("empty or root path is not supported in URL endpoint")),
|
||||
expected_err: Some(Error::other("empty or root path is not supported in URL endpoint")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "http://server:8080/",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("empty or root path is not supported in URL endpoint")),
|
||||
expected_err: Some(Error::other("empty or root path is not supported in URL endpoint")),
|
||||
},
|
||||
TestCase {
|
||||
arg: "192.168.1.210:9000",
|
||||
expected_endpoint: None,
|
||||
expected_type: None,
|
||||
expected_err: Some(Error::from_string("invalid URL endpoint format: missing scheme http or https")),
|
||||
expected_err: Some(Error::other("invalid URL endpoint format: missing scheme http or https")),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
+540
-332
@@ -1,11 +1,11 @@
|
||||
use std::io::{self, ErrorKind};
|
||||
// use crate::quorum::CheckErrorFn;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::{self};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use tracing::error;
|
||||
|
||||
use crate::quorum::CheckErrorFn;
|
||||
use crate::utils::ERROR_TYPE_MASK;
|
||||
use common::error::{Error, Result};
|
||||
pub type Error = DiskError;
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
|
||||
// DiskError == StorageErr
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
@@ -91,6 +91,9 @@ pub enum DiskError {
|
||||
#[error("file is corrupted")]
|
||||
FileCorrupt,
|
||||
|
||||
#[error("short write")]
|
||||
ShortWrite,
|
||||
|
||||
#[error("bit-rot hash algorithm is invalid")]
|
||||
BitrotHashAlgoInvalid,
|
||||
|
||||
@@ -111,58 +114,238 @@ pub enum DiskError {
|
||||
|
||||
#[error("No healing is required")]
|
||||
NoHealRequired,
|
||||
|
||||
#[error("method not allowed")]
|
||||
MethodNotAllowed,
|
||||
|
||||
#[error("erasure write quorum")]
|
||||
ErasureWriteQuorum,
|
||||
|
||||
#[error("erasure read quorum")]
|
||||
ErasureReadQuorum,
|
||||
|
||||
#[error("io error")]
|
||||
Io(io::Error),
|
||||
}
|
||||
|
||||
impl DiskError {
|
||||
/// Checks if the given array of errors contains fatal disk errors.
|
||||
/// If all errors are of the same fatal disk error type, returns the corresponding error.
|
||||
/// Otherwise, returns Ok.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `errs`: A slice of optional errors.
|
||||
///
|
||||
/// # Returns
|
||||
/// If all errors are of the same fatal disk error type, returns the corresponding error.
|
||||
/// Otherwise, returns Ok.
|
||||
pub fn check_disk_fatal_errs(errs: &[Option<Error>]) -> Result<()> {
|
||||
if DiskError::UnsupportedDisk.count_errs(errs) == errs.len() {
|
||||
return Err(DiskError::UnsupportedDisk.into());
|
||||
pub fn other<E>(error: E) -> Self
|
||||
where
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
DiskError::Io(std::io::Error::other(error))
|
||||
}
|
||||
|
||||
pub fn is_all_not_found(errs: &[Option<DiskError>]) -> bool {
|
||||
for err in errs.iter() {
|
||||
if let Some(err) = err {
|
||||
if err == &DiskError::FileNotFound || err == &DiskError::FileVersionNotFound {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if DiskError::FileAccessDenied.count_errs(errs) == errs.len() {
|
||||
return Err(DiskError::FileAccessDenied.into());
|
||||
!errs.is_empty()
|
||||
}
|
||||
|
||||
pub fn is_err_object_not_found(err: &DiskError) -> bool {
|
||||
matches!(err, &DiskError::FileNotFound) || matches!(err, &DiskError::VolumeNotFound)
|
||||
}
|
||||
|
||||
pub fn is_err_version_not_found(err: &DiskError) -> bool {
|
||||
matches!(err, &DiskError::FileVersionNotFound)
|
||||
}
|
||||
|
||||
// /// If all errors are of the same fatal disk error type, returns the corresponding error.
|
||||
// /// Otherwise, returns Ok.
|
||||
// pub fn check_disk_fatal_errs(errs: &[Option<Error>]) -> Result<()> {
|
||||
// if DiskError::UnsupportedDisk.count_errs(errs) == errs.len() {
|
||||
// return Err(DiskError::UnsupportedDisk.into());
|
||||
// }
|
||||
|
||||
// if DiskError::FileAccessDenied.count_errs(errs) == errs.len() {
|
||||
// return Err(DiskError::FileAccessDenied.into());
|
||||
// }
|
||||
|
||||
// if DiskError::DiskNotDir.count_errs(errs) == errs.len() {
|
||||
// return Err(DiskError::DiskNotDir.into());
|
||||
// }
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// pub fn count_errs(&self, errs: &[Option<Error>]) -> usize {
|
||||
// errs.iter()
|
||||
// .filter(|&err| match err {
|
||||
// None => false,
|
||||
// Some(e) => self.is(e),
|
||||
// })
|
||||
// .count()
|
||||
// }
|
||||
|
||||
// pub fn quorum_unformatted_disks(errs: &[Option<Error>]) -> bool {
|
||||
// DiskError::UnformattedDisk.count_errs(errs) > (errs.len() / 2)
|
||||
// }
|
||||
|
||||
// pub fn should_init_erasure_disks(errs: &[Option<Error>]) -> bool {
|
||||
// DiskError::UnformattedDisk.count_errs(errs) == errs.len()
|
||||
// }
|
||||
|
||||
// // Check if the error is a disk error
|
||||
// pub fn is(&self, err: &DiskError) -> bool {
|
||||
// if let Some(e) = err.downcast_ref::<DiskError>() {
|
||||
// e == self
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl From<rustfs_filemeta::Error> for DiskError {
|
||||
fn from(e: rustfs_filemeta::Error) -> Self {
|
||||
match e {
|
||||
rustfs_filemeta::Error::Io(e) => DiskError::other(e),
|
||||
rustfs_filemeta::Error::FileNotFound => DiskError::FileNotFound,
|
||||
rustfs_filemeta::Error::FileVersionNotFound => DiskError::FileVersionNotFound,
|
||||
rustfs_filemeta::Error::FileCorrupt => DiskError::FileCorrupt,
|
||||
rustfs_filemeta::Error::MethodNotAllowed => DiskError::MethodNotAllowed,
|
||||
e => DiskError::other(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if DiskError::DiskNotDir.count_errs(errs) == errs.len() {
|
||||
return Err(DiskError::DiskNotDir.into());
|
||||
impl From<std::io::Error> for DiskError {
|
||||
fn from(e: std::io::Error) -> Self {
|
||||
e.downcast::<DiskError>().unwrap_or_else(DiskError::Io)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DiskError> for std::io::Error {
|
||||
fn from(e: DiskError) -> Self {
|
||||
match e {
|
||||
DiskError::Io(io_error) => io_error,
|
||||
e => std::io::Error::other(e),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count_errs(&self, errs: &[Option<Error>]) -> usize {
|
||||
errs.iter()
|
||||
.filter(|&err| match err {
|
||||
None => false,
|
||||
Some(e) => self.is(e),
|
||||
})
|
||||
.count()
|
||||
impl From<tonic::Status> for DiskError {
|
||||
fn from(e: tonic::Status) -> Self {
|
||||
DiskError::other(e.message().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn quorum_unformatted_disks(errs: &[Option<Error>]) -> bool {
|
||||
DiskError::UnformattedDisk.count_errs(errs) > (errs.len() / 2)
|
||||
}
|
||||
|
||||
pub fn should_init_erasure_disks(errs: &[Option<Error>]) -> bool {
|
||||
DiskError::UnformattedDisk.count_errs(errs) == errs.len()
|
||||
}
|
||||
|
||||
/// Check if the error is a disk error
|
||||
pub fn is(&self, err: &Error) -> bool {
|
||||
if let Some(e) = err.downcast_ref::<DiskError>() {
|
||||
e == self
|
||||
impl From<protos::proto_gen::node_service::Error> for DiskError {
|
||||
fn from(e: protos::proto_gen::node_service::Error) -> Self {
|
||||
if let Some(err) = DiskError::from_u32(e.code) {
|
||||
if matches!(err, DiskError::Io(_)) {
|
||||
DiskError::other(e.error_info)
|
||||
} else {
|
||||
err
|
||||
}
|
||||
} else {
|
||||
false
|
||||
DiskError::other(e.error_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<protos::proto_gen::node_service::Error> for DiskError {
|
||||
fn into(self) -> protos::proto_gen::node_service::Error {
|
||||
protos::proto_gen::node_service::Error {
|
||||
code: self.to_u32(),
|
||||
error_info: self.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for DiskError {
|
||||
fn from(e: serde_json::Error) -> Self {
|
||||
DiskError::other(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rmp_serde::encode::Error> for DiskError {
|
||||
fn from(e: rmp_serde::encode::Error) -> Self {
|
||||
DiskError::other(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rmp::encode::ValueWriteError> for DiskError {
|
||||
fn from(e: rmp::encode::ValueWriteError) -> Self {
|
||||
DiskError::other(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rmp::decode::ValueReadError> for DiskError {
|
||||
fn from(e: rmp::decode::ValueReadError) -> Self {
|
||||
DiskError::other(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::string::FromUtf8Error> for DiskError {
|
||||
fn from(e: std::string::FromUtf8Error) -> Self {
|
||||
DiskError::other(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rmp::decode::NumValueReadError> for DiskError {
|
||||
fn from(e: rmp::decode::NumValueReadError) -> Self {
|
||||
DiskError::other(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<tokio::task::JoinError> for DiskError {
|
||||
fn from(e: tokio::task::JoinError) -> Self {
|
||||
DiskError::other(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for DiskError {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
DiskError::Io(io_error) => DiskError::Io(std::io::Error::new(io_error.kind(), io_error.to_string())),
|
||||
DiskError::MaxVersionsExceeded => DiskError::MaxVersionsExceeded,
|
||||
DiskError::Unexpected => DiskError::Unexpected,
|
||||
DiskError::CorruptedFormat => DiskError::CorruptedFormat,
|
||||
DiskError::CorruptedBackend => DiskError::CorruptedBackend,
|
||||
DiskError::UnformattedDisk => DiskError::UnformattedDisk,
|
||||
DiskError::InconsistentDisk => DiskError::InconsistentDisk,
|
||||
DiskError::UnsupportedDisk => DiskError::UnsupportedDisk,
|
||||
DiskError::DiskFull => DiskError::DiskFull,
|
||||
DiskError::DiskNotDir => DiskError::DiskNotDir,
|
||||
DiskError::DiskNotFound => DiskError::DiskNotFound,
|
||||
DiskError::DiskOngoingReq => DiskError::DiskOngoingReq,
|
||||
DiskError::DriveIsRoot => DiskError::DriveIsRoot,
|
||||
DiskError::FaultyRemoteDisk => DiskError::FaultyRemoteDisk,
|
||||
DiskError::FaultyDisk => DiskError::FaultyDisk,
|
||||
DiskError::DiskAccessDenied => DiskError::DiskAccessDenied,
|
||||
DiskError::FileNotFound => DiskError::FileNotFound,
|
||||
DiskError::FileVersionNotFound => DiskError::FileVersionNotFound,
|
||||
DiskError::TooManyOpenFiles => DiskError::TooManyOpenFiles,
|
||||
DiskError::FileNameTooLong => DiskError::FileNameTooLong,
|
||||
DiskError::VolumeExists => DiskError::VolumeExists,
|
||||
DiskError::IsNotRegular => DiskError::IsNotRegular,
|
||||
DiskError::PathNotFound => DiskError::PathNotFound,
|
||||
DiskError::VolumeNotFound => DiskError::VolumeNotFound,
|
||||
DiskError::VolumeNotEmpty => DiskError::VolumeNotEmpty,
|
||||
DiskError::VolumeAccessDenied => DiskError::VolumeAccessDenied,
|
||||
DiskError::FileAccessDenied => DiskError::FileAccessDenied,
|
||||
DiskError::FileCorrupt => DiskError::FileCorrupt,
|
||||
DiskError::BitrotHashAlgoInvalid => DiskError::BitrotHashAlgoInvalid,
|
||||
DiskError::CrossDeviceLink => DiskError::CrossDeviceLink,
|
||||
DiskError::LessData => DiskError::LessData,
|
||||
DiskError::MoreData => DiskError::MoreData,
|
||||
DiskError::OutdatedXLMeta => DiskError::OutdatedXLMeta,
|
||||
DiskError::PartMissingOrCorrupt => DiskError::PartMissingOrCorrupt,
|
||||
DiskError::NoHealRequired => DiskError::NoHealRequired,
|
||||
DiskError::MethodNotAllowed => DiskError::MethodNotAllowed,
|
||||
DiskError::ErasureWriteQuorum => DiskError::ErasureWriteQuorum,
|
||||
DiskError::ErasureReadQuorum => DiskError::ErasureReadQuorum,
|
||||
DiskError::ShortWrite => DiskError::ShortWrite,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,11 +387,16 @@ impl DiskError {
|
||||
DiskError::OutdatedXLMeta => 0x20,
|
||||
DiskError::PartMissingOrCorrupt => 0x21,
|
||||
DiskError::NoHealRequired => 0x22,
|
||||
DiskError::MethodNotAllowed => 0x23,
|
||||
DiskError::Io(_) => 0x24,
|
||||
DiskError::ErasureWriteQuorum => 0x25,
|
||||
DiskError::ErasureReadQuorum => 0x26,
|
||||
DiskError::ShortWrite => 0x27,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_u32(error: u32) -> Option<Self> {
|
||||
match error & ERROR_TYPE_MASK {
|
||||
match error {
|
||||
0x01 => Some(DiskError::MaxVersionsExceeded),
|
||||
0x02 => Some(DiskError::Unexpected),
|
||||
0x03 => Some(DiskError::CorruptedFormat),
|
||||
@@ -243,6 +431,11 @@ impl DiskError {
|
||||
0x20 => Some(DiskError::OutdatedXLMeta),
|
||||
0x21 => Some(DiskError::PartMissingOrCorrupt),
|
||||
0x22 => Some(DiskError::NoHealRequired),
|
||||
0x23 => Some(DiskError::MethodNotAllowed),
|
||||
0x24 => Some(DiskError::Io(std::io::Error::other(String::new()))),
|
||||
0x25 => Some(DiskError::ErasureWriteQuorum),
|
||||
0x26 => Some(DiskError::ErasureReadQuorum),
|
||||
0x27 => Some(DiskError::ShortWrite),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -250,101 +443,116 @@ impl DiskError {
|
||||
|
||||
impl PartialEq for DiskError {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
core::mem::discriminant(self) == core::mem::discriminant(other)
|
||||
match (self, other) {
|
||||
(DiskError::Io(e1), DiskError::Io(e2)) => e1.kind() == e2.kind() && e1.to_string() == e2.to_string(),
|
||||
_ => self.to_u32() == other.to_u32(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckErrorFn for DiskError {
|
||||
fn is(&self, e: &Error) -> bool {
|
||||
self.is(e)
|
||||
impl Eq for DiskError {}
|
||||
|
||||
impl Hash for DiskError {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
match self {
|
||||
DiskError::Io(e) => e.to_string().hash(state),
|
||||
_ => self.to_u32().hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_disk_err(e: &DiskError) -> Error {
|
||||
match e {
|
||||
DiskError::MaxVersionsExceeded => Error::new(DiskError::MaxVersionsExceeded),
|
||||
DiskError::Unexpected => Error::new(DiskError::Unexpected),
|
||||
DiskError::CorruptedFormat => Error::new(DiskError::CorruptedFormat),
|
||||
DiskError::CorruptedBackend => Error::new(DiskError::CorruptedBackend),
|
||||
DiskError::UnformattedDisk => Error::new(DiskError::UnformattedDisk),
|
||||
DiskError::InconsistentDisk => Error::new(DiskError::InconsistentDisk),
|
||||
DiskError::UnsupportedDisk => Error::new(DiskError::UnsupportedDisk),
|
||||
DiskError::DiskFull => Error::new(DiskError::DiskFull),
|
||||
DiskError::DiskNotDir => Error::new(DiskError::DiskNotDir),
|
||||
DiskError::DiskNotFound => Error::new(DiskError::DiskNotFound),
|
||||
DiskError::DiskOngoingReq => Error::new(DiskError::DiskOngoingReq),
|
||||
DiskError::DriveIsRoot => Error::new(DiskError::DriveIsRoot),
|
||||
DiskError::FaultyRemoteDisk => Error::new(DiskError::FaultyRemoteDisk),
|
||||
DiskError::FaultyDisk => Error::new(DiskError::FaultyDisk),
|
||||
DiskError::DiskAccessDenied => Error::new(DiskError::DiskAccessDenied),
|
||||
DiskError::FileNotFound => Error::new(DiskError::FileNotFound),
|
||||
DiskError::FileVersionNotFound => Error::new(DiskError::FileVersionNotFound),
|
||||
DiskError::TooManyOpenFiles => Error::new(DiskError::TooManyOpenFiles),
|
||||
DiskError::FileNameTooLong => Error::new(DiskError::FileNameTooLong),
|
||||
DiskError::VolumeExists => Error::new(DiskError::VolumeExists),
|
||||
DiskError::IsNotRegular => Error::new(DiskError::IsNotRegular),
|
||||
DiskError::PathNotFound => Error::new(DiskError::PathNotFound),
|
||||
DiskError::VolumeNotFound => Error::new(DiskError::VolumeNotFound),
|
||||
DiskError::VolumeNotEmpty => Error::new(DiskError::VolumeNotEmpty),
|
||||
DiskError::VolumeAccessDenied => Error::new(DiskError::VolumeAccessDenied),
|
||||
DiskError::FileAccessDenied => Error::new(DiskError::FileAccessDenied),
|
||||
DiskError::FileCorrupt => Error::new(DiskError::FileCorrupt),
|
||||
DiskError::BitrotHashAlgoInvalid => Error::new(DiskError::BitrotHashAlgoInvalid),
|
||||
DiskError::CrossDeviceLink => Error::new(DiskError::CrossDeviceLink),
|
||||
DiskError::LessData => Error::new(DiskError::LessData),
|
||||
DiskError::MoreData => Error::new(DiskError::MoreData),
|
||||
DiskError::OutdatedXLMeta => Error::new(DiskError::OutdatedXLMeta),
|
||||
DiskError::PartMissingOrCorrupt => Error::new(DiskError::PartMissingOrCorrupt),
|
||||
DiskError::NoHealRequired => Error::new(DiskError::NoHealRequired),
|
||||
}
|
||||
}
|
||||
// impl CheckErrorFn for DiskError {
|
||||
// fn is(&self, e: &DiskError) -> bool {
|
||||
|
||||
pub fn os_err_to_file_err(e: io::Error) -> Error {
|
||||
match e.kind() {
|
||||
ErrorKind::NotFound => Error::new(DiskError::FileNotFound),
|
||||
ErrorKind::PermissionDenied => Error::new(DiskError::FileAccessDenied),
|
||||
// io::ErrorKind::ConnectionRefused => todo!(),
|
||||
// io::ErrorKind::ConnectionReset => todo!(),
|
||||
// io::ErrorKind::HostUnreachable => todo!(),
|
||||
// io::ErrorKind::NetworkUnreachable => todo!(),
|
||||
// io::ErrorKind::ConnectionAborted => todo!(),
|
||||
// io::ErrorKind::NotConnected => todo!(),
|
||||
// io::ErrorKind::AddrInUse => todo!(),
|
||||
// io::ErrorKind::AddrNotAvailable => todo!(),
|
||||
// io::ErrorKind::NetworkDown => todo!(),
|
||||
// io::ErrorKind::BrokenPipe => todo!(),
|
||||
// io::ErrorKind::AlreadyExists => todo!(),
|
||||
// io::ErrorKind::WouldBlock => todo!(),
|
||||
// io::ErrorKind::NotADirectory => DiskError::FileNotFound,
|
||||
// io::ErrorKind::IsADirectory => DiskError::FileNotFound,
|
||||
// io::ErrorKind::DirectoryNotEmpty => DiskError::VolumeNotEmpty,
|
||||
// io::ErrorKind::ReadOnlyFilesystem => todo!(),
|
||||
// io::ErrorKind::FilesystemLoop => todo!(),
|
||||
// io::ErrorKind::StaleNetworkFileHandle => todo!(),
|
||||
// io::ErrorKind::InvalidInput => todo!(),
|
||||
// io::ErrorKind::InvalidData => todo!(),
|
||||
// io::ErrorKind::TimedOut => todo!(),
|
||||
// io::ErrorKind::WriteZero => todo!(),
|
||||
// io::ErrorKind::StorageFull => DiskError::DiskFull,
|
||||
// io::ErrorKind::NotSeekable => todo!(),
|
||||
// io::ErrorKind::FilesystemQuotaExceeded => todo!(),
|
||||
// io::ErrorKind::FileTooLarge => todo!(),
|
||||
// io::ErrorKind::ResourceBusy => todo!(),
|
||||
// io::ErrorKind::ExecutableFileBusy => todo!(),
|
||||
// io::ErrorKind::Deadlock => todo!(),
|
||||
// io::ErrorKind::CrossesDevices => todo!(),
|
||||
// io::ErrorKind::TooManyLinks =>DiskError::TooManyOpenFiles,
|
||||
// io::ErrorKind::InvalidFilename => todo!(),
|
||||
// io::ErrorKind::ArgumentListTooLong => todo!(),
|
||||
// io::ErrorKind::Interrupted => todo!(),
|
||||
// io::ErrorKind::Unsupported => todo!(),
|
||||
// io::ErrorKind::UnexpectedEof => todo!(),
|
||||
// io::ErrorKind::OutOfMemory => todo!(),
|
||||
// io::ErrorKind::Other => todo!(),
|
||||
// TODO: 把不支持的 king 用字符串处理
|
||||
_ => Error::new(e),
|
||||
}
|
||||
}
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn clone_disk_err(e: &DiskError) -> Error {
|
||||
// match e {
|
||||
// DiskError::MaxVersionsExceeded => DiskError::MaxVersionsExceeded,
|
||||
// DiskError::Unexpected => DiskError::Unexpected,
|
||||
// DiskError::CorruptedFormat => DiskError::CorruptedFormat,
|
||||
// DiskError::CorruptedBackend => DiskError::CorruptedBackend,
|
||||
// DiskError::UnformattedDisk => DiskError::UnformattedDisk,
|
||||
// DiskError::InconsistentDisk => DiskError::InconsistentDisk,
|
||||
// DiskError::UnsupportedDisk => DiskError::UnsupportedDisk,
|
||||
// DiskError::DiskFull => DiskError::DiskFull,
|
||||
// DiskError::DiskNotDir => DiskError::DiskNotDir,
|
||||
// DiskError::DiskNotFound => DiskError::DiskNotFound,
|
||||
// DiskError::DiskOngoingReq => DiskError::DiskOngoingReq,
|
||||
// DiskError::DriveIsRoot => DiskError::DriveIsRoot,
|
||||
// DiskError::FaultyRemoteDisk => DiskError::FaultyRemoteDisk,
|
||||
// DiskError::FaultyDisk => DiskError::FaultyDisk,
|
||||
// DiskError::DiskAccessDenied => DiskError::DiskAccessDenied,
|
||||
// DiskError::FileNotFound => DiskError::FileNotFound,
|
||||
// DiskError::FileVersionNotFound => DiskError::FileVersionNotFound,
|
||||
// DiskError::TooManyOpenFiles => DiskError::TooManyOpenFiles,
|
||||
// DiskError::FileNameTooLong => DiskError::FileNameTooLong,
|
||||
// DiskError::VolumeExists => DiskError::VolumeExists,
|
||||
// DiskError::IsNotRegular => DiskError::IsNotRegular,
|
||||
// DiskError::PathNotFound => DiskError::PathNotFound,
|
||||
// DiskError::VolumeNotFound => DiskError::VolumeNotFound,
|
||||
// DiskError::VolumeNotEmpty => DiskError::VolumeNotEmpty,
|
||||
// DiskError::VolumeAccessDenied => DiskError::VolumeAccessDenied,
|
||||
// DiskError::FileAccessDenied => DiskError::FileAccessDenied,
|
||||
// DiskError::FileCorrupt => DiskError::FileCorrupt,
|
||||
// DiskError::BitrotHashAlgoInvalid => DiskError::BitrotHashAlgoInvalid,
|
||||
// DiskError::CrossDeviceLink => DiskError::CrossDeviceLink,
|
||||
// DiskError::LessData => DiskError::LessData,
|
||||
// DiskError::MoreData => DiskError::MoreData,
|
||||
// DiskError::OutdatedXLMeta => DiskError::OutdatedXLMeta,
|
||||
// DiskError::PartMissingOrCorrupt => DiskError::PartMissingOrCorrupt,
|
||||
// DiskError::NoHealRequired => DiskError::NoHealRequired,
|
||||
// DiskError::Other(s) => DiskError::Other(s.clone()),
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn os_err_to_file_err(e: io::Error) -> Error {
|
||||
// match e.kind() {
|
||||
// ErrorKind::NotFound => Error::new(DiskError::FileNotFound),
|
||||
// ErrorKind::PermissionDenied => Error::new(DiskError::FileAccessDenied),
|
||||
// // io::ErrorKind::ConnectionRefused => todo!(),
|
||||
// // io::ErrorKind::ConnectionReset => todo!(),
|
||||
// // io::ErrorKind::HostUnreachable => todo!(),
|
||||
// // io::ErrorKind::NetworkUnreachable => todo!(),
|
||||
// // io::ErrorKind::ConnectionAborted => todo!(),
|
||||
// // io::ErrorKind::NotConnected => todo!(),
|
||||
// // io::ErrorKind::AddrInUse => todo!(),
|
||||
// // io::ErrorKind::AddrNotAvailable => todo!(),
|
||||
// // io::ErrorKind::NetworkDown => todo!(),
|
||||
// // io::ErrorKind::BrokenPipe => todo!(),
|
||||
// // io::ErrorKind::AlreadyExists => todo!(),
|
||||
// // io::ErrorKind::WouldBlock => todo!(),
|
||||
// // io::ErrorKind::NotADirectory => DiskError::FileNotFound,
|
||||
// // io::ErrorKind::IsADirectory => DiskError::FileNotFound,
|
||||
// // io::ErrorKind::DirectoryNotEmpty => DiskError::VolumeNotEmpty,
|
||||
// // io::ErrorKind::ReadOnlyFilesystem => todo!(),
|
||||
// // io::ErrorKind::FilesystemLoop => todo!(),
|
||||
// // io::ErrorKind::StaleNetworkFileHandle => todo!(),
|
||||
// // io::ErrorKind::InvalidInput => todo!(),
|
||||
// // io::ErrorKind::InvalidData => todo!(),
|
||||
// // io::ErrorKind::TimedOut => todo!(),
|
||||
// // io::ErrorKind::WriteZero => todo!(),
|
||||
// // io::ErrorKind::StorageFull => DiskError::DiskFull,
|
||||
// // io::ErrorKind::NotSeekable => todo!(),
|
||||
// // io::ErrorKind::FilesystemQuotaExceeded => todo!(),
|
||||
// // io::ErrorKind::FileTooLarge => todo!(),
|
||||
// // io::ErrorKind::ResourceBusy => todo!(),
|
||||
// // io::ErrorKind::ExecutableFileBusy => todo!(),
|
||||
// // io::ErrorKind::Deadlock => todo!(),
|
||||
// // io::ErrorKind::CrossesDevices => todo!(),
|
||||
// // io::ErrorKind::TooManyLinks =>DiskError::TooManyOpenFiles,
|
||||
// // io::ErrorKind::InvalidFilename => todo!(),
|
||||
// // io::ErrorKind::ArgumentListTooLong => todo!(),
|
||||
// // io::ErrorKind::Interrupted => todo!(),
|
||||
// // io::ErrorKind::Unsupported => todo!(),
|
||||
// // io::ErrorKind::UnexpectedEof => todo!(),
|
||||
// // io::ErrorKind::OutOfMemory => todo!(),
|
||||
// // io::ErrorKind::Other => todo!(),
|
||||
// // TODO: 把不支持的 king 用字符串处理
|
||||
// _ => Error::new(e),
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub struct FileAccessDeniedWithContext {
|
||||
@@ -359,235 +567,235 @@ impl std::fmt::Display for FileAccessDeniedWithContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unformatted_disk(err: &Error) -> bool {
|
||||
matches!(err.downcast_ref::<DiskError>(), Some(DiskError::UnformattedDisk))
|
||||
}
|
||||
// pub fn is_unformatted_disk(err: &Error) -> bool {
|
||||
// matches!(err.downcast_ref::<DiskError>(), Some(DiskError::UnformattedDisk))
|
||||
// }
|
||||
|
||||
pub fn is_err_file_not_found(err: &Error) -> bool {
|
||||
if let Some(ioerr) = err.downcast_ref::<io::Error>() {
|
||||
return ioerr.kind() == ErrorKind::NotFound;
|
||||
}
|
||||
// pub fn is_err_file_not_found(err: &Error) -> bool {
|
||||
// if let Some(ioerr) = err.downcast_ref::<io::Error>() {
|
||||
// return ioerr.kind() == ErrorKind::NotFound;
|
||||
// }
|
||||
|
||||
matches!(err.downcast_ref::<DiskError>(), Some(DiskError::FileNotFound))
|
||||
}
|
||||
// matches!(err.downcast_ref::<DiskError>(), Some(DiskError::FileNotFound))
|
||||
// }
|
||||
|
||||
pub fn is_err_file_version_not_found(err: &Error) -> bool {
|
||||
matches!(err.downcast_ref::<DiskError>(), Some(DiskError::FileVersionNotFound))
|
||||
}
|
||||
// pub fn is_err_file_version_not_found(err: &Error) -> bool {
|
||||
// matches!(err.downcast_ref::<DiskError>(), Some(DiskError::FileVersionNotFound))
|
||||
// }
|
||||
|
||||
pub fn is_err_volume_not_found(err: &Error) -> bool {
|
||||
matches!(err.downcast_ref::<DiskError>(), Some(DiskError::VolumeNotFound))
|
||||
}
|
||||
// pub fn is_err_volume_not_found(err: &Error) -> bool {
|
||||
// matches!(err.downcast_ref::<DiskError>(), Some(DiskError::VolumeNotFound))
|
||||
// }
|
||||
|
||||
pub fn is_err_eof(err: &Error) -> bool {
|
||||
if let Some(ioerr) = err.downcast_ref::<io::Error>() {
|
||||
return ioerr.kind() == ErrorKind::UnexpectedEof;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_err_eof(err: &Error) -> bool {
|
||||
// if let Some(ioerr) = err.downcast_ref::<io::Error>() {
|
||||
// return ioerr.kind() == ErrorKind::UnexpectedEof;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_no_space(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 28;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_no_space(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// return no == 28;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_invalid_arg(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 22;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_invalid_arg(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// return no == 22;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_io(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 5;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_io(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// return no == 5;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_is_dir(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 21;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_is_dir(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// return no == 21;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_not_dir(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 20;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_not_dir(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// return no == 20;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_too_long(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 63;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_too_long(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// return no == 63;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_too_many_symlinks(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 62;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_too_many_symlinks(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// return no == 62;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_not_empty(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
if no == 66 {
|
||||
return true;
|
||||
}
|
||||
// pub fn is_sys_err_not_empty(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// if no == 66 {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if cfg!(target_os = "solaris") && no == 17 {
|
||||
return true;
|
||||
}
|
||||
// if cfg!(target_os = "solaris") && no == 17 {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if cfg!(target_os = "windows") && no == 145 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
// if cfg!(target_os = "windows") && no == 145 {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_path_not_found(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
if cfg!(target_os = "windows") {
|
||||
if no == 3 {
|
||||
return true;
|
||||
}
|
||||
} else if no == 2 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_path_not_found(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// if cfg!(target_os = "windows") {
|
||||
// if no == 3 {
|
||||
// return true;
|
||||
// }
|
||||
// } else if no == 2 {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_handle_invalid(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
if cfg!(target_os = "windows") {
|
||||
if no == 6 {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_handle_invalid(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// if cfg!(target_os = "windows") {
|
||||
// if no == 6 {
|
||||
// return true;
|
||||
// }
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_cross_device(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 18;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_cross_device(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// return no == 18;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn is_sys_err_too_many_files(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 23 || no == 24;
|
||||
}
|
||||
false
|
||||
}
|
||||
// pub fn is_sys_err_too_many_files(e: &io::Error) -> bool {
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// return no == 23 || no == 24;
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn os_is_not_exist(e: &io::Error) -> bool {
|
||||
e.kind() == ErrorKind::NotFound
|
||||
}
|
||||
// pub fn os_is_not_exist(e: &io::Error) -> bool {
|
||||
// e.kind() == ErrorKind::NotFound
|
||||
// }
|
||||
|
||||
pub fn os_is_permission(e: &io::Error) -> bool {
|
||||
if e.kind() == ErrorKind::PermissionDenied {
|
||||
return true;
|
||||
}
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
if no == 30 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// pub fn os_is_permission(e: &io::Error) -> bool {
|
||||
// if e.kind() == ErrorKind::PermissionDenied {
|
||||
// return true;
|
||||
// }
|
||||
// if let Some(no) = e.raw_os_error() {
|
||||
// if no == 30 {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
false
|
||||
}
|
||||
// false
|
||||
// }
|
||||
|
||||
pub fn os_is_exist(e: &io::Error) -> bool {
|
||||
e.kind() == ErrorKind::AlreadyExists
|
||||
}
|
||||
// pub fn os_is_exist(e: &io::Error) -> bool {
|
||||
// e.kind() == ErrorKind::AlreadyExists
|
||||
// }
|
||||
|
||||
// map_err_not_exists
|
||||
pub fn map_err_not_exists(e: io::Error) -> Error {
|
||||
if os_is_not_exist(&e) {
|
||||
return Error::new(DiskError::VolumeNotEmpty);
|
||||
} else if is_sys_err_io(&e) {
|
||||
return Error::new(DiskError::FaultyDisk);
|
||||
}
|
||||
// // map_err_not_exists
|
||||
// pub fn map_err_not_exists(e: io::Error) -> Error {
|
||||
// if os_is_not_exist(&e) {
|
||||
// return Error::new(DiskError::VolumeNotEmpty);
|
||||
// } else if is_sys_err_io(&e) {
|
||||
// return Error::new(DiskError::FaultyDisk);
|
||||
// }
|
||||
|
||||
Error::new(e)
|
||||
}
|
||||
// Error::new(e)
|
||||
// }
|
||||
|
||||
pub fn convert_access_error(e: io::Error, per_err: DiskError) -> Error {
|
||||
if os_is_not_exist(&e) {
|
||||
return Error::new(DiskError::VolumeNotEmpty);
|
||||
} else if is_sys_err_io(&e) {
|
||||
return Error::new(DiskError::FaultyDisk);
|
||||
} else if os_is_permission(&e) {
|
||||
return Error::new(per_err);
|
||||
}
|
||||
// pub fn convert_access_error(e: io::Error, per_err: DiskError) -> Error {
|
||||
// if os_is_not_exist(&e) {
|
||||
// return Error::new(DiskError::VolumeNotEmpty);
|
||||
// } else if is_sys_err_io(&e) {
|
||||
// return Error::new(DiskError::FaultyDisk);
|
||||
// } else if os_is_permission(&e) {
|
||||
// return Error::new(per_err);
|
||||
// }
|
||||
|
||||
Error::new(e)
|
||||
}
|
||||
// Error::new(e)
|
||||
// }
|
||||
|
||||
pub fn is_all_not_found(errs: &[Option<Error>]) -> bool {
|
||||
for err in errs.iter() {
|
||||
if let Some(err) = err {
|
||||
if let Some(err) = err.downcast_ref::<DiskError>() {
|
||||
match err {
|
||||
DiskError::FileNotFound | DiskError::VolumeNotFound | &DiskError::FileVersionNotFound => {
|
||||
continue;
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// pub fn is_all_not_found(errs: &[Option<Error>]) -> bool {
|
||||
// for err in errs.iter() {
|
||||
// if let Some(err) = err {
|
||||
// if let Some(err) = err.downcast_ref::<DiskError>() {
|
||||
// match err {
|
||||
// DiskError::FileNotFound | DiskError::VolumeNotFound | &DiskError::FileVersionNotFound => {
|
||||
// continue;
|
||||
// }
|
||||
// _ => return false,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
!errs.is_empty()
|
||||
}
|
||||
// !errs.is_empty()
|
||||
// }
|
||||
|
||||
pub fn is_all_volume_not_found(errs: &[Option<Error>]) -> bool {
|
||||
DiskError::VolumeNotFound.count_errs(errs) == errs.len()
|
||||
}
|
||||
// pub fn is_all_volume_not_found(errs: &[Option<Error>]) -> bool {
|
||||
// DiskError::VolumeNotFound.count_errs(errs) == errs.len()
|
||||
// }
|
||||
|
||||
pub fn is_all_buckets_not_found(errs: &[Option<Error>]) -> bool {
|
||||
if errs.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let mut not_found_count = 0;
|
||||
for err in errs.iter().flatten() {
|
||||
match err.downcast_ref() {
|
||||
Some(DiskError::VolumeNotFound) | Some(DiskError::DiskNotFound) => {
|
||||
not_found_count += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
errs.len() == not_found_count
|
||||
}
|
||||
// pub fn is_all_buckets_not_found(errs: &[Option<Error>]) -> bool {
|
||||
// if errs.is_empty() {
|
||||
// return false;
|
||||
// }
|
||||
// let mut not_found_count = 0;
|
||||
// for err in errs.iter().flatten() {
|
||||
// match err.downcast_ref() {
|
||||
// Some(DiskError::VolumeNotFound) | Some(DiskError::DiskNotFound) => {
|
||||
// not_found_count += 1;
|
||||
// }
|
||||
// _ => {}
|
||||
// }
|
||||
// }
|
||||
// errs.len() == not_found_count
|
||||
// }
|
||||
|
||||
pub fn is_err_os_not_exist(err: &Error) -> bool {
|
||||
if let Some(os_err) = err.downcast_ref::<io::Error>() {
|
||||
os_is_not_exist(os_err)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
// pub fn is_err_os_not_exist(err: &Error) -> bool {
|
||||
// if let Some(os_err) = err.downcast_ref::<io::Error>() {
|
||||
// os_is_not_exist(os_err)
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn is_err_os_disk_full(err: &Error) -> bool {
|
||||
if let Some(os_err) = err.downcast_ref::<io::Error>() {
|
||||
is_sys_err_no_space(os_err)
|
||||
} else if let Some(e) = err.downcast_ref::<DiskError>() {
|
||||
e == &DiskError::DiskFull
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
// pub fn is_err_os_disk_full(err: &Error) -> bool {
|
||||
// if let Some(os_err) = err.downcast_ref::<io::Error>() {
|
||||
// is_sys_err_no_space(os_err)
|
||||
// } else if let Some(e) = err.downcast_ref::<DiskError>() {
|
||||
// e == &DiskError::DiskFull
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -0,0 +1,440 @@
|
||||
use super::error::DiskError;
|
||||
|
||||
pub fn to_file_error(io_err: std::io::Error) -> std::io::Error {
|
||||
match io_err.kind() {
|
||||
std::io::ErrorKind::NotFound => DiskError::FileNotFound.into(),
|
||||
std::io::ErrorKind::PermissionDenied => DiskError::FileAccessDenied.into(),
|
||||
std::io::ErrorKind::IsADirectory => DiskError::IsNotRegular.into(),
|
||||
std::io::ErrorKind::NotADirectory => DiskError::FileAccessDenied.into(),
|
||||
std::io::ErrorKind::DirectoryNotEmpty => DiskError::FileAccessDenied.into(),
|
||||
std::io::ErrorKind::UnexpectedEof => DiskError::FaultyDisk.into(),
|
||||
std::io::ErrorKind::TooManyLinks => DiskError::TooManyOpenFiles.into(),
|
||||
std::io::ErrorKind::InvalidInput => DiskError::FileNotFound.into(),
|
||||
std::io::ErrorKind::InvalidData => DiskError::FileCorrupt.into(),
|
||||
std::io::ErrorKind::StorageFull => DiskError::DiskFull.into(),
|
||||
_ => io_err,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_volume_error(io_err: std::io::Error) -> std::io::Error {
|
||||
match io_err.kind() {
|
||||
std::io::ErrorKind::NotFound => DiskError::VolumeNotFound.into(),
|
||||
std::io::ErrorKind::PermissionDenied => DiskError::DiskAccessDenied.into(),
|
||||
std::io::ErrorKind::DirectoryNotEmpty => DiskError::VolumeNotEmpty.into(),
|
||||
std::io::ErrorKind::NotADirectory => DiskError::IsNotRegular.into(),
|
||||
std::io::ErrorKind::Other => match io_err.downcast::<DiskError>() {
|
||||
Ok(err) => match err {
|
||||
DiskError::FileNotFound => DiskError::VolumeNotFound.into(),
|
||||
DiskError::FileAccessDenied => DiskError::DiskAccessDenied.into(),
|
||||
err => err.into(),
|
||||
},
|
||||
Err(err) => to_file_error(err),
|
||||
},
|
||||
_ => to_file_error(io_err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_disk_error(io_err: std::io::Error) -> std::io::Error {
|
||||
match io_err.kind() {
|
||||
std::io::ErrorKind::NotFound => DiskError::DiskNotFound.into(),
|
||||
std::io::ErrorKind::PermissionDenied => DiskError::DiskAccessDenied.into(),
|
||||
std::io::ErrorKind::Other => match io_err.downcast::<DiskError>() {
|
||||
Ok(err) => match err {
|
||||
DiskError::FileNotFound => DiskError::DiskNotFound.into(),
|
||||
DiskError::VolumeNotFound => DiskError::DiskNotFound.into(),
|
||||
DiskError::FileAccessDenied => DiskError::DiskAccessDenied.into(),
|
||||
DiskError::VolumeAccessDenied => DiskError::DiskAccessDenied.into(),
|
||||
err => err.into(),
|
||||
},
|
||||
Err(err) => to_volume_error(err),
|
||||
},
|
||||
_ => to_volume_error(io_err),
|
||||
}
|
||||
}
|
||||
|
||||
// only errors from FileSystem operations
|
||||
pub fn to_access_error(io_err: std::io::Error, per_err: DiskError) -> std::io::Error {
|
||||
match io_err.kind() {
|
||||
std::io::ErrorKind::PermissionDenied => per_err.into(),
|
||||
std::io::ErrorKind::NotADirectory => per_err.into(),
|
||||
std::io::ErrorKind::NotFound => DiskError::VolumeNotFound.into(),
|
||||
std::io::ErrorKind::UnexpectedEof => DiskError::FaultyDisk.into(),
|
||||
std::io::ErrorKind::Other => match io_err.downcast::<DiskError>() {
|
||||
Ok(err) => match err {
|
||||
DiskError::DiskAccessDenied => per_err.into(),
|
||||
DiskError::FileAccessDenied => per_err.into(),
|
||||
DiskError::FileNotFound => DiskError::VolumeNotFound.into(),
|
||||
err => err.into(),
|
||||
},
|
||||
Err(err) => to_volume_error(err),
|
||||
},
|
||||
_ => to_volume_error(io_err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_unformatted_disk_error(io_err: std::io::Error) -> std::io::Error {
|
||||
match io_err.kind() {
|
||||
std::io::ErrorKind::NotFound => DiskError::UnformattedDisk.into(),
|
||||
std::io::ErrorKind::PermissionDenied => DiskError::DiskAccessDenied.into(),
|
||||
std::io::ErrorKind::Other => match io_err.downcast::<DiskError>() {
|
||||
Ok(err) => match err {
|
||||
DiskError::FileNotFound => DiskError::UnformattedDisk.into(),
|
||||
DiskError::DiskNotFound => DiskError::UnformattedDisk.into(),
|
||||
DiskError::VolumeNotFound => DiskError::UnformattedDisk.into(),
|
||||
DiskError::FileAccessDenied => DiskError::DiskAccessDenied.into(),
|
||||
DiskError::DiskAccessDenied => DiskError::DiskAccessDenied.into(),
|
||||
_ => DiskError::CorruptedBackend.into(),
|
||||
},
|
||||
Err(err) => to_unformatted_disk_error(err),
|
||||
},
|
||||
_ => to_unformatted_disk_error(io_err),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::io::{Error as IoError, ErrorKind};
|
||||
|
||||
// Helper function to create IO errors with specific kinds
|
||||
fn create_io_error(kind: ErrorKind) -> IoError {
|
||||
IoError::new(kind, "test error")
|
||||
}
|
||||
|
||||
// Helper function to create IO errors with DiskError as the source
|
||||
fn create_io_error_with_disk_error(disk_error: DiskError) -> IoError {
|
||||
IoError::other(disk_error)
|
||||
}
|
||||
|
||||
// Helper function to check if an IoError contains a specific DiskError
|
||||
fn contains_disk_error(io_error: IoError, expected: DiskError) -> bool {
|
||||
if let Ok(disk_error) = io_error.downcast::<DiskError>() {
|
||||
std::mem::discriminant(&disk_error) == std::mem::discriminant(&expected)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_file_error_basic_conversions() {
|
||||
// Test NotFound -> FileNotFound
|
||||
let result = to_file_error(create_io_error(ErrorKind::NotFound));
|
||||
assert!(contains_disk_error(result, DiskError::FileNotFound));
|
||||
|
||||
// Test PermissionDenied -> FileAccessDenied
|
||||
let result = to_file_error(create_io_error(ErrorKind::PermissionDenied));
|
||||
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
||||
|
||||
// Test IsADirectory -> IsNotRegular
|
||||
let result = to_file_error(create_io_error(ErrorKind::IsADirectory));
|
||||
assert!(contains_disk_error(result, DiskError::IsNotRegular));
|
||||
|
||||
// Test NotADirectory -> FileAccessDenied
|
||||
let result = to_file_error(create_io_error(ErrorKind::NotADirectory));
|
||||
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
||||
|
||||
// Test DirectoryNotEmpty -> FileAccessDenied
|
||||
let result = to_file_error(create_io_error(ErrorKind::DirectoryNotEmpty));
|
||||
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
||||
|
||||
// Test UnexpectedEof -> FaultyDisk
|
||||
let result = to_file_error(create_io_error(ErrorKind::UnexpectedEof));
|
||||
assert!(contains_disk_error(result, DiskError::FaultyDisk));
|
||||
|
||||
// Test TooManyLinks -> TooManyOpenFiles
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let result = to_file_error(create_io_error(ErrorKind::TooManyLinks));
|
||||
assert!(contains_disk_error(result, DiskError::TooManyOpenFiles));
|
||||
}
|
||||
|
||||
// Test InvalidInput -> FileNotFound
|
||||
let result = to_file_error(create_io_error(ErrorKind::InvalidInput));
|
||||
assert!(contains_disk_error(result, DiskError::FileNotFound));
|
||||
|
||||
// Test InvalidData -> FileCorrupt
|
||||
let result = to_file_error(create_io_error(ErrorKind::InvalidData));
|
||||
assert!(contains_disk_error(result, DiskError::FileCorrupt));
|
||||
|
||||
// Test StorageFull -> DiskFull
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let result = to_file_error(create_io_error(ErrorKind::StorageFull));
|
||||
assert!(contains_disk_error(result, DiskError::DiskFull));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_file_error_passthrough_unknown() {
|
||||
// Test that unknown error kinds are passed through unchanged
|
||||
let original = create_io_error(ErrorKind::Interrupted);
|
||||
let result = to_file_error(original);
|
||||
assert_eq!(result.kind(), ErrorKind::Interrupted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_volume_error_basic_conversions() {
|
||||
// Test NotFound -> VolumeNotFound
|
||||
let result = to_volume_error(create_io_error(ErrorKind::NotFound));
|
||||
assert!(contains_disk_error(result, DiskError::VolumeNotFound));
|
||||
|
||||
// Test PermissionDenied -> DiskAccessDenied
|
||||
let result = to_volume_error(create_io_error(ErrorKind::PermissionDenied));
|
||||
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
||||
|
||||
// Test DirectoryNotEmpty -> VolumeNotEmpty
|
||||
let result = to_volume_error(create_io_error(ErrorKind::DirectoryNotEmpty));
|
||||
assert!(contains_disk_error(result, DiskError::VolumeNotEmpty));
|
||||
|
||||
// Test NotADirectory -> IsNotRegular
|
||||
let result = to_volume_error(create_io_error(ErrorKind::NotADirectory));
|
||||
assert!(contains_disk_error(result, DiskError::IsNotRegular));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_volume_error_other_with_disk_error() {
|
||||
// Test Other error kind with FileNotFound DiskError -> VolumeNotFound
|
||||
let io_error = create_io_error_with_disk_error(DiskError::FileNotFound);
|
||||
let result = to_volume_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::VolumeNotFound));
|
||||
|
||||
// Test Other error kind with FileAccessDenied DiskError -> DiskAccessDenied
|
||||
let io_error = create_io_error_with_disk_error(DiskError::FileAccessDenied);
|
||||
let result = to_volume_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
||||
|
||||
// Test Other error kind with other DiskError -> passthrough
|
||||
let io_error = create_io_error_with_disk_error(DiskError::DiskFull);
|
||||
let result = to_volume_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::DiskFull));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_volume_error_fallback_to_file_error() {
|
||||
// Test fallback to to_file_error for unknown error kinds
|
||||
let result = to_volume_error(create_io_error(ErrorKind::Interrupted));
|
||||
assert_eq!(result.kind(), ErrorKind::Interrupted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_disk_error_basic_conversions() {
|
||||
// Test NotFound -> DiskNotFound
|
||||
let result = to_disk_error(create_io_error(ErrorKind::NotFound));
|
||||
assert!(contains_disk_error(result, DiskError::DiskNotFound));
|
||||
|
||||
// Test PermissionDenied -> DiskAccessDenied
|
||||
let result = to_disk_error(create_io_error(ErrorKind::PermissionDenied));
|
||||
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_disk_error_other_with_disk_error() {
|
||||
// Test Other error kind with FileNotFound DiskError -> DiskNotFound
|
||||
let io_error = create_io_error_with_disk_error(DiskError::FileNotFound);
|
||||
let result = to_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::DiskNotFound));
|
||||
|
||||
// Test Other error kind with VolumeNotFound DiskError -> DiskNotFound
|
||||
let io_error = create_io_error_with_disk_error(DiskError::VolumeNotFound);
|
||||
let result = to_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::DiskNotFound));
|
||||
|
||||
// Test Other error kind with FileAccessDenied DiskError -> DiskAccessDenied
|
||||
let io_error = create_io_error_with_disk_error(DiskError::FileAccessDenied);
|
||||
let result = to_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
||||
|
||||
// Test Other error kind with VolumeAccessDenied DiskError -> DiskAccessDenied
|
||||
let io_error = create_io_error_with_disk_error(DiskError::VolumeAccessDenied);
|
||||
let result = to_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
||||
|
||||
// Test Other error kind with other DiskError -> passthrough
|
||||
let io_error = create_io_error_with_disk_error(DiskError::DiskFull);
|
||||
let result = to_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::DiskFull));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_disk_error_fallback_to_volume_error() {
|
||||
// Test fallback to to_volume_error for unknown error kinds
|
||||
let result = to_disk_error(create_io_error(ErrorKind::Interrupted));
|
||||
assert_eq!(result.kind(), ErrorKind::Interrupted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_access_error_basic_conversions() {
|
||||
let permission_error = DiskError::FileAccessDenied;
|
||||
|
||||
// Test PermissionDenied -> specified permission error
|
||||
let result = to_access_error(create_io_error(ErrorKind::PermissionDenied), permission_error);
|
||||
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
||||
|
||||
// Test NotADirectory -> specified permission error
|
||||
let result = to_access_error(create_io_error(ErrorKind::NotADirectory), DiskError::FileAccessDenied);
|
||||
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
||||
|
||||
// Test NotFound -> VolumeNotFound
|
||||
let result = to_access_error(create_io_error(ErrorKind::NotFound), DiskError::FileAccessDenied);
|
||||
assert!(contains_disk_error(result, DiskError::VolumeNotFound));
|
||||
|
||||
// Test UnexpectedEof -> FaultyDisk
|
||||
let result = to_access_error(create_io_error(ErrorKind::UnexpectedEof), DiskError::FileAccessDenied);
|
||||
assert!(contains_disk_error(result, DiskError::FaultyDisk));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_access_error_other_with_disk_error() {
|
||||
let permission_error = DiskError::VolumeAccessDenied;
|
||||
|
||||
// Test Other error kind with DiskAccessDenied -> specified permission error
|
||||
let io_error = create_io_error_with_disk_error(DiskError::DiskAccessDenied);
|
||||
let result = to_access_error(io_error, permission_error);
|
||||
assert!(contains_disk_error(result, DiskError::VolumeAccessDenied));
|
||||
|
||||
// Test Other error kind with FileAccessDenied -> specified permission error
|
||||
let io_error = create_io_error_with_disk_error(DiskError::FileAccessDenied);
|
||||
let result = to_access_error(io_error, DiskError::VolumeAccessDenied);
|
||||
assert!(contains_disk_error(result, DiskError::VolumeAccessDenied));
|
||||
|
||||
// Test Other error kind with FileNotFound -> VolumeNotFound
|
||||
let io_error = create_io_error_with_disk_error(DiskError::FileNotFound);
|
||||
let result = to_access_error(io_error, DiskError::VolumeAccessDenied);
|
||||
assert!(contains_disk_error(result, DiskError::VolumeNotFound));
|
||||
|
||||
// Test Other error kind with other DiskError -> passthrough
|
||||
let io_error = create_io_error_with_disk_error(DiskError::DiskFull);
|
||||
let result = to_access_error(io_error, DiskError::VolumeAccessDenied);
|
||||
assert!(contains_disk_error(result, DiskError::DiskFull));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_access_error_fallback_to_volume_error() {
|
||||
let permission_error = DiskError::FileAccessDenied;
|
||||
|
||||
// Test fallback to to_volume_error for unknown error kinds
|
||||
let result = to_access_error(create_io_error(ErrorKind::Interrupted), permission_error);
|
||||
assert_eq!(result.kind(), ErrorKind::Interrupted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_unformatted_disk_error_basic_conversions() {
|
||||
// Test NotFound -> UnformattedDisk
|
||||
let result = to_unformatted_disk_error(create_io_error(ErrorKind::NotFound));
|
||||
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
||||
|
||||
// Test PermissionDenied -> DiskAccessDenied
|
||||
let result = to_unformatted_disk_error(create_io_error(ErrorKind::PermissionDenied));
|
||||
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_unformatted_disk_error_other_with_disk_error() {
|
||||
// Test Other error kind with FileNotFound -> UnformattedDisk
|
||||
let io_error = create_io_error_with_disk_error(DiskError::FileNotFound);
|
||||
let result = to_unformatted_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
||||
|
||||
// Test Other error kind with DiskNotFound -> UnformattedDisk
|
||||
let io_error = create_io_error_with_disk_error(DiskError::DiskNotFound);
|
||||
let result = to_unformatted_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
||||
|
||||
// Test Other error kind with VolumeNotFound -> UnformattedDisk
|
||||
let io_error = create_io_error_with_disk_error(DiskError::VolumeNotFound);
|
||||
let result = to_unformatted_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
||||
|
||||
// Test Other error kind with FileAccessDenied -> DiskAccessDenied
|
||||
let io_error = create_io_error_with_disk_error(DiskError::FileAccessDenied);
|
||||
let result = to_unformatted_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
||||
|
||||
// Test Other error kind with DiskAccessDenied -> DiskAccessDenied
|
||||
let io_error = create_io_error_with_disk_error(DiskError::DiskAccessDenied);
|
||||
let result = to_unformatted_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
||||
|
||||
// Test Other error kind with other DiskError -> CorruptedBackend
|
||||
let io_error = create_io_error_with_disk_error(DiskError::DiskFull);
|
||||
let result = to_unformatted_disk_error(io_error);
|
||||
assert!(contains_disk_error(result, DiskError::CorruptedBackend));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_unformatted_disk_error_recursive_behavior() {
|
||||
// Test recursive call with non-Other error kind
|
||||
let result = to_unformatted_disk_error(create_io_error(ErrorKind::Interrupted));
|
||||
// This should recursively call to_unformatted_disk_error, which should then
|
||||
// treat it as Other kind and eventually produce CorruptedBackend or similar
|
||||
assert!(result.downcast::<DiskError>().is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_chain_conversions() {
|
||||
// Test complex error conversion chains
|
||||
let original_error = create_io_error(ErrorKind::NotFound);
|
||||
|
||||
// Chain: NotFound -> FileNotFound (via to_file_error) -> VolumeNotFound (via to_volume_error)
|
||||
let file_error = to_file_error(original_error);
|
||||
let volume_error = to_volume_error(file_error);
|
||||
assert!(contains_disk_error(volume_error, DiskError::VolumeNotFound));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cross_platform_error_kinds() {
|
||||
// Test error kinds that may not be available on all platforms
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let result = to_file_error(create_io_error(ErrorKind::TooManyLinks));
|
||||
assert!(contains_disk_error(result, DiskError::TooManyOpenFiles));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let result = to_file_error(create_io_error(ErrorKind::StorageFull));
|
||||
assert!(contains_disk_error(result, DiskError::DiskFull));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_conversion_with_different_kinds() {
|
||||
// Test multiple error kinds to ensure comprehensive coverage
|
||||
let test_cases = vec![
|
||||
(ErrorKind::NotFound, DiskError::FileNotFound),
|
||||
(ErrorKind::PermissionDenied, DiskError::FileAccessDenied),
|
||||
(ErrorKind::IsADirectory, DiskError::IsNotRegular),
|
||||
(ErrorKind::InvalidData, DiskError::FileCorrupt),
|
||||
];
|
||||
|
||||
for (kind, expected_disk_error) in test_cases {
|
||||
let result = to_file_error(create_io_error(kind));
|
||||
assert!(
|
||||
contains_disk_error(result, expected_disk_error.clone()),
|
||||
"Failed for ErrorKind::{:?} -> DiskError::{:?}",
|
||||
kind,
|
||||
expected_disk_error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_volume_error_conversion_chain() {
|
||||
// Test volume error conversion with different input types
|
||||
let test_cases = vec![
|
||||
(ErrorKind::NotFound, DiskError::VolumeNotFound),
|
||||
(ErrorKind::PermissionDenied, DiskError::DiskAccessDenied),
|
||||
(ErrorKind::DirectoryNotEmpty, DiskError::VolumeNotEmpty),
|
||||
];
|
||||
|
||||
for (kind, expected_disk_error) in test_cases {
|
||||
let result = to_volume_error(create_io_error(kind));
|
||||
assert!(
|
||||
contains_disk_error(result, expected_disk_error.clone()),
|
||||
"Failed for ErrorKind::{:?} -> DiskError::{:?}",
|
||||
kind,
|
||||
expected_disk_error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
use super::error::Error;
|
||||
|
||||
pub static OBJECT_OP_IGNORED_ERRS: &[Error] = &[
|
||||
Error::DiskNotFound,
|
||||
Error::FaultyDisk,
|
||||
Error::FaultyRemoteDisk,
|
||||
Error::DiskAccessDenied,
|
||||
Error::DiskOngoingReq,
|
||||
Error::UnformattedDisk,
|
||||
];
|
||||
|
||||
pub static BUCKET_OP_IGNORED_ERRS: &[Error] = &[
|
||||
Error::DiskNotFound,
|
||||
Error::FaultyDisk,
|
||||
Error::FaultyRemoteDisk,
|
||||
Error::DiskAccessDenied,
|
||||
Error::UnformattedDisk,
|
||||
];
|
||||
|
||||
pub static BASE_IGNORED_ERRS: &[Error] = &[Error::DiskNotFound, Error::FaultyDisk, Error::FaultyRemoteDisk];
|
||||
|
||||
pub fn reduce_write_quorum_errs(errors: &[Option<Error>], ignored_errs: &[Error], quorun: usize) -> Option<Error> {
|
||||
reduce_quorum_errs(errors, ignored_errs, quorun, Error::ErasureWriteQuorum)
|
||||
}
|
||||
|
||||
pub fn reduce_read_quorum_errs(errors: &[Option<Error>], ignored_errs: &[Error], quorun: usize) -> Option<Error> {
|
||||
reduce_quorum_errs(errors, ignored_errs, quorun, Error::ErasureReadQuorum)
|
||||
}
|
||||
|
||||
pub fn reduce_quorum_errs(errors: &[Option<Error>], ignored_errs: &[Error], quorun: usize, quorun_err: Error) -> Option<Error> {
|
||||
let (max_count, err) = reduce_errs(errors, ignored_errs);
|
||||
if max_count >= quorun {
|
||||
err
|
||||
} else {
|
||||
Some(quorun_err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reduce_errs(errors: &[Option<Error>], ignored_errs: &[Error]) -> (usize, Option<Error>) {
|
||||
let nil_error = Error::other("nil".to_string());
|
||||
let err_counts =
|
||||
errors
|
||||
.iter()
|
||||
.map(|e| e.as_ref().unwrap_or(&nil_error).clone())
|
||||
.fold(std::collections::HashMap::new(), |mut acc, e| {
|
||||
if is_ignored_err(ignored_errs, &e) {
|
||||
return acc;
|
||||
}
|
||||
*acc.entry(e).or_insert(0) += 1;
|
||||
acc
|
||||
});
|
||||
|
||||
let (err, max_count) = err_counts
|
||||
.into_iter()
|
||||
.max_by(|(e1, c1), (e2, c2)| {
|
||||
// Prefer Error::Nil if present in a tie
|
||||
let count_cmp = c1.cmp(c2);
|
||||
if count_cmp == std::cmp::Ordering::Equal {
|
||||
match (e1.to_string().as_str(), e2.to_string().as_str()) {
|
||||
("nil", _) => std::cmp::Ordering::Greater,
|
||||
(_, "nil") => std::cmp::Ordering::Less,
|
||||
(a, b) => a.cmp(&b),
|
||||
}
|
||||
} else {
|
||||
count_cmp
|
||||
}
|
||||
})
|
||||
.unwrap_or((nil_error.clone(), 0));
|
||||
|
||||
(max_count, if err == nil_error { None } else { Some(err) })
|
||||
}
|
||||
|
||||
pub fn is_ignored_err(ignored_errs: &[Error], err: &Error) -> bool {
|
||||
ignored_errs.iter().any(|e| e == err)
|
||||
}
|
||||
|
||||
pub fn count_errs(errors: &[Option<Error>], err: &Error) -> usize {
|
||||
errors.iter().filter(|&e| e.as_ref() == Some(err)).count()
|
||||
}
|
||||
|
||||
pub fn is_all_buckets_not_found(errs: &[Option<Error>]) -> bool {
|
||||
for err in errs.iter() {
|
||||
if let Some(err) = err {
|
||||
if err == &Error::DiskNotFound || err == &Error::VolumeNotFound {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
!errs.is_empty()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn err_io(msg: &str) -> Error {
|
||||
Error::Io(std::io::Error::other(msg))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reduce_errs_basic() {
|
||||
let e1 = err_io("a");
|
||||
let e2 = err_io("b");
|
||||
let errors = vec![Some(e1.clone()), Some(e1.clone()), Some(e2.clone()), None];
|
||||
let ignored = vec![];
|
||||
let (count, err) = reduce_errs(&errors, &ignored);
|
||||
assert_eq!(count, 2);
|
||||
assert_eq!(err, Some(e1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reduce_errs_ignored() {
|
||||
let e1 = err_io("a");
|
||||
let e2 = err_io("b");
|
||||
let errors = vec![Some(e1.clone()), Some(e2.clone()), Some(e1.clone()), Some(e2.clone()), None];
|
||||
let ignored = vec![e2.clone()];
|
||||
let (count, err) = reduce_errs(&errors, &ignored);
|
||||
assert_eq!(count, 2);
|
||||
assert_eq!(err, Some(e1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reduce_quorum_errs() {
|
||||
let e1 = err_io("a");
|
||||
let e2 = err_io("b");
|
||||
let errors = vec![Some(e1.clone()), Some(e1.clone()), Some(e2.clone()), None];
|
||||
let ignored = vec![];
|
||||
let quorum_err = Error::FaultyDisk;
|
||||
// quorum = 2, should return e1
|
||||
let res = reduce_quorum_errs(&errors, &ignored, 2, quorum_err.clone());
|
||||
assert_eq!(res, Some(e1));
|
||||
// quorum = 3, should return quorum error
|
||||
let res = reduce_quorum_errs(&errors, &ignored, 3, quorum_err.clone());
|
||||
assert_eq!(res, Some(quorum_err));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_errs() {
|
||||
let e1 = err_io("a");
|
||||
let e2 = err_io("b");
|
||||
let errors = vec![Some(e1.clone()), Some(e2.clone()), Some(e1.clone()), None];
|
||||
assert_eq!(count_errs(&errors, &e1), 2);
|
||||
assert_eq!(count_errs(&errors, &e2), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_ignored_err() {
|
||||
let e1 = err_io("a");
|
||||
let e2 = err_io("b");
|
||||
let ignored = vec![e1.clone()];
|
||||
assert!(is_ignored_err(&ignored, &e1));
|
||||
assert!(!is_ignored_err(&ignored, &e2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reduce_errs_nil_tiebreak() {
|
||||
// Error::Nil and another error have the same count, should prefer Nil
|
||||
let e1 = err_io("a");
|
||||
let e2 = err_io("b");
|
||||
let errors = vec![Some(e1.clone()), Some(e2.clone()), None, Some(e1.clone()), None]; // e1:1, Nil:1
|
||||
let ignored = vec![];
|
||||
let (count, err) = reduce_errs(&errors, &ignored);
|
||||
assert_eq!(count, 2);
|
||||
assert_eq!(err, None); // None means Error::Nil is preferred
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
use super::error::{Error, Result};
|
||||
use super::{error::DiskError, DiskInfo};
|
||||
use common::error::{Error, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Error as JsonError;
|
||||
use uuid::Uuid;
|
||||
@@ -110,7 +110,7 @@ pub struct FormatV3 {
|
||||
impl TryFrom<&[u8]> for FormatV3 {
|
||||
type Error = JsonError;
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, JsonError> {
|
||||
fn try_from(data: &[u8]) -> std::result::Result<Self, Self::Error> {
|
||||
serde_json::from_slice(data)
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,7 @@ impl TryFrom<&[u8]> for FormatV3 {
|
||||
impl TryFrom<&str> for FormatV3 {
|
||||
type Error = JsonError;
|
||||
|
||||
fn try_from(data: &str) -> Result<Self, JsonError> {
|
||||
fn try_from(data: &str) -> std::result::Result<Self, Self::Error> {
|
||||
serde_json::from_str(data)
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ impl FormatV3 {
|
||||
self.erasure.sets.iter().map(|v| v.len()).sum()
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> Result<String, JsonError> {
|
||||
pub fn to_json(&self) -> std::result::Result<String, JsonError> {
|
||||
serde_json::to_string(self)
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ impl FormatV3 {
|
||||
return Err(Error::from(DiskError::DiskNotFound));
|
||||
}
|
||||
if disk_id == Uuid::max() {
|
||||
return Err(Error::msg("disk offline"));
|
||||
return Err(Error::other("disk offline"));
|
||||
}
|
||||
|
||||
for (i, set) in self.erasure.sets.iter().enumerate() {
|
||||
@@ -180,7 +180,7 @@ impl FormatV3 {
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::msg(format!("disk id not found {}", disk_id)))
|
||||
Err(Error::other(format!("disk id not found {}", disk_id)))
|
||||
}
|
||||
|
||||
pub fn check_other(&self, other: &FormatV3) -> Result<()> {
|
||||
@@ -189,7 +189,7 @@ impl FormatV3 {
|
||||
tmp.erasure.this = Uuid::nil();
|
||||
|
||||
if self.erasure.sets.len() != other.erasure.sets.len() {
|
||||
return Err(Error::from_string(format!(
|
||||
return Err(Error::other(format!(
|
||||
"Expected number of sets {}, got {}",
|
||||
self.erasure.sets.len(),
|
||||
other.erasure.sets.len()
|
||||
@@ -198,7 +198,7 @@ impl FormatV3 {
|
||||
|
||||
for i in 0..self.erasure.sets.len() {
|
||||
if self.erasure.sets[i].len() != other.erasure.sets[i].len() {
|
||||
return Err(Error::from_string(format!(
|
||||
return Err(Error::other(format!(
|
||||
"Each set should be of same size, expected {}, got {}",
|
||||
self.erasure.sets[i].len(),
|
||||
other.erasure.sets[i].len()
|
||||
@@ -207,7 +207,7 @@ impl FormatV3 {
|
||||
|
||||
for j in 0..self.erasure.sets[i].len() {
|
||||
if self.erasure.sets[i][j] != other.erasure.sets[i][j] {
|
||||
return Err(Error::from_string(format!(
|
||||
return Err(Error::other(format!(
|
||||
"UUID on positions {}:{} do not match with, expected {:?} got {:?}: (%w)",
|
||||
i,
|
||||
j,
|
||||
@@ -226,7 +226,7 @@ impl FormatV3 {
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::msg(format!(
|
||||
Err(Error::other(format!(
|
||||
"DriveID {:?} not found in any drive sets {:?}",
|
||||
this, other.erasure.sets
|
||||
)))
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
use std::{fs::Metadata, path::Path};
|
||||
|
||||
use tokio::{
|
||||
fs::{self, File},
|
||||
io,
|
||||
};
|
||||
|
||||
pub const SLASH_SEPARATOR: &str = "/";
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn same_file(f1: &Metadata, f2: &Metadata) -> bool {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
if f1.dev() != f2.dev() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if f1.ino() != f2.ino() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if f1.size() != f2.size() {
|
||||
return false;
|
||||
}
|
||||
if f1.permissions() != f2.permissions() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if f1.mtime() != f2.mtime() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn same_file(f1: &Metadata, f2: &Metadata) -> bool {
|
||||
if f1.permissions() != f2.permissions() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if f1.file_type() != f2.file_type() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if f1.len() != f2.len() {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
type FileMode = usize;
|
||||
|
||||
pub const O_RDONLY: FileMode = 0x00000;
|
||||
pub const O_WRONLY: FileMode = 0x00001;
|
||||
pub const O_RDWR: FileMode = 0x00002;
|
||||
pub const O_CREATE: FileMode = 0x00040;
|
||||
// pub const O_EXCL: FileMode = 0x00080;
|
||||
// pub const O_NOCTTY: FileMode = 0x00100;
|
||||
pub const O_TRUNC: FileMode = 0x00200;
|
||||
// pub const O_NONBLOCK: FileMode = 0x00800;
|
||||
pub const O_APPEND: FileMode = 0x00400;
|
||||
// pub const O_SYNC: FileMode = 0x01000;
|
||||
// pub const O_ASYNC: FileMode = 0x02000;
|
||||
// pub const O_CLOEXEC: FileMode = 0x80000;
|
||||
|
||||
// read: bool,
|
||||
// write: bool,
|
||||
// append: bool,
|
||||
// truncate: bool,
|
||||
// create: bool,
|
||||
// create_new: bool,
|
||||
|
||||
pub async fn open_file(path: impl AsRef<Path>, mode: FileMode) -> io::Result<File> {
|
||||
let mut opts = fs::OpenOptions::new();
|
||||
|
||||
match mode & (O_RDONLY | O_WRONLY | O_RDWR) {
|
||||
O_RDONLY => {
|
||||
opts.read(true);
|
||||
}
|
||||
O_WRONLY => {
|
||||
opts.write(true);
|
||||
}
|
||||
O_RDWR => {
|
||||
opts.read(true);
|
||||
opts.write(true);
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
||||
if mode & O_CREATE != 0 {
|
||||
opts.create(true);
|
||||
}
|
||||
|
||||
if mode & O_APPEND != 0 {
|
||||
opts.append(true);
|
||||
}
|
||||
|
||||
if mode & O_TRUNC != 0 {
|
||||
opts.truncate(true);
|
||||
}
|
||||
|
||||
opts.open(path.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn access(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
fs::metadata(path).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn access_std(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
std::fs::metadata(path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn lstat(path: impl AsRef<Path>) -> io::Result<Metadata> {
|
||||
fs::metadata(path).await
|
||||
}
|
||||
|
||||
pub fn lstat_std(path: impl AsRef<Path>) -> io::Result<Metadata> {
|
||||
std::fs::metadata(path)
|
||||
}
|
||||
|
||||
pub async fn make_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
fs::create_dir_all(path.as_ref()).await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
pub async fn remove(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
let meta = fs::metadata(path.as_ref()).await?;
|
||||
if meta.is_dir() {
|
||||
fs::remove_dir(path.as_ref()).await
|
||||
} else {
|
||||
fs::remove_file(path.as_ref()).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn remove_all(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
let meta = fs::metadata(path.as_ref()).await?;
|
||||
if meta.is_dir() {
|
||||
fs::remove_dir_all(path.as_ref()).await
|
||||
} else {
|
||||
fs::remove_file(path.as_ref()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
pub fn remove_std(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
let meta = std::fs::metadata(path.as_ref())?;
|
||||
if meta.is_dir() {
|
||||
std::fs::remove_dir(path.as_ref())
|
||||
} else {
|
||||
std::fs::remove_file(path.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_all_std(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
let meta = std::fs::metadata(path.as_ref())?;
|
||||
if meta.is_dir() {
|
||||
std::fs::remove_dir_all(path.as_ref())
|
||||
} else {
|
||||
std::fs::remove_file(path.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn mkdir(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
fs::create_dir(path.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
|
||||
fs::rename(from, to).await
|
||||
}
|
||||
|
||||
pub fn rename_std(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
|
||||
std::fs::rename(from, to)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
pub async fn read_file(path: impl AsRef<Path>) -> io::Result<Vec<u8>> {
|
||||
fs::read(path.as_ref()).await
|
||||
}
|
||||
+211
-429
File diff suppressed because it is too large
Load Diff
+601
-576
File diff suppressed because it is too large
Load Diff
+21
-38
@@ -3,31 +3,28 @@ use std::{
|
||||
path::{Component, Path},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
disk::error::{is_sys_err_not_dir, is_sys_err_path_not_found, os_is_not_exist},
|
||||
utils::{self, os::same_disk},
|
||||
};
|
||||
use common::error::{Error, Result};
|
||||
use super::error::Result;
|
||||
use crate::disk::error_conv::to_file_error;
|
||||
use tokio::fs;
|
||||
|
||||
use super::error::{os_err_to_file_err, os_is_exist, DiskError};
|
||||
use super::error::DiskError;
|
||||
|
||||
pub fn check_path_length(path_name: &str) -> Result<()> {
|
||||
// Apple OS X path length is limited to 1016
|
||||
if cfg!(target_os = "macos") && path_name.len() > 1016 {
|
||||
return Err(Error::new(DiskError::FileNameTooLong));
|
||||
return Err(DiskError::FileNameTooLong);
|
||||
}
|
||||
|
||||
// Disallow more than 1024 characters on windows, there
|
||||
// are no known name_max limits on Windows.
|
||||
if cfg!(target_os = "windows") && path_name.len() > 1024 {
|
||||
return Err(Error::new(DiskError::FileNameTooLong));
|
||||
return Err(DiskError::FileNameTooLong);
|
||||
}
|
||||
|
||||
// On Unix we reject paths if they are just '.', '..' or '/'
|
||||
let invalid_paths = [".", "..", "/"];
|
||||
if invalid_paths.contains(&path_name) {
|
||||
return Err(Error::new(DiskError::FileAccessDenied));
|
||||
return Err(DiskError::FileAccessDenied);
|
||||
}
|
||||
|
||||
// Check each path segment length is > 255 on all Unix
|
||||
@@ -40,7 +37,7 @@ pub fn check_path_length(path_name: &str) -> Result<()> {
|
||||
_ => {
|
||||
count += 1;
|
||||
if count > 255 {
|
||||
return Err(Error::new(DiskError::FileNameTooLong));
|
||||
return Err(DiskError::FileNameTooLong);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,19 +52,15 @@ pub fn is_root_disk(disk_path: &str, root_disk: &str) -> Result<bool> {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
same_disk(disk_path, root_disk)
|
||||
rustfs_utils::os::same_disk(disk_path, root_disk).map_err(|e| to_file_error(e).into())
|
||||
}
|
||||
|
||||
pub async fn make_dir_all(path: impl AsRef<Path>, base_dir: impl AsRef<Path>) -> Result<()> {
|
||||
check_path_length(path.as_ref().to_string_lossy().to_string().as_str())?;
|
||||
|
||||
if let Err(e) = reliable_mkdir_all(path.as_ref(), base_dir.as_ref()).await {
|
||||
if is_sys_err_not_dir(&e) || is_sys_err_path_not_found(&e) {
|
||||
return Err(Error::new(DiskError::FileAccessDenied));
|
||||
}
|
||||
|
||||
return Err(os_err_to_file_err(e));
|
||||
}
|
||||
reliable_mkdir_all(path.as_ref(), base_dir.as_ref())
|
||||
.await
|
||||
.map_err(to_file_error)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -77,7 +70,7 @@ pub async fn is_empty_dir(path: impl AsRef<Path>) -> bool {
|
||||
}
|
||||
|
||||
// read_dir count read limit. when count == 0 unlimit.
|
||||
pub async fn read_dir(path: impl AsRef<Path>, count: i32) -> Result<Vec<String>> {
|
||||
pub async fn read_dir(path: impl AsRef<Path>, count: i32) -> std::io::Result<Vec<String>> {
|
||||
let mut entries = fs::read_dir(path.as_ref()).await?;
|
||||
|
||||
let mut volumes = Vec::new();
|
||||
@@ -96,7 +89,7 @@ pub async fn read_dir(path: impl AsRef<Path>, count: i32) -> Result<Vec<String>>
|
||||
if file_type.is_file() {
|
||||
volumes.push(name);
|
||||
} else if file_type.is_dir() {
|
||||
volumes.push(format!("{}{}", name, utils::path::SLASH_SEPARATOR));
|
||||
volumes.push(format!("{}{}", name, super::fs::SLASH_SEPARATOR));
|
||||
}
|
||||
count -= 1;
|
||||
if count == 0 {
|
||||
@@ -115,17 +108,7 @@ pub async fn rename_all(
|
||||
) -> Result<()> {
|
||||
reliable_rename(src_file_path, dst_file_path.as_ref(), base_dir)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if is_sys_err_not_dir(&e) || !os_is_not_exist(&e) || is_sys_err_path_not_found(&e) {
|
||||
Error::new(DiskError::FileAccessDenied)
|
||||
} else if os_is_not_exist(&e) {
|
||||
Error::new(DiskError::FileNotFound)
|
||||
} else if os_is_exist(&e) {
|
||||
Error::new(DiskError::IsNotRegular)
|
||||
} else {
|
||||
Error::new(e)
|
||||
}
|
||||
})?;
|
||||
.map_err(|e| to_file_error(e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -144,8 +127,8 @@ pub async fn reliable_rename(
|
||||
|
||||
let mut i = 0;
|
||||
loop {
|
||||
if let Err(e) = utils::fs::rename_std(src_file_path.as_ref(), dst_file_path.as_ref()) {
|
||||
if os_is_not_exist(&e) && i == 0 {
|
||||
if let Err(e) = super::fs::rename_std(src_file_path.as_ref(), dst_file_path.as_ref()) {
|
||||
if e.kind() == io::ErrorKind::NotFound && i == 0 {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
@@ -171,7 +154,7 @@ pub async fn reliable_mkdir_all(path: impl AsRef<Path>, base_dir: impl AsRef<Pat
|
||||
let mut base_dir = base_dir.as_ref();
|
||||
loop {
|
||||
if let Err(e) = os_mkdir_all(path.as_ref(), base_dir).await {
|
||||
if os_is_not_exist(&e) && i == 0 {
|
||||
if e.kind() == io::ErrorKind::NotFound && i == 0 {
|
||||
i += 1;
|
||||
|
||||
if let Some(base_parent) = base_dir.parent() {
|
||||
@@ -200,8 +183,8 @@ pub async fn os_mkdir_all(dir_path: impl AsRef<Path>, base_dir: impl AsRef<Path>
|
||||
|
||||
if let Some(parent) = dir_path.as_ref().parent() {
|
||||
// 不支持递归,直接 create_dir_all 了
|
||||
if let Err(e) = utils::fs::make_dir_all(&parent).await {
|
||||
if os_is_exist(&e) {
|
||||
if let Err(e) = super::fs::make_dir_all(&parent).await {
|
||||
if e.kind() == io::ErrorKind::AlreadyExists {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -210,8 +193,8 @@ pub async fn os_mkdir_all(dir_path: impl AsRef<Path>, base_dir: impl AsRef<Path>
|
||||
// Box::pin(os_mkdir_all(&parent, &base_dir)).await?;
|
||||
}
|
||||
|
||||
if let Err(e) = utils::fs::mkdir(dir_path.as_ref()).await {
|
||||
if os_is_exist(&e) {
|
||||
if let Err(e) = super::fs::mkdir(dir_path.as_ref()).await {
|
||||
if e.kind() == io::ErrorKind::AlreadyExists {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
+93
-174
@@ -1,6 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use futures::lock::Mutex;
|
||||
use http::{HeaderMap, Method};
|
||||
use protos::{
|
||||
node_service_time_out_client,
|
||||
proto_gen::node_service::{
|
||||
@@ -11,6 +12,8 @@ use protos::{
|
||||
},
|
||||
};
|
||||
use rmp_serde::Serializer;
|
||||
use rustfs_filemeta::{FileInfo, MetaCacheEntry, MetacacheWriter, RawFileInfo};
|
||||
use rustfs_rio::{HttpReader, Reader};
|
||||
use serde::Serialize;
|
||||
use tokio::{
|
||||
io::AsyncWrite,
|
||||
@@ -21,26 +24,19 @@ use tonic::Request;
|
||||
use tracing::info;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::error::{Error, Result};
|
||||
use super::{
|
||||
endpoint::Endpoint, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskLocation, DiskOption,
|
||||
FileInfoVersions, ReadMultipleReq, ReadMultipleResp, ReadOptions, RenameDataResp, UpdateMetadataOpts, VolumeInfo,
|
||||
WalkDirOptions,
|
||||
};
|
||||
use crate::{
|
||||
disk::error::DiskError,
|
||||
heal::{
|
||||
data_scanner::ShouldSleepFn,
|
||||
data_usage_cache::{DataUsageCache, DataUsageEntry},
|
||||
heal_commands::{HealScanMode, HealingTracker},
|
||||
},
|
||||
store_api::{FileInfo, RawFileInfo},
|
||||
|
||||
use crate::heal::{
|
||||
data_scanner::ShouldSleepFn,
|
||||
data_usage_cache::{DataUsageCache, DataUsageEntry},
|
||||
heal_commands::{HealScanMode, HealingTracker},
|
||||
};
|
||||
use crate::{disk::MetaCacheEntry, metacache::writer::MetacacheWriter};
|
||||
use crate::{
|
||||
io::{FileReader, FileWriter, HttpFileReader, HttpFileWriter},
|
||||
utils::proto_err_to_err,
|
||||
};
|
||||
use common::error::{Error, Result};
|
||||
use crate::io::{FileWriter, HttpFileWriter};
|
||||
use protos::proto_gen::node_service::RenamePartRequst;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -150,7 +146,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("make_volume");
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(MakeVolumeRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -159,11 +155,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.make_volume(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -174,7 +166,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("make_volumes");
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(MakeVolumesRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volumes: volumes.iter().map(|s| (*s).to_string()).collect(),
|
||||
@@ -183,11 +175,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.make_volumes(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -198,7 +186,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("list_volumes");
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(ListVolumesRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
});
|
||||
@@ -206,11 +194,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.list_volumes(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
let infos = response
|
||||
@@ -227,7 +211,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("stat_volume");
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(StatVolumeRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -236,11 +220,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.stat_volume(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
let volume_info = serde_json::from_str::<VolumeInfo>(&response.volume_info)?;
|
||||
@@ -253,7 +233,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("delete_volume {}/{}", self.endpoint.to_string(), volume);
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(DeleteVolumeRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -262,11 +242,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.delete_volume(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -283,7 +259,7 @@ impl DiskAPI for RemoteDisk {
|
||||
opts.serialize(&mut Serializer::new(&mut buf))?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(WalkDirRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
walk_dir_options: buf,
|
||||
@@ -294,14 +270,14 @@ impl DiskAPI for RemoteDisk {
|
||||
match response.next().await {
|
||||
Some(Ok(resp)) => {
|
||||
if !resp.success {
|
||||
return Err(Error::from_string(resp.error_info.unwrap_or("".to_string())));
|
||||
return Err(Error::other(resp.error_info.unwrap_or_default()));
|
||||
}
|
||||
let entry = serde_json::from_str::<MetaCacheEntry>(&resp.meta_cache_entry)
|
||||
.map_err(|_| Error::from_string(format!("Unexpected response: {:?}", response)))?;
|
||||
.map_err(|_| Error::other(format!("Unexpected response: {:?}", response)))?;
|
||||
out.write_obj(&entry).await?;
|
||||
}
|
||||
None => break,
|
||||
_ => return Err(Error::from_string(format!("Unexpected response: {:?}", response))),
|
||||
_ => return Err(Error::other(format!("Unexpected response: {:?}", response))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +305,7 @@ impl DiskAPI for RemoteDisk {
|
||||
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(DeleteVersionRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -342,11 +318,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.delete_version(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
// let raw_file_info = serde_json::from_str::<RawFileInfo>(&response.raw_file_info)?;
|
||||
@@ -369,7 +341,7 @@ impl DiskAPI for RemoteDisk {
|
||||
}
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(DeleteVersionsRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -377,13 +349,10 @@ impl DiskAPI for RemoteDisk {
|
||||
opts,
|
||||
});
|
||||
|
||||
// TODO: use Error not string
|
||||
let response = client.delete_versions(request).await?.into_inner();
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
let errors = response
|
||||
.errors
|
||||
@@ -392,7 +361,7 @@ impl DiskAPI for RemoteDisk {
|
||||
if error.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Error::from_string(error))
|
||||
Some(Error::other(error.to_string()))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@@ -406,7 +375,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let paths = paths.to_owned();
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(DeletePathsRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -416,11 +385,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.delete_paths(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -432,7 +397,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let file_info = serde_json::to_string(&fi)?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(WriteMetadataRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -443,11 +408,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.write_metadata(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -461,7 +422,7 @@ impl DiskAPI for RemoteDisk {
|
||||
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(UpdateMetadataRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -473,11 +434,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.update_metadata(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -496,7 +453,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let opts = serde_json::to_string(opts)?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(ReadVersionRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -508,11 +465,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.read_version(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
let file_info = serde_json::from_str::<FileInfo>(&response.file_info)?;
|
||||
@@ -525,7 +478,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("read_xl {}/{}/{}", self.endpoint.to_string(), volume, path);
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(ReadXlRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -536,11 +489,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.read_xl(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
let raw_file_info = serde_json::from_str::<RawFileInfo>(&response.raw_file_info)?;
|
||||
@@ -561,7 +510,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let file_info = serde_json::to_string(&fi)?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(RenameDataRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
src_volume: src_volume.to_string(),
|
||||
@@ -574,11 +523,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.rename_data(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
let rename_data_resp = serde_json::from_str::<RenameDataResp>(&response.rename_data_resp)?;
|
||||
@@ -591,7 +536,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("list_dir {}/{}", volume, _dir_path);
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(ListDirRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -600,39 +545,43 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.list_dir(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(response.volumes)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
async fn read_file(&self, volume: &str, path: &str) -> Result<FileReader> {
|
||||
async fn read_file(&self, volume: &str, path: &str) -> Result<Box<dyn Reader>> {
|
||||
info!("read_file {}/{}", volume, path);
|
||||
Ok(Box::new(
|
||||
HttpFileReader::new(self.endpoint.grid_host().as_str(), self.endpoint.to_string().as_str(), volume, path, 0, 0)
|
||||
.await?,
|
||||
))
|
||||
|
||||
let url = format!(
|
||||
"{}/rustfs/rpc/read_file_stream?disk={}&volume={}&path={}&offset={}&length={}",
|
||||
self.endpoint.grid_host(),
|
||||
urlencoding::encode(self.endpoint.to_string().as_str()),
|
||||
urlencoding::encode(volume),
|
||||
urlencoding::encode(path),
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
Ok(Box::new(HttpReader::new(url, Method::GET, HeaderMap::new()).await?))
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
async fn read_file_stream(&self, volume: &str, path: &str, offset: usize, length: usize) -> Result<FileReader> {
|
||||
async fn read_file_stream(&self, volume: &str, path: &str, offset: usize, length: usize) -> Result<Box<dyn Reader>> {
|
||||
info!("read_file_stream {}/{}/{}", self.endpoint.to_string(), volume, path);
|
||||
Ok(Box::new(
|
||||
HttpFileReader::new(
|
||||
self.endpoint.grid_host().as_str(),
|
||||
self.endpoint.to_string().as_str(),
|
||||
volume,
|
||||
path,
|
||||
offset,
|
||||
length,
|
||||
)
|
||||
.await?,
|
||||
))
|
||||
let url = format!(
|
||||
"{}/rustfs/rpc/read_file_stream?disk={}&volume={}&path={}&offset={}&length={}",
|
||||
self.endpoint.grid_host(),
|
||||
urlencoding::encode(self.endpoint.to_string().as_str()),
|
||||
urlencoding::encode(volume),
|
||||
urlencoding::encode(path),
|
||||
offset,
|
||||
length
|
||||
);
|
||||
|
||||
Ok(Box::new(HttpReader::new(url, Method::GET, HeaderMap::new()).await?))
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
@@ -666,7 +615,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("rename_file");
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(RenameFileRequst {
|
||||
disk: self.endpoint.to_string(),
|
||||
src_volume: src_volume.to_string(),
|
||||
@@ -678,11 +627,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.rename_file(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -693,7 +638,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("rename_part {}/{}", src_volume, src_path);
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(RenamePartRequst {
|
||||
disk: self.endpoint.to_string(),
|
||||
src_volume: src_volume.to_string(),
|
||||
@@ -706,11 +651,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.rename_part(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -722,7 +663,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let options = serde_json::to_string(&opt)?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(DeleteRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -733,11 +674,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.delete(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -749,7 +686,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let file_info = serde_json::to_string(&fi)?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(VerifyFileRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -760,11 +697,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.verify_file(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
let check_parts_resp = serde_json::from_str::<CheckPartsResp>(&response.check_parts_resp)?;
|
||||
@@ -778,7 +711,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let file_info = serde_json::to_string(&fi)?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(CheckPartsRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -789,11 +722,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.check_parts(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
let check_parts_resp = serde_json::from_str::<CheckPartsResp>(&response.check_parts_resp)?;
|
||||
@@ -807,7 +736,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let read_multiple_req = serde_json::to_string(&req)?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(ReadMultipleRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
read_multiple_req,
|
||||
@@ -816,11 +745,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.read_multiple(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
let read_multiple_resps = response
|
||||
@@ -837,7 +762,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("write_all");
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(WriteAllRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -848,11 +773,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.write_all(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -863,7 +784,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("read_all {}/{}", volume, path);
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(ReadAllRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: volume.to_string(),
|
||||
@@ -873,7 +794,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.read_all(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return Err(Error::new(DiskError::FileNotFound));
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
Ok(response.data)
|
||||
@@ -884,7 +805,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let opts = serde_json::to_string(&opts)?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
let request = Request::new(DiskInfoRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
opts,
|
||||
@@ -893,11 +814,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let response = client.disk_info(request).await?.into_inner();
|
||||
|
||||
if !response.success {
|
||||
return if let Some(err) = &response.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
return Err(response.error.unwrap_or_default().into());
|
||||
}
|
||||
|
||||
let disk_info = serde_json::from_str::<DiskInfo>(&response.disk_info)?;
|
||||
@@ -917,7 +834,7 @@ impl DiskAPI for RemoteDisk {
|
||||
let cache = serde_json::to_string(cache)?;
|
||||
let mut client = node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?;
|
||||
.map_err(|err| Error::other(format!("can not get client, err: {}", err)))?;
|
||||
|
||||
let (tx, rx) = mpsc::channel(10);
|
||||
let in_stream = ReceiverStream::new(rx);
|
||||
@@ -927,7 +844,9 @@ impl DiskAPI for RemoteDisk {
|
||||
cache,
|
||||
scan_mode: scan_mode as u64,
|
||||
};
|
||||
tx.send(request).await?;
|
||||
tx.send(request)
|
||||
.await
|
||||
.map_err(|err| Error::other(format!("can not send request, err: {}", err)))?;
|
||||
|
||||
loop {
|
||||
match response.next().await {
|
||||
@@ -939,10 +858,10 @@ impl DiskAPI for RemoteDisk {
|
||||
let data_usage_cache = serde_json::from_str::<DataUsageCache>(&resp.data_usage_cache)?;
|
||||
return Ok(data_usage_cache);
|
||||
} else {
|
||||
return Err(Error::from_string("scan was interrupted"));
|
||||
return Err(Error::other("scan was interrupted"));
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::from_string("scan was interrupted")),
|
||||
_ => return Err(Error::other("scan was interrupted")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user