- Sequential file reading works
- FAT32 file system driver is defined - Automount implemented - Unified file operations implemented - File listing implemented
This commit is contained in:
parent
af2db137f9
commit
d7a5a49394
@ -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
|
||||
|
208
fs/fat32/fat32.c
208
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
|
||||
@ -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 };
|
||||
/**
|
||||
* 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
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MBR_MAX_PARTITIONS (4)
|
||||
|
||||
// partition entry
|
||||
|
||||
typedef struct {
|
||||
|
243
mount/mount.c
243
mount/mount.c
@ -1,5 +1,246 @@
|
||||
#include <stddef.h>
|
||||
#include <memory.h>
|
||||
#include "mount.h"
|
||||
#include "../MassStorage.h"
|
||||
#include "../mbr/mbr.h"
|
||||
#include "../fs/fat32/fat32.h"
|
||||
|
||||
int mnt_automount_disk() {
|
||||
#define AUTOMOUNT_SECTOR_SIZE (512)
|
||||
|
||||
#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);
|
||||
}
|
@ -2,18 +2,47 @@
|
||||
#define EMBPART_MOUNT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#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
|
||||
|
Loading…
x
Reference in New Issue
Block a user