#include "fs.h"
#include "alloc.h"
#include "screen.h"
#include "rootfs.h"
FileSystemNode *gFileSystemRoot = NULL; // The root of the filesystem.
#define FILESYSTEM_CAPACITY 10
static FileSystem gRegisteredFileSystems[FILESYSTEM_CAPACITY];
static int gNextFileSystemIndex = 0;
void initializeVFS() {
memset((uint8*)gRegisteredFileSystems, 0, sizeof(gRegisteredFileSystems));
gFileSystemRoot = initializeRootFS();
mkdir_fs(gFileSystemRoot, "dev", 0);
mkdir_fs(gFileSystemRoot, "initrd", 0);
}
FileSystemNode* getFileSystemRootNode() {
return gFileSystemRoot;
}
void copyFileDescriptors(Process* fromProcess, Process* toProcess) {
for (int i = 0; i < MAX_OPENED_FILES; ++i) {
File* original = fromProcess->fd[i];
if (original) {
File* file = kmalloc(sizeof(File));
memcpy((uint8*)file, (uint8*)original, sizeof(File));
file->process = toProcess;
file->thread = NULL;
toProcess->fd[i] = file;
}
}
}
int getFileSystemNodePath(FileSystemNode *node, char* buffer, uint32 bufferSize) {
if (node == gFileSystemRoot) {
if (bufferSize > 1) {
buffer[0] = '/';
buffer[1] = '\0';
return 1;
}
else {
return -1;
}
}
char targetPath[128];
FileSystemNode *n = node;
int charIndex = 127;
targetPath[charIndex] = '\0';
while (NULL != n) {
int length = strlen(n->name);
charIndex -= length;
if (charIndex < 2) {
return -1;
}
if (NULL != n->parent) {
strcpyNonNull(targetPath + charIndex, n->name);
charIndex -= 1;
targetPath[charIndex] = '/';
}
n = n->parent;
}
int len = 127 - charIndex;
//printkf("getFileSystemNodePath: len:[%s] %d\n", targetPath + charIndex, len);
if (bufferSize < len) {
return -1;
}
strcpy(buffer, targetPath + charIndex);
return len;
}
BOOL resolvePath(const char* path, char* buffer, int bufferSize) {
int lengthPath = strlen(path);
if (path[0] != '/') {
return FALSE;
}
if (bufferSize < 2) {
return FALSE;
}
buffer[0] = '/';
buffer[1] = '\0';
int index = 0;
int indexBuffer = 1;
while (index < lengthPath - 1) {
while (path[++index] == '/');//eliminate successive
const char* current = path + index;
int nextIndex = strFirstIndexOf(path + index, '/');
int lengthToken = 0;
if (nextIndex >= 0) {
const char* next = path + index + nextIndex;
lengthToken = next - (path + index);
}
else {
lengthToken = strlen(current);
}
if (lengthToken > 0) {
index += lengthToken;
if (strncmp(current, "..", 2) == 0) {
--indexBuffer;
while (indexBuffer > 0) {
--indexBuffer;
if (buffer[indexBuffer] == '/') {
break;
}
buffer[indexBuffer] = '\0';
}
++indexBuffer;
continue;
}
else if (strncmp(current, ".", 1) == 0) {
continue;
}
if (indexBuffer + lengthToken + 2 > bufferSize) {
return FALSE;
}
strncpy(buffer + indexBuffer, current, lengthToken);
indexBuffer += lengthToken;
if (current[lengthToken] == '/') {
buffer[indexBuffer++] = '/';
}
buffer[indexBuffer] = '\0';
}
}
if (indexBuffer > 2) {
if (buffer[indexBuffer - 1] == '/') {
buffer[indexBuffer - 1] = '\0';
}
}
return TRUE;
}
uint32 read_fs(File *file, uint32 size, uint8 *buffer) {
if (file->node->read != 0) {
return file->node->read(file, size, buffer);
}
return -1;
}
uint32 write_fs(File *file, uint32 size, uint8 *buffer) {
if (file->node->write != 0) {
return file->node->write(file, size, buffer);
}
return -1;
}
File *open_fs(FileSystemNode *node, uint32 flags) {
return open_fs_forProcess(getCurrentThread(), node, flags);
}
File *open_fs_forProcess(Thread* thread, FileSystemNode *node, uint32 flags) {
Process* process = thread->owner;
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL ) {
node = node->mountPoint;
}
if (node->open != NULL) {
File* file = kmalloc(sizeof(File));
memset((uint8*)file, 0, sizeof(File));
file->node = node;
file->process = process;
file->thread = thread;
BOOL success = node->open(file, flags);
if (success) {
//printkf("Opened:%s\n", file->node->name);
int32 fd = addFileToProcess(file->process, file);
if (fd < 0) {
//TODO: sett errno max files opened already
printkf("Maxfiles opened already!!\n");
close_fs(file);
file = NULL;
}
}
else {
kfree(file);
}
return file;
}
return NULL;
}
void close_fs(File *file) {
if (file->node->close != NULL) {
file->node->close(file);
}
removeFileFromProcess(file->process, file);
kfree(file);
}
int32 ioctl_fs(File *file, int32 request, void * argp) {
if (file->node->ioctl != NULL) {
return file->node->ioctl(file, request, argp);
}
return 0;
}
int32 lseek_fs(File *file, int32 offset, int32 whence) {
if (file->node->lseek != NULL) {
return file->node->lseek(file, offset, whence);
}
return 0;
}
int32 ftruncate_fs(File* file, int32 length) {
if (file->node->ftruncate != NULL) {
return file->node->ftruncate(file, length);
}
return -1;
}
int32 stat_fs(FileSystemNode *node, struct stat *buf) {
#define __S_IFDIR 0040000 /* Directory. */
#define __S_IFCHR 0020000 /* Character device. */
#define __S_IFBLK 0060000 /* Block device. */
#define __S_IFREG 0100000 /* Regular file. */
#define __S_IFIFO 0010000 /* FIFO. */
#define __S_IFLNK 0120000 /* Symbolic link. */
#define __S_IFSOCK 0140000 /* Socket. */
if (node->stat != NULL) {
int32 val = node->stat(node, buf);
if (val == 1) {
//return value of 1 from driver means we should fill buf here.
if ((node->nodeType & FT_Directory) == FT_Directory) {
buf->st_mode = __S_IFDIR;
}
else if ((node->nodeType & FT_CharacterDevice) == FT_CharacterDevice) {
buf->st_mode = __S_IFCHR;
}
else if ((node->nodeType & FT_BlockDevice) == FT_BlockDevice) {
buf->st_mode = __S_IFBLK;
}
else if ((node->nodeType & FT_Pipe) == FT_Pipe) {
buf->st_mode = __S_IFIFO;
}
else if ((node->nodeType & FT_SymbolicLink) == FT_SymbolicLink) {
buf->st_mode = __S_IFLNK;
}
else if ((node->nodeType & FT_File) == FT_File) {
buf->st_mode = __S_IFREG;
}
buf->st_size = node->length;
return 0;
}
else {
return val;
}
}
return -1;
}
FileSystemDirent *readdir_fs(FileSystemNode *node, uint32 index) {
//printkf("readdir_fs: node->name:%s index:%d\n", node->name, index);
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL ) {
if (NULL == node->mountPoint->readdir) {
WARNING("mounted fs does not have readdir!\n");
}
else {
return node->mountPoint->readdir(node->mountPoint, index);
}
}
else if ( (node->nodeType & FT_Directory) == FT_Directory && node->readdir != NULL ) {
return node->readdir(node, index);
}
return NULL;
}
FileSystemNode *finddir_fs(FileSystemNode *node, char *name) {
//printkf("finddir_fs: name:%s\n", name);
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL ) {
if (NULL == node->mountPoint->finddir) {
WARNING("mounted fs does not have finddir!\n");
}
else {
return node->mountPoint->finddir(node->mountPoint, name);
}
}
else if ( (node->nodeType & FT_Directory) == FT_Directory && node->finddir != NULL ) {
return node->finddir(node, name);
}
return NULL;
}
BOOL mkdir_fs(FileSystemNode *node, const char *name, uint32 flags) {
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL ) {
if (node->mountPoint->mkdir) {
return node->mountPoint->mkdir(node->mountPoint, name, flags);
}
}
else if ( (node->nodeType & FT_Directory) == FT_Directory && node->mkdir != NULL ) {
return node->mkdir(node, name, flags);
}
return FALSE;
}
void* mmap_fs(File* file, uint32 size, uint32 offset, uint32 flags) {
if (file->node->mmap) {
return file->node->mmap(file, size, offset, flags);
}
return NULL;
}
BOOL munmap_fs(File* file, void* address, uint32 size) {
if (file->node->munmap) {
return file->node->munmap(file, address, size);
}
return FALSE;
}
FileSystemNode *getFileSystemNode(const char *path) {
//printkf("getFileSystemNode:%s *0\n", path);
if (path[0] != '/') {
//We require absolute path!
return NULL;
}
char realPath[256];
BOOL resolved = resolvePath(path, realPath, 256);
if (FALSE == resolved) {
return NULL;
}
const char* inputPath = realPath;
int pathLength = strlen(inputPath);
if (pathLength < 1) {
return NULL;
}
//printkf("getFileSystemNode:%s *1\n", path);
FileSystemNode* root = getFileSystemRootNode();
if (pathLength == 1) {
return root;
}
int nextIndex = 0;
FileSystemNode* node = root;
//printkf("getFileSystemNode:%s *2\n", path);
char buffer[64];
do {
do_start:
inputPath = inputPath + nextIndex + 1;
nextIndex = strFirstIndexOf(inputPath, '/');
if (nextIndex == 0) {
//detected successive slash
goto do_start;
}
if (nextIndex > 0) {
int tokenSize = nextIndex;
strncpy(buffer, inputPath, tokenSize);
buffer[tokenSize] = '\0';
}
else {
//Last part
strcpy(buffer, inputPath);
}
//printkf("getFileSystemNode:%s *3\n", path);
node = finddir_fs(node, buffer);
//printkf("getFileSystemNode:%s *4\n", path);
if (NULL == node) {
return NULL;
}
} while (nextIndex > 0);
return node;
}
FileSystemNode* getFileSystemNodeAbsoluteOrRelative(const char* path, Process* process) {
FileSystemNode* node = NULL;
if (process) {
if ('\0' == path[0]) {
//empty
}
else if ('/' == path[0]) {
//absolute
node = getFileSystemNode(path);
}
else {
//relative
if (process->workingDirectory) {
char buffer[256];
if (getFileSystemNodePath(process->workingDirectory, buffer, 256) >= 0) {
strcat(buffer, "/");
strcat(buffer, path);
//printkf("getFileSystemNodeAbsoluteOrRelative:[%s]\n", buffer);
node = getFileSystemNode(buffer);
}
}
}
}
return node;
}
BOOL registerFileSystem(FileSystem* fs) {
if (strlen(fs->name) <= 0) {
return FALSE;
}
for (int i = 0; i < gNextFileSystemIndex; ++i) {
if (strcmp(gRegisteredFileSystems[i].name, fs->name) == 0) {
//name is in use
return FALSE;
}
}
gRegisteredFileSystems[gNextFileSystemIndex++] = *fs;
return TRUE;
}
BOOL mountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data) {
FileSystem* fs = NULL;
for (int i = 0; i < gNextFileSystemIndex; ++i) {
if (strcmp(gRegisteredFileSystems[i].name, fsType) == 0) {
fs = &gRegisteredFileSystems[i];
break;
}
}
if (NULL == fs) {
return FALSE;
}
return fs->mount(source, target, flags, data);
}
BOOL checkMountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data) {
FileSystem* fs = NULL;
for (int i = 0; i < gNextFileSystemIndex; ++i) {
if (strcmp(gRegisteredFileSystems[i].name, fsType) == 0) {
fs = &gRegisteredFileSystems[i];
break;
}
}
if (NULL == fs) {
return FALSE;
}
return fs->checkMount(source, target, flags, data);
}