From d7a5a4939468a285264f3b1f3022a66218ec2041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiesner=20Andr=C3=A1s?= Date: Sat, 11 Nov 2023 18:03:23 +0100 Subject: [PATCH] - Sequential file reading works - FAT32 file system driver is defined - Automount implemented - Unified file operations implemented - File listing implemented --- embpart.h | 9 ++ fs/fat32/fat32.c | 216 +++++++++++++++++++++++++++++------------ fs/fat32/fat32.h | 4 + fs/fs_driver.h | 2 + mbr/mbr.h | 2 + mount/mount.c | 245 ++++++++++++++++++++++++++++++++++++++++++++++- mount/mount.h | 35 ++++++- 7 files changed, 446 insertions(+), 67 deletions(-) diff --git a/embpart.h b/embpart.h index ea64aed..e6d5065 100644 --- a/embpart.h +++ b/embpart.h @@ -1,6 +1,15 @@ #ifndef EMBPART_EMBPART_H #define EMBPART_EMBPART_H +#include "fs/fat32/fat32.h" +#include "fs/fs_driver.h" + #include "mbr/mbr.h" +#include "mount/mount.h" + +#include "file_interface.h" + +#include "MassStorage.h" + #endif //EMBPART_EMBPART_H diff --git a/fs/fat32/fat32.c b/fs/fat32/fat32.c index 2f9b4ba..7c9fdeb 100644 --- a/fs/fat32/fat32.c +++ b/fs/fat32/fat32.c @@ -15,6 +15,34 @@ static inline void fat32_copy_second_to_first_buffer() { memcpy(buffer, buffer + SECTOR_SIZE, SECTOR_SIZE); } +#define FETCH_MSTG const MassStorage * mstg = ctrl->mstg +#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) + +/** + * Check if entry is in the second half of the buffer and load the next sector if it was. Also maintain the sector counter and + * the *entry pointer + * @param ctrl pointer to FAT32 control block + * @param entry pointer to pointer (sic!) to a file entry residing in the buffer + * @param sector pointer to sector count corresponding to the first hald of the working buffer + */ +static inline void fat32_check_sector_crossing_and_load(const Fat32_CtrlBlock * ctrl, Fat32_FileEntry ** entry, uint32_t * sector) { + // if we crossed the first buffer - second buffer border, then + // copy the second buffer to the first one and load the next sector + // to the second buffer + if ((void *) *entry > (void *) (buffer + SECTOR_SIZE)) { + // copy the second buffer to the first one + fat32_copy_second_to_first_buffer(); + (*sector)++; + + FETCH_MSTG; + READ_MSTG_TO_SECOND_BUFFER(*sector + 1); + + // modify the entry pointer, since it's been moved + *entry = (Fat32_FileEntry *) (((uint8_t *) (*entry)) - SECTOR_SIZE); + } // TODO also must pay attention on crossing not just sector, but cluster boundaries +} + /** * Get first sector of a cluster. A cluster may be composed of multiple sectors. * @param ctrl Pointer to FAT32 control block @@ -56,10 +84,6 @@ int fat32_load(Fat32_CtrlBlock *ctrl, uint32_t bpb_s, const MassStorage *mstg) { return 0; } -#define FETCH_MSTG const MassStorage * mstg = ctrl->mstg -#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) - /** * Dummy function converting 16-bit Unicode character to UTF-8 type. Just chops the upper byte * @param unicode Unicode character @@ -153,13 +177,14 @@ uint16_t fat32_get_file_entry(Fat32_FileEntry **const entry, char *entry_name) { name_len = fat32_trim_str_right(entry_name); // trim residual whitespaces } else { // if the entry has only a short name memcpy(entry_name, finalEntry->short_fname, 8); // copy basename + entry_name[8] = '\0'; name_len = fat32_trim_str_right(entry_name); // trim whitespaces if (!((attribs & FAT32_FATT_VOLUME) || (attribs & FAT32_FATT_DIRECTORY))) { // omit dot if volume label or directory entry_name[name_len++] = '.'; // insert dot } memcpy(entry_name + name_len, finalEntry->extension, 3); // copy extension name_len = fat32_trim_str_right(entry_name); // trim whitespaces - if (entry_name[name_len - 1] == '.') { // chop dot if no extension + if (!(attribs & FAT32_FATT_DIRECTORY) && (entry_name[name_len - 1] == '.')) { // chop dot if no extension and not directory name_len--; } entry_name[name_len] = '\0'; // terminate string @@ -229,7 +254,8 @@ static inline uint32_t fat32_get_first_cluster(const Fat32_FileEntry *entry) { } /** - * The function locates a file based on its full path. + * The function locates a file based on its full path. If path is empty and root is requested, then it returns pointer to + * the first root directory ENTRY, not to a entry pointing to the root directory. * @param ctrl pointer to a FAT32 control block * @param path full path of the file to be located * @param file_entry_ba if not NULL, then the function returns here the file entry's byte address (on the mass storage); untouched if file not found @@ -253,6 +279,13 @@ const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char char entry_name[FAT32_MAX_BASENAME_LENGTH + 1]; // entry name Fat32_FileEntry *entry = NULL; // entry iterator + // handle opening the root, return pointer to first ENTRY in the root directory (see description!) + if (path[0] == '\0') { + file_found = true; // the root directory always exists + entry = (Fat32_FileEntry *) buffer; // root directory ENTRIES is in the root sector + } + + // if not root directory, then... while ((!file_found) && (!no_such_file)) { // traversing tree levels // extract first basename uint16_t basename_len = fat32_extract_next_basename_length(path_iter); // get basename length @@ -281,18 +314,21 @@ const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char entry++; - // if we crossed the first buffer - second buffer border, then - // copy the second buffer to the first one and load the next sector - // to the second buffer - if ((void *) entry > (void *) (buffer + SECTOR_SIZE)) { - // copy the second buffer to the first one - fat32_copy_second_to_first_buffer(); - sector++; - READ_MSTG_TO_SECOND_BUFFER(sector + 1); + // check sector and cluster boundary crossing + fat32_check_sector_crossing_and_load(ctrl, &entry, §or); - // modify the entry pointer, since it's been moved - entry = (Fat32_FileEntry *) (((uint8_t *) (entry)) - SECTOR_SIZE); - } +// // if we crossed the first buffer - second buffer border, then +// // copy the second buffer to the first one and load the next sector +// // to the second buffer +// if ((void *) entry > (void *) (buffer + SECTOR_SIZE)) { +// // copy the second buffer to the first one +// fat32_copy_second_to_first_buffer(); +// sector++; +// READ_MSTG_TO_SECOND_BUFFER(sector + 1); +// +// // modify the entry pointer, since it's been moved +// entry = (Fat32_FileEntry *) (((uint8_t *) (entry)) - SECTOR_SIZE); +// } // TODO also must pay attention on crossing not just sector, but cluster boundaries } @@ -301,9 +337,6 @@ const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char if (basename_entry_found) { if (path_iter[0] == '\0') { // ...and it's the end of the path file_found = true; // ...then the file is found - if (file_entry_ba != NULL) { // if file entry writeback address if provided - *file_entry_ba = sector * ctrl->bytes_per_sector + (((uint8_t *) entry) - buffer); - } } else { // ...if it's not the end of the path, then load the cluster corresponding to the entry // determine sector number uint32_t next_cluster = fat32_get_first_cluster(entry); @@ -322,48 +355,15 @@ const Fat32_FileEntry *fat32_locate_file(const Fat32_CtrlBlock *ctrl, const char // return with appropriate value if (!no_such_file) { + if (file_entry_ba != NULL) { // if file entry writeback address if provided + *file_entry_ba = sector * ctrl->bytes_per_sector + (((uint8_t *) entry) - buffer); + } return entry; } else { return NULL; } } -// TODO subject to change, must include cluster crossing check -int fat32_list_dir(const Fat32_CtrlBlock *ctrl, const char *dir) { -// // TODO find directory -// -// // read root directory -// FETCH_MSTG; -// uint32_t sector = ctrl->root_s; -// READ_MSTG_TO_FIRST_BUFFER(sector); -// READ_MSTG_TO_SECOND_BUFFER(sector + 1); -// -// // acquire pointer to the beginning of the file entry table -// Fat32_FileEntry *entry = (Fat32_FileEntry *) buffer; -// while (entry->short_fname[0] != 0x00) { -// if (entry->short_fname[0] != FAT32_UNUSED_FILE_ENTRY) { -// fat32_print_file_entry(&entry); -// } -// entry++; -// -// // if we crossed the first buffer - second buffer border, then -// // copy the second buffer to the first one and load the next sector -// // to the second buffer -// if ((void *) entry > (void *) (buffer + SECTOR_SIZE)) { -// // copy the second buffer to the first one -// fat32_copy_second_to_first_buffer(); -// sector++; -// READ_MSTG_TO_SECOND_BUFFER(sector + 1); -// -// // modify the entry pointer, since it's been moved -// entry = (Fat32_FileEntry *) (((uint8_t *) (entry)) - SECTOR_SIZE); -// } -// } -// -// return 0; - return 0; -} - /** * Get the sequence number of the sector holding the byte pointed by address. * @param ctrl pointer to FAT32 control block @@ -380,12 +380,12 @@ static inline uint32_t fat32_get_sector_by_byte_address(const Fat32_CtrlBlock *c * @param ba byte address of the file entry * @return pointer to file entry */ -static inline const Fat32_FileEntry * fat32_get_file_entry_by_byte_address(const Fat32_CtrlBlock * ctrl, uint32_t ba) { +static inline const Fat32_FileEntry *fat32_get_file_entry_by_byte_address(const Fat32_CtrlBlock *ctrl, uint32_t ba) { uint32_t sector = fat32_get_sector_by_byte_address(ctrl, ba); uint32_t offset = ba % ctrl->bytes_per_sector; FETCH_MSTG; READ_MSTG_TO_FIRST_BUFFER(sector); - return (Fat32_FileEntry *)(buffer + offset); + return (Fat32_FileEntry *) (buffer + offset); } /** @@ -582,7 +582,7 @@ uint32_t fat32_seek_stream(const Fat32_CtrlBlock *ctrl, uint32_t pos, Fat32_File } } } else { // if seeking backwards, then no acceleration is available - const Fat32_FileEntry * entry = fat32_get_file_entry_by_byte_address(ctrl, file_helper->entry_ba); // fetch file entry + const Fat32_FileEntry *entry = fat32_get_file_entry_by_byte_address(ctrl, file_helper->entry_ba); // fetch file entry 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 @@ -605,7 +605,7 @@ uint32_t fat32_seek_stream(const Fat32_CtrlBlock *ctrl, uint32_t pos, Fat32_File uint32_t fat32_read_file_stream(const Fat32_CtrlBlock *ctrl, Fat32_FileHelper *file_helper, uint32_t len, uint8_t *p) { FETCH_MSTG; - Fat32_SeekHint * seek_hint = &file_helper->last_pos; + Fat32_SeekHint *seek_hint = &file_helper->last_pos; uint32_t pos_in_sector = seek_hint->pos - seek_hint->sector_begin_pos; // determine position in current sector @@ -614,6 +614,7 @@ uint32_t fat32_read_file_stream(const Fat32_CtrlBlock *ctrl, Fat32_FileHelper *f // cap length, don't read after the end of the file uint32_t read_len = MIN(len, file_helper->size - seek_hint->pos); uint32_t offset = 0; + uint32_t final_read_len = read_len; // a variable we will return with // reading from a file may involve reading across cluster boundaries @@ -649,9 +650,100 @@ uint32_t fat32_read_file_stream(const Fat32_CtrlBlock *ctrl, Fat32_FileHelper *f seek_hint->pos += copy_size; } - return read_len; + return final_read_len; } // ---------------------- -Fs_Driver fat32_driver = { (fs_drv_open) fat32_open_file }; \ No newline at end of file +/** + * List directory. (I) + * @param ctrl pointer to FAT32 control block + * @param dir path of directory being listed + * @return 0 if successful, anything else refers to errors + */ +int fat32_list_dir(const Fat32_CtrlBlock *ctrl, const char *dir) { + uint32_t cluster, sector; + const Fat32_FileEntry *dir_entry = NULL; + if (dir[0] != '\0') { // if listing anything different from root directory + dir_entry = fat32_locate_file(ctrl, dir, NULL); // search dir entry + if (dir_entry == NULL) { // if file is not found at all + MSG("Directory '%s' could not be located!\n", dir); + return -1; + } else if ((dir[0] != '\0') && !(dir_entry->attributes & FAT32_FATT_DIRECTORY)) { // if found but it's no directory + MSG("It's not a directory!\n"); + return 0; + } + + cluster = fat32_get_first_cluster(dir_entry); // get first cluster + sector = fat32_get_first_sector_of_cluster(ctrl, cluster); // get first (absolute) sector of the cluster + } else { // if listing from the root sector + sector = ctrl->root_s; // get root directory's (absolute) sector + } + + // fill buffers + FETCH_MSTG; + READ_MSTG_TO_FIRST_BUFFER(sector); + READ_MSTG_TO_SECOND_BUFFER(sector + 1); + + // acquire pointer to the beginning of the file entry table + Fat32_FileEntry *entry = (Fat32_FileEntry *) buffer; + while (entry->short_fname[0] != 0x00) { + if (entry->short_fname[0] != FAT32_UNUSED_FILE_ENTRY) { + fat32_print_file_entry(&entry); + } + entry++; + + // check sector and cluster boundary crossing + fat32_check_sector_crossing_and_load(ctrl, &entry, §or); + } + + return 0; +} + +/** + * Get FAT32 volume label. + * @param ctrl pointer to FAT32 control block + * @param label free space of at least 12 bytes (including terminating zero) for storing volume label + * @param maxLen maximum string length + */ +void fat32_get_volume_label(const Fat32_CtrlBlock * ctrl, char * label, uint16_t maxLen) { + // fill buffers + char entry_name[261]; + uint32_t sector = ctrl->root_s; + FETCH_MSTG; + READ_MSTG_TO_FIRST_BUFFER(sector); + READ_MSTG_TO_SECOND_BUFFER(sector + 1); + + // acquire pointer to the beginning of the file entry table + Fat32_FileEntry *entry = (Fat32_FileEntry *) buffer; + while (entry->short_fname[0] != 0x00) { + if (entry->short_fname[0] != FAT32_UNUSED_FILE_ENTRY) { + fat32_get_file_entry(&entry, entry_name); + if (entry->attributes & FAT32_FATT_VOLUME) { // search for volume name entry + strncpy(label, entry_name, maxLen); + label[maxLen] = '\0'; + } + } + entry++; + + // check sector and cluster boundary crossing + fat32_check_sector_crossing_and_load(ctrl, &entry, §or); + } +} + +// ---------------------- + +static int fat32_drv_read(const void * ctrl, void * file, unsigned long len, void * buf) { + return (int) fat32_read_file_stream((Fat32_CtrlBlock *) ctrl, (Fat32_FileHelper *) file, len, (uint8_t *) buf); +} + +static int fat32_drv_seek(const void * ctrl, void * file, unsigned long pos) { + return (int) fat32_seek_stream((Fat32_CtrlBlock *) ctrl, pos, (Fat32_FileHelper *) file); +} + +Fs_Driver fat32_driver = { + (fs_drv_open) fat32_open_file, // open + (fs_drv_seek) fat32_drv_seek, // seek + (fs_drv_read) fat32_drv_read, // read + (fs_drv_list) fat32_list_dir // list files +}; \ No newline at end of file diff --git a/fs/fat32/fat32.h b/fs/fat32/fat32.h index 6ee5281..07d97c2 100644 --- a/fs/fat32/fat32.h +++ b/fs/fat32/fat32.h @@ -11,6 +11,9 @@ #define MSG(...) printf(__VA_ARGS__) #endif +#define FAT32_CHS_PART_ID (0x0B) +#define FAT32_LBA_PART_ID (0x0C) + typedef struct { uint8_t boot_jump[3]; // jump instruction used for bootable volume uint8_t formatter_name[8]; // identification of application or OS formatted this device @@ -123,5 +126,6 @@ uint32_t fat32_seek_stream(const Fat32_CtrlBlock *ctrl, uint32_t pos, Fat32_File uint32_t fat32_read_file_stream(const Fat32_CtrlBlock *ctrl, Fat32_FileHelper *file_helper, uint32_t len, uint8_t *p); +void fat32_get_volume_label(const Fat32_CtrlBlock * ctrl, char * label, uint16_t maxLen); #endif //EMBPART_FAT32_H diff --git a/fs/fs_driver.h b/fs/fs_driver.h index 3e668de..3a40f36 100644 --- a/fs/fs_driver.h +++ b/fs/fs_driver.h @@ -4,12 +4,14 @@ typedef int (*fs_drv_open)(const void * ctrl, const char * path, void * file); typedef int (*fs_drv_seek)(const void * ctrl, void * file, unsigned long pos); typedef int (*fs_drv_read)(const void * ctrl, void * file, unsigned long len, void * buf); +typedef int (*fs_drv_list)(const void * ctrl, const char * path); // File system driver typedef struct { fs_drv_open open; fs_drv_seek seek; fs_drv_read read; + fs_drv_list list; } Fs_Driver; #endif //EMBPART_FS_DRIVER_H diff --git a/mbr/mbr.h b/mbr/mbr.h index a436113..f447910 100644 --- a/mbr/mbr.h +++ b/mbr/mbr.h @@ -3,6 +3,8 @@ #include +#define MBR_MAX_PARTITIONS (4) + // partition entry typedef struct { diff --git a/mount/mount.c b/mount/mount.c index 68608c6..054cccb 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -1,5 +1,246 @@ +#include +#include #include "mount.h" +#include "../MassStorage.h" +#include "../mbr/mbr.h" +#include "../fs/fat32/fat32.h" -int mnt_automount_disk() { +#define AUTOMOUNT_SECTOR_SIZE (512) -} \ No newline at end of file +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +static Mnt_MountTable mtab = { 0 }; +static Mnt_FileTable ftab = { 0 }; + +/** + * Attempts to mount a volume. + * @param mstg pointer to Mass Storage object + * @param part pointer to partition entry + * @return 0 if concluded without error (even if partition of unknown type could not be mounted) + */ +static int mnt_mount_volume(MassStorage * mstg, const PartEntry * part) { + // fetch common partition details + Mnt_Volume * next_entry = mtab.vols + mtab.mounted_vols; // pointer to control block area + uint8_t * cbk = next_entry->fs_control_block_area; // control block area to be written + next_entry->mnt_name[MNT_MAX_MOUNT_NAME_LENGTH] = '\0'; // write terminating zero in advance + int mount_success = -1; + + // attempt to mount partition + switch (part->part_type) { + case 0: // empty slot + break; + case FAT32_CHS_PART_ID: // FAT32 + case FAT32_LBA_PART_ID: { + Fat32_CtrlBlock *ctrl = (Fat32_CtrlBlock *) cbk; + mount_success = fat32_load(ctrl, part->lba_fa, mstg); + if (mount_success == 0) { + fat32_get_volume_label(ctrl, next_entry->mnt_name, MNT_MAX_MOUNT_NAME_LENGTH); // get volume name + next_entry->driver = fat32_driver; // assign driver + } + } + break; + default: // unmountable file system's found on the disk + MSG("Unknown file system type: %d, cannot mount!\n", part->part_type); + break; + } + + // if succeeded, then maintain mount table + if (mount_success > -1) { + next_entry->part_size = part->sector_count * AUTOMOUNT_SECTOR_SIZE; // save volume size + mtab.mounted_vols++; // increase number of mounted partitions + } + + return 0; +} + +/** + * Attempt to automount disk volumes. + * @param mstg pointer to Mass Storage object + * @return 0 if successful + */ +int mnt_automount_disk(MassStorage * mstg) { + // load the first sector + uint8_t buf[AUTOMOUNT_SECTOR_SIZE]; + mstg->read_sector(mstg, 0, buf); + + // fetch partitions from the disk + const PartEntry * partList = mbr_get_partitions(buf); + if (partList == NULL) { // not an MBR disk + return 0; + } + + // if it's an MBR disk, iterate over all four partition slots + mtab.mounted_vols = 0; + PartEntry parts[MBR_MAX_PARTITIONS]; + memcpy(parts, partList, sizeof(PartEntry) * MBR_MAX_PARTITIONS); // copy partition table + for (uint8_t i = 0; (i < MBR_MAX_PARTITIONS) && (mtab.mounted_vols < MNT_MAX_MOUNTED_VOLUMES); i++) { + const PartEntry * part = parts + i; // fetch a partition + mnt_mount_volume(mstg, part); // attempt mounting a volume + } + + return 0; +} + +/** + * Get volume by name. + * @param name volume name + * @return pointer to volume, if found OR NULL + */ +Mnt_Volume * mnt_get_volume_by_name(const char * name) { + Mnt_Volume * vol = NULL; + for (uint8_t i = 0; i < mtab.mounted_vols; i++) { + if (!strncmp(mtab.vols[i].mnt_name, name, MNT_MAX_MOUNT_NAME_LENGTH)) { + vol = mtab.vols + i; + break; + } + } + return vol; +} + +#define MNT_DIRSEP '/' + +/** + * Separate volume name and the path relative to the volume's root. + * @param volpath string of /volume/path + * @param volname pointer to free area up to max_volname_len bytes + * @param max_volname_len size of free area not including terminating zero + * @return pointer to the relative path + */ +const char * mnt_separate_volume_path(const char * volpath, char * volname, uint16_t max_volname_len) { + const char * iter = volpath; + + // strip first '/' + if (*iter == MNT_DIRSEP) { + iter++; + } + + // search the end of volume name + uint16_t i = 0; + while ((*iter != MNT_DIRSEP) && (*iter != '\0')) { + if (i < max_volname_len) { // copy only so many that we can store + volname[i++] = *iter; + } + iter++; + } + volname[i] = '\0'; + + // skip '/' at the end of the volume name + if (*iter == MNT_DIRSEP) { + iter++; + } + + return iter; +} + +/** + * Get volume by name extracted from a file's path stored on the volume. + * @param volpath path beginning with the /volume name/ + * @param path path of the file on the volume (relative to volume root) + * @return pointer to a mounted volume OR NULL if not found + */ +Mnt_Volume * mnt_get_volume_by_path(const char * volpath, const char ** path) { + const char * ret; + char volname[MNT_MAX_MOUNT_NAME_LENGTH + 1]; + ret = mnt_separate_volume_path(volpath, volname, MNT_MAX_MOUNT_NAME_LENGTH); + if (path != NULL) { + *path = ret; + } + + return mnt_get_volume_by_name(volname); +} + +#define MNT_FTAB_BLOCK_FREE (0) +#define MNT_FTAB_BLOCK_OCCUPIED (1) + +/** + * Allocate space for a newly opened file's helper object. + * @return allocated slot OR NULL is allocation was not possible + */ +Mnt_File * mnt_alloc_file_helper() { + Mnt_File * slot = NULL; + for (uint8_t i = 0; i < MNT_MAX_OPEN_FILES; i++) { + if (ftab.files[i].ctrl_word == MNT_FTAB_BLOCK_FREE) { + ftab.files[i].ctrl_word = MNT_FTAB_BLOCK_OCCUPIED; + slot = ftab.files + i; + break; + } + } + return slot; +} + +/** + * Release file helper. + * @param helper pointer to helper + */ +void mnt_free_file_helper(Mnt_File * file) { + file->ctrl_word = MNT_FTAB_BLOCK_FREE; +} + +// ----------------------- + +/** + * List directory. + * @param dir path to the directory + */ +void mnt_list(const char *dir) { + // if + if ((dir[0] == '\0') || ((dir[0] == MNT_DIRSEP) && (dir[1] == '\0'))) { + for (uint8_t i = 0; i < mtab.mounted_vols; i++) { + MSG("/%s VOLUME\n", mtab.vols[i].mnt_name); + } + return; + } + + // if not empty path is specified + const char * relpath; + Mnt_Volume * vol = mnt_get_volume_by_path(dir, &relpath); + if (vol != NULL) { + (vol->driver).list((void *) vol->fs_control_block_area, relpath); + } +} + +/** + * Open file. + * @param path full path to file + * @return pointer to file handle + */ +Mnt_File * mnt_open(const char * path) { + Mnt_File * file = NULL; + const char * relpath; + Mnt_Volume * vol = mnt_get_volume_by_path(path, &relpath); + if (vol != NULL) { + file = mnt_alloc_file_helper(); + if (file != NULL) { + file->vol = vol; + (vol->driver).open(vol->fs_control_block_area, relpath, file->helper); + } + } + return file; +} + +/** + * Read from the file. + * @param file pointer to Mnt_File object + * @param len (desired) read length + * @param buf destination buffer + * @return actual read length + */ +int mnt_read(Mnt_File * file, unsigned long len, void * buf) { + Mnt_Volume * vol = file->vol; + return vol->driver.read(vol->fs_control_block_area, (void *) file->helper, len, buf); +} + +/** + * Seek the file. + * @param file pointer to Mnt_File object + * @param pos position from the beginning + * @return ??? + */ +int mnt_seek(Mnt_File * file, unsigned long pos) { + Mnt_Volume * vol = file->vol; + return vol->driver.seek(vol->fs_control_block_area, (void *) file->helper, pos); +} + +void mnt_close(Mnt_File *file) { + mnt_free_file_helper(file); +} diff --git a/mount/mount.h b/mount/mount.h index dae9167..1e6b996 100644 --- a/mount/mount.h +++ b/mount/mount.h @@ -2,18 +2,47 @@ #define EMBPART_MOUNT_H #include +#include "../MassStorage.h" +#include "../fs/fs_driver.h" #define MNT_MAX_MOUNTED_VOLUMES (4) #define MNT_MAX_MOUNT_NAME_LENGTH (15) +#define MNT_CTRL_BLOCK_PREALLOC_SIZE (64) +#define MNT_MAX_OPEN_FILES (6) +#define MNT_FILE_HELPER_PREALLOC_SIZE (47) typedef struct { - void * fs_control_block; // pointer to file system control block uint32_t part_size; // partition size char mnt_name[MNT_MAX_MOUNT_NAME_LENGTH + 1]; // name of the mount -} Mnt_MountEntry; + Fs_Driver driver; // file system driver + uint8_t fs_control_block_area[MNT_CTRL_BLOCK_PREALLOC_SIZE]; // pointer to file system control block +} Mnt_Volume; typedef struct { - Mnt_MountEntry vols[MNT_MAX_MOUNTED_VOLUMES]; // volume slots + Mnt_Volume vols[MNT_MAX_MOUNTED_VOLUMES]; // volume slots + uint8_t mounted_vols; // number of mounted volumes } Mnt_MountTable; +typedef struct { + Mnt_Volume * vol; // pointer to volume + uint8_t helper[MNT_FILE_HELPER_PREALLOC_SIZE]; // pointer to helper object + uint8_t ctrl_word; // control word +} Mnt_File; + +typedef struct { + Mnt_File files[MNT_MAX_OPEN_FILES]; // file helpers +} Mnt_FileTable; + +int mnt_automount_disk(MassStorage * mstg); // attempt to automount volumes + +void mnt_list(const char * dir); + +Mnt_File * mnt_open(const char * path); + +int mnt_read(Mnt_File * file, unsigned long len, void * buf); + +int mnt_seek(Mnt_File * file, unsigned long pos); + +void mnt_close(Mnt_File * file); + #endif //EMBPART_MOUNT_H