From 85bc0ce2d551f8c52ab13aa25365cc85ce2f5991 Mon Sep 17 00:00:00 2001 From: weisd Date: Tue, 18 Nov 2025 09:24:22 +0800 Subject: [PATCH] fix: filemeta version handling and delete operations (#879) * fix filemeta version * fix clippy * fix delete version * fix clippy/test --- crates/ahm/src/heal/erasure_healer.rs | 4 +- crates/ahm/src/heal/resume.rs | 2 +- crates/ahm/src/heal/storage.rs | 3 +- crates/ahm/tests/lifecycle_cache_test.rs | 12 ++-- .../ahm/tests/lifecycle_integration_test.rs | 8 +-- .../ecstore/src/bucket/bucket_target_sys.rs | 9 +-- crates/ecstore/src/disk/local.rs | 5 +- crates/ecstore/src/rpc/remote_disk.rs | 2 +- crates/ecstore/src/set_disk.rs | 3 +- crates/filemeta/src/filemeta.rs | 70 +++++++++++-------- crates/obs/src/telemetry.rs | 8 +-- crates/signer/src/request_signature_v4.rs | 18 ++--- rustfs/src/main.rs | 2 +- rustfs/src/storage/ecfs.rs | 4 +- rustfs/src/storage/helper.rs | 2 +- rustfs/src/storage/options.rs | 37 ++++------ 16 files changed, 93 insertions(+), 96 deletions(-) diff --git a/crates/ahm/src/heal/erasure_healer.rs b/crates/ahm/src/heal/erasure_healer.rs index 4731cde27..ff028d0fa 100644 --- a/crates/ahm/src/heal/erasure_healer.rs +++ b/crates/ahm/src/heal/erasure_healer.rs @@ -363,7 +363,7 @@ impl ErasureSetHealer { let _permit = semaphore .acquire() .await - .map_err(|e| Error::other(format!("Failed to acquire semaphore for bucket heal: {}", e)))?; + .map_err(|e| Error::other(format!("Failed to acquire semaphore for bucket heal: {e}")))?; if cancel_token.is_cancelled() { return Err(Error::TaskCancelled); @@ -461,7 +461,7 @@ impl ErasureSetHealer { let _permit = semaphore .acquire() .await - .map_err(|e| Error::other(format!("Failed to acquire semaphore for object heal: {}", e)))?; + .map_err(|e| Error::other(format!("Failed to acquire semaphore for object heal: {e}")))?; match storage.heal_object(&bucket, &object, None, &heal_opts).await { Ok((_result, None)) => { diff --git a/crates/ahm/src/heal/resume.rs b/crates/ahm/src/heal/resume.rs index bf6dd03db..397727850 100644 --- a/crates/ahm/src/heal/resume.rs +++ b/crates/ahm/src/heal/resume.rs @@ -30,7 +30,7 @@ const RESUME_CHECKPOINT_FILE: &str = "ahm_checkpoint.json"; /// Helper function to convert Path to &str, returning an error if conversion fails fn path_to_str(path: &Path) -> Result<&str> { path.to_str() - .ok_or_else(|| Error::other(format!("Invalid UTF-8 path: {:?}", path))) + .ok_or_else(|| Error::other(format!("Invalid UTF-8 path: {path:?}"))) } /// resume state diff --git a/crates/ahm/src/heal/storage.rs b/crates/ahm/src/heal/storage.rs index b928a4a4a..dddada2c9 100644 --- a/crates/ahm/src/heal/storage.rs +++ b/crates/ahm/src/heal/storage.rs @@ -180,8 +180,7 @@ impl HealStorageAPI for ECStoreHealStorage { MAX_READ_BYTES, bucket, object ); return Err(Error::other(format!( - "Object too large: {} bytes (max: {} bytes) for {}/{}", - n_read, MAX_READ_BYTES, bucket, object + "Object too large: {n_read} bytes (max: {MAX_READ_BYTES} bytes) for {bucket}/{object}" ))); } } diff --git a/crates/ahm/tests/lifecycle_cache_test.rs b/crates/ahm/tests/lifecycle_cache_test.rs index 2a61b18bc..5748ed259 100644 --- a/crates/ahm/tests/lifecycle_cache_test.rs +++ b/crates/ahm/tests/lifecycle_cache_test.rs @@ -144,7 +144,7 @@ async fn setup_test_env() -> (Vec, Arc) { let mut wtxn = lmdb_env.write_txn().unwrap(); let db = match lmdb_env .database_options() - .name(&format!("bucket_{}", bucket_name)) + .name(&format!("bucket_{bucket_name}")) .types::, LifecycleContentCodec>() .flags(DatabaseFlags::DUP_SORT) //.dup_sort_comparator::<>() @@ -152,7 +152,7 @@ async fn setup_test_env() -> (Vec, Arc) { { Ok(db) => db, Err(err) => { - panic!("lmdb error: {}", err); + panic!("lmdb error: {err}"); } }; let _ = wtxn.commit(); @@ -199,7 +199,7 @@ async fn upload_test_object(ecstore: &Arc, bucket: &str, object: &str, .await .expect("Failed to upload test object"); - println!("object_info1: {:?}", object_info); + println!("object_info1: {object_info:?}"); info!("Uploaded test object: {}/{} ({} bytes)", bucket, object, object_info.size); } @@ -456,7 +456,7 @@ mod serial_tests { } let object_info = convert_record_to_object_info(record); - println!("object_info2: {:?}", object_info); + println!("object_info2: {object_info:?}"); let mod_time = object_info.mod_time.unwrap_or(OffsetDateTime::now_utc()); let expiry_time = rustfs_ecstore::bucket::lifecycle::lifecycle::expected_expiry_time(mod_time, 1); @@ -494,9 +494,9 @@ mod serial_tests { type_, object_name, } = &elm.1; - println!("cache row:{} {} {} {:?} {}", ver_no, ver_id, mod_time, type_, object_name); + println!("cache row:{ver_no} {ver_id} {mod_time} {type_:?} {object_name}"); } - println!("row:{:?}", row); + println!("row:{row:?}"); } //drop(iter); wtxn.commit().unwrap(); diff --git a/crates/ahm/tests/lifecycle_integration_test.rs b/crates/ahm/tests/lifecycle_integration_test.rs index 21ab31225..f491531cb 100644 --- a/crates/ahm/tests/lifecycle_integration_test.rs +++ b/crates/ahm/tests/lifecycle_integration_test.rs @@ -277,11 +277,11 @@ async fn create_test_tier(server: u32) { }; let mut tier_config_mgr = GLOBAL_TierConfigMgr.write().await; if let Err(err) = tier_config_mgr.add(args, false).await { - println!("tier_config_mgr add failed, e: {:?}", err); + println!("tier_config_mgr add failed, e: {err:?}"); panic!("tier add failed. {err}"); } if let Err(e) = tier_config_mgr.save().await { - println!("tier_config_mgr save failed, e: {:?}", e); + println!("tier_config_mgr save failed, e: {e:?}"); panic!("tier save failed"); } println!("Created test tier: COLDTIER44"); @@ -299,7 +299,7 @@ async fn object_exists(ecstore: &Arc, bucket: &str, object: &str) -> bo #[allow(dead_code)] async fn object_is_delete_marker(ecstore: &Arc, bucket: &str, object: &str) -> bool { if let Ok(oi) = (**ecstore).get_object_info(bucket, object, &ObjectOptions::default()).await { - println!("oi: {:?}", oi); + println!("oi: {oi:?}"); oi.delete_marker } else { println!("object_is_delete_marker is error"); @@ -311,7 +311,7 @@ async fn object_is_delete_marker(ecstore: &Arc, bucket: &str, object: & #[allow(dead_code)] async fn object_is_transitioned(ecstore: &Arc, bucket: &str, object: &str) -> bool { if let Ok(oi) = (**ecstore).get_object_info(bucket, object, &ObjectOptions::default()).await { - println!("oi: {:?}", oi); + println!("oi: {oi:?}"); !oi.transitioned_object.status.is_empty() } else { println!("object_is_transitioned is error"); diff --git a/crates/ecstore/src/bucket/bucket_target_sys.rs b/crates/ecstore/src/bucket/bucket_target_sys.rs index 079c8cc59..99b38ff43 100644 --- a/crates/ecstore/src/bucket/bucket_target_sys.rs +++ b/crates/ecstore/src/bucket/bucket_target_sys.rs @@ -1106,18 +1106,15 @@ impl TargetClient { SdkError::ServiceError(oe) => match oe.into_err() { HeadBucketError::NotFound(_) => Ok(false), other => Err(S3ClientError::new(format!( - "failed to check bucket exists for bucket:{} please check the bucket name and credentials, error:{:?}", - bucket, other + "failed to check bucket exists for bucket:{bucket} please check the bucket name and credentials, error:{other:?}" ))), }, SdkError::DispatchFailure(e) => Err(S3ClientError::new(format!( - "failed to dispatch bucket exists for bucket:{} error:{:?}", - bucket, e + "failed to dispatch bucket exists for bucket:{bucket} error:{e:?}" ))), _ => Err(S3ClientError::new(format!( - "failed to check bucket exists for bucket:{} error:{:?}", - bucket, e + "failed to check bucket exists for bucket:{bucket} error:{e:?}" ))), }, } diff --git a/crates/ecstore/src/disk/local.rs b/crates/ecstore/src/disk/local.rs index 7c38645e5..7f746af34 100644 --- a/crates/ecstore/src/disk/local.rs +++ b/crates/ecstore/src/disk/local.rs @@ -806,7 +806,7 @@ impl LocalDisk { Ok((bytes, modtime)) } - async fn delete_versions_internal(&self, volume: &str, path: &str, fis: &Vec) -> Result<()> { + async fn delete_versions_internal(&self, volume: &str, path: &str, fis: &[FileInfo]) -> Result<()> { let volume_dir = self.get_bucket_path(volume)?; let xlpath = self.get_object_path(volume, format!("{path}/{STORAGE_FORMAT_FILE}").as_str())?; @@ -820,7 +820,7 @@ impl LocalDisk { fm.unmarshal_msg(&data)?; - for fi in fis { + for fi in fis.iter() { let data_dir = match fm.delete_version(fi) { Ok(res) => res, Err(err) => { @@ -2300,7 +2300,6 @@ impl DiskAPI for LocalDisk { let buf = match self.read_all_data(volume, &volume_dir, &xl_path).await { Ok(res) => res, Err(err) => { - // if err != DiskError::FileNotFound { return Err(err); } diff --git a/crates/ecstore/src/rpc/remote_disk.rs b/crates/ecstore/src/rpc/remote_disk.rs index db10534f0..99086a880 100644 --- a/crates/ecstore/src/rpc/remote_disk.rs +++ b/crates/ecstore/src/rpc/remote_disk.rs @@ -1085,7 +1085,7 @@ mod tests { drop(listener); - let url = url::Url::parse(&format!("http://{}:{}/data/rustfs0", ip, port)).unwrap(); + let url = url::Url::parse(&format!("http://{ip}:{port}/data/rustfs0")).unwrap(); let endpoint = Endpoint { url, is_local: false, diff --git a/crates/ecstore/src/set_disk.rs b/crates/ecstore/src/set_disk.rs index e2d2d8d6c..54a31dd37 100644 --- a/crates/ecstore/src/set_disk.rs +++ b/crates/ecstore/src/set_disk.rs @@ -4247,7 +4247,6 @@ impl StorageAPI for SetDisks { for (_, mut fi_vers) in vers_map { fi_vers.versions.sort_by(|a, b| a.deleted.cmp(&b.deleted)); - fi_vers.versions.reverse(); if let Some(index) = fi_vers.versions.iter().position(|fi| fi.deleted) { fi_vers.versions.truncate(index + 1); @@ -4652,7 +4651,7 @@ impl StorageAPI for SetDisks { let tgt_client = match tier_config_mgr.get_driver(&opts.transition.tier).await { Ok(client) => client, Err(err) => { - return Err(Error::other(format!("remote tier error: {}", err))); + return Err(Error::other(format!("remote tier error: {err}"))); } }; diff --git a/crates/filemeta/src/filemeta.rs b/crates/filemeta/src/filemeta.rs index c63ae87fa..fcf667474 100644 --- a/crates/filemeta/src/filemeta.rs +++ b/crates/filemeta/src/filemeta.rs @@ -427,11 +427,19 @@ impl FileMeta { return; } - self.versions.reverse(); - - // for _v in self.versions.iter() { - // // warn!("sort {} {:?}", i, v); - // } + self.versions.sort_by(|a, b| { + if a.header.mod_time != b.header.mod_time { + b.header.mod_time.cmp(&a.header.mod_time) + } else if a.header.version_type != b.header.version_type { + b.header.version_type.cmp(&a.header.version_type) + } else if a.header.version_id != b.header.version_id { + b.header.version_id.cmp(&a.header.version_id) + } else if a.header.flags != b.header.flags { + b.header.flags.cmp(&a.header.flags) + } else { + b.cmp(a) + } + }); } // Find version @@ -489,25 +497,27 @@ impl FileMeta { self.versions.sort_by(|a, b| { if a.header.mod_time != b.header.mod_time { - a.header.mod_time.cmp(&b.header.mod_time) + b.header.mod_time.cmp(&a.header.mod_time) } else if a.header.version_type != b.header.version_type { - a.header.version_type.cmp(&b.header.version_type) + b.header.version_type.cmp(&a.header.version_type) } else if a.header.version_id != b.header.version_id { - a.header.version_id.cmp(&b.header.version_id) + b.header.version_id.cmp(&a.header.version_id) } else if a.header.flags != b.header.flags { - a.header.flags.cmp(&b.header.flags) + b.header.flags.cmp(&a.header.flags) } else { - a.cmp(b) + b.cmp(a) } }); Ok(()) } - pub fn add_version(&mut self, fi: FileInfo) -> Result<()> { - let vid = fi.version_id; + pub fn add_version(&mut self, mut fi: FileInfo) -> Result<()> { + if fi.version_id.is_none() { + fi.version_id = Some(Uuid::nil()); + } if let Some(ref data) = fi.data { - let key = vid.unwrap_or_default().to_string(); + let key = fi.version_id.unwrap_or_default().to_string(); self.data.replace(&key, data.to_vec())?; } @@ -551,7 +561,6 @@ impl FileMeta { } } } - Err(Error::other("add_version failed")) // if !ver.valid() { @@ -583,12 +592,19 @@ impl FileMeta { } // delete_version deletes version, returns data_dir + #[tracing::instrument(skip(self))] pub fn delete_version(&mut self, fi: &FileInfo) -> Result> { + let vid = if fi.version_id.is_none() { + Some(Uuid::nil()) + } else { + Some(fi.version_id.unwrap()) + }; + let mut ventry = FileMetaVersion::default(); if fi.deleted { ventry.version_type = VersionType::Delete; ventry.delete_marker = Some(MetaDeleteMarker { - version_id: fi.version_id, + version_id: vid, mod_time: fi.mod_time, ..Default::default() }); @@ -689,8 +705,10 @@ impl FileMeta { } } + let mut found_index = None; + for (i, ver) in self.versions.iter().enumerate() { - if ver.header.version_id != fi.version_id { + if ver.header.version_id != vid { continue; } @@ -701,7 +719,7 @@ impl FileMeta { let mut v = self.get_idx(i)?; if v.delete_marker.is_none() { v.delete_marker = Some(MetaDeleteMarker { - version_id: fi.version_id, + version_id: vid, mod_time: fi.mod_time, meta_sys: HashMap::new(), }); @@ -767,7 +785,7 @@ impl FileMeta { self.versions.remove(i); if (fi.mark_deleted && fi.version_purge_status() != VersionPurgeStatusType::Complete) - || (fi.deleted && fi.version_id.is_none()) + || (fi.deleted && vid == Some(Uuid::nil())) { self.add_version_filemata(ventry)?; } @@ -803,18 +821,11 @@ impl FileMeta { return Ok(old_dir); } + found_index = Some(i); } } } - let mut found_index = None; - for (i, version) in self.versions.iter().enumerate() { - if version.header.version_type == VersionType::Object && version.header.version_id == fi.version_id { - found_index = Some(i); - break; - } - } - let Some(i) = found_index else { if fi.deleted { self.add_version_filemata(ventry)?; @@ -1521,7 +1532,8 @@ impl FileMetaVersionHeader { cur.read_exact(&mut buf)?; self.version_id = { let id = Uuid::from_bytes(buf); - if id.is_nil() { None } else { Some(id) } + // if id.is_nil() { None } else { Some(id) } + Some(id) }; // mod_time @@ -1695,7 +1707,7 @@ impl MetaObject { } pub fn into_fileinfo(&self, volume: &str, path: &str, all_parts: bool) -> FileInfo { - let version_id = self.version_id.filter(|&vid| !vid.is_nil()); + // let version_id = self.version_id.filter(|&vid| !vid.is_nil()); let parts = if all_parts { let mut parts = vec![ObjectPartInfo::default(); self.part_numbers.len()]; @@ -1799,7 +1811,7 @@ impl MetaObject { .unwrap_or_default(); FileInfo { - version_id, + version_id: self.version_id, erasure, data_dir: self.data_dir, mod_time: self.mod_time, diff --git a/crates/obs/src/telemetry.rs b/crates/obs/src/telemetry.rs index e52ec230e..1488495a0 100644 --- a/crates/obs/src/telemetry.rs +++ b/crates/obs/src/telemetry.rs @@ -272,8 +272,7 @@ fn init_file_logging(config: &OtelConfig, logger_level: &str, is_production: boo if (current & !desired) != 0 { if let Err(e) = fs::set_permissions(log_directory, Permissions::from_mode(desired)) { return Err(TelemetryError::SetPermissions(format!( - "dir='{}', want={:#o}, have={:#o}, err={}", - log_directory, desired, current, e + "dir='{log_directory}', want={desired:#o}, have={current:#o}, err={e}" ))); } // Second verification @@ -281,15 +280,14 @@ fn init_file_logging(config: &OtelConfig, logger_level: &str, is_production: boo let after = meta2.permissions().mode() & 0o777; if after != desired { return Err(TelemetryError::SetPermissions(format!( - "dir='{}', want={:#o}, after={:#o}", - log_directory, desired, after + "dir='{log_directory}', want={desired:#o}, after={after:#o}" ))); } } } } Err(e) => { - return Err(TelemetryError::Io(format!("stat '{}' failed: {}", log_directory, e))); + return Err(TelemetryError::Io(format!("stat '{log_directory}' failed: {e}"))); } } } diff --git a/crates/signer/src/request_signature_v4.rs b/crates/signer/src/request_signature_v4.rs index 6a4700b45..747d9a7b3 100644 --- a/crates/signer/src/request_signature_v4.rs +++ b/crates/signer/src/request_signature_v4.rs @@ -543,7 +543,7 @@ mod tests { *req.uri_mut() = Uri::from_parts(parts).unwrap(); let canonical_request = get_canonical_request(&req, &v4_ignored_headers, &get_hashed_payload(&req)); - println!("canonical_request: \n{}\n", canonical_request); + println!("canonical_request: \n{canonical_request}\n"); assert_eq!( canonical_request, concat!( @@ -562,7 +562,7 @@ mod tests { ); let string_to_sign = get_string_to_sign_v4(t, region, &canonical_request, service); - println!("string_to_sign: \n{}\n", string_to_sign); + println!("string_to_sign: \n{string_to_sign}\n"); assert_eq!( string_to_sign, concat!( @@ -576,7 +576,7 @@ mod tests { let signing_key = get_signing_key(secret_access_key, region, t, service); let signature = get_signature(signing_key, &string_to_sign); - println!("signature: \n{}\n", signature); + println!("signature: \n{signature}\n"); assert_eq!(signature, "73fad2dfea0727e10a7179bf49150360a56f2e6b519c53999fd6e011152187d0"); } @@ -608,7 +608,7 @@ mod tests { println!("{:?}", req.uri().query()); let canonical_request = get_canonical_request(&req, &v4_ignored_headers, &get_hashed_payload(&req)); - println!("canonical_request: \n{}\n", canonical_request); + println!("canonical_request: \n{canonical_request}\n"); assert_eq!( canonical_request, concat!( @@ -627,7 +627,7 @@ mod tests { ); let string_to_sign = get_string_to_sign_v4(t, region, &canonical_request, service); - println!("string_to_sign: \n{}\n", string_to_sign); + println!("string_to_sign: \n{string_to_sign}\n"); assert_eq!( string_to_sign, concat!( @@ -641,7 +641,7 @@ mod tests { let signing_key = get_signing_key(secret_access_key, region, t, service); let signature = get_signature(signing_key, &string_to_sign); - println!("signature: \n{}\n", signature); + println!("signature: \n{signature}\n"); assert_eq!(signature, "dfbed913d1982428f6224ee506431fc133dbcad184194c0cbf01bc517435788a"); } @@ -673,7 +673,7 @@ mod tests { println!("{:?}", req.uri().query()); let canonical_request = get_canonical_request(&req, &v4_ignored_headers, &get_hashed_payload(&req)); - println!("canonical_request: \n{}\n", canonical_request); + println!("canonical_request: \n{canonical_request}\n"); assert_eq!( canonical_request, concat!( @@ -692,7 +692,7 @@ mod tests { ); let string_to_sign = get_string_to_sign_v4(t, region, &canonical_request, service); - println!("string_to_sign: \n{}\n", string_to_sign); + println!("string_to_sign: \n{string_to_sign}\n"); assert_eq!( string_to_sign, concat!( @@ -706,7 +706,7 @@ mod tests { let signing_key = get_signing_key(secret_access_key, region, t, service); let signature = get_signature(signing_key, &string_to_sign); - println!("signature: \n{}\n", signature); + println!("signature: \n{signature}\n"); assert_eq!(signature, "c7c7c6e12e5709c0c2ffc4707600a86c3cd261dd1de7409126a17f5b08c58dfa"); } diff --git a/rustfs/src/main.rs b/rustfs/src/main.rs index 8d5fb3274..593f1b714 100644 --- a/rustfs/src/main.rs +++ b/rustfs/src/main.rs @@ -114,7 +114,7 @@ async fn async_main() -> Result<()> { let guard = match init_obs(Some(opt.clone().obs_endpoint)).await { Ok(g) => g, Err(e) => { - println!("Failed to initialize observability: {}", e); + println!("Failed to initialize observability: {e}"); return Err(Error::other(e)); } }; diff --git a/rustfs/src/storage/ecfs.rs b/rustfs/src/storage/ecfs.rs index 656ae4bcc..5ce2ae3a7 100644 --- a/rustfs/src/storage/ecfs.rs +++ b/rustfs/src/storage/ecfs.rs @@ -1077,7 +1077,7 @@ impl S3 for FS { warn!("unable to restore transitioned bucket/object {}/{}: {}", bucket, object, err.to_string()); return Err(S3Error::with_message( S3ErrorCode::Custom("ErrRestoreTransitionedObject".into()), - format!("unable to restore transitioned bucket/object {}/{}: {}", bucket, object, err), + format!("unable to restore transitioned bucket/object {bucket}/{object}: {err}"), )); } @@ -1329,7 +1329,7 @@ impl S3 for FS { } if is_dir_object(&object.object_name) && object.version_id.is_none() { - object.version_id = Some(Uuid::max()); + object.version_id = Some(Uuid::nil()); } if replicate_deletes { diff --git a/rustfs/src/storage/helper.rs b/rustfs/src/storage/helper.rs index f72f1b1aa..31ad115a1 100644 --- a/rustfs/src/storage/helper.rs +++ b/rustfs/src/storage/helper.rs @@ -157,7 +157,7 @@ impl OperationHelper { .clone() .status(status) .status_code(status_code) - .time_to_response(format!("{:.2?}", ttr)) + .time_to_response(format!("{ttr:.2?}")) .time_to_response_in_ns(ttr.as_nanos().to_string()) .build(); diff --git a/rustfs/src/storage/options.rs b/rustfs/src/storage/options.rs index ca3c750dd..f2075a0f6 100644 --- a/rustfs/src/storage/options.rs +++ b/rustfs/src/storage/options.rs @@ -65,15 +65,12 @@ pub async fn del_opts( let vid = vid.map(|v| v.as_str().trim().to_owned()); if let Some(ref id) = vid { - if let Err(err) = Uuid::parse_str(id.as_str()) { + if *id != Uuid::nil().to_string() + && let Err(err) = Uuid::parse_str(id.as_str()) + { error!("del_opts: invalid version id: {} error: {}", id, err); return Err(StorageError::InvalidVersionID(bucket.to_owned(), object.to_owned(), id.clone())); } - - if !versioned { - error!("del_opts: object not versioned: {}", object); - return Err(StorageError::InvalidArgument(bucket.to_owned(), object.to_owned(), id.clone())); - } } let mut opts = put_opts_from_headers(headers, metadata.clone()).map_err(|err| { @@ -83,7 +80,7 @@ pub async fn del_opts( opts.version_id = { if is_dir_object(object) && vid.is_none() { - Some(Uuid::max().to_string()) + Some(Uuid::nil().to_string()) } else { vid } @@ -113,13 +110,11 @@ pub async fn get_opts( let vid = vid.map(|v| v.as_str().trim().to_owned()); if let Some(ref id) = vid { - if let Err(_err) = Uuid::parse_str(id.as_str()) { + if *id != Uuid::nil().to_string() + && let Err(_err) = Uuid::parse_str(id.as_str()) + { return Err(StorageError::InvalidVersionID(bucket.to_owned(), object.to_owned(), id.clone())); } - - if !versioned { - return Err(StorageError::InvalidArgument(bucket.to_owned(), object.to_owned(), id.clone())); - } } let mut opts = get_default_opts(headers, HashMap::new(), false) @@ -127,7 +122,7 @@ pub async fn get_opts( opts.version_id = { if is_dir_object(object) && vid.is_none() { - Some(Uuid::max().to_string()) + Some(Uuid::nil().to_string()) } else { vid } @@ -189,13 +184,11 @@ pub async fn put_opts( let vid = vid.map(|v| v.as_str().trim().to_owned()); if let Some(ref id) = vid { - if let Err(_err) = Uuid::parse_str(id.as_str()) { + if *id != Uuid::nil().to_string() + && let Err(_err) = Uuid::parse_str(id.as_str()) + { return Err(StorageError::InvalidVersionID(bucket.to_owned(), object.to_owned(), id.clone())); } - - if !versioned { - return Err(StorageError::InvalidArgument(bucket.to_owned(), object.to_owned(), id.clone())); - } } let mut opts = put_opts_from_headers(headers, metadata) @@ -203,7 +196,7 @@ pub async fn put_opts( opts.version_id = { if is_dir_object(object) && vid.is_none() { - Some(Uuid::max().to_string()) + Some(Uuid::nil().to_string()) } else { vid } @@ -603,7 +596,7 @@ mod tests { assert!(result.is_ok()); let opts = result.unwrap(); - assert_eq!(opts.version_id, Some(Uuid::max().to_string())); + assert_eq!(opts.version_id, Some(Uuid::nil().to_string())); } #[tokio::test] @@ -676,7 +669,7 @@ mod tests { assert!(result.is_ok()); let opts = result.unwrap(); - assert_eq!(opts.version_id, Some(Uuid::max().to_string())); + assert_eq!(opts.version_id, Some(Uuid::nil().to_string())); } #[tokio::test] @@ -720,7 +713,7 @@ mod tests { assert!(result.is_ok()); let opts = result.unwrap(); - assert_eq!(opts.version_id, Some(Uuid::max().to_string())); + assert_eq!(opts.version_id, Some(Uuid::nil().to_string())); } #[tokio::test]