Nigel
b07b4f0d38
Problem: As our kernel grows we need more complex datastructures and functions these would come from the standard C/C++ library with normal programs. The kernel is a freestanding programme and has no access to standard libraries. Solution: We build a mini version of the standard C/C++ library which will contain the datastructures and functions we want. This library can then be statically linked into our kernel binary. Making it a statically linked library also gives more structure to the project. Keeping these random functions and datastructures in the kernel just clutters the kernel source code with less relevant source code.
417 lines
12 KiB
C++
417 lines
12 KiB
C++
#include "VFS.h"
|
|
#include "../filesystem/FAT/BiosParameterBlock.h"
|
|
#include "../drivers/ide/ide.h"
|
|
#include "../drivers/ata/ataDevice.h"
|
|
#include "../partitiontable/mbr/MasterBootRecord.h"
|
|
#include "../memory/KernelHeap.h"
|
|
#include "../../CoreLib/Memory.h"
|
|
#include "../filesystem/FAT/DirectoryEntry.h"
|
|
|
|
MOUNT_INFO mountInfo;
|
|
|
|
PFILESYSTEM _filesystems[DEVICE_MAX];
|
|
|
|
FILE volOpenFile(const char* fname)
|
|
{
|
|
if(fname){
|
|
unsigned char device = 'a';
|
|
|
|
char* filename = (char*) fname;
|
|
|
|
if(fname[1]== ':'){
|
|
device = fname[0];
|
|
filename += 2; // strip the volume component from the path
|
|
}
|
|
|
|
if(_filesystems[device - 'a']){
|
|
FILE file = _filesystems[device-'a']->Open(filename);
|
|
file.device = device;
|
|
return file;
|
|
}
|
|
}
|
|
|
|
FILE file;
|
|
file.flags = FS_INVALID;
|
|
return file;
|
|
}
|
|
|
|
extern void volReadFile(PFILE file, unsigned char* Buffer, unsigned int length)
|
|
{
|
|
|
|
}
|
|
extern void volCloseFile(PFILE file)
|
|
{
|
|
if( file->device < DEVICE_MAX){
|
|
// _filesystems[file->device]->Close(file);
|
|
}
|
|
}
|
|
|
|
extern void volRegisterFilesystem(PFILESYSTEM fsys , unsigned int deviceID){
|
|
if(deviceID < DEVICE_MAX)
|
|
if(fsys)
|
|
_filesystems[deviceID] = fsys;
|
|
}
|
|
|
|
extern void volUnregisterFilesystem(PFILESYSTEM){
|
|
|
|
}
|
|
|
|
extern void volUnregisterFileSystemByID(unsigned int deviceID){
|
|
|
|
}
|
|
|
|
enum BUS_PORT {
|
|
Primary = 0x1f0,
|
|
Secondary = 0x170
|
|
};
|
|
|
|
bool driveAvailable(){
|
|
int devNumber = 0;
|
|
for ( auto device : ide_devices){
|
|
if(!device.Reserved)
|
|
continue;
|
|
devNumber++;
|
|
}
|
|
|
|
|
|
// FIXME: If no drive is connected we continue trying to read from
|
|
// a not connected drive!
|
|
ATA_DEVICE::Identify((uint16_t) BUS_PORT::Primary, DEVICE_DRIVE::MASTER);
|
|
return true;
|
|
}
|
|
|
|
MBR* getPartitions(bool DEBUG = false){
|
|
const int C = 0;
|
|
const int H = 0;
|
|
const int HPC = 16;
|
|
const int SPT = 63;
|
|
|
|
int S =1;
|
|
uint32_t LBA = (C*HPC+H) * SPT + (S-1);
|
|
MBR* mbr =(MBR*) malloc(sizeof (MBR));
|
|
|
|
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, LBA, (uint16_t*)mbr);
|
|
|
|
if(DEBUG){
|
|
printf("BootSector: 0x%x\n", mbr->ValidBootsector );
|
|
for( int i = 0 ; i < 4 ; i ++){
|
|
PartitionTableEntry PT = mbr->TableEntries[i];
|
|
|
|
printf("Partition %d [ %d sectors, PartitionType: 0x%x, 0x%x, \nLBA Start: 0x%x ]\n" ,
|
|
i, PT.Number_sectors_inPartition, PT.PartitionType, mbr->uniqueID, PT.LBA_partition_start );
|
|
}
|
|
|
|
}
|
|
|
|
return mbr;
|
|
}
|
|
|
|
BiosParameterBlock* getBPB(MBR* mbr, bool DEBUG =false ){
|
|
BiosParameterBlock* bpb = (BiosParameterBlock*) malloc(sizeof(BiosParameterBlock));
|
|
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, mbr->TableEntries[0].LBA_partition_start, (uint16_t*) bpb);
|
|
|
|
if(DEBUG)
|
|
{
|
|
printf("OEM ID: %s\n", bpb->OEM_id);
|
|
printf("Bytes per sector: %d\n", bpb->BytesPerSector);
|
|
printf("Sectors per cluster: %d\n", bpb->SectorsPerCluster);
|
|
printf("Reserved sectors: %d\n", bpb->ReservedSectors);
|
|
printf("Number of FAT: %d\n", bpb->NumberOfFileAllocationTables);
|
|
printf("Number of Dir entries: %d\n", bpb->NumberOfDirectoryEntries);
|
|
printf("Total Sectors in volume: %d\n", bpb->TotalSectorsInLogicalVolume);
|
|
printf("Sectors per FAT: %d\n", bpb->NumberOfSectorsPerFAT);
|
|
}
|
|
|
|
|
|
|
|
return bpb;
|
|
}
|
|
|
|
uint16_t* ReadFAT (BiosParameterBlock& bpb , MBR& mbr, bool DEBUG = false ) {
|
|
uint32_t FATAddress = mbr.TableEntries[0].LBA_partition_start + bpb.ReservedSectors ;
|
|
uint16_t* FAT = (uint16_t*)malloc(sizeof (uint16_t) * 256);
|
|
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, FATAddress, FAT );
|
|
|
|
// Show data in terminal
|
|
if(DEBUG){
|
|
for( unsigned int i =0 ; i < 256 ; i++) {
|
|
printf("0x%x ", (unsigned short)FAT[i]);
|
|
}
|
|
kterm_put('\n');
|
|
}
|
|
|
|
return FAT;
|
|
}
|
|
void readFile(uint32_t DataRegion, DirectoryEntry* entry, uint16_t FATentry, BiosParameterBlock& bpb ){
|
|
printf("Show contents");
|
|
|
|
printf("Start cluster of the file: 0x%x\n", entry->StartingCluster);
|
|
|
|
printf("IS it only 1 cluster? %s\n", FATentry == 0xFFFF ? "Yes" : "No");
|
|
|
|
uint32_t sector = DataRegion + ((entry->StartingCluster - 0x02) * bpb.SectorsPerCluster);
|
|
|
|
|
|
uint16_t dataBlob[256];
|
|
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, sector, dataBlob);
|
|
for (unsigned short n: dataBlob) {
|
|
kterm_put(n & 0x00ff);
|
|
|
|
kterm_put(n >> 8);
|
|
}
|
|
kterm_put('\n');
|
|
}
|
|
void listFilesInRoot(MBR& mbr, BiosParameterBlock& bpb ){
|
|
auto FATAddress = mbr.TableEntries[0].LBA_partition_start + bpb.ReservedSectors;
|
|
uint32_t RootDirectoryRegion = FATAddress + ( bpb.NumberOfFileAllocationTables * bpb.NumberOfSectorsPerFAT );
|
|
uint32_t DataRegion = RootDirectoryRegion + ((bpb.NumberOfDirectoryEntries * 32) / bpb.BytesPerSector );
|
|
uint16_t* FAT = ReadFAT(bpb, mbr);
|
|
|
|
uint16_t data2 [256];
|
|
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, RootDirectoryRegion, data2 );
|
|
auto* RootDirectory = (DirectoryEntry*) data2;
|
|
|
|
// List files in root
|
|
for(int i= 0; i < sizeof (data2) / sizeof (DirectoryEntry); i++ ) {
|
|
auto *entry = (DirectoryEntry * )((uint32_t) RootDirectory + (i * sizeof(DirectoryEntry)));
|
|
|
|
if (entry->filename[0] == (uint8_t) 0x00)
|
|
continue; // There are no more entries in this directory or the entry is free
|
|
|
|
if ((entry->attribute & 0x01) == 0x01 || (entry->attribute & 0x20) == 0x20)
|
|
continue; // Skip listing if hidden or Achieve flag is set
|
|
|
|
// Print the filename;
|
|
for (char n: entry->filename) {
|
|
if (n == 0x20)
|
|
break;
|
|
kterm_put(n);
|
|
}
|
|
for (unsigned char n: entry->Extension) {
|
|
kterm_put(n);
|
|
}
|
|
kterm_put('\n');
|
|
|
|
|
|
printf("Attribute: %x \n", entry->attribute);
|
|
printf("FileSize: %d Bytes\n", entry->FilesizeInBytes);
|
|
|
|
if (entry->FilesizeInBytes != 0x0 && (entry->attribute == 0x08)) {
|
|
readFile(DataRegion,entry, FAT[i], bpb);
|
|
}
|
|
|
|
}
|
|
free(FAT);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
FILE fsysFatDirectory (const char* DirectoryName){
|
|
FILE file;
|
|
unsigned char* buf;
|
|
PDIRECTORY directory;
|
|
|
|
char DosFileName[11];
|
|
ToDosFileName(DirectoryName, DosFileName, 11);
|
|
DosFileName[11] =0;
|
|
|
|
for (int sector=0; sector <14 ; sector++){
|
|
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, mountInfo.rootOffset + sector, (uint16_t*)buf);
|
|
directory = (PDIRECTORY) buf;
|
|
|
|
for (int i =0; i < 16; i++){
|
|
char name[11];
|
|
memcpy(name, directory->Filename, 11);
|
|
name[11]=0;
|
|
|
|
if(strncmp(DosFileName, name, 11) == 0){
|
|
strcpy(file.name, DirectoryName);
|
|
file.id = 0;
|
|
file.currentCluster = directory->FirstCluster;
|
|
file.eof = 0;
|
|
file.filelength = directory->FileSize;
|
|
|
|
if(directory->Attrib == 0x10){
|
|
file.flags = FS_DIRECTORY;
|
|
} else {
|
|
file.flags = FS_FILE;
|
|
}
|
|
return file;
|
|
}
|
|
directory++;
|
|
}
|
|
}
|
|
|
|
// Can't find file
|
|
file.flags = FS_INVALID;
|
|
return file;
|
|
|
|
}
|
|
*/
|
|
|
|
void fsysFATRead(PFILE file, unsigned char* buffer, unsigned int length){
|
|
if(file){
|
|
unsigned int physSector = 32 + (file->currentCluster - 1);
|
|
const unsigned int SECTOR_SIZE = 512;
|
|
// read sector
|
|
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, physSector, (uint16_t*) buffer );
|
|
|
|
unsigned int FAT_Offset = file->currentCluster + (file->currentCluster /2);
|
|
unsigned int FAT_Sector = 1 + (FAT_Offset / SECTOR_SIZE);
|
|
unsigned int entryOffset =FAT_Offset % SECTOR_SIZE;
|
|
|
|
uint8_t FAT[SECTOR_SIZE*2];
|
|
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, FAT_Sector,(uint16_t*) FAT); // Read 1st FAT sector
|
|
|
|
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, FAT_Sector +1, (uint16_t*)FAT+SECTOR_SIZE);
|
|
|
|
// read entry for next cluster
|
|
uint16_t nextCluster = *(uint16_t*) &FAT[entryOffset];
|
|
|
|
// test if entry is odd or even
|
|
if(file->currentCluster & 0x0001){
|
|
nextCluster>>= 4; // grab the high 12 bits
|
|
}else{
|
|
nextCluster &= 0x0FFF; // grab the low 12 bits
|
|
}
|
|
|
|
// test for end of file
|
|
if(nextCluster >= 0xff8){
|
|
file->eof -1;
|
|
return;
|
|
}
|
|
|
|
// test for file corruption
|
|
if(nextCluster == 0){
|
|
file->eof =1;
|
|
return;
|
|
}
|
|
|
|
// set next cluster
|
|
file->currentCluster = nextCluster;
|
|
|
|
|
|
}
|
|
}
|
|
/*
|
|
FILE fsysFatOpenSubDir(FILE kFile, const char* filename){
|
|
FILE file;
|
|
|
|
char DosFileName[11];
|
|
ToDosFileName(filename, DosFileName, 11);
|
|
DosFileName[11] = 0;
|
|
|
|
while(!kFile.eof){
|
|
//read directory
|
|
unsigned char buf[512];
|
|
fsysFATRead(&file, buf, 512);
|
|
|
|
PDIRECTORY pkDir = (PDIRECTORY) buf;
|
|
|
|
for (unsigned int i = 0; i < 16; i++){
|
|
// get current filename
|
|
char name[11];
|
|
memcpy(name, pkDir->Filename, 11);
|
|
name[11] = 0;
|
|
|
|
if(strncmp(name, DosFileName, 11) == 0){
|
|
strcpy(file.name, filename);
|
|
file.id = 0;
|
|
file.currentCluster = pkDir->FirstCluster;
|
|
file.filelength = pkDir->FileSize;
|
|
file.eof = 0;
|
|
|
|
// set file type;
|
|
if(pkDir->Attrib == 0x10){
|
|
file.flags = FS_DIRECTORY;
|
|
} else{
|
|
file.flags = FS_FILE;
|
|
}
|
|
|
|
return file;
|
|
}
|
|
// go to next entry
|
|
pkDir++;
|
|
}
|
|
}
|
|
// unable to find file
|
|
file.flags = FS_INVALID;
|
|
return file;
|
|
}
|
|
*/
|
|
|
|
void FileSystem::initialize()
|
|
{
|
|
MBR* mbr = getPartitions();
|
|
BiosParameterBlock* bootsector = getBPB(mbr);
|
|
listFilesInRoot(*mbr, *bootsector);
|
|
|
|
free(mbr);
|
|
free(bootsector);
|
|
/*
|
|
mountInfo.numSectors = bootsector->NumberOfSectorsPerFAT;
|
|
mountInfo.fatOffset = 1;
|
|
mountInfo.fatSize = bootsector->NumberOfSectorsPerFAT;
|
|
mountInfo.fatEntrySize = 8;
|
|
mountInfo.numRootEntries = bootsector->NumberOfDirectoryEntries;
|
|
mountInfo.rootOffset = (bootsector->NumberOfFileAllocationTables * bootsector->NumberOfSectorsPerFAT) + 1;
|
|
mountInfo.rootSize = (bootsector->NumberOfDirectoryEntries * 32) / bootsector->BytesPerSector;
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
char* FindNextEntryName (char* path )
|
|
{
|
|
int length = strlen(path);
|
|
|
|
char* name = path;
|
|
int i = 0;
|
|
|
|
if( name[0] == '/')
|
|
i++;
|
|
|
|
while ( name[i] != '/' && i <= length)
|
|
i++;
|
|
|
|
char* s = (char*) malloc(i + 1 * sizeof(char));
|
|
for ( int a = 0; a < i; a++)
|
|
s[a] = path[a];
|
|
|
|
s[i + 1] = '\0';
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileSystem::ResolvePath(Path &path)
|
|
{
|
|
// See reference material (1) https://man7.org/linux/man-pages/man7/path_resolution.7.html
|
|
|
|
char* string_path = path.str();
|
|
void* cpy = string_path;
|
|
|
|
bool isAbsolutePath = string_path[0] == '/';
|
|
if(isAbsolutePath)
|
|
{
|
|
// strip the first slash
|
|
string_path++;
|
|
}
|
|
|
|
char* entry_name = FindNextEntryName(string_path);
|
|
printf("Look for entry with name: %s\n", entry_name);
|
|
int skip = strlen(entry_name);
|
|
free(entry_name);
|
|
|
|
|
|
entry_name = FindNextEntryName(string_path + skip);
|
|
printf("Look for entry with name: %s\n", entry_name);
|
|
skip = strlen(entry_name);
|
|
free(entry_name);
|
|
|
|
free(cpy);
|
|
|
|
} |