xattr.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. //! Extended attributes (xattrs) are typically stored in a separate data block
  2. //! on the disk and referenced from inodes via `inode.file_acl*`.
  3. //!
  4. //! There are two places where extended attributes can be found. The first place
  5. //! is between the end of each inode entry and the beginning of the next inode
  6. //! entry. The second place where extended attributes can be found is in the block
  7. //! pointed to by `inode.file_acl`.
  8. //!
  9. //! We only implement the seperate data block storage of extended attributes.
  10. use super::{AsBytes, Block};
  11. use crate::constants::*;
  12. use crate::prelude::*;
  13. use core::cmp::Ordering;
  14. /// The beginning of an extended attribute block.
  15. #[repr(C)]
  16. #[derive(Debug)]
  17. pub struct XattrHeader {
  18. /// Magic number for identification, 0xEA020000.
  19. magic: u32,
  20. /// Reference count.
  21. refcount: u32,
  22. /// Number of disk blocks used.
  23. blocks: u32,
  24. /// Hash value of all attributes. (UNUSED by now)
  25. hash: u32,
  26. /// Checksum of the extended attribute block.
  27. checksum: u32,
  28. /// Reserved for future use.
  29. reserved: [u32; 3],
  30. }
  31. unsafe impl AsBytes for XattrHeader {}
  32. impl XattrHeader {
  33. const XATTR_MAGIC: u32 = 0xEA020000;
  34. pub fn new() -> Self {
  35. XattrHeader {
  36. magic: Self::XATTR_MAGIC,
  37. refcount: 1,
  38. blocks: 1,
  39. hash: 0,
  40. checksum: 0,
  41. reserved: [0; 3],
  42. }
  43. }
  44. }
  45. /// Following the struct `XattrHeader` is an array of `XattrEntry`.
  46. #[repr(C)]
  47. #[derive(Debug)]
  48. pub struct XattrEntry {
  49. /// Length of name.
  50. name_len: u8,
  51. /// Attribute name index.
  52. ///
  53. /// To reduce the amount of on-disk space that the keys consume, the
  54. /// beginningof the key string is matched against the attribute name
  55. /// index. If a match is found, the attribute name index field is set,
  56. /// and matching string is removed from the key name.
  57. name_index: u8,
  58. /// Location of this attribute's value on the disk block where
  59. /// it is stored. For a block this value is relative to the start
  60. /// of the block (i.e. the header).
  61. /// value = `block[value_offset..value_offset + value_size]`
  62. value_offset: u16,
  63. /// The inode where the value is stored. Zero indicates the value
  64. /// is in the same block as this entry (FIXED 0 by now)
  65. value_inum: u32,
  66. /// Length of attribute value.
  67. value_size: u32,
  68. /// Hash value of attribute name and attribute value (UNUSED by now)
  69. hash: u32,
  70. /// Attribute name, max 255 bytes.
  71. name: [u8; 255],
  72. }
  73. /// Fake xattr entry. A normal entry without `name` field.
  74. #[repr(C)]
  75. pub struct FakeXattrEntry {
  76. name_len: u8,
  77. name_index: u8,
  78. value_offset: u16,
  79. value_inum: u32,
  80. value_size: u32,
  81. hash: u32,
  82. }
  83. unsafe impl AsBytes for FakeXattrEntry {}
  84. /// The actual size of the extended attribute entry is determined by `name_len`.
  85. /// So we need to implement `AsBytes` methods specifically for `XattrEntry`.
  86. unsafe impl AsBytes for XattrEntry {
  87. fn from_bytes(bytes: &[u8]) -> Self {
  88. let fake_entry = FakeXattrEntry::from_bytes(bytes);
  89. let mut entry = XattrEntry {
  90. name_len: fake_entry.name_len,
  91. name_index: fake_entry.name_index,
  92. value_offset: fake_entry.value_offset,
  93. value_inum: fake_entry.value_inum,
  94. value_size: fake_entry.value_size,
  95. hash: fake_entry.hash,
  96. name: [0; 255],
  97. };
  98. let name_len = entry.name_len as usize;
  99. let name_offset = size_of::<FakeXattrEntry>();
  100. entry.name[..name_len].copy_from_slice(&bytes[name_offset..name_offset + name_len]);
  101. entry
  102. }
  103. fn to_bytes(&self) -> &[u8] {
  104. let name_len = self.name_len as usize;
  105. unsafe {
  106. core::slice::from_raw_parts(
  107. self as *const Self as *const u8,
  108. size_of::<FakeXattrEntry>() + name_len,
  109. )
  110. }
  111. }
  112. }
  113. impl XattrEntry {
  114. /// Create a new xattr entry.
  115. pub fn new(name: &str, value_size: usize, value_offset: usize) -> Self {
  116. let mut name_bytes = [0u8; 255];
  117. let (name_index, name) = Self::match_name(name);
  118. let name_len = name.as_bytes().len();
  119. name_bytes[..name_len].copy_from_slice(name.as_bytes());
  120. Self {
  121. name_len: name.len() as u8,
  122. name_index,
  123. value_offset: value_offset as u16,
  124. value_inum: 0,
  125. value_size: value_size as u32,
  126. hash: 0,
  127. name: name_bytes,
  128. }
  129. }
  130. /// Get the name of the xattr entry
  131. pub fn name(&self) -> String {
  132. let prefix = match self.name_index {
  133. 1 => "user.",
  134. 2 => "system.posix_acl_access.",
  135. 3 => "system.posix_acl_default.",
  136. 4 => "trusted.",
  137. 6 => "security.",
  138. 7 => "system.",
  139. _ => "",
  140. };
  141. let name_bytes = &self.name[..self.name_len as usize];
  142. let name = unsafe { String::from_utf8_unchecked(name_bytes.to_vec()) };
  143. prefix.to_string() + &name
  144. }
  145. /// Get the required size to save a xattr entry, 4-byte aligned
  146. pub fn required_size(name: &str) -> usize {
  147. let (_, name) = Self::match_name(name);
  148. let name_len = name.len();
  149. // FakeXattrEntry + name -> align to 4
  150. (core::mem::size_of::<FakeXattrEntry>() + name_len + 3) / 4 * 4
  151. }
  152. /// Get the used size of this xattr entry, 4-bytes alighed
  153. pub fn used_size(&self) -> usize {
  154. (core::mem::size_of::<FakeXattrEntry>() + self.name_len as usize + 3) / 4 * 4
  155. }
  156. /// Compare the name of the xattr entry with a given name
  157. pub fn compare_name(&self, name: &str) -> Ordering {
  158. let (name_index, name) = Self::match_name(name);
  159. match self.name_index.cmp(&name_index) {
  160. Ordering::Equal => {}
  161. ordering => return ordering,
  162. };
  163. match self.name_len.cmp(&(name.len() as u8)) {
  164. Ordering::Equal => {}
  165. ordering => return ordering,
  166. }
  167. self.name[..self.name_len as usize].cmp(name.as_bytes())
  168. }
  169. /// Match the attribute name prefix to get name index. If one is found,
  170. /// return the name index and the string with the prefix removed.
  171. fn match_name(name: &str) -> (u8, &str) {
  172. let prefixes = [
  173. ("user.", 1),
  174. ("system.posix_acl_access.", 2),
  175. ("system.posix_acl_default.", 3),
  176. ("trusted.", 4),
  177. ("security.", 6),
  178. ("system.", 7),
  179. ];
  180. for (prefix, index) in prefixes {
  181. if name.starts_with(prefix) {
  182. return (index, &name[prefix.len()..]);
  183. }
  184. }
  185. (0, name)
  186. }
  187. }
  188. /// The block that stores extended attributes for an inode. The block is
  189. /// pointed to `by inode.file_acl`.
  190. ///
  191. /// `XattrHeader` is the beginning of an extended attribute block. Following
  192. /// the struct `XattrHeader` is an array of `XattrEntry`. Attribute values
  193. /// follow the end of the entry table. The values are stored starting at the
  194. /// end of the block and grow towards the xattr_header/xattr_entry table. When
  195. /// the two collide, the disk block fills up, and the filesystem returns `ENOSPC`.
  196. pub struct XattrBlock(Block);
  197. impl XattrBlock {
  198. /// Wrap a data block as `XattrBlock`.
  199. pub fn new(block: Block) -> Self {
  200. XattrBlock(block)
  201. }
  202. /// Get the wrapped block.
  203. pub fn block(self) -> Block {
  204. self.0
  205. }
  206. /// Initialize a xattr block, write a `XattrHeader` to the
  207. /// beginning of the block.
  208. pub fn init(&mut self) {
  209. let header = XattrHeader::new();
  210. self.0.write_offset_as(0, &header);
  211. }
  212. /// Get a xattr by name, return the value.
  213. pub fn get(&self, name: &str) -> Option<&[u8]> {
  214. let mut entry_start = size_of::<XattrHeader>();
  215. // Iterate over entry table
  216. while entry_start < BLOCK_SIZE {
  217. // Check `name_len`, 0 indicates the end of the entry table.
  218. if self.0.data[entry_start] == 0 {
  219. // Target xattr not found
  220. break;
  221. }
  222. let entry: XattrEntry = self.0.read_offset_as(entry_start);
  223. if entry.compare_name(name).is_eq() {
  224. let offset = entry.value_offset as usize;
  225. let size = entry.value_size as usize;
  226. return Some(&self.0.data[offset..offset + size]);
  227. }
  228. entry_start += entry.used_size();
  229. }
  230. None
  231. }
  232. /// List all xattr names
  233. pub fn list(&self) -> Vec<String> {
  234. let mut entry_start = size_of::<XattrHeader>();
  235. let mut names = Vec::new();
  236. // Iterate over entry table
  237. while entry_start < BLOCK_SIZE {
  238. // Check `name_len`, 0 indicates the end of the entry table.
  239. if self.0.data[entry_start] == 0 {
  240. break;
  241. }
  242. let entry: XattrEntry = self.0.read_offset_as(entry_start);
  243. names.push(entry.name());
  244. entry_start += entry.used_size();
  245. }
  246. names
  247. }
  248. /// Insert a xattr entry into the block. Return true if success.
  249. pub fn insert(&mut self, name: &str, value: &[u8]) -> bool {
  250. let mut p_entry = size_of::<XattrHeader>();
  251. let mut p_value = BLOCK_SIZE;
  252. let mut is_ins_pos_found = false;
  253. let mut ins_entry_pos = p_entry;
  254. let mut ins_value_pos = p_value;
  255. let ins_entry_size = XattrEntry::required_size(name);
  256. let ins_value_size = value.len();
  257. // Iterate over entry table, find the position to insert entry
  258. // and the end of entry table
  259. while p_entry < BLOCK_SIZE {
  260. // Check `name_len`, 0 indicates the end of the entry table.
  261. if self.0.data[p_entry] == 0 {
  262. // Reach the end of table
  263. break;
  264. }
  265. let entry: XattrEntry = self.0.read_offset_as(p_entry);
  266. if !is_ins_pos_found && entry.compare_name(name).is_gt() {
  267. // Insert before this entry
  268. ins_entry_pos = p_entry;
  269. ins_value_pos = p_value;
  270. is_ins_pos_found = true;
  271. }
  272. p_value = entry.value_offset as usize;
  273. p_entry += entry.used_size();
  274. }
  275. if !is_ins_pos_found {
  276. // Insert at the end of table
  277. ins_entry_pos = p_entry;
  278. ins_value_pos = p_value;
  279. }
  280. // `ins_entry_pos` points to the position to insert entry,
  281. // `ins_value_pos - ins_value_size` points to the position to insert value.
  282. // `p_entry` points to the start of blank area,
  283. // `p_value` points to the last value,
  284. // `[p_entry, p_value)` is the blank area.
  285. // Check space, '+1' is reserved for blank area
  286. if p_value - p_entry < ins_entry_size + ins_value_size + 1 {
  287. // Not enough space
  288. return false;
  289. }
  290. // Move the entries from `ins_entry_pos` to `p_entry`
  291. // Copy `[ins_entry_pos, p_entry)` to `[ins_entry_pos+ins_entry_size, p_entry+ins_entry_size)`
  292. self.0
  293. .data
  294. .copy_within(ins_entry_pos..p_entry, ins_entry_pos + ins_entry_size);
  295. // Set `[ins_entry_pos..ins_entry_pos+entry_req_size)` to 0
  296. self.0.data[ins_entry_pos..ins_entry_pos + ins_entry_size].fill(0);
  297. // Move the corresponding values
  298. // Copy `[p_value, ins_value_pos)` to `[p_value-ins_value_size, ins_value_pos-ins_value_size)`
  299. self.0
  300. .data
  301. .copy_within(p_value..ins_value_pos, p_value - ins_value_size);
  302. // Set `[ins_value_pos-ins_value_size, ins_value_pos)` to 0
  303. self.0.data[ins_value_pos - ins_value_size..ins_value_pos].fill(0);
  304. // Update the value offset of the moved entries
  305. let mut p_entry2 = ins_entry_pos + ins_entry_size;
  306. while p_entry2 < p_entry + ins_entry_size {
  307. let mut entry: XattrEntry = self.0.read_offset_as(p_entry2);
  308. entry.value_offset -= ins_value_size as u16;
  309. self.0.write_offset_as(p_entry2, &entry);
  310. p_entry2 += entry.used_size();
  311. }
  312. // Insert entry to `[ins_entry_pos, ins_entry_pos+ins_entry_size)`
  313. let entry = XattrEntry::new(name, value.len(), ins_value_pos - ins_value_size);
  314. self.0.write_offset_as(ins_entry_pos, &entry);
  315. // Insert value to `[ins_value_pos-ins_value_size, ins_value_pos)`
  316. self.0.write_offset(ins_value_pos - ins_value_size, value);
  317. true
  318. }
  319. /// Remove a xattr entry from the block. Return true if success.
  320. pub fn remove(&mut self, name: &str) -> bool {
  321. let mut p_entry = size_of::<XattrHeader>();
  322. let mut p_value = BLOCK_SIZE;
  323. let mut is_rem_pos_found = false;
  324. let mut rem_entry_pos = p_entry;
  325. let mut rem_value_pos = p_value;
  326. let mut rem_entry_size = 0;
  327. let mut rem_value_size = 0;
  328. // Iterate over entry table, find the entry to remove
  329. while p_entry < BLOCK_SIZE {
  330. // Check `name_len`, 0 indicates the end of the entry table.
  331. if self.0.data[p_entry] == 0 {
  332. break;
  333. }
  334. let entry: XattrEntry = self.0.read_offset_as(p_entry);
  335. p_value = entry.value_offset as usize;
  336. // Compare name
  337. if !is_rem_pos_found && entry.compare_name(name).is_eq() {
  338. rem_entry_pos = p_entry;
  339. rem_value_pos = p_value;
  340. rem_entry_size = entry.used_size();
  341. rem_value_size = entry.value_size as usize;
  342. is_rem_pos_found = true;
  343. }
  344. p_entry += entry.used_size();
  345. }
  346. if !is_rem_pos_found {
  347. return false;
  348. }
  349. // `rem_entry_pos` points to the entry to remove,
  350. // `rem_value_pos` points to the value to remove.
  351. // `p_entry` points to the start of blank area,
  352. // `p_value` points to the last value,
  353. // `[p_entry, p_value)` is the blank area.
  354. // Move the following entries
  355. // Copy `[rem_entry_pos + rem_entry_size, p_entry)` to `[rem_entry_pos, p_entry - rem_entry_size)`
  356. self.0
  357. .data
  358. .copy_within(rem_entry_pos + rem_entry_size..p_entry, rem_entry_pos);
  359. // Set `[p_entry - rem_entry_size, p_entry)` to 0
  360. self.0.data[p_entry - rem_entry_size..p_entry].fill(0);
  361. // Move the corresponding values
  362. // Copy `[p_value, rem_value_pos)` to `[p_value + rem_value_size, rem_value_pos + rem_value_size)`
  363. self.0.data.copy_within(
  364. p_value..rem_value_pos,
  365. p_value + rem_value_size,
  366. );
  367. // Set `[p_value, p_value + rem_value_size)` to 0
  368. self.0.data[p_value..p_value + rem_value_size].fill(0);
  369. // Update the value offset of the moved entries
  370. let mut p_entry2 = rem_entry_pos;
  371. while p_entry2 < p_entry - rem_entry_size {
  372. let mut entry: XattrEntry = self.0.read_offset_as(p_entry2);
  373. entry.value_offset += rem_value_size as u16;
  374. self.0.write_offset_as(p_entry2, &entry);
  375. p_entry2 += entry.used_size();
  376. }
  377. true
  378. }
  379. }