You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

515 lines
14KB

  1. // Copyright 2011 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // Provides minimal support for reading a FAT16/FAT32 file system. Limitations:
  19. // - Read-only.
  20. // - The API only exposes the root directory ; though there's a hacky way of
  21. // reading other directories through manipulation of the not-so-opaque handle.
  22. // - Files must be represented by a 83 name when loaded. This is not a big
  23. // problem since this code will be used to open only one pre-determined file
  24. // anyway.
  25. //
  26. // The safe template parameter enables:
  27. // - More error checking of arguments / call sequences.
  28. // - Concurrent read/write/enumeration of several files/directories.
  29. #ifndef AVRLIBX_FILESYSTEM_FAT_FILE_READER_H_
  30. #define AVRLIBX_FILESYSTEM_FAT_FILE_READER_H_
  31. #include <string.h>
  32. #include "avrlibx/avrlibx.h"
  33. namespace avrlibx {
  34. struct Partition {
  35. uint8_t state;
  36. uint8_t start_head;
  37. uint16_t start_cylinder_sector;
  38. uint8_t type;
  39. uint8_t end_head;
  40. uint16_t end_cylinder_sector;
  41. uint32_t sector_offset;
  42. uint32_t num_sectors;
  43. };
  44. struct MBR {
  45. uint8_t code[446];
  46. Partition partition[4];
  47. uint8_t signature;
  48. };
  49. struct BootSector {
  50. uint8_t jmp_boot[3];
  51. char oem_name[8];
  52. uint16_t bytes_per_sector;
  53. uint8_t sec_per_cluster;
  54. uint16_t reserved_sec_count;
  55. uint8_t num_fats;
  56. uint16_t root_entry_count;
  57. uint16_t total_sec;
  58. uint8_t media;
  59. uint16_t fat_size;
  60. uint16_t sector_per_track;
  61. uint16_t num_heads;
  62. uint32_t hidden_sec;
  63. uint32_t total_sector;
  64. union {
  65. struct {
  66. uint16_t drive_number;
  67. uint8_t ext_signature;
  68. uint32_t volume_id;
  69. char label[11];
  70. char fs_type[8];
  71. uint8_t padding[28];
  72. } fat16;
  73. struct {
  74. uint32_t fat_size;
  75. uint16_t flags;
  76. uint16_t version;
  77. uint32_t root_sector;
  78. uint16_t info_sector;
  79. uint16_t backup_sector;
  80. uint8_t reserved[12];
  81. uint16_t drive_number;
  82. uint8_t ext_signature;
  83. uint32_t volume_id;
  84. char label[11];
  85. char fs_type[8];
  86. } fat32;
  87. };
  88. uint8_t bootstrap_code[420];
  89. uint16_t signature;
  90. };
  91. enum DirAttribute {
  92. FILE_READ_ONLY = 1,
  93. FILE_HIDDEN = 2,
  94. FILE_SYSTEM = 4,
  95. FILE_VOLUME = 8,
  96. FILE_LFN = 15,
  97. FILE_DIRECTORY = 16,
  98. FILE_ARCHIVE = 32,
  99. FILE_ATTRIBUTES = 0x3f,
  100. };
  101. struct DirectoryEntry {
  102. char name[11];
  103. uint8_t attribute;
  104. uint8_t reserved;
  105. uint8_t creation_time_tenth;
  106. uint32_t creation_time;
  107. uint16_t last_access_time;
  108. uint16_t first_cluster_high;
  109. uint32_t last_write_time;
  110. uint16_t first_cluster;
  111. uint32_t file_size;
  112. uint8_t is_volume() { return attribute & FILE_VOLUME; }
  113. uint8_t is_file() { return !(attribute & (FILE_VOLUME | FILE_DIRECTORY)); }
  114. };
  115. union Sector {
  116. uint8_t bytes[512];
  117. uint16_t words[256];
  118. uint32_t dwords[128];
  119. DirectoryEntry entries[16];
  120. MBR mbr;
  121. BootSector boot;
  122. };
  123. enum FatFileReaderStatus {
  124. FFR_OK = 0,
  125. FFR_ERROR_INIT,
  126. FFR_ERROR_READ,
  127. FFR_ERROR_DISK_FORMAT_ERROR,
  128. FFR_ERROR_NO_FAT,
  129. FFR_ERROR_NO_MORE_FILES,
  130. FFR_ERROR_BAD_FILE,
  131. FFR_ERROR_FILE_NOT_FOUND,
  132. };
  133. enum FatType {
  134. FFR_FAT_UNKNOWN = 0,
  135. FFR_FAT16 = 16,
  136. FFR_FAT32 = 32
  137. };
  138. enum HandleType {
  139. FFR_DIR_HANDLE = 0,
  140. FFR_FILE_HANDLE
  141. };
  142. struct FsHandle {
  143. HandleType type;
  144. // Position of the sector within the cluster. When this is equal to
  145. // sector_size_ (number of sectors per cluster), we should use the FAT to
  146. // follow the link to the next sector.
  147. uint8_t cluster_position;
  148. // Position within file (byte) or directory list (entry#).
  149. uint16_t cursor;
  150. // The cluster/sector to be read at the next Read/Next operation.
  151. uint32_t cluster;
  152. uint32_t sector;
  153. // The cluster read during the most recent operation.
  154. uint32_t current_sector;
  155. DirectoryEntry entry;
  156. uint8_t eof() { return entry.file_size == 0; }
  157. };
  158. template<typename Media, bool safe = false>
  159. class FATFileReader {
  160. public:
  161. FATFileReader() { }
  162. // Init the media access layer and look for a FAT file system in the first
  163. // partition.
  164. static FatFileReaderStatus Init() {
  165. fat_type_ = FFR_FAT_UNKNOWN;
  166. if (Media::Init()) {
  167. return FFR_ERROR_INIT;
  168. }
  169. // Is the VBR on sector 0?
  170. uint32_t boot_sector = 0;
  171. FatFileReaderStatus status = FindBootSector(boot_sector);
  172. if (status == FFR_ERROR_READ || status == FFR_ERROR_DISK_FORMAT_ERROR) {
  173. return status;
  174. }
  175. if (status == FFR_ERROR_NO_FAT) {
  176. // There is a partition table. Read first partition.
  177. boot_sector = sector_.mbr.partition[0].sector_offset;
  178. status = FindBootSector(boot_sector);
  179. if (status != FFR_OK) {
  180. return status;
  181. }
  182. }
  183. // Read FS layout.
  184. uint32_t fat_size = sector_.boot.fat_size;
  185. if (fat_type_ == FFR_FAT32) {
  186. fat_size = sector_.boot.fat32.fat_size;
  187. }
  188. if (safe) {
  189. fat_size *= sector_.boot.num_fats;
  190. } else {
  191. if (sector_.boot.num_fats == 2) {
  192. fat_size += fat_size;
  193. }
  194. }
  195. fat_sector_ = boot_sector + sector_.boot.reserved_sec_count;
  196. cluster_size_ = sector_.boot.sec_per_cluster;
  197. uint32_t start = fat_sector_ + fat_size;
  198. root_dir_ = fat_type_ == FFR_FAT32 ? sector_.boot.fat32.root_sector : start;
  199. data_sector_ = start + (sector_.boot.root_entry_count / 16);
  200. return FFR_OK;
  201. }
  202. // Open the root directory and start iterating on the file list.
  203. static FatFileReaderStatus OpenRootDir(FsHandle* handle) {
  204. memset(handle, 0, sizeof(FsHandle));
  205. if (fat_type_ == FFR_FAT32) {
  206. handle->cluster = root_dir_;
  207. handle->sector = cluster_to_sector(root_dir_);
  208. } else {
  209. handle->sector = root_dir_;
  210. }
  211. return FFR_OK;
  212. }
  213. // Iterate on the next file in the opened directory.
  214. static FatFileReaderStatus Next(FsHandle* handle) {
  215. if (safe && handle->type != FFR_DIR_HANDLE) {
  216. return FFR_ERROR_NO_MORE_FILES;
  217. }
  218. if (safe && SyncCache(handle)) {
  219. return FFR_ERROR_READ;
  220. }
  221. while (1) {
  222. // Every 16th entry, we need to move to the next sector.
  223. uint8_t offset = (handle->cursor & 0x0f);
  224. if (offset == 0) {
  225. // We have reached the end of the cluster on a FAT32 system!
  226. if (ReadNextSector(handle)) {
  227. return FFR_ERROR_READ;
  228. }
  229. }
  230. ++handle->cursor;
  231. memcpy(&handle->entry, &sector_.entries[offset], sizeof(DirectoryEntry));
  232. // Stop if end of table is reached.
  233. if (handle->entry.name[0] == 0) {
  234. break;
  235. }
  236. // Skip volumes.
  237. if (handle->entry.is_volume()) {
  238. continue;
  239. }
  240. // Skip current directory, or deleted files
  241. if (handle->entry.name[0] == '.' || handle->entry.name[0] == 0xe5) {
  242. continue;
  243. }
  244. return FFR_OK;
  245. }
  246. return FFR_ERROR_NO_MORE_FILES;
  247. };
  248. // Open a file identified by a 83 name.
  249. static FatFileReaderStatus Open(const char* name83, FsHandle* handle) {
  250. OpenRootDir(handle);
  251. while (Next(handle) == FFR_OK) {
  252. if (!memcmp(name83, handle->entry.name, 11)) {
  253. return Open(handle);
  254. }
  255. }
  256. return FFR_ERROR_FILE_NOT_FOUND;
  257. }
  258. // Open a file identified by a directory handle.
  259. static FatFileReaderStatus Open(FsHandle* handle) {
  260. if (safe && (handle->type != FFR_DIR_HANDLE ||
  261. handle->entry.name[0] == 0 ||
  262. handle->entry.name[0] == 0xe5 ||
  263. (!handle->entry.is_file()))) {
  264. return FFR_ERROR_BAD_FILE;
  265. }
  266. LongWord c;
  267. c.words[0] = handle->entry.first_cluster;
  268. c.words[1] = handle->entry.first_cluster_high;
  269. uint32_t cluster = c.value;
  270. if (!is_valid_cluster(cluster)) {
  271. return FFR_ERROR_BAD_FILE;
  272. }
  273. handle->type = FFR_FILE_HANDLE;
  274. handle->cluster = cluster;
  275. handle->cluster_position = 0;
  276. handle->sector = cluster_to_sector(cluster);
  277. handle->cursor = 0;
  278. return FFR_OK;
  279. }
  280. // Read data from a file.
  281. static uint16_t Read(FsHandle* handle, uint16_t size, uint8_t* buffer) {
  282. if (safe && handle->type != FFR_FILE_HANDLE) {
  283. return 0;
  284. }
  285. if (safe && SyncCache(handle)) {
  286. return FFR_ERROR_READ;
  287. }
  288. uint16_t read = 0;
  289. uint32_t remaining = handle->entry.file_size;
  290. while (size && remaining) {
  291. if (handle->cursor == 0) {
  292. if (ReadNextSector(handle)) {
  293. break;
  294. }
  295. }
  296. uint16_t readable = 512 - handle->cursor;
  297. if (readable > size) {
  298. readable = size;
  299. }
  300. if (readable > remaining) {
  301. readable = remaining;
  302. }
  303. uint16_t count = readable;
  304. while (count) {
  305. *buffer++ = sector_.bytes[handle->cursor++];
  306. --count;
  307. }
  308. size -= readable;
  309. read += readable;
  310. remaining -= readable;
  311. if (handle->cursor == 512) {
  312. handle->cursor = 0;
  313. }
  314. }
  315. handle->entry.file_size = remaining;
  316. return read;
  317. }
  318. private:
  319. // Check if a cluster number is valid.
  320. static inline uint8_t is_valid_cluster(uint32_t cluster) {
  321. if (fat_type_ == FFR_FAT16) {
  322. return (cluster >= 2 && cluster <= 0xffef);
  323. } else {
  324. return (cluster >= 2 && cluster <= 0x0fffffef);
  325. }
  326. }
  327. // Follow the FAT linked list.
  328. static uint32_t NextCluster(uint32_t cluster) {
  329. if (cluster < 2) {
  330. return 0;
  331. }
  332. uint32_t fat_sector = fat_sector_;
  333. fat_sector += (fat_type_ == FFR_FAT16) ? (cluster >> 8) : (cluster >> 7);
  334. if (ReadSector(fat_sector)) {
  335. return 0;
  336. }
  337. uint32_t next_cluster = (fat_type_ == FFR_FAT16)
  338. ? sector_.words[cluster & 0xff]
  339. : sector_.dwords[cluster & 0x7f] & 0x0fffffff;
  340. return next_cluster;
  341. }
  342. // Check that the sector fetched into memory is the right one for the present
  343. // file read / directory iteration operation. If this is not the case, read
  344. // from media layer.
  345. static uint8_t SyncCache(FsHandle* handle) __attribute__((noinline)) {
  346. if (fetched_sector_ != handle->current_sector) {
  347. return ReadSector(handle->current_sector);
  348. }
  349. return 0;
  350. }
  351. // Shortcut for reading a sector into memory.
  352. static uint8_t ReadSector(uint32_t sector) __attribute__((noinline)) {
  353. if (Media::ReadSectors(sector, 1, sector_.bytes)) {
  354. return 1;
  355. } else {
  356. if (safe) {
  357. fetched_sector_ = sector;
  358. }
  359. return 0;
  360. }
  361. }
  362. // Read the next sector for the current object (directory or file).
  363. // If the end of a cluster is reached, get the next cluster from the FAT.
  364. static FatFileReaderStatus ReadNextSector(FsHandle* handle) {
  365. if (handle->cluster && handle->cluster_position == cluster_size_) {
  366. uint32_t next_cluster = NextCluster(handle->cluster);
  367. if (next_cluster == 0) {
  368. return FFR_ERROR_READ;
  369. } else if (!is_valid_cluster(next_cluster)) {
  370. return FFR_ERROR_READ;
  371. }
  372. handle->cluster = next_cluster;
  373. handle->sector = cluster_to_sector(handle->cluster);
  374. handle->cluster_position = 0;
  375. }
  376. if (ReadSector(handle->sector)) {
  377. return FFR_ERROR_READ;
  378. }
  379. if (safe) {
  380. handle->current_sector = handle->sector;
  381. }
  382. ++handle->sector;
  383. ++handle->cluster_position;
  384. return FFR_OK;
  385. }
  386. // Convert a cluster index to a sector address.
  387. static uint32_t cluster_to_sector(uint32_t cluster) __attribute__((noinline)) {
  388. cluster -= 2;
  389. uint8_t shift = cluster_size_;
  390. shift >>= 1;
  391. while (shift) {
  392. shift >>= 1;
  393. cluster <<= 1;
  394. }
  395. return cluster + data_sector_;
  396. }
  397. // Look for a FAT FS at a given sector.
  398. static FatFileReaderStatus FindBootSector(uint32_t sector) {
  399. if (ReadSector(sector)) {
  400. return FFR_ERROR_READ;
  401. }
  402. if (sector_.boot.signature != 0xaa55) {
  403. return FFR_ERROR_DISK_FORMAT_ERROR;
  404. }
  405. if (sector_.boot.fat16.fs_type[0] == 'F' &&
  406. sector_.boot.fat16.fs_type[1] == 'A') {
  407. fat_type_ = FFR_FAT16;
  408. return FFR_OK;
  409. }
  410. if (sector_.boot.fat32.fs_type[0] == 'F' &&
  411. sector_.boot.fat32.fs_type[1] == 'A') {
  412. fat_type_ = FFR_FAT32;
  413. return FFR_OK;
  414. }
  415. return FFR_ERROR_NO_FAT;
  416. }
  417. static uint32_t fetched_sector_;
  418. static Sector sector_;
  419. static FatType fat_type_;
  420. static uint8_t cluster_size_;
  421. // Root directory sector for FAT16 ; cluster for FAT32
  422. static uint32_t root_dir_;
  423. static uint32_t fat_sector_;
  424. static uint32_t data_sector_;
  425. DISALLOW_COPY_AND_ASSIGN(FATFileReader);
  426. };
  427. /* static */
  428. template<typename M, bool s> Sector FATFileReader<M, s>::sector_;
  429. /* static */
  430. template<typename M, bool s> uint32_t FATFileReader<M, s>::fetched_sector_;
  431. /* static */
  432. template<typename M, bool s> FatType FATFileReader<M, s>::fat_type_;
  433. /* static */
  434. template<typename M, bool s> uint8_t FATFileReader<M, s>::cluster_size_;
  435. /* static */
  436. template<typename M, bool s> uint32_t FATFileReader<M, s>::fat_sector_;
  437. /* static */
  438. template<typename M, bool s> uint32_t FATFileReader<M, s>::root_dir_;
  439. /* static */
  440. template<typename M, bool s> uint32_t FATFileReader<M, s>::data_sector_;
  441. // This is how the media access layer can be implemented.
  442. struct DummyMediaInterface {
  443. static uint8_t Init() {
  444. return 0;
  445. }
  446. static uint8_t ReadSectors(uint32_t start, uint8_t num_sectors, uint8_t* data) {
  447. memset(data, 0, 512);
  448. return 0;
  449. }
  450. };
  451. } // namespace avrlibx
  452. #endif // AVRLIBX_FILESYSTEM_FAT_FILE_READER_H_