1use alloc::{collections::BTreeMap, string::String, vec::Vec};
12
13#[cfg(not(target_arch = "aarch64"))]
14use spin::RwLock;
15
16#[cfg(target_arch = "aarch64")]
17use super::bare_lock::RwLock;
18use crate::error::{FsError, KernelError};
19
20pub const XATTR_MAX_VALUE_SIZE: usize = 65536;
26
27pub const XATTR_MAX_ATTRS_PER_INODE: usize = 256;
29
30pub const XATTR_MAX_NAME_LEN: usize = 255;
32
33pub const XATTR_CREATE: u32 = 1;
35
36pub const XATTR_REPLACE: u32 = 2;
38
39struct XattrStore {
50 attrs: BTreeMap<u64, BTreeMap<String, Vec<u8>>>,
52}
53
54impl XattrStore {
55 const fn new() -> Self {
56 Self {
57 attrs: BTreeMap::new(),
58 }
59 }
60}
61
62static XATTR_STORE: RwLock<XattrStore> = RwLock::new(XattrStore::new());
64
65const VALID_NAMESPACES: &[&str] = &["user.", "system."];
71
72fn validate_name(name: &str) -> Result<(), KernelError> {
75 if name.is_empty() {
76 return Err(KernelError::InvalidArgument {
77 name: "xattr_name",
78 value: "empty name",
79 });
80 }
81
82 if name.len() > XATTR_MAX_NAME_LEN {
83 return Err(KernelError::InvalidArgument {
84 name: "xattr_name",
85 value: "name too long",
86 });
87 }
88
89 for ns in VALID_NAMESPACES {
90 if name.starts_with(ns) {
91 if name.len() == ns.len() {
93 return Err(KernelError::InvalidArgument {
94 name: "xattr_name",
95 value: "empty attribute after namespace",
96 });
97 }
98 return Ok(());
99 }
100 }
101
102 Err(KernelError::InvalidArgument {
103 name: "xattr_name",
104 value: "unsupported namespace",
105 })
106}
107
108pub fn getxattr(inode: u64, name: &str) -> Result<Vec<u8>, KernelError> {
117 validate_name(name)?;
118
119 let store = XATTR_STORE.read();
120 let inode_attrs = store
121 .attrs
122 .get(&inode)
123 .ok_or(KernelError::FsError(FsError::NotFound))?;
124
125 inode_attrs
126 .get(name)
127 .cloned()
128 .ok_or(KernelError::FsError(FsError::NotFound))
129}
130
131pub fn setxattr(inode: u64, name: &str, value: &[u8], flags: u32) -> Result<(), KernelError> {
144 validate_name(name)?;
145
146 if value.len() > XATTR_MAX_VALUE_SIZE {
147 return Err(KernelError::InvalidArgument {
148 name: "xattr_value",
149 value: "value too large",
150 });
151 }
152
153 let mut store = XATTR_STORE.write();
154 let inode_attrs = store.attrs.entry(inode).or_default();
155
156 let exists = inode_attrs.contains_key(name);
157
158 if flags & XATTR_CREATE != 0 && exists {
160 return Err(KernelError::FsError(FsError::AlreadyExists));
161 }
162 if flags & XATTR_REPLACE != 0 && !exists {
163 return Err(KernelError::FsError(FsError::NotFound));
164 }
165
166 if !exists && inode_attrs.len() >= XATTR_MAX_ATTRS_PER_INODE {
168 return Err(KernelError::ResourceExhausted {
169 resource: "xattr slots",
170 });
171 }
172
173 inode_attrs.insert(String::from(name), Vec::from(value));
174 Ok(())
175}
176
177pub fn listxattr(inode: u64) -> Result<Vec<String>, KernelError> {
181 let store = XATTR_STORE.read();
182 match store.attrs.get(&inode) {
183 Some(inode_attrs) => Ok(inode_attrs.keys().cloned().collect()),
184 None => Ok(Vec::new()),
185 }
186}
187
188pub fn removexattr(inode: u64, name: &str) -> Result<(), KernelError> {
192 validate_name(name)?;
193
194 let mut store = XATTR_STORE.write();
195 let inode_attrs = store
196 .attrs
197 .get_mut(&inode)
198 .ok_or(KernelError::FsError(FsError::NotFound))?;
199
200 if inode_attrs.remove(name).is_none() {
201 return Err(KernelError::FsError(FsError::NotFound));
202 }
203
204 if inode_attrs.is_empty() {
206 store.attrs.remove(&inode);
207 }
208
209 Ok(())
210}
211
212pub fn cleanup_inode_xattrs(inode: u64) {
217 let mut store = XATTR_STORE.write();
218 store.attrs.remove(&inode);
219}
220
221pub fn count_xattrs(inode: u64) -> usize {
225 let store = XATTR_STORE.read();
226 store.attrs.get(&inode).map_or(0, BTreeMap::len)
227}
228
229#[cfg(test)]
234mod tests {
235 #[allow(unused_imports)]
236 use alloc::vec;
237
238 use super::*;
239
240 const BASE_INODE: u64 = 0xFFFF_0000;
243
244 #[test]
247 fn test_validate_name_user_ns() {
248 assert!(validate_name("user.mime_type").is_ok());
249 }
250
251 #[test]
252 fn test_validate_name_system_ns() {
253 assert!(validate_name("system.selinux").is_ok());
254 }
255
256 #[test]
257 fn test_validate_name_bad_ns() {
258 assert!(validate_name("trusted.key").is_err());
259 assert!(validate_name("security.ima").is_err());
260 }
261
262 #[test]
263 fn test_validate_name_empty() {
264 assert!(validate_name("").is_err());
265 }
266
267 #[test]
268 fn test_validate_name_no_attr_after_ns() {
269 assert!(validate_name("user.").is_err());
270 assert!(validate_name("system.").is_err());
271 }
272
273 #[test]
274 fn test_validate_name_too_long() {
275 let long_name = alloc::format!("user.{}", "a".repeat(XATTR_MAX_NAME_LEN));
276 assert!(validate_name(&long_name).is_err());
277 }
278
279 #[test]
282 fn test_set_and_get() {
283 let inode = BASE_INODE + 1;
284 cleanup_inode_xattrs(inode);
286
287 setxattr(inode, "user.color", b"blue", 0).unwrap();
288 let val = getxattr(inode, "user.color").unwrap();
289 assert_eq!(val, b"blue");
290
291 cleanup_inode_xattrs(inode);
292 }
293
294 #[test]
295 fn test_set_replaces_existing() {
296 let inode = BASE_INODE + 2;
297 cleanup_inode_xattrs(inode);
298
299 setxattr(inode, "user.key", b"v1", 0).unwrap();
300 setxattr(inode, "user.key", b"v2", 0).unwrap();
301 assert_eq!(getxattr(inode, "user.key").unwrap(), b"v2");
302
303 cleanup_inode_xattrs(inode);
304 }
305
306 #[test]
307 fn test_set_create_flag_rejects_existing() {
308 let inode = BASE_INODE + 3;
309 cleanup_inode_xattrs(inode);
310
311 setxattr(inode, "user.key", b"v1", 0).unwrap();
312 let result = setxattr(inode, "user.key", b"v2", XATTR_CREATE);
313 assert_eq!(
314 result.unwrap_err(),
315 KernelError::FsError(FsError::AlreadyExists)
316 );
317
318 cleanup_inode_xattrs(inode);
319 }
320
321 #[test]
322 fn test_set_replace_flag_rejects_new() {
323 let inode = BASE_INODE + 4;
324 cleanup_inode_xattrs(inode);
325
326 let result = setxattr(inode, "user.key", b"v1", XATTR_REPLACE);
327 assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NotFound));
328
329 cleanup_inode_xattrs(inode);
330 }
331
332 #[test]
333 fn test_set_value_too_large() {
334 let inode = BASE_INODE + 5;
335 cleanup_inode_xattrs(inode);
336
337 let big = vec![0u8; XATTR_MAX_VALUE_SIZE + 1];
338 let result = setxattr(inode, "user.big", &big, 0);
339 assert!(result.is_err());
340
341 cleanup_inode_xattrs(inode);
342 }
343
344 #[test]
345 fn test_set_max_attrs_per_inode() {
346 let inode = BASE_INODE + 6;
347 cleanup_inode_xattrs(inode);
348
349 for i in 0..XATTR_MAX_ATTRS_PER_INODE {
350 let name = alloc::format!("user.attr{}", i);
351 setxattr(inode, &name, b"x", 0).unwrap();
352 }
353
354 let result = setxattr(inode, "user.overflow", b"x", 0);
356 assert_eq!(
357 result.unwrap_err(),
358 KernelError::ResourceExhausted {
359 resource: "xattr slots",
360 }
361 );
362
363 cleanup_inode_xattrs(inode);
364 }
365
366 #[test]
367 fn test_set_invalid_namespace() {
368 let inode = BASE_INODE + 7;
369 let result = setxattr(inode, "trusted.secret", b"val", 0);
370 assert!(result.is_err());
371 }
372
373 #[test]
376 fn test_get_nonexistent_inode() {
377 let inode = BASE_INODE + 8;
378 cleanup_inode_xattrs(inode);
379
380 let result = getxattr(inode, "user.nope");
381 assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NotFound));
382 }
383
384 #[test]
385 fn test_get_nonexistent_attr() {
386 let inode = BASE_INODE + 9;
387 cleanup_inode_xattrs(inode);
388
389 setxattr(inode, "user.exists", b"yes", 0).unwrap();
390 let result = getxattr(inode, "user.missing");
391 assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NotFound));
392
393 cleanup_inode_xattrs(inode);
394 }
395
396 #[test]
399 fn test_list_empty() {
400 let inode = BASE_INODE + 10;
401 cleanup_inode_xattrs(inode);
402
403 let names = listxattr(inode).unwrap();
404 assert!(names.is_empty());
405 }
406
407 #[test]
408 fn test_list_multiple() {
409 let inode = BASE_INODE + 11;
410 cleanup_inode_xattrs(inode);
411
412 setxattr(inode, "user.a", b"1", 0).unwrap();
413 setxattr(inode, "system.b", b"2", 0).unwrap();
414 setxattr(inode, "user.c", b"3", 0).unwrap();
415
416 let mut names = listxattr(inode).unwrap();
417 names.sort();
418 assert_eq!(names.len(), 3);
419 assert_eq!(names[0], "system.b");
420 assert_eq!(names[1], "user.a");
421 assert_eq!(names[2], "user.c");
422
423 cleanup_inode_xattrs(inode);
424 }
425
426 #[test]
429 fn test_remove() {
430 let inode = BASE_INODE + 12;
431 cleanup_inode_xattrs(inode);
432
433 setxattr(inode, "user.del", b"bye", 0).unwrap();
434 removexattr(inode, "user.del").unwrap();
435
436 let result = getxattr(inode, "user.del");
437 assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NotFound));
438 }
439
440 #[test]
441 fn test_remove_nonexistent() {
442 let inode = BASE_INODE + 13;
443 cleanup_inode_xattrs(inode);
444
445 let result = removexattr(inode, "user.ghost");
446 assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NotFound));
447 }
448
449 #[test]
450 fn test_remove_cleans_inode_entry() {
451 let inode = BASE_INODE + 14;
452 cleanup_inode_xattrs(inode);
453
454 setxattr(inode, "user.only", b"val", 0).unwrap();
455 removexattr(inode, "user.only").unwrap();
456
457 let names = listxattr(inode).unwrap();
460 assert!(names.is_empty());
461 }
462
463 #[test]
466 fn test_cleanup() {
467 let inode = BASE_INODE + 15;
468 cleanup_inode_xattrs(inode);
469
470 setxattr(inode, "user.a", b"1", 0).unwrap();
471 setxattr(inode, "user.b", b"2", 0).unwrap();
472 assert_eq!(count_xattrs(inode), 2);
473
474 cleanup_inode_xattrs(inode);
475 assert_eq!(count_xattrs(inode), 0);
476 }
477
478 #[test]
481 fn test_count() {
482 let inode = BASE_INODE + 16;
483 cleanup_inode_xattrs(inode);
484
485 assert_eq!(count_xattrs(inode), 0);
486 setxattr(inode, "user.x", b"val", 0).unwrap();
487 assert_eq!(count_xattrs(inode), 1);
488 setxattr(inode, "system.y", b"val", 0).unwrap();
489 assert_eq!(count_xattrs(inode), 2);
490
491 cleanup_inode_xattrs(inode);
492 }
493
494 #[test]
497 fn test_empty_value() {
498 let inode = BASE_INODE + 17;
499 cleanup_inode_xattrs(inode);
500
501 setxattr(inode, "user.empty", b"", 0).unwrap();
502 let val = getxattr(inode, "user.empty").unwrap();
503 assert!(val.is_empty());
504
505 cleanup_inode_xattrs(inode);
506 }
507
508 #[test]
509 fn test_max_value_size() {
510 let inode = BASE_INODE + 18;
511 cleanup_inode_xattrs(inode);
512
513 let data = vec![0xABu8; XATTR_MAX_VALUE_SIZE];
514 setxattr(inode, "user.big", &data, 0).unwrap();
515 let val = getxattr(inode, "user.big").unwrap();
516 assert_eq!(val.len(), XATTR_MAX_VALUE_SIZE);
517
518 cleanup_inode_xattrs(inode);
519 }
520
521 #[test]
522 fn test_binary_value() {
523 let inode = BASE_INODE + 19;
524 cleanup_inode_xattrs(inode);
525
526 let binary: Vec<u8> = (0..=255u8).collect();
527 setxattr(inode, "user.bin", &binary, 0).unwrap();
528 assert_eq!(getxattr(inode, "user.bin").unwrap(), binary);
529
530 cleanup_inode_xattrs(inode);
531 }
532
533 #[test]
534 fn test_replace_flag_succeeds_on_existing() {
535 let inode = BASE_INODE + 20;
536 cleanup_inode_xattrs(inode);
537
538 setxattr(inode, "user.key", b"old", 0).unwrap();
539 setxattr(inode, "user.key", b"new", XATTR_REPLACE).unwrap();
540 assert_eq!(getxattr(inode, "user.key").unwrap(), b"new");
541
542 cleanup_inode_xattrs(inode);
543 }
544
545 #[test]
546 fn test_create_flag_succeeds_on_new() {
547 let inode = BASE_INODE + 21;
548 cleanup_inode_xattrs(inode);
549
550 setxattr(inode, "user.fresh", b"val", XATTR_CREATE).unwrap();
551 assert_eq!(getxattr(inode, "user.fresh").unwrap(), b"val");
552
553 cleanup_inode_xattrs(inode);
554 }
555
556 #[test]
557 fn test_multiple_inodes_isolated() {
558 let inode_a = BASE_INODE + 22;
559 let inode_b = BASE_INODE + 23;
560 cleanup_inode_xattrs(inode_a);
561 cleanup_inode_xattrs(inode_b);
562
563 setxattr(inode_a, "user.key", b"from_a", 0).unwrap();
564 setxattr(inode_b, "user.key", b"from_b", 0).unwrap();
565
566 assert_eq!(getxattr(inode_a, "user.key").unwrap(), b"from_a");
567 assert_eq!(getxattr(inode_b, "user.key").unwrap(), b"from_b");
568
569 cleanup_inode_xattrs(inode_a);
570 cleanup_inode_xattrs(inode_b);
571 }
572}