mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-20 19:42:17 +00:00
chore: upgrade dependencies and migrate to aws-lc-rs (#1333)
This commit is contained in:
+137
-142
@@ -288,15 +288,15 @@ impl LocalDisk {
|
||||
let path = path_join(&[trash.clone(), name.into()]);
|
||||
|
||||
if file_type.is_dir() {
|
||||
if let Err(e) = tokio::fs::remove_dir_all(path).await {
|
||||
if e.kind() != ErrorKind::NotFound {
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
} else if let Err(e) = tokio::fs::remove_file(path).await {
|
||||
if e.kind() != ErrorKind::NotFound {
|
||||
if let Err(e) = tokio::fs::remove_dir_all(path).await
|
||||
&& e.kind() != ErrorKind::NotFound
|
||||
{
|
||||
return Err(e.into());
|
||||
}
|
||||
} else if let Err(e) = tokio::fs::remove_file(path).await
|
||||
&& e.kind() != ErrorKind::NotFound
|
||||
{
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -684,13 +684,11 @@ impl LocalDisk {
|
||||
Err(err) => {
|
||||
if err == Error::FileNotFound
|
||||
&& !skip_access_checks(volume_dir.as_ref().to_string_lossy().to_string().as_str())
|
||||
&& let Err(e) = access(volume_dir.as_ref()).await
|
||||
&& e.kind() == ErrorKind::NotFound
|
||||
{
|
||||
if let Err(e) = access(volume_dir.as_ref()).await {
|
||||
if e.kind() == ErrorKind::NotFound {
|
||||
// warn!("read_metadata_with_dmtime os err {:?}", &aerr);
|
||||
return Err(DiskError::VolumeNotFound);
|
||||
}
|
||||
}
|
||||
// warn!("read_metadata_with_dmtime os err {:?}", &aerr);
|
||||
return Err(DiskError::VolumeNotFound);
|
||||
}
|
||||
|
||||
Err(err)
|
||||
@@ -763,13 +761,13 @@ impl LocalDisk {
|
||||
let mut f = match super::fs::open_file(file_path.as_ref(), O_RDONLY).await {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
if e.kind() == ErrorKind::NotFound && !skip_access_checks(volume) {
|
||||
if let Err(er) = access(volume_dir.as_ref()).await {
|
||||
if er.kind() == ErrorKind::NotFound {
|
||||
warn!("read_all_data_with_dmtime os err {:?}", &er);
|
||||
return Err(DiskError::VolumeNotFound);
|
||||
}
|
||||
}
|
||||
if e.kind() == ErrorKind::NotFound
|
||||
&& !skip_access_checks(volume)
|
||||
&& let Err(er) = access(volume_dir.as_ref()).await
|
||||
&& er.kind() == ErrorKind::NotFound
|
||||
{
|
||||
warn!("read_all_data_with_dmtime os err {:?}", &er);
|
||||
return Err(DiskError::VolumeNotFound);
|
||||
}
|
||||
|
||||
return Err(to_file_error(e).into());
|
||||
@@ -828,10 +826,10 @@ impl LocalDisk {
|
||||
let _ = fm.data.remove(vec![vid, dir]);
|
||||
|
||||
let dir_path = self.get_object_path(volume, format!("{path}/{dir}").as_str())?;
|
||||
if let Err(err) = self.move_to_trash(&dir_path, true, false).await {
|
||||
if !(err == DiskError::FileNotFound || err == DiskError::VolumeNotFound) {
|
||||
return Err(err);
|
||||
}
|
||||
if let Err(err) = self.move_to_trash(&dir_path, true, false).await
|
||||
&& !(err == DiskError::FileNotFound || err == DiskError::VolumeNotFound)
|
||||
{
|
||||
return Err(err);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1051,11 +1049,11 @@ impl LocalDisk {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(forward) = &forward {
|
||||
if &entry < forward {
|
||||
*item = "".to_owned();
|
||||
continue;
|
||||
}
|
||||
if let Some(forward) = &forward
|
||||
&& &entry < forward
|
||||
{
|
||||
*item = "".to_owned();
|
||||
continue;
|
||||
}
|
||||
|
||||
if entry.ends_with(SLASH_SEPARATOR) {
|
||||
@@ -1133,10 +1131,10 @@ impl LocalDisk {
|
||||
})
|
||||
.await?;
|
||||
|
||||
if opts.recursive {
|
||||
if let Err(er) = Box::pin(self.scan_dir(pop, prefix.clone(), opts, out, objs_returned)).await {
|
||||
error!("scan_dir err {:?}", er);
|
||||
}
|
||||
if opts.recursive
|
||||
&& let Err(er) = Box::pin(self.scan_dir(pop, prefix.clone(), opts, out, objs_returned)).await
|
||||
{
|
||||
error!("scan_dir err {:?}", er);
|
||||
}
|
||||
dir_stack.pop();
|
||||
}
|
||||
@@ -1200,10 +1198,10 @@ impl LocalDisk {
|
||||
})
|
||||
.await?;
|
||||
|
||||
if opts.recursive {
|
||||
if let Err(er) = Box::pin(self.scan_dir(dir, prefix.clone(), opts, out, objs_returned)).await {
|
||||
warn!("scan_dir err {:?}", &er);
|
||||
}
|
||||
if opts.recursive
|
||||
&& let Err(er) = Box::pin(self.scan_dir(dir, prefix.clone(), opts, out, objs_returned)).await
|
||||
{
|
||||
warn!("scan_dir err {:?}", &er);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1345,23 +1343,23 @@ impl DiskAPI for LocalDisk {
|
||||
|
||||
if format_info.file_info.is_some() && id.is_some() {
|
||||
// check last check time
|
||||
if let Some(last_check) = format_info.last_check {
|
||||
if last_check.unix_timestamp() + 1 < OffsetDateTime::now_utc().unix_timestamp() {
|
||||
return Ok(id);
|
||||
}
|
||||
if let Some(last_check) = format_info.last_check
|
||||
&& last_check.unix_timestamp() + 1 < OffsetDateTime::now_utc().unix_timestamp()
|
||||
{
|
||||
return Ok(id);
|
||||
}
|
||||
}
|
||||
|
||||
let file_meta = self.check_format_json().await?;
|
||||
|
||||
if let Some(file_info) = &format_info.file_info {
|
||||
if super::fs::same_file(&file_meta, file_info) {
|
||||
let mut format_info = self.format_info.write().await;
|
||||
format_info.last_check = Some(OffsetDateTime::now_utc());
|
||||
drop(format_info);
|
||||
if let Some(file_info) = &format_info.file_info
|
||||
&& super::fs::same_file(&file_meta, file_info)
|
||||
{
|
||||
let mut format_info = self.format_info.write().await;
|
||||
format_info.last_check = Some(OffsetDateTime::now_utc());
|
||||
drop(format_info);
|
||||
|
||||
return Ok(id);
|
||||
}
|
||||
return Ok(id);
|
||||
}
|
||||
|
||||
debug!("get_disk_id: read format.json");
|
||||
@@ -1420,10 +1418,10 @@ impl DiskAPI for LocalDisk {
|
||||
#[tracing::instrument(skip(self))]
|
||||
async fn delete(&self, volume: &str, path: &str, opt: DeleteOptions) -> Result<()> {
|
||||
let volume_dir = self.get_bucket_path(volume)?;
|
||||
if !skip_access_checks(volume) {
|
||||
if let Err(e) = access(&volume_dir).await {
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
if !skip_access_checks(volume)
|
||||
&& let Err(e) = access(&volume_dir).await
|
||||
{
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
|
||||
let file_path = volume_dir.join(Path::new(&path));
|
||||
@@ -1438,10 +1436,10 @@ impl DiskAPI for LocalDisk {
|
||||
#[tracing::instrument(skip(self))]
|
||||
async fn verify_file(&self, volume: &str, path: &str, fi: &FileInfo) -> Result<CheckPartsResp> {
|
||||
let volume_dir = self.get_bucket_path(volume)?;
|
||||
if !skip_access_checks(volume) {
|
||||
if let Err(e) = access(&volume_dir).await {
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
if !skip_access_checks(volume)
|
||||
&& let Err(e) = access(&volume_dir).await
|
||||
{
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
|
||||
let mut resp = CheckPartsResp {
|
||||
@@ -1466,14 +1464,14 @@ impl DiskAPI for LocalDisk {
|
||||
.await
|
||||
.err();
|
||||
resp.results[i] = conv_part_err_to_int(&err);
|
||||
if resp.results[i] == CHECK_PART_UNKNOWN {
|
||||
if let Some(err) = err {
|
||||
error!("verify_file: failed to bitrot verify file: {:?}, error: {:?}", &part_path, &err);
|
||||
if err == DiskError::FileAccessDenied {
|
||||
continue;
|
||||
}
|
||||
info!("part unknown, disk: {}, path: {:?}", self.to_string(), part_path);
|
||||
if resp.results[i] == CHECK_PART_UNKNOWN
|
||||
&& let Some(err) = err
|
||||
{
|
||||
error!("verify_file: failed to bitrot verify file: {:?}, error: {:?}", &part_path, &err);
|
||||
if err == DiskError::FileAccessDenied {
|
||||
continue;
|
||||
}
|
||||
info!("part unknown, disk: {}, path: {:?}", self.to_string(), part_path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1572,13 +1570,12 @@ impl DiskAPI for LocalDisk {
|
||||
let e: DiskError = to_file_error(err).into();
|
||||
|
||||
if e == DiskError::FileNotFound {
|
||||
if !skip_access_checks(volume) {
|
||||
if let Err(err) = access(&volume_dir).await {
|
||||
if err.kind() == ErrorKind::NotFound {
|
||||
resp.results[i] = CHECK_PART_VOLUME_NOT_FOUND;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if !skip_access_checks(volume)
|
||||
&& let Err(err) = access(&volume_dir).await
|
||||
&& err.kind() == ErrorKind::NotFound
|
||||
{
|
||||
resp.results[i] = CHECK_PART_VOLUME_NOT_FOUND;
|
||||
continue;
|
||||
}
|
||||
resp.results[i] = CHECK_PART_FILE_NOT_FOUND;
|
||||
} else {
|
||||
@@ -1634,11 +1631,11 @@ impl DiskAPI for LocalDisk {
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(meta) = meta_op {
|
||||
if !meta.is_dir() {
|
||||
warn!("rename_part src is not dir {:?}", &src_file_path);
|
||||
return Err(DiskError::FileAccessDenied);
|
||||
}
|
||||
if let Some(meta) = meta_op
|
||||
&& !meta.is_dir()
|
||||
{
|
||||
warn!("rename_part src is not dir {:?}", &src_file_path);
|
||||
return Err(DiskError::FileAccessDenied);
|
||||
}
|
||||
|
||||
remove_std(&dst_file_path).map_err(to_file_error)?;
|
||||
@@ -1695,10 +1692,10 @@ impl DiskAPI for LocalDisk {
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(meta) = meta_op {
|
||||
if !meta.is_dir() {
|
||||
return Err(DiskError::FileAccessDenied);
|
||||
}
|
||||
if let Some(meta) = meta_op
|
||||
&& !meta.is_dir()
|
||||
{
|
||||
return Err(DiskError::FileAccessDenied);
|
||||
}
|
||||
|
||||
remove(&dst_file_path).await.map_err(to_file_error)?;
|
||||
@@ -1814,10 +1811,10 @@ impl DiskAPI for LocalDisk {
|
||||
async fn list_dir(&self, origvolume: &str, volume: &str, dir_path: &str, count: i32) -> Result<Vec<String>> {
|
||||
if !origvolume.is_empty() {
|
||||
let origvolume_dir = self.get_bucket_path(origvolume)?;
|
||||
if !skip_access_checks(origvolume) {
|
||||
if let Err(e) = access(origvolume_dir).await {
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
if !skip_access_checks(origvolume)
|
||||
&& let Err(e) = access(origvolume_dir).await
|
||||
{
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1827,10 +1824,11 @@ impl DiskAPI for LocalDisk {
|
||||
let entries = match os::read_dir(&dir_path_abs, count).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
if e.kind() == std::io::ErrorKind::NotFound && !skip_access_checks(volume) {
|
||||
if let Err(e) = access(&volume_dir).await {
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
if e.kind() == std::io::ErrorKind::NotFound
|
||||
&& !skip_access_checks(volume)
|
||||
&& let Err(e) = access(&volume_dir).await
|
||||
{
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
|
||||
return Err(to_file_error(e).into());
|
||||
@@ -1845,10 +1843,10 @@ impl DiskAPI for LocalDisk {
|
||||
async fn walk_dir<W: AsyncWrite + Unpin + Send>(&self, opts: WalkDirOptions, wr: &mut W) -> Result<()> {
|
||||
let volume_dir = self.get_bucket_path(&opts.bucket)?;
|
||||
|
||||
if !skip_access_checks(&opts.bucket) {
|
||||
if let Err(e) = access(&volume_dir).await {
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
if !skip_access_checks(&opts.bucket)
|
||||
&& let Err(e) = access(&volume_dir).await
|
||||
{
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
|
||||
let mut wr = wr;
|
||||
@@ -1909,19 +1907,19 @@ impl DiskAPI for LocalDisk {
|
||||
dst_path: &str,
|
||||
) -> Result<RenameDataResp> {
|
||||
let src_volume_dir = self.get_bucket_path(src_volume)?;
|
||||
if !skip_access_checks(src_volume) {
|
||||
if let Err(e) = super::fs::access_std(&src_volume_dir) {
|
||||
info!("access checks failed, src_volume_dir: {:?}, err: {}", src_volume_dir, e.to_string());
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
if !skip_access_checks(src_volume)
|
||||
&& let Err(e) = super::fs::access_std(&src_volume_dir)
|
||||
{
|
||||
info!("access checks failed, src_volume_dir: {:?}, err: {}", src_volume_dir, e.to_string());
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
|
||||
let dst_volume_dir = self.get_bucket_path(dst_volume)?;
|
||||
if !skip_access_checks(dst_volume) {
|
||||
if let Err(e) = super::fs::access_std(&dst_volume_dir) {
|
||||
info!("access checks failed, dst_volume_dir: {:?}, err: {}", dst_volume_dir, e.to_string());
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
if !skip_access_checks(dst_volume)
|
||||
&& let Err(e) = super::fs::access_std(&dst_volume_dir)
|
||||
{
|
||||
info!("access checks failed, dst_volume_dir: {:?}, err: {}", dst_volume_dir, e.to_string());
|
||||
return Err(to_access_error(e, DiskError::VolumeAccessDenied).into());
|
||||
}
|
||||
|
||||
// xl.meta path
|
||||
@@ -1973,19 +1971,18 @@ impl DiskAPI for LocalDisk {
|
||||
|
||||
let mut xlmeta = FileMeta::new();
|
||||
|
||||
if let Some(dst_buf) = has_dst_buf.as_ref() {
|
||||
if FileMeta::is_xl2_v1_format(dst_buf) {
|
||||
if let Ok(nmeta) = FileMeta::load(dst_buf) {
|
||||
xlmeta = nmeta
|
||||
}
|
||||
}
|
||||
if let Some(dst_buf) = has_dst_buf.as_ref()
|
||||
&& FileMeta::is_xl2_v1_format(dst_buf)
|
||||
&& let Ok(nmeta) = FileMeta::load(dst_buf)
|
||||
{
|
||||
xlmeta = nmeta
|
||||
}
|
||||
|
||||
let mut skip_parent = dst_volume_dir.clone();
|
||||
if has_dst_buf.as_ref().is_some() {
|
||||
if let Some(parent) = dst_file_path.parent() {
|
||||
skip_parent = parent.to_path_buf();
|
||||
}
|
||||
if has_dst_buf.as_ref().is_some()
|
||||
&& let Some(parent) = dst_file_path.parent()
|
||||
{
|
||||
skip_parent = parent.to_path_buf();
|
||||
}
|
||||
|
||||
// TODO: Healing
|
||||
@@ -2017,22 +2014,20 @@ impl DiskAPI for LocalDisk {
|
||||
.await?;
|
||||
if let Some((src_data_path, dst_data_path)) = has_data_dir_path.as_ref() {
|
||||
let no_inline = fi.data.is_none() && fi.size > 0;
|
||||
if no_inline {
|
||||
if let Err(err) = rename_all(&src_data_path, &dst_data_path, &skip_parent).await {
|
||||
let _ = self.delete_file(&dst_volume_dir, dst_data_path, false, false).await;
|
||||
info!(
|
||||
"rename all failed src_data_path: {:?}, dst_data_path: {:?}, err: {:?}",
|
||||
src_data_path, dst_data_path, err
|
||||
);
|
||||
return Err(err);
|
||||
}
|
||||
if no_inline && let Err(err) = rename_all(&src_data_path, &dst_data_path, &skip_parent).await {
|
||||
let _ = self.delete_file(&dst_volume_dir, dst_data_path, false, false).await;
|
||||
info!(
|
||||
"rename all failed src_data_path: {:?}, dst_data_path: {:?}, err: {:?}",
|
||||
src_data_path, dst_data_path, err
|
||||
);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(old_data_dir) = has_old_data_dir {
|
||||
// preserve current xl.meta inside the oldDataDir.
|
||||
if let Some(dst_buf) = has_dst_buf {
|
||||
if let Err(err) = self
|
||||
if let Some(dst_buf) = has_dst_buf
|
||||
&& let Err(err) = self
|
||||
.write_all_private(
|
||||
dst_volume,
|
||||
format!("{}/{}/{}", &dst_path, &old_data_dir.to_string(), STORAGE_FORMAT_FILE).as_str(),
|
||||
@@ -2041,10 +2036,9 @@ impl DiskAPI for LocalDisk {
|
||||
&skip_parent,
|
||||
)
|
||||
.await
|
||||
{
|
||||
info!("write_all_private failed err: {:?}", err);
|
||||
return Err(err);
|
||||
}
|
||||
{
|
||||
info!("write_all_private failed err: {:?}", err);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2075,11 +2069,11 @@ impl DiskAPI for LocalDisk {
|
||||
#[tracing::instrument(skip(self))]
|
||||
async fn make_volumes(&self, volumes: Vec<&str>) -> Result<()> {
|
||||
for vol in volumes {
|
||||
if let Err(e) = self.make_volume(vol).await {
|
||||
if e != DiskError::VolumeExists {
|
||||
error!("local disk make volumes failed: {e}");
|
||||
return Err(e);
|
||||
}
|
||||
if let Err(e) = self.make_volume(vol).await
|
||||
&& e != DiskError::VolumeExists
|
||||
{
|
||||
error!("local disk make volumes failed: {e}");
|
||||
return Err(e);
|
||||
}
|
||||
// TODO: health check
|
||||
}
|
||||
@@ -2313,10 +2307,11 @@ impl DiskAPI for LocalDisk {
|
||||
let old_path = file_path.join(Path::new(uuid.to_string().as_str()));
|
||||
check_path_length(old_path.to_string_lossy().as_ref())?;
|
||||
|
||||
if let Err(err) = self.move_to_trash(&old_path, true, false).await {
|
||||
if err != DiskError::FileNotFound && err != DiskError::VolumeNotFound {
|
||||
return Err(err);
|
||||
}
|
||||
if let Err(err) = self.move_to_trash(&old_path, true, false).await
|
||||
&& err != DiskError::FileNotFound
|
||||
&& err != DiskError::VolumeNotFound
|
||||
{
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2328,13 +2323,13 @@ impl DiskAPI for LocalDisk {
|
||||
}
|
||||
|
||||
// opts.undo_write && opts.old_data_dir.is_some_and(f)
|
||||
if let Some(old_data_dir) = opts.old_data_dir {
|
||||
if opts.undo_write {
|
||||
let src_path =
|
||||
file_path.join(Path::new(format!("{old_data_dir}{SLASH_SEPARATOR}{STORAGE_FORMAT_FILE_BACKUP}").as_str()));
|
||||
let dst_path = file_path.join(Path::new(format!("{path}{SLASH_SEPARATOR}{STORAGE_FORMAT_FILE}").as_str()));
|
||||
return rename_all(src_path, dst_path, file_path).await;
|
||||
}
|
||||
if let Some(old_data_dir) = opts.old_data_dir
|
||||
&& opts.undo_write
|
||||
{
|
||||
let src_path =
|
||||
file_path.join(Path::new(format!("{old_data_dir}{SLASH_SEPARATOR}{STORAGE_FORMAT_FILE_BACKUP}").as_str()));
|
||||
let dst_path = file_path.join(Path::new(format!("{path}{SLASH_SEPARATOR}{STORAGE_FORMAT_FILE}").as_str()));
|
||||
return rename_all(src_path, dst_path, file_path).await;
|
||||
}
|
||||
|
||||
self.delete_file(&volume_dir, &xl_path, true, false).await
|
||||
|
||||
@@ -147,11 +147,11 @@ async fn reliable_rename(
|
||||
dst_file_path: impl AsRef<Path>,
|
||||
base_dir: impl AsRef<Path>,
|
||||
) -> io::Result<()> {
|
||||
if let Some(parent) = dst_file_path.as_ref().parent() {
|
||||
if !file_exists(parent) {
|
||||
// info!("reliable_rename reliable_mkdir_all parent: {:?}", parent);
|
||||
reliable_mkdir_all(parent, base_dir.as_ref()).await?;
|
||||
}
|
||||
if let Some(parent) = dst_file_path.as_ref().parent()
|
||||
&& !file_exists(parent)
|
||||
{
|
||||
// info!("reliable_rename reliable_mkdir_all parent: {:?}", parent);
|
||||
reliable_mkdir_all(parent, base_dir.as_ref()).await?;
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
@@ -190,12 +190,11 @@ pub async fn reliable_mkdir_all(path: impl AsRef<Path>, base_dir: impl AsRef<Pat
|
||||
if e.kind() == io::ErrorKind::NotFound && i == 0 {
|
||||
i += 1;
|
||||
|
||||
if let Some(base_parent) = base_dir.parent() {
|
||||
if let Some(c) = base_parent.components().next() {
|
||||
if c != Component::RootDir {
|
||||
base_dir = base_parent
|
||||
}
|
||||
}
|
||||
if let Some(base_parent) = base_dir.parent()
|
||||
&& let Some(c) = base_parent.components().next()
|
||||
&& c != Component::RootDir
|
||||
{
|
||||
base_dir = base_parent
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user