#include <kernel/kernel.h>
#include <kernel/driver.h>
#include <kernel/fs.h>
#include <kernel/hash.h>
#include <errno.h>
#include <stdlib.h>
#include <wchar.h>
bool vfsRequest(device_t* dev, request_t* req);
typedef struct vfs_t vfs_t;
struct vfs_t
{
device_t dev;
hashtable_t *mounts;
};
vfs_t vfs =
{
{
NULL,
vfsRequest,
NULL, NULL,
NULL
},
NULL
};
extern device_t vfs_devices;
device_t *ramMountFs(driver_t *driver, const wchar_t *path, device_t *dev);
bool vfsRequest(device_t* dev, request_t* req)
{
wchar_t mount[MAX_PATH], *ch;
const wchar_t *path;
vfs_t *vfs = (vfs_t*) dev;
hashelem_t elem, *found;
request_t openreq;
status_t hr;
switch (req->code)
{
case DEV_REMOVE:
case DEV_OPEN:
case DEV_CLOSE:
hndSignal(req->event, true);
return true;
case FS_OPEN:
path = req->params.fs_open.name;
if (*path == '/')
path++;
ch = wcschr(path, '/');
if (ch)
wcsncpy(mount, path, ch - path);
else
wcscpy(mount, path);
path += wcslen(mount);
req->params.fs_open.fd = NULL;
found = hashFind(vfs->mounts, mount);
if (found == NULL)
{
wprintf(L"%s: mount point not found\n", mount);
req->result = ENOTFOUND;
return false;
}
openreq.code = FS_OPEN;
openreq.params.fs_open.name = path;
openreq.params.fs_open.name_length = sizeof(wchar_t) * (wcslen(path) + 1);
hr = devRequestSync((device_t*) found->data, &openreq);
if (hr == 0)
{
req->params.fs_open.fd = openreq.params.fs_open.fd;
hndSignal(req->event, true);
return true;
}
else
{
req->result = openreq.result;
return false;
}
case FS_MOUNT:
elem.str = wcsdup(req->params.fs_mount.name);
elem.data = req->params.fs_mount.dev;
hashInsert(vfs->mounts, &elem);
hndSignal(req->event, true);
return true;
}
req->result = ENOTIMPL;
return false;
}
bool fsMount(const wchar_t* name, const wchar_t* fsd, device_t* device)
{
request_t req;
driver_t* drv;
status_t hr;
drv = devInstallNewDevice(fsd, NULL);
if (drv == NULL || drv->mount_fs == NULL)
{
hndFree(drv);
return false;
}
req.code = FS_MOUNT;
req.params.fs_mount.name = name;
req.params.fs_mount.name_length = sizeof(wchar_t) * (wcslen(name) + 1);
req.params.fs_mount.dev = drv->mount_fs(drv, name, device);
hndFree(drv);
hr = devRequestSync(&vfs.dev, &req);
if (hr)
errno = hr;
return hr == 0;
}
bool vfsInit()
{
device_t *ram;
wchar_t *name;
request_t req;
vfs.mounts = hashCreate(31);
/*
* Mount devices and ramdisk directories manually because they're not real
* drivers.
*/
req.code = FS_MOUNT;
name = L"devices";
req.params.fs_mount.name = name;
req.params.fs_mount.name_length = sizeof(wchar_t) * (wcslen(name) + 1);
req.params.fs_mount.dev = &vfs_devices;
devRequestSync(&vfs.dev, &req);
name = L"boot";
ram = ramMountFs(NULL, name, NULL);
wprintf(L"vfsInit: mounting ramdisk...");
if (ram)
{
req.params.fs_mount.name = name;
req.params.fs_mount.name_length = sizeof(wchar_t) * (wcslen(name) + 1);
req.params.fs_mount.dev = ram;
devRequestSync(&vfs.dev, &req);
wprintf(L"done (%p)\n", ram);
}
else
wprintf(L"failed\n");
return true;
}
bool fsFullPath(const wchar_t* src, wchar_t* dst);
const wchar_t *procCwd()
{
if (current &&
current->process &&
current->process->info)
return current->process->info->cwd;
else
return L"/boot";
}
file_t* fsOpen(const wchar_t* path)
{
wchar_t fullpath[256];
request_t req;
status_t hr;
if (!fsFullPath(path, fullpath))
return NULL;
req.code = FS_OPEN;
req.params.fs_open.name = fullpath;
req.params.fs_open.name_length = sizeof(wchar_t) * (wcslen(path) + 1);
hr = devRequestSync(&vfs.dev, &req);
if (hr != 0)
{
errno = hr;
return NULL;
}
else
return req.params.fs_open.fd;
}
bool fsClose(file_t* fd)
{
request_t req;
status_t hr;
if (fd == NULL)
{
errno = EINVALID;
return false;
}
req.code = FS_CLOSE;
req.params.fs_close.fd = fd;
hr = devRequestSync(fd->fsd, &req);
if (hr)
errno = hr;
return hr == 0;
}
size_t fsRead(file_t* fd, void* buffer, size_t length)
{
request_t req;
status_t hr;
if (fd == NULL)
{
errno = EINVALID;
return false;
}
req.code = FS_READ;
req.params.fs_read.buffer = (addr_t) buffer;
req.params.fs_read.length = length;
req.params.fs_read.fd = fd;
hr = devRequestSync(fd->fsd, &req);
if (hr)
{
errno = hr;
return (size_t) -1;
}
else
return req.params.fs_read.length;
}
void fsSeek(file_t *fd, qword pos)
{
/* xxx - need to get the FSD to do this */
fd->pos = pos;
}
qword fsGetLength(file_t* fd)
{
request_t req;
status_t hr;
if (fd == NULL)
{
errno = EINVALID;
return false;
}
req.code = FS_GETLENGTH;
req.params.fs_getlength.length = 0;
req.params.fs_getlength.fd = fd;
hr = devRequestSync(fd->fsd, &req);
if (hr)
{
errno = hr;
return (qword) -1;
}
else
return req.params.fs_getlength.length;
}