260 lines
6.4 KiB
C++
260 lines
6.4 KiB
C++
|
#include "FileSystemType.h"
|
||
|
#include "FileSystemInfo.h"
|
||
|
#include "PathWalker.h"
|
||
|
#include "VirtualFileSystem.h"
|
||
|
#include "Dentry.h"
|
||
|
#include "Superblock.h"
|
||
|
#include "VfsMount.h"
|
||
|
#include "kstring.h"
|
||
|
#include "assert.h"
|
||
|
#include "BDManager.h"
|
||
|
#include "BDVirtualDevice.h"
|
||
|
#include "Thread.h"
|
||
|
|
||
|
#include "console/kprintf.h"
|
||
|
|
||
|
VirtualFileSystem vfs;
|
||
|
|
||
|
void VirtualFileSystem::initialize()
|
||
|
{
|
||
|
new (this) VirtualFileSystem();
|
||
|
}
|
||
|
|
||
|
VirtualFileSystem::VirtualFileSystem()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
VirtualFileSystem::~VirtualFileSystem()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
int32 VirtualFileSystem::registerFileSystem(FileSystemType *file_system_type)
|
||
|
{
|
||
|
assert(file_system_type);
|
||
|
assert(file_system_type->getFSName());
|
||
|
|
||
|
// check whether a file system type with that name has already been
|
||
|
// registered
|
||
|
if (getFsType(file_system_type->getFSName()))
|
||
|
return -1;
|
||
|
file_system_types_.push_back(file_system_type);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int32 VirtualFileSystem::unregisterFileSystem(FileSystemType *file_system_type)
|
||
|
{
|
||
|
assert(file_system_type != 0);
|
||
|
|
||
|
const char *fs_name = file_system_type->getFSName();
|
||
|
for (FileSystemType* fst : file_system_types_)
|
||
|
{
|
||
|
if (strcmp(fst->getFSName(), fs_name) == 0)
|
||
|
delete fst;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
FileSystemType *VirtualFileSystem::getFsType(const char* fs_name)
|
||
|
{
|
||
|
assert(fs_name);
|
||
|
|
||
|
for (FileSystemType* fst : file_system_types_)
|
||
|
{
|
||
|
if (strcmp(fst->getFSName(), fs_name) == 0)
|
||
|
return fst;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
VfsMount *VirtualFileSystem::getVfsMount(const Dentry* dentry, bool is_root)
|
||
|
{
|
||
|
assert(dentry);
|
||
|
|
||
|
if (is_root == false)
|
||
|
{
|
||
|
for (VfsMount* mnt : mounts_)
|
||
|
{
|
||
|
debug(VFS, "getVfsMount> mnt->getMountPoint()->getName() : %s\n", mnt->getMountPoint()->getName());
|
||
|
if (!is_root && (mnt->getMountPoint()) == dentry)
|
||
|
return mnt;
|
||
|
else if (mnt->getRoot() == dentry)
|
||
|
return mnt;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
FileSystemInfo *VirtualFileSystem::rootMount(const char *fs_name, uint32 /*flags*/)
|
||
|
{
|
||
|
FileSystemType *fst = getFsType(fs_name);
|
||
|
if(!fst)
|
||
|
{
|
||
|
debug(VFS, "Unknown file system %s\n", fs_name);
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
if(fst->getFSFlags() & FS_REQUIRES_DEV)
|
||
|
{
|
||
|
debug(VFS, "Only file systems that do not require a device are currently supported as root file system\n");
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
debug(VFS, "Create root %s superblock\n", fst->getFSName());
|
||
|
Superblock *super = fst->createSuper(-1);
|
||
|
super = fst->readSuper(super, 0);
|
||
|
|
||
|
Dentry *root = super->getRoot();
|
||
|
|
||
|
super->setMountPoint(root);
|
||
|
root->setMountedRoot(root);
|
||
|
|
||
|
VfsMount *root_mount = new VfsMount(0, root, root, super, 0);
|
||
|
|
||
|
mounts_.push_back(root_mount);
|
||
|
superblocks_.push_back(super);
|
||
|
|
||
|
// fs_info initialize
|
||
|
FileSystemInfo *fs_info = new FileSystemInfo();
|
||
|
Path root_path(root, root_mount);
|
||
|
fs_info->setRoot(root_path);
|
||
|
fs_info->setPwd(root_path);
|
||
|
|
||
|
assert(root_mount->getParent() == root_mount);
|
||
|
assert(root_mount->getMountPoint() == root);
|
||
|
assert(root->getParent() == root);
|
||
|
assert(root->getMountedRoot() == root);
|
||
|
assert(super->getMountPoint() == super->getRoot());
|
||
|
|
||
|
return fs_info;
|
||
|
}
|
||
|
|
||
|
int32 VirtualFileSystem::mount(const char* dev_name, const char* dir_name, const char* fs_name, uint32 /*flags*/)
|
||
|
{
|
||
|
debug(VFS, "Mount fs %s at %s with device %s\n", fs_name, dir_name, dev_name ? dev_name : "(null)");
|
||
|
|
||
|
if ((!dir_name) || (!fs_name))
|
||
|
return -1;
|
||
|
|
||
|
FileSystemType *fst = getFsType(fs_name);
|
||
|
if (!fst)
|
||
|
return -1;
|
||
|
|
||
|
if ((fst->getFSFlags() & FS_REQUIRES_DEV) && !dev_name)
|
||
|
return -1;
|
||
|
|
||
|
FileSystemInfo *fs_info = currentThread->getWorkingDirInfo();
|
||
|
assert(fs_info);
|
||
|
|
||
|
uint32_t dev = -1;
|
||
|
if(fst->getFSFlags() & FS_REQUIRES_DEV)
|
||
|
{
|
||
|
BDVirtualDevice* bddev = BDManager::getInstance()->getDeviceByName(dev_name);
|
||
|
if (!bddev)
|
||
|
{
|
||
|
debug(VFS, "mount: device with name %s doesn't exist\n", dev_name);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
dev = bddev->getDeviceNumber();
|
||
|
debug(VFS, "mount: dev_nr: %d\n", dev);
|
||
|
}
|
||
|
|
||
|
// Find mount point
|
||
|
Path mountpoint_path;
|
||
|
int32 success = PathWalker::pathWalk(dir_name, fs_info->getPwd(), fs_info->getRoot(), mountpoint_path);
|
||
|
|
||
|
if (success != 0)
|
||
|
{
|
||
|
debug(VFS, "mount: Could not find mountpoint\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// create a new superblock
|
||
|
debug(VFS, "Create %s superblock\n", fst->getFSName());
|
||
|
Superblock *super = fst->createSuper(dev);
|
||
|
if (!super)
|
||
|
{
|
||
|
debug(VFS, "mount: Superblock creation failed\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
debug(VFS, "mount: Fill superblock\n");
|
||
|
super = fst->readSuper(super, 0); //?
|
||
|
|
||
|
Dentry *root = super->getRoot();
|
||
|
assert(root->getParent() == root);
|
||
|
|
||
|
super->setMountPoint(mountpoint_path.dentry_); // Set mountpoint for new superblock
|
||
|
mountpoint_path.dentry_->setMountedRoot(root); // Mountpoint mounts new superblock root
|
||
|
|
||
|
// create a new vfs_mount
|
||
|
VfsMount* new_mount = new VfsMount(mountpoint_path.mnt_, mountpoint_path.dentry_, root, super, 0);
|
||
|
mounts_.push_back(new_mount);
|
||
|
superblocks_.push_back(super);
|
||
|
|
||
|
assert(new_mount->getParent() == mountpoint_path.mnt_);
|
||
|
assert(new_mount->getMountPoint() == mountpoint_path.dentry_);
|
||
|
assert(new_mount->getSuperblock() == super);
|
||
|
assert(new_mount->getRoot() == root);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int32 VirtualFileSystem::rootUmount()
|
||
|
{
|
||
|
if (superblocks_.size() == 0)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
VfsMount *root_vfs_mount = mounts_.at(0);
|
||
|
delete root_vfs_mount;
|
||
|
|
||
|
Superblock *root_sb = superblocks_.at(0);
|
||
|
delete root_sb;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int32 VirtualFileSystem::umount(const char* dir_name, uint32 /*flags*/)
|
||
|
{
|
||
|
FileSystemInfo *fs_info = currentThread->getWorkingDirInfo();
|
||
|
if (dir_name == 0)
|
||
|
return -1;
|
||
|
|
||
|
Path mountpount_path;
|
||
|
int32 success = PathWalker::pathWalk(dir_name, fs_info->getPwd(), fs_info->getRoot(), mountpount_path);
|
||
|
|
||
|
if (success != 0)
|
||
|
{
|
||
|
debug(VFS, "(umount) unable to find mountpoint\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
debug(VFS, "(umount) mountpoint found\n");
|
||
|
assert(mountpount_path.mnt_);
|
||
|
|
||
|
// in the case, the current-directory is in the local-root of the umounted
|
||
|
// filesystem
|
||
|
if (fs_info->getPwd().mnt_ == mountpount_path.mnt_)
|
||
|
{
|
||
|
if (fs_info->getPwd().dentry_ == mountpount_path.dentry_)
|
||
|
{
|
||
|
debug(VFS, "(umount) the mount point exchange\n");
|
||
|
fs_info->setPwd(Path(mountpount_path.mnt_->getMountPoint(), mountpount_path.mnt_->getParent()));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
debug(VFS, "(umount) set PWD NULL\n");
|
||
|
fs_info->setPwd(Path());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Superblock *sb = mountpount_path.mnt_->getSuperblock();
|
||
|
|
||
|
mounts_.remove(mountpount_path.mnt_);
|
||
|
delete mountpount_path.mnt_;
|
||
|
delete sb;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|