luxos/Kernel/hal/vfs.c

244 lines
5.5 KiB
C

#include <array.h>
#include <memory.h>
#include <fileio.h>
#include <debugio.h>
#include <stdlib.h>
#define BAD 0xffffffff
DynamicArray fsList;
DynamicArray mpList;
FileSystem* fsArray;
MountPoint* mpArray;
void VfsInstall ()
{
DynamicArrayCreate(sizeof(FileSystem), &fsList);
DynamicArrayCreate(sizeof(MountPoint), &mpList);
fsArray = (FileSystem*) fsList.Data;
mpArray = (MountPoint*) mpList.Data;
Log("VFS", "%#Vfs now in business.\n", ColorLightGreen);
}
void VfsInstallFs (FileSystem* fs)
{
fs->Id = fsList.Size;
DynamicArrayPush(fs, &fsList);
Log("VFS", "Installed file system %#%s%# (id=%u).\n", ColorWhite, fs->Name,
ColorLightGray, fs->Id);
}
int32 _VfsFindDevice (string name)
{
int32 i;
for (i = 0; (uint32)i < mpList.Size; i++)
if (mpArray[i].Id != BAD && strcmp (name, mpArray[i].Name) == 0) return i;
return -1;
}
string _VfsGetDevice (string path, int32* dev)
{
// Make sure path is valid
if (!path || *path != '/') {
*dev = -1; return NULL;
}
// Do we need to return root?
path++;
if (*path == '\0') return NULL; // Yes, but not implemented yet
// Find the next '/'
int32 i, index = -1, len = strlen(path);
for (i = 0; i < len && index == -1; i++)
if (path[i] == '/') index = i;
if (index == -1) index = len;
// Find the device
*dev = -1;
for (i = 0; (uint32)i < mpList.Size && *dev == -1; i++)
if (mpArray[i].Id != BAD && strncmp(path, mpArray[i].Name, index) == 0)
*dev = i;
return &path[index];
}
int32 _VfsDetectFs (MountPoint* mp)
{
int32 i;
for (i = 0; (uint32)i < fsList.Size; i++)
if (fsArray[i].Detect && fsArray[i].Detect(mp)) return i;
return -1;
}
int32 VfsTestDevname (string name)
{
// Check if name exists
uint8 success = (_VfsFindDevice(name) == -1);
// Set up for search
char find;
uint32 len = strlen(name);
name[len+1] = '\0';
// Name exists? Try a number
for (find = '0'; find <= '9' && !success; find++)
{
name[len] = find;
success = (_VfsFindDevice(name) == -1);
}
// Whoa... nothing? Try the alphabet.
for (find = 'a'; find <= 'z' && !success; find++)
{
name[len] = find;
success = (_VfsFindDevice(name) == -1);
}
return success;
}
MountPoint* VfsMount (string devname, DevReadRoutine R, DevWriteRoutine W, uint32 bs)
{
// Create a mount point
MountPoint mp ;
strcpy(mp.Name, devname);
mp.BlockSize = bs;
mp.Read = R;
mp.Write = W;
// Detect file system
int32 fsid = _VfsDetectFs(&mp);
if (fsid == -1) {
Error("VFS", "%#Failed to mount device %s: could not find a file system.\n", ColorLightRed, devname);
return NULL;
}
mp.FsId = (uint32) fsid;
// Rename if it has problems
if (!VfsTestDevname(mp.Name)) {
Error("VFS", "%#Failed to mount device %s: bad name.\n", ColorLightRed, devname);
return NULL;
}
// Find an empty slot
uint32 empty = BAD, i;
for (i = 0; i < mpList.Size && empty == BAD; i++)
if (mpArray[i].Id == BAD) empty = i;
// Mount it
if (empty == BAD) {
mp.Id = mpList.Size;
DynamicArrayPush(&mp, &mpList);
}
else {
mp.Id = empty;
memcpy ( &mpArray[empty], &mp, sizeof(MountPoint));
}
// Tell the FS to mount the device
if (fsArray[fsid].MountDevice)
fsArray[fsid].MountDevice(&mpArray[mp.Id]);
// Log
Log("VFS", "Mounted device %#%s%# using the %#%s%# file system.\n", ColorWhite, mp.Name,
ColorLightGray, ColorWhite, fsArray[fsid].Name, ColorLightGray);
return &mpArray[mp.Id];
}
void VfsUnmount (uint32 devid)
{
if (fsArray[mpArray[devid].FsId].UnmountDevice)
fsArray[mpArray[devid].FsId].UnmountDevice(&mpArray[devid],0);
// Invalidate ID
mpArray[devid].Id = BAD;
// We shouldn't remove it from the array, because it will invalidate
// all other devices' IDs.
}
// Returns pointer to FILE structure that was inputed if success, null otherwise
FILE* VfsOpen (FILE* file, string path)
{
if (!file) return NULL;
// Parse string
int32 dev; string temp;
temp = _VfsGetDevice(path, &dev);
file->DeviceId = dev;
// Device not found, or Open routine doesn't exist
if (dev == -1 || !fsArray[mpArray[dev].FsId].Open) return NULL;
// Ask the FS to do the 'opening'
return fsArray[mpArray[dev].FsId].Open(&mpArray[dev],file,temp);
}
DirectoryEntry* VfsTest (string path)
{
// Parse string
int32 dev;
path = _VfsGetDevice(path, &dev);
// Device not found, or Open routine doesn't exist
if (dev == -1 || !fsArray[mpArray[dev].FsId].Test) return NULL;
// Ask the FS to do the 'opening'
return fsArray[mpArray[dev].FsId].Test(&mpArray[dev],path);
}
FILE* VfsClose (FILE* file)
{
if (!file) return NULL;
MountPoint* mp = &(mpArray[file->DeviceId]);
if (!fsArray[mp->FsId].Close) return NULL;
return fsArray[mp->FsId].Close(mp,file);
}
uint32 VfsRead (FILE* file, uint32 bsz, uint32 n, uint8* buffer)
{
if (!file) return NULL;
MountPoint* mp = &(mpArray[file->DeviceId]);
if (!fsArray[mp->FsId].Read) return NULL;
return fsArray[mp->FsId].Read(mp, file, bsz, n, buffer);
}
uint32 VfsWrite (FILE* file, uint32 bsz, uint32 n, uint8* buffer)
{
if (!file) return NULL;
MountPoint* mp = &(mpArray[file->DeviceId]);
if (!fsArray[mp->FsId].Write) return NULL;
return fsArray[mp->FsId].Write(mp, file, bsz, n, buffer);
}
DirectoryEntry* VfsReadDirectory (FILE* handle, uint32 index)
{
if (!handle) return NULL;
MountPoint* mp = &(mpArray[handle->DeviceId]);
// Don't try to read files as directories
if ((handle->Flags & 0x7) == FileFile) return NULL;
// Ask FS to make the read
if (!fsArray[mp->FsId].ReadDirectory) return NULL;
return fsArray[mp->FsId].ReadDirectory(mp, handle, index);
}
MountPoint* VfsGetMountPoint (uint32 dev_id)
{
if (dev_id < mpList.Size) return &mpArray[dev_id];
return NULL;
}