1use std::path::Path;
2
3use crate::error::{Error, Result};
4use crate::namespace::MapEntry;
5
6pub fn parse_id_map(content: &str) -> Result<Vec<MapEntry>> {
9 let mut entries = Vec::new();
10
11 for line in content.lines() {
12 let line = line.trim();
13 if line.is_empty() {
14 continue;
15 }
16
17 let parts: Vec<&str> = line.split_whitespace().collect();
18 if parts.len() != 3 {
19 continue; }
21
22 let inside_start: u32 = parts[0].parse().map_err(|_| {
23 Error::NamespaceParseError(Path::new("/proc/self/uid_map").to_path_buf())
24 })?;
25 let outside_start: u32 = parts[1].parse().map_err(|_| {
26 Error::NamespaceParseError(Path::new("/proc/self/uid_map").to_path_buf())
27 })?;
28 let count: u32 = parts[2].parse().map_err(|_| {
29 Error::NamespaceParseError(Path::new("/proc/self/uid_map").to_path_buf())
30 })?;
31
32 entries.push(MapEntry::new(inside_start, outside_start, count));
33 }
34
35 Ok(entries)
36}
37
38pub fn current_uid_map() -> Result<Vec<MapEntry>> {
40 let path = Path::new("/proc/self/uid_map");
41 let content = std::fs::read_to_string(path).map_err(|e| Error::Io {
42 path: path.to_path_buf(),
43 source: e,
44 })?;
45 parse_id_map(&content)
46}
47
48pub fn current_gid_map() -> Result<Vec<MapEntry>> {
50 let path = Path::new("/proc/self/gid_map");
51 let content = std::fs::read_to_string(path).map_err(|e| Error::Io {
52 path: path.to_path_buf(),
53 source: e,
54 })?;
55 parse_id_map(&content)
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn test_parse_identity_mapping() {
64 let content = " 0 0 4294967295\n";
66 let entries = parse_id_map(content).unwrap();
67 assert_eq!(entries.len(), 1);
68 assert_eq!(entries[0].inside_start, 0);
69 assert_eq!(entries[0].outside_start, 0);
70 assert_eq!(entries[0].count, 4294967295);
71 }
72
73 #[test]
74 fn test_parse_podman_mapping() {
75 let content = " 0 1000 1\n 1 100000 65536\n";
77 let entries = parse_id_map(content).unwrap();
78 assert_eq!(entries.len(), 2);
79
80 assert_eq!(entries[0].inside_start, 0);
81 assert_eq!(entries[0].outside_start, 1000);
82 assert_eq!(entries[0].count, 1);
83
84 assert_eq!(entries[1].inside_start, 1);
85 assert_eq!(entries[1].outside_start, 100000);
86 assert_eq!(entries[1].count, 65536);
87 }
88
89 #[test]
90 fn test_parse_empty() {
91 let entries = parse_id_map("").unwrap();
92 assert!(entries.is_empty());
93 }
94
95 #[test]
96 fn test_parse_whitespace_only() {
97 let entries = parse_id_map(" \n\n \n").unwrap();
98 assert!(entries.is_empty());
99 }
100
101 #[test]
102 fn test_parse_multiple_ranges() {
103 let content = "0 1000 1\n1 100000 10000\n10001 200000 50000\n";
104 let entries = parse_id_map(content).unwrap();
105 assert_eq!(entries.len(), 3);
106 }
107}