xattr.rs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. /// The beginning of an extended attribute block.
  14. #[repr(C)]
  15. #[derive(Debug)]
  16. pub struct XattrHeader {
  17. /// Magic number for identification, 0xEA020000.
  18. magic: u32,
  19. /// Reference count.
  20. refcount: u32,
  21. /// Number of disk blocks used.
  22. blocks: u32,
  23. /// Hash value of all attributes. (UNUSED by now)
  24. hash: u32,
  25. /// Checksum of the extended attribute block.
  26. checksum: u32,
  27. /// Reserved for future use.
  28. reserved: [u32; 3],
  29. }
  30. unsafe impl AsBytes for XattrHeader {}
  31. impl XattrHeader {
  32. const XATTR_MAGIC: u32 = 0xEA020000;
  33. pub fn new() -> Self {
  34. XattrHeader {
  35. magic: Self::XATTR_MAGIC,
  36. refcount: 1,
  37. blocks: 1,
  38. hash: 0,
  39. checksum: 0,
  40. reserved: [0; 3],
  41. }
  42. }
  43. }
  44. /// Following the struct `XattrHeader` is an array of `XattrEntry`.
  45. #[repr(C)]
  46. #[derive(Debug)]
  47. pub struct XattrEntry {
  48. /// Length of name.
  49. name_len: u8,
  50. /// Attribute name index (UNUSED by now)
  51. name_index: u8,
  52. /// Location of this attribute's value on the disk block where
  53. /// it is stored. For a block this value is relative to the start
  54. /// of the block (i.e. the header).
  55. /// value = `block[value_offset..value_offset + value_size]`
  56. value_offset: u16,
  57. /// The inode where the value is stored. Zero indicates the value
  58. /// is in the same block as this entry (FIXED 0 by now)
  59. value_inum: u32,
  60. /// Length of attribute value.
  61. value_size: u32,
  62. /// Hash value of attribute name and attribute value (UNUSED by now)
  63. hash: u32,
  64. /// Attribute name, max 255 bytes.
  65. name: [u8; 255],
  66. }
  67. /// Fake xattr entry. A normal entry without `name` field.
  68. #[repr(C)]
  69. pub struct FakeXattrEntry {
  70. name_len: u8,
  71. name_index: u8,
  72. value_offset: u16,
  73. value_inum: u32,
  74. value_size: u32,
  75. hash: u32,
  76. }
  77. unsafe impl AsBytes for FakeXattrEntry {}
  78. /// The actual size of the extended attribute entry is determined by `name_len`.
  79. /// So we need to implement `AsBytes` methods specifically for `XattrEntry`.
  80. unsafe impl AsBytes for XattrEntry {
  81. fn from_bytes(bytes: &[u8]) -> Self {
  82. let fake_entry = FakeXattrEntry::from_bytes(bytes);
  83. let mut entry = XattrEntry {
  84. name_len: fake_entry.name_len,
  85. name_index: fake_entry.name_index,
  86. value_offset: fake_entry.value_offset,
  87. value_inum: fake_entry.value_inum,
  88. value_size: fake_entry.value_size,
  89. hash: fake_entry.hash,
  90. name: [0; 255],
  91. };
  92. let name_len = entry.name_len as usize;
  93. let name_offset = size_of::<FakeXattrEntry>();
  94. entry.name[..name_len].copy_from_slice(&bytes[name_offset..name_offset + name_len]);
  95. entry
  96. }
  97. fn to_bytes(&self) -> &[u8] {
  98. let name_len = self.name_len as usize;
  99. unsafe {
  100. core::slice::from_raw_parts(
  101. self as *const Self as *const u8,
  102. size_of::<FakeXattrEntry>() + name_len,
  103. )
  104. }
  105. }
  106. }
  107. impl XattrEntry {
  108. /// Create a new xattr entry.
  109. pub fn new(name: &str, value_size: usize, value_offset: usize) -> Self {
  110. let mut name_bytes = [0u8; 255];
  111. let name_len = name.as_bytes().len();
  112. name_bytes[..name_len].copy_from_slice(name.as_bytes());
  113. Self {
  114. name_len: name.len() as u8,
  115. name_index: 0,
  116. value_offset: value_offset as u16,
  117. value_inum: 0,
  118. value_size: value_size as u32,
  119. hash: 0,
  120. name: name_bytes,
  121. }
  122. }
  123. /// Get the required size to save a xattr entry, 4-byte aligned
  124. pub fn required_size(name_len: usize) -> usize {
  125. // u32 + u16 + u8 + Ext4DirEnInner + name -> align to 4
  126. (core::mem::size_of::<FakeXattrEntry>() + name_len + 3) / 4 * 4
  127. }
  128. /// Get the used size of this xattr entry, 4-bytes alighed
  129. pub fn used_size(&self) -> usize {
  130. Self::required_size(self.name_len as usize)
  131. }
  132. }
  133. /// The block that stores extended attributes for an inode. The block is
  134. /// pointed to `by inode.file_acl`.
  135. ///
  136. /// `XattrHeader` is the beginning of an extended attribute block. Following
  137. /// the struct `XattrHeader` is an array of `XattrEntry`. Attribute values
  138. /// follow the end of the entry table. The values are stored starting at the
  139. /// end of the block and grow towards the xattr_header/xattr_entry table. When
  140. /// the two collide, the disk block fills up, and the filesystem returns `ENOSPC`.
  141. pub struct XattrBlock(Block);
  142. impl XattrBlock {
  143. pub fn new(block: Block) -> Self {
  144. XattrBlock(block)
  145. }
  146. pub fn init(&mut self) {
  147. let header = XattrHeader::new();
  148. self.0.write_offset_as(0, &header);
  149. }
  150. pub fn block(self) -> Block {
  151. self.0
  152. }
  153. /// Get a xattr by name, return the value.
  154. pub fn get(&self, name: &str) -> Option<&[u8]> {
  155. let mut entry_start = size_of::<XattrHeader>();
  156. // Iterate over entry table
  157. while entry_start < BLOCK_SIZE {
  158. // Check `name_len`, 0 indicates the end of the entry table.
  159. if self.0.data[entry_start] == 0 {
  160. // Target xattr not found
  161. break;
  162. }
  163. let entry: XattrEntry = self.0.read_offset_as(entry_start);
  164. // Compare name
  165. if name.as_bytes() == &entry.name[..entry.name_len as usize] {
  166. return Some(
  167. &self
  168. .0
  169. .read_offset(entry.value_offset as usize, entry.value_size as usize),
  170. );
  171. }
  172. entry_start += entry.used_size();
  173. }
  174. None
  175. }
  176. /// Insert a xattr entry into the block. Return true if success.
  177. pub fn insert(&mut self, name: &str, value: &[u8]) -> bool {
  178. let mut entry_start = size_of::<XattrHeader>();
  179. let mut value_end = BLOCK_SIZE;
  180. // Iterate over entry table, find the position to insert entry
  181. while entry_start < BLOCK_SIZE {
  182. // Check `name_len`, 0 indicates the end of the entry table.
  183. if self.0.data[entry_start] == 0 {
  184. // Insert to the end of table
  185. break;
  186. }
  187. let entry: XattrEntry = self.0.read_offset_as(entry_start);
  188. entry_start += entry.used_size();
  189. value_end = entry.value_offset as usize;
  190. }
  191. // `[entry_start, value_end)` is the empty space
  192. // Check space
  193. let required_size = XattrEntry::required_size(name.len()) + value.len() + 1;
  194. if value_end - entry_start < required_size {
  195. return false;
  196. }
  197. // Insert entry
  198. let value_offset = value_end - value.len();
  199. let entry = XattrEntry::new(name, value.len(), value_offset);
  200. self.0.write_offset_as(entry_start, &entry);
  201. // Insert value
  202. self.0.write_offset(value_offset, value);
  203. true
  204. }
  205. /// Remove a xattr entry from the block. Return true if success.
  206. pub fn remove(&mut self, name: &str) -> bool {
  207. let mut entry_start = size_of::<XattrHeader>();
  208. // Iterate over entry table, find the position to remove entry
  209. while entry_start < BLOCK_SIZE {
  210. // Check `name_len`, 0 indicates the end of the entry table.
  211. if self.0.data[entry_start] == 0 {
  212. // Target xattr not found
  213. return false;
  214. }
  215. let entry: XattrEntry = self.0.read_offset_as(entry_start);
  216. // Compare name
  217. if name.as_bytes() == &entry.name[..entry.name_len as usize] {
  218. break;
  219. }
  220. entry_start += entry.used_size();
  221. }
  222. // `entry_start` now points to the removed entry.
  223. let removed_entry: XattrEntry = self.0.read_offset_as(entry_start);
  224. let removed_entry_size = removed_entry.used_size();
  225. // `value_end` points to the end of removed value
  226. let mut value_end = removed_entry.value_offset as usize + removed_entry.value_size as usize;
  227. // Move the following entries and values
  228. while entry_start + removed_entry_size < BLOCK_SIZE {
  229. let next_entry_start = entry_start + removed_entry_size;
  230. // Check `name_len`, 0 indicates the end of the entry table.
  231. if self.0.data[next_entry_start] == 0 {
  232. break;
  233. }
  234. // Get the entry to move
  235. let mut next_entry: XattrEntry = self.0.read_offset_as(next_entry_start);
  236. // Get its value
  237. let next_value = self
  238. .0
  239. .read_offset(
  240. next_entry.value_offset as usize,
  241. next_entry.value_size as usize,
  242. )
  243. .to_owned();
  244. // Move the value
  245. let value_offset = value_end - next_value.len();
  246. self.0.write_offset(value_offset, &next_value);
  247. // Update entry
  248. next_entry.value_offset = value_offset as u16;
  249. // Write the entry to block
  250. self.0.write_offset_as(entry_start, &next_entry);
  251. // Update offset
  252. value_end -= next_value.len();
  253. entry_start += next_entry.used_size();
  254. }
  255. // Clear [entry_offset, value_offset)
  256. self.0.data[entry_start..value_end].fill(0);
  257. true
  258. }
  259. }