File reading works (with random access), file interface is basically defined, crossing cluster boundaries is not yet implemented in directory listing and file location operation
This commit is contained in:
parent
1e6e6253b9
commit
de52ac5d35
@ -10,4 +10,6 @@ add_library(embpart embpart.c
|
|||||||
fs/fat32/fat32.c
|
fs/fat32/fat32.c
|
||||||
fs/fat32/fat32.h
|
fs/fat32/fat32.h
|
||||||
MassStorage.c
|
MassStorage.c
|
||||||
MassStorage.h)
|
MassStorage.h
|
||||||
|
file_interface.c
|
||||||
|
file_interface.h)
|
13
file_interface.c
Normal file
13
file_interface.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Created by epagris on 2023.10.03..
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "file_interface.h"
|
||||||
|
|
||||||
|
ssize_t fi_read(void *ptr, size_t size, File *f) {
|
||||||
|
return f->read(ptr, size, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t fi_seek(File *f, int32_t offset, uint8_t whence) {
|
||||||
|
return f->seek(f, offset, whence);
|
||||||
|
}
|
16
file_interface.h
Normal file
16
file_interface.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef EMBPART_FILE_INTERFACE_H
|
||||||
|
#define EMBPART_FILE_INTERFACE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef struct File_ {
|
||||||
|
uint8_t data[32];
|
||||||
|
ssize_t (*read)(void * ptr, size_t size, struct File_ * f);
|
||||||
|
ssize_t (*seek)(struct File_ * f, int32_t offset, uint8_t whence);
|
||||||
|
} File;
|
||||||
|
|
||||||
|
ssize_t fi_read(void * ptr, size_t size, File * f);
|
||||||
|
ssize_t fi_seek(File * f, int32_t offset, uint8_t whence);
|
||||||
|
|
||||||
|
#endif //EMBPART_FILE_INTERFACE_H
|
250
fs/fat32/fat32.c
250
fs/fat32/fat32.c
@ -12,14 +12,30 @@
|
|||||||
#define SECTOR_SIZE (512)
|
#define SECTOR_SIZE (512)
|
||||||
static uint8_t buffer[2 * SECTOR_SIZE]; // TODO access to this variable should be protected!
|
static uint8_t buffer[2 * SECTOR_SIZE]; // TODO access to this variable should be protected!
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy first buffer to the second one
|
||||||
|
*/
|
||||||
static inline void fat32_copy_second_to_first_buffer() {
|
static inline void fat32_copy_second_to_first_buffer() {
|
||||||
memcpy(buffer, buffer + SECTOR_SIZE, SECTOR_SIZE);
|
memcpy(buffer, buffer + SECTOR_SIZE, SECTOR_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get first sector of a cluster. A cluster may be composed of multiple sectors.
|
||||||
|
* @param ctrl Pointer to FAT32 control block
|
||||||
|
* @param cluster sequence number of a cluster
|
||||||
|
* @return sequence number of the cluster's first sector
|
||||||
|
*/
|
||||||
static inline uint32_t fat32_get_first_sector_of_cluster(const Fat32_CtrlBlock *ctrl, uint32_t cluster) {
|
static inline uint32_t fat32_get_first_sector_of_cluster(const Fat32_CtrlBlock *ctrl, uint32_t cluster) {
|
||||||
return (cluster - 2) * ctrl->sectors_per_cluster + ctrl->data_s;
|
return (cluster - 2) * ctrl->sectors_per_cluster + ctrl->data_s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load FAT32 file system. Cannot load FAT12 or FAT16.
|
||||||
|
* @param ctrl pointer to UNFILLED FAT32 control block
|
||||||
|
* @param bpb_s sequence number of the BIOS Parameter Blocks' sector
|
||||||
|
* @param mstg pointer to az existing Mass Storage object (holding read and write functions)
|
||||||
|
* @return 0 if loading was successful, anything else indicates loading failure
|
||||||
|
*/
|
||||||
int fat32_load(Fat32_CtrlBlock *ctrl, uint32_t bpb_s, const MassStorage *mstg) {
|
int fat32_load(Fat32_CtrlBlock *ctrl, uint32_t bpb_s, const MassStorage *mstg) {
|
||||||
ctrl->mstg = mstg;
|
ctrl->mstg = mstg;
|
||||||
|
|
||||||
@ -48,11 +64,21 @@ int fat32_load(Fat32_CtrlBlock *ctrl, uint32_t bpb_s, const MassStorage *mstg) {
|
|||||||
#define READ_MSTG_TO_FIRST_BUFFER(idx) MSTG_READ(mstg, (idx), buffer)
|
#define READ_MSTG_TO_FIRST_BUFFER(idx) MSTG_READ(mstg, (idx), buffer)
|
||||||
#define READ_MSTG_TO_SECOND_BUFFER(idx) MSTG_READ(mstg, (idx), buffer + SECTOR_SIZE)
|
#define READ_MSTG_TO_SECOND_BUFFER(idx) MSTG_READ(mstg, (idx), buffer + SECTOR_SIZE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dummy function converting 16-bit Unicode character to UTF-8 type. Just chops the upper byte
|
||||||
|
* @param unicode Unicode character
|
||||||
|
* @return UTF-8 character
|
||||||
|
*/
|
||||||
// TODO some dirty function to chop the high byte from the unicode charcode...
|
// TODO some dirty function to chop the high byte from the unicode charcode...
|
||||||
static inline uint8_t fat32_unicode_to_utf8(uint16_t unicode) {
|
static inline uint8_t fat32_unicode_to_utf8(uint16_t unicode) {
|
||||||
return unicode & 0x00FF;
|
return unicode & 0x00FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function, that trims the trailing whitespaces. The function returns with the trimmed string length.
|
||||||
|
* @param str string to trim
|
||||||
|
* @return trimmed length
|
||||||
|
*/
|
||||||
uint32_t fat32_trim_str_right(char *str) {
|
uint32_t fat32_trim_str_right(char *str) {
|
||||||
uint32_t len = 0;
|
uint32_t len = 0;
|
||||||
while (*str > ' ') {
|
while (*str > ' ') {
|
||||||
@ -63,6 +89,13 @@ uint32_t fat32_trim_str_right(char *str) {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function that fetches the non-continuously stored Long File Name from an LFN-entry.
|
||||||
|
* @param lfnEntry pointer to an LFN entry
|
||||||
|
* @param str pointer to string destination buffer
|
||||||
|
* @return string length (=13)
|
||||||
|
*/
|
||||||
// TODO loop unroll!
|
// TODO loop unroll!
|
||||||
uint16_t fat32_extract_lfn_text(const Fat32_LongFileNameEntry *lfnEntry, char *str) {
|
uint16_t fat32_extract_lfn_text(const Fat32_LongFileNameEntry *lfnEntry, char *str) {
|
||||||
uint16_t idx = 0;
|
uint16_t idx = 0;
|
||||||
@ -81,6 +114,13 @@ uint16_t fat32_extract_lfn_text(const Fat32_LongFileNameEntry *lfnEntry, char *s
|
|||||||
#define LONG_FILE_NAME_ATTRIB_TEST(a) ((a) & (1 << 3)) && ((a) & (1 << 2)) && ((a) & (1 << 1)) && ((a) & (1))
|
#define LONG_FILE_NAME_ATTRIB_TEST(a) ((a) & (1 << 3)) && ((a) & (1 << 2)) && ((a) & (1 << 1)) && ((a) & (1))
|
||||||
#define LINELENGTH (32)
|
#define LINELENGTH (32)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next file entry from a list. LFN entries preceding the seeked file entry are unified, entry is advanced,
|
||||||
|
* so that at return *entry points to the actual file entry and not to some LFN fragments.
|
||||||
|
* @param entry pointer to pointer (sic!) of an entry
|
||||||
|
* @param entry_name pointer to entry name writeback area
|
||||||
|
* @return length of entry name (may be used to avoid strlen() calls)
|
||||||
|
*/
|
||||||
uint16_t fat32_get_file_entry(Fat32_FileEntry **const entry, char *entry_name) {
|
uint16_t fat32_get_file_entry(Fat32_FileEntry **const entry, char *entry_name) {
|
||||||
//static char entry_name[261];
|
//static char entry_name[261];
|
||||||
bool done = false;
|
bool done = false;
|
||||||
@ -132,6 +172,12 @@ uint16_t fat32_get_file_entry(Fat32_FileEntry **const entry, char *entry_name) {
|
|||||||
return name_len;
|
return name_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a file entry: NAME ATTRIBS SIZE. Contains calls to fat32_get_file_entry(), that's why entry is maintained
|
||||||
|
* the same way as documented at fat32_get_file_entry().
|
||||||
|
* @param entry pointer to pointer (sic!) to a file entry. See fat32_get_file_entry() docs.
|
||||||
|
* @return 0 if successful
|
||||||
|
*/
|
||||||
int fat32_print_file_entry(Fat32_FileEntry **const entry) {
|
int fat32_print_file_entry(Fat32_FileEntry **const entry) {
|
||||||
static char entry_name[261];
|
static char entry_name[261];
|
||||||
uint16_t name_len = fat32_get_file_entry(entry, entry_name);
|
uint16_t name_len = fat32_get_file_entry(entry, entry_name);
|
||||||
@ -165,12 +211,35 @@ int fat32_print_file_entry(Fat32_FileEntry **const entry) {
|
|||||||
#define FAT32_DIRECTORY_SEPARATOR ('/')
|
#define FAT32_DIRECTORY_SEPARATOR ('/')
|
||||||
#define FAT32_MAX_BASENAME_LENGTH (47)
|
#define FAT32_MAX_BASENAME_LENGTH (47)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the next basename from a full path. Does not modify the path string, only returns with
|
||||||
|
* the length of the next basename token. Like a simplified strtok().
|
||||||
|
* @param path pointer to full path
|
||||||
|
* @return next basename token length
|
||||||
|
*/
|
||||||
static inline uint16_t fat32_extract_next_basename_length(const char *path) {
|
static inline uint16_t fat32_extract_next_basename_length(const char *path) {
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
for (i = 0; (path[i] != FAT32_DIRECTORY_SEPARATOR) && (path[i] != '\0'); i++) {}
|
for (i = 0; (path[i] != FAT32_DIRECTORY_SEPARATOR) && (path[i] != '\0'); i++) {}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the sequence number of the first cluster of a file entry.
|
||||||
|
* @param entry pointer to a file entry
|
||||||
|
* @return sequence number of the first cluster of a file entry
|
||||||
|
*/
|
||||||
|
static inline uint32_t fat32_get_first_cluster(const Fat32_FileEntry *entry) {
|
||||||
|
return (entry->first_cluster_high << 16) | (entry->first_cluster_low);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function locates a file based on its full path.
|
||||||
|
* @param ctrl pointer to a FAT32 control block
|
||||||
|
* @param path full path of the file to be located
|
||||||
|
* @return pointer to the file entry. Caution! This pointer is only valid until no further
|
||||||
|
* call is made to fat32_* functions, since all functions involve the same buffer.
|
||||||
|
* Functions invalidating buffer content are marked with (I).
|
||||||
|
*/
|
||||||
const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char *path) {
|
const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char *path) {
|
||||||
FETCH_MSTG;
|
FETCH_MSTG;
|
||||||
|
|
||||||
@ -194,6 +263,9 @@ const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char
|
|||||||
memcpy(basename, path_iter, copy_len); // extract basename
|
memcpy(basename, path_iter, copy_len); // extract basename
|
||||||
basename[copy_len] = '\0'; // NULL-termination
|
basename[copy_len] = '\0'; // NULL-termination
|
||||||
path_iter += basename_len; // advance basename
|
path_iter += basename_len; // advance basename
|
||||||
|
if (*path_iter == FAT32_DIRECTORY_SEPARATOR) { // skip directory separator, but don't skip zero termination
|
||||||
|
path_iter++;
|
||||||
|
}
|
||||||
|
|
||||||
// search for basename in the current directory
|
// search for basename in the current directory
|
||||||
// acquire pointer to the beginning of the file entry table
|
// acquire pointer to the beginning of the file entry table
|
||||||
@ -224,6 +296,8 @@ const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char
|
|||||||
// modify the entry pointer, since it's been moved
|
// modify the entry pointer, since it's been moved
|
||||||
entry = (Fat32_FileEntry *) (((uint8_t *) (entry)) - SECTOR_SIZE);
|
entry = (Fat32_FileEntry *) (((uint8_t *) (entry)) - SECTOR_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO also must pay attention on crossing not just sector, but cluster boundaries
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the basename entry is found...
|
// if the basename entry is found...
|
||||||
@ -232,7 +306,7 @@ const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char
|
|||||||
file_found = true; // ...then the file is found
|
file_found = true; // ...then the file is found
|
||||||
} else { // ...if it's not the end of the path, then load the cluster corresponding to the entry
|
} else { // ...if it's not the end of the path, then load the cluster corresponding to the entry
|
||||||
// determine sector number
|
// determine sector number
|
||||||
uint32_t next_cluster = (entry->first_cluster_high << 16) | (entry->first_cluster_low);
|
uint32_t next_cluster = fat32_get_first_cluster(entry);
|
||||||
uint32_t next_sector = fat32_get_first_sector_of_cluster(ctrl, next_cluster);
|
uint32_t next_sector = fat32_get_first_sector_of_cluster(ctrl, next_cluster);
|
||||||
|
|
||||||
// load sectors
|
// load sectors
|
||||||
@ -252,44 +326,74 @@ const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO subject to change, must include cluster crossing check
|
||||||
int fat32_list_dir(const Fat32_CtrlBlock *ctrl, const char *dir) {
|
int fat32_list_dir(const Fat32_CtrlBlock *ctrl, const char *dir) {
|
||||||
// TODO find directory
|
// // TODO find directory
|
||||||
|
//
|
||||||
// read root directory
|
// // read root directory
|
||||||
FETCH_MSTG;
|
// FETCH_MSTG;
|
||||||
uint32_t sector = ctrl->root_s;
|
// uint32_t sector = ctrl->root_s;
|
||||||
READ_MSTG_TO_FIRST_BUFFER(sector);
|
// READ_MSTG_TO_FIRST_BUFFER(sector);
|
||||||
READ_MSTG_TO_SECOND_BUFFER(sector + 1);
|
// READ_MSTG_TO_SECOND_BUFFER(sector + 1);
|
||||||
|
//
|
||||||
// acquire pointer to the beginning of the file entry table
|
// // acquire pointer to the beginning of the file entry table
|
||||||
Fat32_FileEntry *entry = (Fat32_FileEntry *) buffer;
|
// Fat32_FileEntry *entry = (Fat32_FileEntry *) buffer;
|
||||||
while (entry->short_fname[0] != 0x00) {
|
// while (entry->short_fname[0] != 0x00) {
|
||||||
if (entry->short_fname[0] != FAT32_UNUSED_FILE_ENTRY) {
|
// if (entry->short_fname[0] != FAT32_UNUSED_FILE_ENTRY) {
|
||||||
fat32_print_file_entry(&entry);
|
// fat32_print_file_entry(&entry);
|
||||||
}
|
// }
|
||||||
entry++;
|
// entry++;
|
||||||
|
//
|
||||||
// if we crossed the first buffer - second buffer border, then
|
// // if we crossed the first buffer - second buffer border, then
|
||||||
// copy the second buffer to the first one and load the next sector
|
// // copy the second buffer to the first one and load the next sector
|
||||||
// to the second buffer
|
// // to the second buffer
|
||||||
if ((void *) entry > (void *) (buffer + SECTOR_SIZE)) {
|
// if ((void *) entry > (void *) (buffer + SECTOR_SIZE)) {
|
||||||
// copy the second buffer to the first one
|
// // copy the second buffer to the first one
|
||||||
fat32_copy_second_to_first_buffer();
|
// fat32_copy_second_to_first_buffer();
|
||||||
sector++;
|
// sector++;
|
||||||
READ_MSTG_TO_SECOND_BUFFER(sector + 1);
|
// READ_MSTG_TO_SECOND_BUFFER(sector + 1);
|
||||||
|
//
|
||||||
// modify the entry pointer, since it's been moved
|
// // modify the entry pointer, since it's been moved
|
||||||
entry = (Fat32_FileEntry *) (((uint8_t *) (entry)) - SECTOR_SIZE);
|
// entry = (Fat32_FileEntry *) (((uint8_t *) (entry)) - SECTOR_SIZE);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// return 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the sector's sequence number corresponding to the specific cluster identified by its sequence number.
|
||||||
|
* @param ctrl pointer to FAT32 control block
|
||||||
|
* @param cluster sequence number of a cluster
|
||||||
|
* @return sequence number of the sector holding the FAT entry corresponding to the cluster
|
||||||
|
*/
|
||||||
static inline uint32_t fat32_get_fat_entry_sector_by_cluster_index(const Fat32_CtrlBlock *ctrl, uint32_t cluster) {
|
static inline uint32_t fat32_get_fat_entry_sector_by_cluster_index(const Fat32_CtrlBlock *ctrl, uint32_t cluster) {
|
||||||
return cluster * sizeof(Fat32_FatTableEntry) / ctrl->bytes_per_sector + ctrl->fat_s;
|
return cluster * sizeof(Fat32_FatTableEntry) / ctrl->bytes_per_sector + ctrl->fat_s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sequence number of the next chained cluster. (I)
|
||||||
|
* @param ctrl pointer to FAT32 control block
|
||||||
|
* @param cluster sequence number of a cluster
|
||||||
|
* @return sequence number of the cluster following the passed one in the chain
|
||||||
|
*/
|
||||||
|
static inline uint32_t fat32_get_next_chained_cluster(const Fat32_CtrlBlock *ctrl, uint32_t cluster) {
|
||||||
|
FETCH_MSTG;
|
||||||
|
uint32_t sector = fat32_get_fat_entry_sector_by_cluster_index(ctrl, cluster); // fetch read FAT entry's sector
|
||||||
|
READ_MSTG_TO_FIRST_BUFFER(sector);
|
||||||
|
Fat32_FatTableEntry *fat_iter = ((Fat32_FatTableEntry *) buffer) + (cluster % ctrl->fat_entries_per_sector); // get FAT iter
|
||||||
|
uint32_t next_cluster = (*fat_iter) & ~(0xF << 28); // mask lower 28-bits
|
||||||
|
return next_cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sequence number of the cluster storing a specific byte position (pos) if the file's first cluster is given.
|
||||||
|
* @param ctrl pointer to FAT32 control block
|
||||||
|
* @param first_cluster sequence number of the first cluster of the file
|
||||||
|
* @param pos byte position
|
||||||
|
* @return sequence number of the cluster
|
||||||
|
*/
|
||||||
static inline uint32_t fat32_get_cluster_from_pos(const Fat32_CtrlBlock *ctrl, uint32_t first_cluster, uint32_t pos) {
|
static inline uint32_t fat32_get_cluster_from_pos(const Fat32_CtrlBlock *ctrl, uint32_t first_cluster, uint32_t pos) {
|
||||||
FETCH_MSTG;
|
FETCH_MSTG;
|
||||||
uint32_t cluster_link_number = pos / (ctrl->sectors_per_cluster * ctrl->bytes_per_sector); // calculate the sequence number of the FAT entry containing the reference to the desired data cluster
|
uint32_t cluster_link_number = pos / (ctrl->sectors_per_cluster * ctrl->bytes_per_sector); // calculate the sequence number of the FAT entry containing the reference to the desired data cluster
|
||||||
@ -307,18 +411,82 @@ static inline uint32_t fat32_get_cluster_from_pos(const Fat32_CtrlBlock * ctrl,
|
|||||||
uint32_t next_cluster = (*fat_iter) & ~(0xF << 28);
|
uint32_t next_cluster = (*fat_iter) & ~(0xF << 28);
|
||||||
if (next_cluster >= 2 && next_cluster <= 0xFFFFFEF) {
|
if (next_cluster >= 2 && next_cluster <= 0xFFFFFEF) {
|
||||||
cluster = next_cluster;
|
cluster = next_cluster;
|
||||||
}
|
} // TODO last chained cluster?
|
||||||
}
|
}
|
||||||
return cluster;
|
return cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fat32_read_file(const Fat32_CtrlBlock * ctrl, const Fat32_FileEntry * entry, uint32_t pos, uint32_t len, uint8_t * p) {
|
/**
|
||||||
FETCH_MSTG;
|
* Gets how many bytes a cluster contains.
|
||||||
uint32_t first_cluster = (entry->first_cluster_high << 16) | (entry->first_cluster_low);
|
* @param ctrl pointer to FAT32 control block
|
||||||
uint32_t cluster = fat32_get_cluster_from_pos(ctrl, first_cluster, pos);
|
* @return bytes per cluster
|
||||||
uint32_t sector = fat32_get_first_sector_of_cluster(ctrl, cluster);
|
*/
|
||||||
READ_MSTG_TO_FIRST_BUFFER(sector);
|
static inline uint32_t fat32_get_bytes_per_cluster(const Fat32_CtrlBlock *ctrl) {
|
||||||
uint32_t pos_in_sector = pos % ctrl->bytes_per_sector;
|
return ctrl->bytes_per_sector * ctrl->sectors_per_cluster;
|
||||||
memcpy(p, buffer + pos_in_sector, len);
|
}
|
||||||
return len; // TODO
|
|
||||||
|
/**
|
||||||
|
* Read a file using "random access".
|
||||||
|
* @param ctrl pointer to FAT32 control block
|
||||||
|
* @param entry pointer to the corresponding file entry
|
||||||
|
* @param pos read start position
|
||||||
|
* @param len read length
|
||||||
|
* @param p pointer to output buffer
|
||||||
|
* @return the number of bytes read
|
||||||
|
*/
|
||||||
|
uint32_t fat32_read_file(const Fat32_CtrlBlock *ctrl, const Fat32_FileEntry *entry, uint32_t pos, uint32_t len, uint8_t *p) {
|
||||||
|
// check position validity and check that the entry corresponds to a file, not to a directory or volume
|
||||||
|
uint8_t attr = entry->attributes;
|
||||||
|
if ((pos >= entry->size) || (attr & FAT32_FATT_DIRECTORY) || (attr & FAT32_FATT_VOLUME)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FETCH_MSTG;
|
||||||
|
uint32_t first_cluster = fat32_get_first_cluster(entry); // get first cluster of the entry
|
||||||
|
uint32_t cluster = fat32_get_cluster_from_pos(ctrl, first_cluster, pos); // get cluster sequence number of the file using the read position
|
||||||
|
uint32_t first_sector = fat32_get_first_sector_of_cluster(ctrl, cluster); // get the first sector of the cluster
|
||||||
|
uint32_t bytes_per_cluster = fat32_get_bytes_per_cluster(ctrl); // get number of bytes per cluster
|
||||||
|
uint32_t pos_in_cluster = pos % bytes_per_cluster; // transform read position to a relative read position from the cluster beginning
|
||||||
|
uint32_t sector_of_cluster = pos_in_cluster / ctrl->bytes_per_sector; // get the sequence number of sector in the cluster that will be read
|
||||||
|
uint32_t sector = first_sector + sector_of_cluster; // offset the sectors based on relative read position
|
||||||
|
uint32_t pos_in_sector = pos % ctrl->bytes_per_sector; // count read position relative from sector's beginning
|
||||||
|
|
||||||
|
READ_MSTG_TO_FIRST_BUFFER(sector);
|
||||||
|
|
||||||
|
// cap length, don't read after the end of the file
|
||||||
|
uint32_t read_len = MIN(len, entry->size - pos);
|
||||||
|
uint32_t offset = 0;
|
||||||
|
|
||||||
|
// reading from a file may involve reading across cluster boundaries
|
||||||
|
|
||||||
|
// 1. read the beginning from the first cluster
|
||||||
|
uint32_t first_read_len = MIN(read_len, ctrl->bytes_per_sector - pos);
|
||||||
|
memcpy(p, buffer + pos_in_sector, first_read_len);
|
||||||
|
read_len -= first_read_len; // decrease the total read len with the number of bytes read from the first sector of the file
|
||||||
|
offset += first_read_len; // advance offset
|
||||||
|
|
||||||
|
// 2. read from intermediate sectors and read from the final sector
|
||||||
|
|
||||||
|
// if the remaining read length is non-zero, then maintain buffered sectors
|
||||||
|
while (read_len > 0) {
|
||||||
|
sector_of_cluster++; // increase sector index
|
||||||
|
if (sector_of_cluster >= ctrl->sectors_per_cluster) { // if we crossed a cluster boundary, then load the next cluster's first sector in chain
|
||||||
|
cluster = fat32_get_next_chained_cluster(ctrl, cluster); // get next cluster
|
||||||
|
first_sector = fat32_get_first_sector_of_cluster(ctrl, cluster);
|
||||||
|
sector = first_sector; // set the sector number to the first sector of the cluster
|
||||||
|
sector_of_cluster = 0; // it's the zeroth sector of the cluster
|
||||||
|
READ_MSTG_TO_FIRST_BUFFER(sector); // load the newly determined cluster's first sector
|
||||||
|
} else { // if we didn't cross a cluster boundary, then...
|
||||||
|
sector++; //...just increase the sector count
|
||||||
|
READ_MSTG_TO_FIRST_BUFFER(sector); // ...and load that sector
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the whole sector or some portion of the sector counting from the sector's begin
|
||||||
|
uint32_t copy_size = MIN(ctrl->bytes_per_sector, read_len);
|
||||||
|
memcpy(p + offset, buffer, copy_size);
|
||||||
|
read_len -= copy_size;
|
||||||
|
offset += copy_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_len;
|
||||||
}
|
}
|
@ -91,11 +91,24 @@ typedef struct {
|
|||||||
uint16_t ustrBC[2]; // characters 11-12
|
uint16_t ustrBC[2]; // characters 11-12
|
||||||
} __attribute__((packed)) Fat32_LongFileNameEntry;
|
} __attribute__((packed)) Fat32_LongFileNameEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t pos; // byte position
|
||||||
|
uint32_t cluster; // cluster corresponding to the position
|
||||||
|
uint32_t sector; // sector of the last read
|
||||||
|
uint32_t sector_begin_pos; // byte position of the sector's begin
|
||||||
|
} Fat32_SeekHint;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Fat32_CtrlBlock * ctrl; // pointer FAT32 control block
|
||||||
|
Fat32_SeekHint last_pos; // last read position
|
||||||
|
uint32_t entry_pos; // FileEntry byte position
|
||||||
|
} Fat32_FileHelper;
|
||||||
|
|
||||||
int fat32_load(Fat32_CtrlBlock *ctrl, uint32_t bpb_s, const MassStorage * mstg);
|
int fat32_load(Fat32_CtrlBlock *ctrl, uint32_t bpb_s, const MassStorage * mstg);
|
||||||
|
|
||||||
int fat32_list_dir(const Fat32_CtrlBlock *ctrl, const char * dir);
|
int fat32_list_dir(const Fat32_CtrlBlock *ctrl, const char * dir);
|
||||||
|
|
||||||
int fat32_read_file(const Fat32_CtrlBlock * ctrl, const Fat32_FileEntry * entry, uint32_t pos, uint32_t len, uint8_t * p);
|
uint32_t fat32_read_file(const Fat32_CtrlBlock * ctrl, const Fat32_FileEntry * entry, uint32_t pos, uint32_t len, uint8_t * p);
|
||||||
|
|
||||||
const Fat32_FileEntry * fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char *path);
|
const Fat32_FileEntry * fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char *path);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user