diff --git a/Kernel/Syscalls/mount.cpp b/Kernel/Syscalls/mount.cpp index 6311852dec..00d68006aa 100644 --- a/Kernel/Syscalls/mount.cpp +++ b/Kernel/Syscalls/mount.cpp @@ -18,6 +18,63 @@ namespace Kernel { +static ErrorOr> create_ram_backed_filesystem_instance(StringView fs_type) +{ + RefPtr fs; + if (fs_type == "proc"sv || fs_type == "ProcFS"sv) { + fs = TRY(ProcFS::try_create()); + } else if (fs_type == "devpts"sv || fs_type == "DevPtsFS"sv) { + fs = TRY(DevPtsFS::try_create()); + } else if (fs_type == "dev"sv || fs_type == "DevTmpFS"sv) { + fs = TRY(DevTmpFS::try_create()); + } else if (fs_type == "sys"sv || fs_type == "SysFS"sv) { + fs = TRY(SysFS::try_create()); + } else if (fs_type == "tmp"sv || fs_type == "TmpFS"sv) { + fs = TRY(TmpFS::try_create()); + } + if (!fs) + return ENODEV; + return fs.release_nonnull(); +} + +static bool filesystem_mount_require_open_file_description(StringView fs_type) +{ + if (fs_type == "ext2"sv || fs_type == "Ext2FS"sv) { + return true; + } else if (fs_type == "9p"sv || fs_type == "Plan9FS"sv) { + return true; + } else if (fs_type == "iso9660"sv || fs_type == "ISO9660FS"sv) { + return true; + } + return false; +} + +static ErrorOr> create_open_file_description_backed_filesystem_instance(StringView fs_type, OpenFileDescription& description) +{ + RefPtr fs; + + if (fs_type == "ext2"sv || fs_type == "Ext2FS"sv) { + if (!description.file().is_block_device()) + return ENOTBLK; + if (!description.file().is_seekable()) { + dbgln("mount: this is not a seekable file"); + return ENODEV; + } + fs = TRY(Ext2FS::try_create(description)); + } else if (fs_type == "9p"sv || fs_type == "Plan9FS"sv) { + fs = TRY(Plan9FS::try_create(description)); + } else if (fs_type == "iso9660"sv || fs_type == "ISO9660FS"sv) { + if (!description.file().is_seekable()) { + dbgln("mount: this is not a seekable file"); + return ENODEV; + } + fs = TRY(ISO9660FS::try_create(description)); + } + if (!fs) + return ENODEV; + return fs.release_nonnull(); +} + ErrorOr Process::sys$mount(Userspace user_params) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this) @@ -59,58 +116,26 @@ ErrorOr Process::sys$mount(Userspace u return 0; } - RefPtr fs; - - if (fs_type == "ext2"sv || fs_type == "Ext2FS"sv) { - if (description_or_error.is_error()) - return EBADF; - auto description = description_or_error.release_value(); - if (!description->file().is_block_device()) - return ENOTBLK; - if (!description->file().is_seekable()) { - dbgln("mount: this is not a seekable file"); - return ENODEV; - } - - auto source_pseudo_path = TRY(description->pseudo_path()); - dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target); - - fs = TRY(Ext2FS::try_create(*description)); - } else if (fs_type == "9p"sv || fs_type == "Plan9FS"sv) { - if (description_or_error.is_error()) - return EBADF; - auto description = description_or_error.release_value(); - fs = TRY(Plan9FS::try_create(*description)); - } else if (fs_type == "proc"sv || fs_type == "ProcFS"sv) { - fs = TRY(ProcFS::try_create()); - } else if (fs_type == "devpts"sv || fs_type == "DevPtsFS"sv) { - fs = TRY(DevPtsFS::try_create()); - } else if (fs_type == "dev"sv || fs_type == "DevTmpFS"sv) { - fs = TRY(DevTmpFS::try_create()); - } else if (fs_type == "sys"sv || fs_type == "SysFS"sv) { - fs = TRY(SysFS::try_create()); - } else if (fs_type == "tmp"sv || fs_type == "TmpFS"sv) { - fs = TRY(TmpFS::try_create()); - } else if (fs_type == "iso9660"sv || fs_type == "ISO9660FS"sv) { - if (description_or_error.is_error()) - return EBADF; - auto description = description_or_error.release_value(); - if (!description->file().is_seekable()) { - dbgln("mount: this is not a seekable file"); - return ENODEV; - } - auto source_pseudo_path = TRY(description->pseudo_path()); - dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target); - fs = TRY(ISO9660FS::try_create(*description)); - } else { - return ENODEV; + // Note: Try to determine as early as possible if we deal with a filesystem type + // that must be backed by a open file description, so if there's no such valid + // description, we can fail with EBADF now. + if (filesystem_mount_require_open_file_description(fs_type) && description_or_error.is_error()) { + return EBADF; } - if (!fs) - return ENOMEM; + if (description_or_error.is_error()) { + auto synthetic_filesystem = TRY(create_ram_backed_filesystem_instance(fs_type)); + TRY(synthetic_filesystem->initialize()); + TRY(VirtualFileSystem::the().mount(*synthetic_filesystem, target_custody, params.flags)); + return 0; + } + auto description = description_or_error.release_value(); + auto open_file_description_backed_filesystem = TRY(create_open_file_description_backed_filesystem_instance(fs_type, description)); + auto source_pseudo_path = TRY(description->pseudo_path()); + dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target); + TRY(open_file_description_backed_filesystem->initialize()); + TRY(VirtualFileSystem::the().mount(*open_file_description_backed_filesystem, target_custody, params.flags)); - TRY(fs->initialize()); - TRY(VirtualFileSystem::the().mount(fs.release_nonnull(), target_custody, params.flags)); return 0; }