Add default storage class to ListObjectsV2 (#765)

* Add InvalidRangeSpec error

* Add EntityTooSmall to from_u32

* Add InvalidRangeSpec to from_u32

* Map InvalidRangeSpec to correct S3ErrorCode

* Return Error::InvalidRangeSpec

* Use auto implementation

* Add default storage class to ListObjectsV2

Resolves #764

* Add storage_class to response

* Make storage class optional so default won't be an empty string

---------

Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
Niklas Mollenhauer
2025-10-31 12:32:25 +01:00
committed by GitHub
parent 325ff62684
commit 79012be2c8
2 changed files with 12 additions and 0 deletions
+11
View File
@@ -14,6 +14,7 @@
use crate::bucket::metadata_sys::get_versioning_config; use crate::bucket::metadata_sys::get_versioning_config;
use crate::bucket::versioning::VersioningApi as _; use crate::bucket::versioning::VersioningApi as _;
use crate::config::storageclass;
use crate::disk::DiskStore; use crate::disk::DiskStore;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::store_utils::clean_metadata; use crate::store_utils::clean_metadata;
@@ -33,6 +34,7 @@ use rustfs_madmin::heal_commands::HealResultItem;
use rustfs_rio::Checksum; use rustfs_rio::Checksum;
use rustfs_rio::{DecompressReader, HashReader, LimitReader, WarpReader}; use rustfs_rio::{DecompressReader, HashReader, LimitReader, WarpReader};
use rustfs_utils::CompressionAlgorithm; use rustfs_utils::CompressionAlgorithm;
use rustfs_utils::http::AMZ_STORAGE_CLASS;
use rustfs_utils::http::headers::{AMZ_OBJECT_TAGGING, RESERVED_METADATA_PREFIX_LOWER}; use rustfs_utils::http::headers::{AMZ_OBJECT_TAGGING, RESERVED_METADATA_PREFIX_LOWER};
use rustfs_utils::path::decode_dir_object; use rustfs_utils::path::decode_dir_object;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -518,6 +520,7 @@ impl From<s3s::dto::CompletedPart> for CompletePart {
pub struct ObjectInfo { pub struct ObjectInfo {
pub bucket: String, pub bucket: String,
pub name: String, pub name: String,
pub storage_class: Option<String>,
pub mod_time: Option<OffsetDateTime>, pub mod_time: Option<OffsetDateTime>,
pub size: i64, pub size: i64,
// Actual size is the real size of the object uploaded by client. // Actual size is the real size of the object uploaded by client.
@@ -557,6 +560,7 @@ impl Clone for ObjectInfo {
Self { Self {
bucket: self.bucket.clone(), bucket: self.bucket.clone(),
name: self.name.clone(), name: self.name.clone(),
storage_class: self.storage_class.clone(),
mod_time: self.mod_time, mod_time: self.mod_time,
size: self.size, size: self.size,
actual_size: self.actual_size, actual_size: self.actual_size,
@@ -689,6 +693,12 @@ impl ObjectInfo {
v v
}; };
// Extract storage class from metadata, default to STANDARD if not found
let storage_class = metadata
.get(AMZ_STORAGE_CLASS)
.cloned()
.or_else(|| Some(storageclass::STANDARD.to_string()));
// Convert parts from rustfs_filemeta::ObjectPartInfo to store_api::ObjectPartInfo // Convert parts from rustfs_filemeta::ObjectPartInfo to store_api::ObjectPartInfo
let parts = fi let parts = fi
.parts .parts
@@ -727,6 +737,7 @@ impl ObjectInfo {
user_defined: metadata, user_defined: metadata,
transitioned_object, transitioned_object,
checksum: fi.checksum.clone(), checksum: fi.checksum.clone(),
storage_class,
..Default::default() ..Default::default()
} }
} }
+1
View File
@@ -2218,6 +2218,7 @@ impl S3 for FS {
last_modified: v.mod_time.map(Timestamp::from), last_modified: v.mod_time.map(Timestamp::from),
size: Some(v.get_actual_size().unwrap_or_default()), size: Some(v.get_actual_size().unwrap_or_default()),
e_tag: v.etag.clone().map(|etag| to_s3s_etag(&etag)), e_tag: v.etag.clone().map(|etag| to_s3s_etag(&etag)),
storage_class: v.storage_class.clone().map(ObjectStorageClass::from),
..Default::default() ..Default::default()
}; };