1use super::codec::{CanonicalDecodeError, DecodeLimits, Decoder, Encoder};
4use super::types::digest_object;
5use crate::storage::{ObjectId, ObjectKind, object_digest};
6
7const DOMAIN: &[u8; 8] = b"ACYFSMET";
8const VERSION: u16 = 1;
9
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub enum MetadataField<T> {
13 Unavailable,
15 Value(T),
17}
18
19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub struct FileMetadata {
25 pub posix_mode: MetadataField<u32>,
27 pub posix_uid: MetadataField<u32>,
29 pub posix_gid: MetadataField<u32>,
31 pub posix_flags: MetadataField<u64>,
33 pub windows_attributes: MetadataField<u32>,
35 pub created_ns: MetadataField<i64>,
37 pub modified_ns: MetadataField<i64>,
39 pub accessed_ns: MetadataField<i64>,
41 pub changed_ns: MetadataField<i64>,
43 pub named_attributes: MetadataField<ObjectId>,
45 pub acl: MetadataField<ObjectId>,
47 pub security_descriptor: MetadataField<ObjectId>,
49}
50
51impl Default for FileMetadata {
52 fn default() -> Self {
53 Self {
54 posix_mode: MetadataField::Unavailable,
55 posix_uid: MetadataField::Unavailable,
56 posix_gid: MetadataField::Unavailable,
57 posix_flags: MetadataField::Unavailable,
58 windows_attributes: MetadataField::Unavailable,
59 created_ns: MetadataField::Unavailable,
60 modified_ns: MetadataField::Unavailable,
61 accessed_ns: MetadataField::Unavailable,
62 changed_ns: MetadataField::Unavailable,
63 named_attributes: MetadataField::Unavailable,
64 acl: MetadataField::Unavailable,
65 security_descriptor: MetadataField::Unavailable,
66 }
67 }
68}
69
70impl FileMetadata {
71 fn validate(self) -> Result<(), CanonicalDecodeError> {
72 validate_object(
73 self.named_attributes,
74 ObjectKind::AttributePage,
75 "named attributes",
76 )?;
77 validate_object(self.acl, ObjectKind::Blob, "acl")?;
78 validate_object(
79 self.security_descriptor,
80 ObjectKind::Blob,
81 "security descriptor",
82 )
83 }
84}
85
86pub fn encode_file_metadata(metadata: FileMetadata) -> Result<Vec<u8>, CanonicalDecodeError> {
92 metadata.validate()?;
93 let mut encoder = Encoder::new(DOMAIN, VERSION);
94 encode_u32(&mut encoder, metadata.posix_mode);
95 encode_u32(&mut encoder, metadata.posix_uid);
96 encode_u32(&mut encoder, metadata.posix_gid);
97 encode_u64(&mut encoder, metadata.posix_flags);
98 encode_u32(&mut encoder, metadata.windows_attributes);
99 encode_i64(&mut encoder, metadata.created_ns);
100 encode_i64(&mut encoder, metadata.modified_ns);
101 encode_i64(&mut encoder, metadata.accessed_ns);
102 encode_i64(&mut encoder, metadata.changed_ns);
103 encode_object(&mut encoder, metadata.named_attributes);
104 encode_object(&mut encoder, metadata.acl);
105 encode_object(&mut encoder, metadata.security_descriptor);
106 Ok(encoder.finish())
107}
108
109pub fn decode_file_metadata(
116 bytes: &[u8],
117 limits: DecodeLimits,
118) -> Result<FileMetadata, CanonicalDecodeError> {
119 let mut decoder = Decoder::new(bytes, DOMAIN, VERSION, limits.maximum_object_bytes)?;
120 let metadata = FileMetadata {
121 posix_mode: decode_u32(&mut decoder, "posix_mode")?,
122 posix_uid: decode_u32(&mut decoder, "posix_uid")?,
123 posix_gid: decode_u32(&mut decoder, "posix_gid")?,
124 posix_flags: decode_u64(&mut decoder, "posix_flags")?,
125 windows_attributes: decode_u32(&mut decoder, "windows_attributes")?,
126 created_ns: decode_i64(&mut decoder, "created_ns")?,
127 modified_ns: decode_i64(&mut decoder, "modified_ns")?,
128 accessed_ns: decode_i64(&mut decoder, "accessed_ns")?,
129 changed_ns: decode_i64(&mut decoder, "changed_ns")?,
130 named_attributes: decode_object(
131 &mut decoder,
132 ObjectKind::AttributePage,
133 "named_attributes",
134 )?,
135 acl: decode_object(&mut decoder, ObjectKind::Blob, "acl")?,
136 security_descriptor: decode_object(&mut decoder, ObjectKind::Blob, "security_descriptor")?,
137 };
138 decoder.finish()?;
139 metadata.validate()?;
140 Ok(metadata)
141}
142
143pub fn file_metadata_id(metadata: FileMetadata) -> Result<ObjectId, CanonicalDecodeError> {
149 let bytes = encode_file_metadata(metadata)?;
150 Ok(ObjectId {
151 kind: ObjectKind::Metadata,
152 digest: object_digest(ObjectKind::Metadata, &bytes),
153 })
154}
155
156fn encode_u32(encoder: &mut Encoder, field: MetadataField<u32>) {
157 match field {
158 MetadataField::Unavailable => encoder.u8(0),
159 MetadataField::Value(value) => {
160 encoder.u8(1);
161 encoder.u32(value);
162 }
163 }
164}
165
166fn encode_u64(encoder: &mut Encoder, field: MetadataField<u64>) {
167 match field {
168 MetadataField::Unavailable => encoder.u8(0),
169 MetadataField::Value(value) => {
170 encoder.u8(1);
171 encoder.u64(value);
172 }
173 }
174}
175
176fn encode_i64(encoder: &mut Encoder, field: MetadataField<i64>) {
177 match field {
178 MetadataField::Unavailable => encoder.u8(0),
179 MetadataField::Value(value) => {
180 encoder.u8(1);
181 encoder.i64(value);
182 }
183 }
184}
185
186fn encode_object(encoder: &mut Encoder, field: MetadataField<ObjectId>) {
187 match field {
188 MetadataField::Unavailable => encoder.u8(0),
189 MetadataField::Value(object) => {
190 encoder.u8(1);
191 encoder.fixed(object.digest.as_bytes());
192 }
193 }
194}
195
196fn decode_u32(
197 decoder: &mut Decoder<'_>,
198 field: &'static str,
199) -> Result<MetadataField<u32>, CanonicalDecodeError> {
200 match decoder.u8()? {
201 0 => Ok(MetadataField::Unavailable),
202 1 => Ok(MetadataField::Value(decoder.u32()?)),
203 tag => Err(CanonicalDecodeError::UnknownTag { field, tag }),
204 }
205}
206
207fn decode_u64(
208 decoder: &mut Decoder<'_>,
209 field: &'static str,
210) -> Result<MetadataField<u64>, CanonicalDecodeError> {
211 match decoder.u8()? {
212 0 => Ok(MetadataField::Unavailable),
213 1 => Ok(MetadataField::Value(decoder.u64()?)),
214 tag => Err(CanonicalDecodeError::UnknownTag { field, tag }),
215 }
216}
217
218fn decode_i64(
219 decoder: &mut Decoder<'_>,
220 field: &'static str,
221) -> Result<MetadataField<i64>, CanonicalDecodeError> {
222 match decoder.u8()? {
223 0 => Ok(MetadataField::Unavailable),
224 1 => Ok(MetadataField::Value(decoder.i64()?)),
225 tag => Err(CanonicalDecodeError::UnknownTag { field, tag }),
226 }
227}
228
229fn decode_object(
230 decoder: &mut Decoder<'_>,
231 kind: ObjectKind,
232 field: &'static str,
233) -> Result<MetadataField<ObjectId>, CanonicalDecodeError> {
234 match decoder.u8()? {
235 0 => Ok(MetadataField::Unavailable),
236 1 => Ok(MetadataField::Value(digest_object(kind, decoder.fixed()?))),
237 tag => Err(CanonicalDecodeError::UnknownTag { field, tag }),
238 }
239}
240
241fn validate_object(
242 field: MetadataField<ObjectId>,
243 kind: ObjectKind,
244 name: &'static str,
245) -> Result<(), CanonicalDecodeError> {
246 if let MetadataField::Value(object) = field
247 && object.kind != kind
248 {
249 return Err(CanonicalDecodeError::Invariant(format!(
250 "{name} has the wrong object kind"
251 )));
252 }
253 Ok(())
254}
255
256#[cfg(test)]
257#[path = "tests/metadata.rs"]
258mod tests;