dir.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. use super::file::ClusterReadIterator;
  2. use crate::kernel::constants::EINVAL;
  3. use crate::prelude::*;
  4. use alloc::{string::String, sync::Arc};
  5. use itertools::Itertools;
  6. #[repr(C, packed)]
  7. pub(super) struct RawDirEntry {
  8. name: [u8; 8],
  9. extension: [u8; 3],
  10. attr: u8,
  11. reserved: u8,
  12. create_time_tenth: u8,
  13. create_time: u16,
  14. create_date: u16,
  15. access_date: u16,
  16. cluster_high: u16,
  17. modify_time: u16,
  18. modify_date: u16,
  19. cluster_low: u16,
  20. size: u32,
  21. }
  22. pub(super) struct FatDirectoryEntry {
  23. pub filename: Arc<[u8]>,
  24. pub cluster: u32,
  25. pub size: u32,
  26. pub entry_offset: u32,
  27. pub is_directory: bool,
  28. // TODO:
  29. // create_time: u32,
  30. // modify_time: u32,
  31. }
  32. impl RawDirEntry {
  33. const ATTR_RO: u8 = 0x01;
  34. const ATTR_HIDDEN: u8 = 0x02;
  35. const ATTR_SYSTEM: u8 = 0x04;
  36. const ATTR_VOLUME_ID: u8 = 0x08;
  37. const ATTR_DIRECTORY: u8 = 0x10;
  38. #[allow(dead_code)]
  39. const ATTR_ARCHIVE: u8 = 0x20;
  40. const RESERVED_FILENAME_LOWERCASE: u8 = 0x08;
  41. fn filename(&self) -> &[u8] {
  42. self.name.trim_ascii_end()
  43. }
  44. fn extension(&self) -> &[u8] {
  45. self.extension.trim_ascii_end()
  46. }
  47. fn is_filename_lowercase(&self) -> bool {
  48. self.reserved & Self::RESERVED_FILENAME_LOWERCASE != 0
  49. }
  50. fn is_long_filename(&self) -> bool {
  51. self.attr == (Self::ATTR_RO | Self::ATTR_HIDDEN | Self::ATTR_SYSTEM | Self::ATTR_VOLUME_ID)
  52. }
  53. fn is_volume_id(&self) -> bool {
  54. self.attr & Self::ATTR_VOLUME_ID != 0
  55. }
  56. fn is_free(&self) -> bool {
  57. self.name[0] == 0x00
  58. }
  59. fn is_deleted(&self) -> bool {
  60. self.name[0] == 0xE5
  61. }
  62. fn is_invalid(&self) -> bool {
  63. self.is_volume_id() || self.is_free() || self.is_deleted()
  64. }
  65. fn is_directory(&self) -> bool {
  66. self.attr & Self::ATTR_DIRECTORY != 0
  67. }
  68. fn long_filename(&self) -> Option<[u16; 13]> {
  69. if !self.is_long_filename() {
  70. return None;
  71. }
  72. let mut name = [0; 13];
  73. name[0] = u16::from_le_bytes([self.name[1], self.name[2]]);
  74. name[1] = u16::from_le_bytes([self.name[3], self.name[4]]);
  75. name[2] = u16::from_le_bytes([self.name[5], self.name[6]]);
  76. name[3] = u16::from_le_bytes([self.name[7], self.extension[0]]);
  77. name[4] = u16::from_le_bytes([self.extension[1], self.extension[2]]);
  78. name[5] = self.create_time;
  79. name[6] = self.create_date;
  80. name[7] = self.access_date;
  81. name[8] = self.cluster_high;
  82. name[9] = self.modify_time;
  83. name[10] = self.modify_date;
  84. name[11] = self.size as u16;
  85. name[12] = (self.size >> 16) as u16;
  86. Some(name)
  87. }
  88. }
  89. impl<'data, I> RawDirs<'data> for I where I: ClusterReadIterator<'data> {}
  90. trait RawDirs<'data>: ClusterReadIterator<'data> {
  91. fn raw_dirs(self) -> impl Iterator<Item = KResult<&'data RawDirEntry>> + 'data
  92. where
  93. Self: Sized,
  94. {
  95. const ENTRY_SIZE: usize = size_of::<RawDirEntry>();
  96. self.map(|result| {
  97. let data = result?;
  98. if data.len() % ENTRY_SIZE != 0 {
  99. return Err(EINVAL);
  100. }
  101. Ok(unsafe {
  102. core::slice::from_raw_parts(
  103. data.as_ptr() as *const RawDirEntry,
  104. data.len() / ENTRY_SIZE,
  105. )
  106. })
  107. })
  108. .flatten_ok()
  109. }
  110. }
  111. pub(super) trait Dirs<'data>: ClusterReadIterator<'data> {
  112. fn dirs(self) -> impl Iterator<Item = KResult<FatDirectoryEntry>> + 'data
  113. where
  114. Self: Sized;
  115. }
  116. impl<'data, I> Dirs<'data> for I
  117. where
  118. I: ClusterReadIterator<'data>,
  119. {
  120. fn dirs(self) -> impl Iterator<Item = KResult<FatDirectoryEntry>> + 'data
  121. where
  122. Self: Sized,
  123. {
  124. self.raw_dirs().real_dirs()
  125. }
  126. }
  127. trait RealDirs<'data>: Iterator<Item = KResult<&'data RawDirEntry>> + 'data {
  128. fn real_dirs(self) -> DirsIter<'data, Self>
  129. where
  130. Self: Sized;
  131. }
  132. impl<'data, I> RealDirs<'data> for I
  133. where
  134. I: Iterator<Item = KResult<&'data RawDirEntry>> + 'data,
  135. {
  136. fn real_dirs(self) -> DirsIter<'data, Self>
  137. where
  138. Self: Sized,
  139. {
  140. DirsIter { iter: self }
  141. }
  142. }
  143. pub(super) struct DirsIter<'data, I>
  144. where
  145. I: Iterator<Item = KResult<&'data RawDirEntry>> + 'data,
  146. {
  147. iter: I,
  148. }
  149. impl<'data, I> Iterator for DirsIter<'data, I>
  150. where
  151. I: Iterator<Item = KResult<&'data RawDirEntry>> + 'data,
  152. {
  153. type Item = KResult<FatDirectoryEntry>;
  154. fn next(&mut self) -> Option<Self::Item> {
  155. let mut filename = String::new();
  156. let mut entry_offset = 0;
  157. let entry = loop {
  158. let entry = match self.iter.next()? {
  159. Ok(entry) => entry,
  160. Err(err) => return Some(Err(err)),
  161. };
  162. entry_offset += 1;
  163. let long_filename = entry.long_filename();
  164. if entry.is_invalid() {
  165. if let Some(long_filename) = long_filename {
  166. let long_filename = long_filename
  167. .iter()
  168. .position(|&ch| ch == 0)
  169. .map(|pos| &long_filename[..pos])
  170. .unwrap_or(&long_filename);
  171. filename.extend(
  172. long_filename
  173. .into_iter()
  174. .map(|&ch| char::from_u32(ch as u32).unwrap_or('?'))
  175. .rev(),
  176. );
  177. }
  178. continue;
  179. }
  180. break entry;
  181. };
  182. let filename: Arc<[u8]> = if filename.is_empty() {
  183. let mut filename = entry.filename().to_vec();
  184. let extension = entry.extension();
  185. if !extension.is_empty() {
  186. filename.push(b'.');
  187. filename.extend_from_slice(extension);
  188. }
  189. if entry.is_filename_lowercase() {
  190. filename.make_ascii_lowercase();
  191. }
  192. filename.into()
  193. } else {
  194. let mut bytes = filename.into_bytes();
  195. bytes.reverse();
  196. bytes.into()
  197. };
  198. Some(Ok(FatDirectoryEntry {
  199. size: entry.size,
  200. entry_offset,
  201. filename,
  202. cluster: entry.cluster_low as u32 | (((entry.cluster_high & !0xF000) as u32) << 16),
  203. is_directory: entry.is_directory(),
  204. }))
  205. }
  206. }