Skip to main content

rc_core/admin/
bucket_metadata.rs

1//! Typed, bounded RustFS bucket-metadata archive operations.
2
3use async_trait::async_trait;
4use zeroize::Zeroizing;
5
6use crate::Result;
7
8/// Runtime capability required by bucket-metadata archive commands.
9pub const BUCKET_METADATA_CAPABILITY: &str = "admin.bucket-metadata";
10
11/// RustFS server limit for both exported and imported bucket-metadata archives.
12pub const MAX_BUCKET_METADATA_ARCHIVE_BYTES: usize = 100 * 1024 * 1024;
13
14/// An owned archive whose storage is cleared when dropped.
15pub struct BucketMetadataArchive {
16    bytes: Zeroizing<Vec<u8>>,
17}
18
19impl BucketMetadataArchive {
20    pub fn new(bytes: Vec<u8>) -> Result<Self> {
21        if bytes.len() > MAX_BUCKET_METADATA_ARCHIVE_BYTES {
22            return Err(crate::Error::RequestRejected(format!(
23                "Bucket metadata archive size {} exceeds the {} byte limit",
24                bytes.len(),
25                MAX_BUCKET_METADATA_ARCHIVE_BYTES
26            )));
27        }
28        Ok(Self {
29            bytes: Zeroizing::new(bytes),
30        })
31    }
32
33    pub fn as_bytes(&self) -> &[u8] {
34        self.bytes.as_slice()
35    }
36
37    pub fn into_bytes(self) -> Zeroizing<Vec<u8>> {
38        self.bytes
39    }
40}
41
42#[async_trait]
43pub trait BucketMetadataApi: Send + Sync {
44    /// Export every bucket, or one selected bucket, as a bounded ZIP archive.
45    async fn export_bucket_metadata(&self, bucket: Option<&str>) -> Result<BucketMetadataArchive>;
46
47    /// Import a prevalidated bounded archive. Mutations are never retried automatically.
48    async fn import_bucket_metadata(&self, archive: BucketMetadataArchive) -> Result<()>;
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn archive_rejects_oversized_input() {
57        let bytes = vec![0; MAX_BUCKET_METADATA_ARCHIVE_BYTES + 1];
58        assert!(BucketMetadataArchive::new(bytes).is_err());
59    }
60}