284 lines
8.3 KiB
C
284 lines
8.3 KiB
C
#include "mount.h"
|
|
#include "../MassStorage.h"
|
|
#include "../fs/fat32/fat32.h"
|
|
#include "../mbr/mbr.h"
|
|
#include <memory.h>
|
|
#include <stddef.h>
|
|
|
|
#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) && (ftab.open_files < 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;
|
|
ftab.open_files++;
|
|
break;
|
|
}
|
|
}
|
|
return slot;
|
|
}
|
|
|
|
/**
|
|
* Release file helper.
|
|
* @param helper pointer to helper
|
|
*/
|
|
void mnt_free_file_helper(Mnt_File *file) {
|
|
if (ftab.open_files > 0) {
|
|
file->ctrl_word = MNT_FTAB_BLOCK_FREE;
|
|
ftab.open_files--;
|
|
}
|
|
}
|
|
|
|
// -----------------------
|
|
|
|
/**
|
|
* 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 %.3f MB VOLUME\n", mtab.vols[i].mnt_name, mtab.vols[i].part_size * 1E-06);
|
|
}
|
|
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;
|
|
int success = (vol->driver).open(vol->fs_control_block_area, relpath, file->helper);
|
|
if (success != 0) { // release file helper if could not open file
|
|
mnt_free_file_helper(file);
|
|
file = NULL;
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
|
|
// --------------
|
|
|
|
/**
|
|
* Get file system name from type ID.
|
|
* @param fst file system type ID
|
|
* @return file system name
|
|
*/
|
|
static inline const char *mnt_fs_type_to_str(uint8_t fst) {
|
|
switch (fst) {
|
|
case FAT32_CHS_PART_ID:
|
|
case FAT32_LBA_PART_ID:
|
|
return "FAT32";
|
|
default:
|
|
return "N/A";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print state and statistical infromation.
|
|
*/
|
|
void mnt_print_info() {
|
|
MSG("\n\n---- MOUNT/FILES stats ----\n");
|
|
MSG(" Mounted volumes: %u\n", mtab.mounted_vols);
|
|
for (uint32_t i = 0; i < mtab.mounted_vols; i++) {
|
|
MSG(" /%s %.3f MB\n", mtab.vols[i].mnt_name, mtab.vols[i].part_size * 1E-06);
|
|
}
|
|
MSG(" Open files: %u\n\n", ftab.open_files);
|
|
MSG("---------------------------\n\n");
|
|
}
|