diff --git a/Cargo.lock b/Cargo.lock index 863abecadff..3bbe1eaf7a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5095,6 +5095,7 @@ dependencies = [ "thiserror", "tokio", "tracing", + "tracing-test", "typetag", "webc", ] @@ -5707,6 +5708,7 @@ dependencies = [ "serde", "serde_json", "sha2", + "shared-buffer", "spinoff", "tar", "target-lexicon 0.12.12", @@ -6585,9 +6587,9 @@ dependencies = [ [[package]] name = "webc" -version = "5.8.0" +version = "5.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac815d472f09ed064ef70a3046843972646727cbe55db795dd8a9925b76ed0c4" +checksum = "973ca5a91b4fb3e4bb37cfebe03ef9364d0aff2765256abefdb7e79dc9188483" dependencies = [ "anyhow", "base64", diff --git a/Cargo.toml b/Cargo.toml index 8e573bd6bad..2e49f9b5fe1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,7 +87,10 @@ version = "4.2.3" enumset = "1.1.0" memoffset = "0.9.0" wasmer-toml = "0.9.2" -webc = { version = "5.8.0", default-features = false, features = ["package"] } +dashmap = "5.4.0" +webc = { version = "5.8.1", default-features = false, features = ["package"] } +shared-buffer = "0.1" +tempfile = "3.6.0" [build-dependencies] test-generator = { path = "tests/lib/test-generator" } @@ -107,7 +110,7 @@ criterion = { version = "0.5", default-features = false } lazy_static = "1.4" serial_test = "0.5" compiler-test-derive = { path = "tests/lib/compiler-test-derive" } -tempfile = "3.6.0" +tempfile.workspace = true # For logging tests using the `RUST_LOG=debug` when testing test-log = { version = "0.2", default-features = false, features = ["trace"] } tracing = { version = "0.1", default-features = false, features = ["log"] } diff --git a/build.rs b/build.rs index d069178ba04..06ba24f91b5 100644 --- a/build.rs +++ b/build.rs @@ -79,8 +79,6 @@ fn main() -> anyhow::Result<()> { ("host_fs", "WasiFileSystemKind::Host"), ("mem_fs", "WasiFileSystemKind::InMemory"), ("tmp_fs", "WasiFileSystemKind::Tmp"), - ("passthru_fs", "WasiFileSystemKind::PassthruMemory"), - ("union_fs", "WasiFileSystemKind::UnionHostMemory"), ("root_fs", "WasiFileSystemKind::RootFileSystemBuilder"), ] { with_test_module(wasitests, wasi_filesystem_test_name, |wasitests| { diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index bf55f26c981..c9c4444f651 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -34,7 +34,7 @@ bytes = "1" wat = { version = "=1.0.71", optional = true } tracing = { version = "0.1", optional = true } rustc-demangle = "0.1" -shared-buffer = "0.1" +shared-buffer.workspace = true # Dependencies and Development Dependencies for `sys`. [target.'cfg(not(target_arch = "wasm32"))'.dependencies] @@ -60,7 +60,7 @@ winapi = "0.3" # - Development Dependencies for `sys`. [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] wat = "1.0" -tempfile = "3.6.0" +tempfile.workspace = true anyhow = "1.0" macro-wasmer-universal-test = { version = "4.2.3", path = "./macro-wasmer-universal-test" } diff --git a/lib/c-api/Cargo.toml b/lib/c-api/Cargo.toml index d835a2438cf..389542e39a2 100644 --- a/lib/c-api/Cargo.toml +++ b/lib/c-api/Cargo.toml @@ -33,7 +33,7 @@ wasmer-emscripten = { version = "=4.2.3", path = "../emscripten", optional = tru wasmer-middlewares = { version = "=4.2.3", path = "../middlewares", optional = true } wasmer-types = { version = "=4.2.3", path = "../types" } wasmer-wasix = { version = "0.16.0", path = "../wasix", features = ["host-fs", "host-vnet"], optional = true } -webc = { version = "5.0", optional = true } +webc = { workspace = true, optional = true } virtual-fs = { version = "0.9.0", path = "../virtual-fs", optional = true, default-features = false, features = ["static-fs"] } enumset.workspace = true cfg-if = "1.0" diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 508293dcb93..e308dd08dee 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -19,7 +19,7 @@ use std::sync::Arc; #[cfg(feature = "webc_runner")] use wasmer_api::{AsStoreMut, Imports, Module}; use wasmer_wasix::{ - default_fs_backing, get_wasi_version, + get_wasi_version, runtime::task_manager::{tokio::TokioTaskManager, InlineWaker}, virtual_fs::AsyncReadExt, virtual_fs::VirtualFile, @@ -55,7 +55,7 @@ pub unsafe extern "C" fn wasi_config_new( inherit_stdout: true, inherit_stderr: true, inherit_stdin: true, - builder: WasiEnv::builder(prog_name).fs(default_fs_backing()), + builder: WasiEnv::builder(prog_name), runtime: Some(runtime), })) } @@ -259,7 +259,7 @@ fn prepare_webc_env( len: usize, package_name: &str, ) -> Option<(WasiFunctionEnv, Imports)> { - use virtual_fs::static_fs::StaticFileSystem; + use virtual_fs::static_fs::WebCStaticFileSystem; use webc::v1::{FsEntryType, WebC}; let store_mut = store.as_store_mut(); @@ -294,7 +294,7 @@ fn prepare_webc_env( }) .collect::>(); - let filesystem = Box::new(StaticFileSystem::init(slice, package_name)?); + let filesystem = Box::new(WebCStaticFileSystem::init(slice, package_name)?); let mut builder = config.builder.runtime(Arc::new(rt)); if !config.inherit_stdout { diff --git a/lib/cache/Cargo.toml b/lib/cache/Cargo.toml index c088fb21fdd..2d0f6c6657a 100644 --- a/lib/cache/Cargo.toml +++ b/lib/cache/Cargo.toml @@ -20,7 +20,7 @@ blake3 = "1.0" [dev-dependencies] criterion = { version = "0.5", default-features = false } -tempfile = "3.6.0" +tempfile.workspace = true rand = "0.8.3" wasmer = { path = "../api", version = "=4.2.3", default-features = false, features = ["sys", "cranelift"] } wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=4.2.3" } diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index f000e756315..0c6698b4bb3 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -63,8 +63,9 @@ virtual-fs = { version = "0.9.0", path = "../virtual-fs", default-features = fal virtual-net = { version = "0.6.1", path = "../virtual-net" } # Wasmer-owned dependencies. -webc = { workspace = true } wasmer-deploy-cli = { version = "=0.1.29", default-features = false } +webc.workspace = true +shared-buffer.workspace = true # Third-party dependencies. @@ -78,7 +79,7 @@ distance = "0.4" # For the inspect subcommand bytesize = "1.0" cfg-if = "1.0" -tempfile = "3.6.0" +tempfile.workspace = true serde = { version = "1.0.147", features = ["derive"] } dirs = { version = "4.0" } serde_json = { version = "1.0" } diff --git a/lib/cli/src/commands/run/mod.rs b/lib/cli/src/commands/run/mod.rs index c7af2cc2c97..cc16f8dd483 100644 --- a/lib/cli/src/commands/run/mod.rs +++ b/lib/cli/src/commands/run/mod.rs @@ -47,12 +47,91 @@ use wasmer_wasix::{ }, Runtime, }; -use webc::{metadata::Manifest, Container}; +use webc::{ + metadata::{Manifest, UrlOrManifest}, + AbstractWebc, Container, Volume, +}; use crate::{commands::run::wasi::Wasi, error::PrettyError, logging::Output, store::StoreOptions}; const TICK: Duration = Duration::from_millis(250); +use shared_buffer::OwnedBuffer; +use std::borrow::Cow; + +#[derive(Debug)] +struct WebcPatch { + pub(crate) base: Option, + pub patched_manifest: Manifest, +} + +impl WebcPatch { + pub fn new(base: Container, uses: Vec) -> Self { + let mut manifest = base.manifest().clone(); + Self { + base: Some(base), + patched_manifest: Self::add_uses_to_manifest(manifest, uses), + } + } + fn add_uses_to_manifest(mut manifest: Manifest, uses: Vec) -> Manifest { + for use_ in uses { + manifest + .use_map + .insert(use_.clone(), UrlOrManifest::RegistryDependentUrl(use_)); + } + manifest + } + pub fn with_uses(uses: Vec) -> Self { + let manifest = Manifest::default(); + Self { + base: None, + patched_manifest: Self::add_uses_to_manifest(manifest, uses), + } + } +} + +/// We use this to patch the dependencies at runtime +/// So the user can do `--use` to set their own dependencies +impl AbstractWebc for WebcPatch { + fn manifest(&self) -> &Manifest { + &self.patched_manifest + } + + fn atom_names(&self) -> Vec> { + self.base + .as_ref() + .map(|base| { + base.atoms() + .keys() + .map(String::to_owned) + .map(Cow::from) + .collect() + }) + .unwrap_or(vec![]) + } + + fn get_atom(&self, name: &str) -> Option { + self.base.as_ref().and_then(|base| base.get_atom(name)) + } + + fn volume_names(&self) -> Vec> { + self.base + .as_ref() + .map(|base| { + base.volumes() + .keys() + .map(String::to_owned) + .map(Cow::from) + .collect() + }) + .unwrap_or(vec![]) + } + + fn get_volume(&self, name: &str) -> Option { + self.base.as_ref().and_then(|base| base.get_volume(name)) + } +} + /// The unstable `wasmer run` subcommand. #[derive(Debug, Parser)] pub struct Run { @@ -122,9 +201,33 @@ impl Run { let result = { match target { ExecutableTarget::WebAssembly { module, path } => { - self.execute_wasm(&path, &module, store, runtime) + let pkg = if !self.wasi.uses.is_empty() { + let patched_container = + Container::new(WebcPatch::with_uses(self.wasi.uses.clone())); + let inner_runtime = runtime.clone(); + let pkg = runtime.task_manager().spawn_and_block_on(async move { + BinaryPackage::from_webc(&patched_container, inner_runtime.as_ref()) + .await + })?; + Some(pkg) + } else { + None + }; + + self.execute_wasm(&path, &module, store, pkg.as_ref(), runtime) + } + ExecutableTarget::Container(container) => { + pb.set_message("Resolving dependencies"); + + let patched_container = + Container::new(WebcPatch::new(container, self.wasi.uses.clone())); + let inner_runtime = runtime.clone(); + let pkg = runtime.task_manager().spawn_and_block_on(async move { + BinaryPackage::from_webc(&patched_container, inner_runtime.as_ref()).await + })?; + + self.execute_webc(&pkg, runtime) } - ExecutableTarget::Package(pkg) => self.execute_webc(&pkg, runtime), } }; @@ -141,12 +244,13 @@ impl Run { path: &Path, module: &Module, mut store: Store, + pkg: Option<&BinaryPackage>, runtime: Arc, ) -> Result<(), Error> { if wasmer_emscripten::is_emscripten_module(module) { self.execute_emscripten_module() } else if wasmer_wasix::is_wasi_module(module) || wasmer_wasix::is_wasix_module(module) { - self.execute_wasi_module(path, module, runtime, store) + self.execute_wasi_module(path, module, runtime, pkg, store) } else { self.execute_pure_wasm_module(module, &mut store) } @@ -228,12 +332,13 @@ impl Run { ) -> Result<(), Error> { let mut runner = wasmer_wasix::runners::wcgi::WcgiRunner::new(); + let root_fs = self.wasi.get_fs()?; runner .config() .args(self.args.clone()) .addr(self.wcgi.addr) .envs(self.wasi.env_vars.clone()) - .map_directories(self.wasi.mapped_dirs.clone()) + .with_fs(root_fs) .callbacks(Callbacks::new(self.wcgi.addr)) .inject_packages(uses); *runner.config().capabilities() = self.wasi.capabilities(); @@ -298,8 +403,9 @@ impl Run { .with_args(&self.args) .with_injected_packages(packages) .with_envs(self.wasi.env_vars.clone()) + .with_fs(self.wasi.get_fs()?) + .with_current_dir(PathBuf::from(Wasi::MAPPED_CURRENT_DIR_DEFAULT_PATH)) .with_mapped_host_commands(self.wasi.build_mapped_commands()?) - .with_mapped_directories(self.wasi.build_mapped_directories()?) .with_forward_host_env(self.wasi.forward_host_env) .with_capabilities(self.wasi.capabilities()); @@ -312,15 +418,17 @@ impl Run { wasm_path: &Path, module: &Module, runtime: Arc, + pkg: Option<&BinaryPackage>, mut store: Store, ) -> Result<(), Error> { let program_name = wasm_path.display().to_string(); - let runner = self.build_wasi_runner(&runtime)?; + let mut runner = self.build_wasi_runner(&runtime)?; runner.run_wasm( runtime, &program_name, module, + pkg, self.wasi.enable_async_threads, ) } @@ -488,10 +596,10 @@ impl PackageSource { pb.set_message("Loading from the registry"); let inner_pck = pkg.clone(); let inner_rt = rt.clone(); - let pkg = rt.task_manager().spawn_and_block_on(async move { - BinaryPackage::from_registry(&inner_pck, inner_rt.as_ref()).await + let container = rt.task_manager().spawn_and_block_on(async move { + BinaryPackage::get_container_from_registry(&inner_pck, inner_rt.as_ref()).await })?; - Ok(ExecutableTarget::Package(pkg)) + Ok(ExecutableTarget::Container(container)) } } } @@ -557,7 +665,7 @@ impl TargetOnDisk { #[derive(Debug, Clone)] enum ExecutableTarget { WebAssembly { module: Module, path: PathBuf }, - Package(BinaryPackage), + Container(Container), } impl ExecutableTarget { @@ -574,14 +682,7 @@ impl ExecutableTarget { let manifest_path = dir.join("wasmer.toml"); let webc = webc::wasmer_package::Package::from_manifest(manifest_path)?; let container = Container::from(webc); - - pb.set_message("Resolving dependencies"); - let inner_runtime = runtime.clone(); - let pkg = runtime.task_manager().spawn_and_block_on(async move { - BinaryPackage::from_webc(&container, inner_runtime.as_ref()).await - })?; - - Ok(ExecutableTarget::Package(pkg)) + Ok(ExecutableTarget::Container(container)) } /// Try to load a file into something that can be used to run it. @@ -619,13 +720,7 @@ impl ExecutableTarget { } TargetOnDisk::LocalWebc => { let container = Container::from_disk(path)?; - pb.set_message("Resolving dependencies"); - - let inner_runtime = runtime.clone(); - let pkg = runtime.task_manager().spawn_and_block_on(async move { - BinaryPackage::from_webc(&container, inner_runtime.as_ref()).await - })?; - Ok(ExecutableTarget::Package(pkg)) + Ok(ExecutableTarget::Container(container)) } } } diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 744b2876dfd..da84e98b5ae 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -10,13 +10,13 @@ use bytes::Bytes; use clap::Parser; use tokio::runtime::Handle; use url::Url; -use virtual_fs::{DeviceFile, FileSystem, PassthruFileSystem, RootFileSystemBuilder}; +use virtual_fs::host_fs::FileSystem as HostFileSystem; +use virtual_fs::{DeviceFile, FileSystem, RootFileSystemBuilder}; use wasmer::{Engine, Function, Instance, Memory32, Memory64, Module, RuntimeError, Store, Value}; use wasmer_registry::wasmer_env::WasmerEnv; use wasmer_wasix::{ bin_factory::BinaryPackage, capabilities::Capabilities, - default_fs_backing, get_wasi_versions, http::HttpClient, os::{tty_sys::SysTty, TtyBridge}, rewind_ext, @@ -91,6 +91,10 @@ pub struct Wasi { )] enable_experimental_io_devices: bool, + /// Mount a new host's /tmp directory into the guest + #[clap(long = "host-tmp")] + pub(crate) mount_host_tmp: bool, + /// Enable networking with the host network. /// /// Allows WASI modules to open TCP and UDP connections, create sockets, ... @@ -125,7 +129,7 @@ pub struct RunProperties { #[allow(dead_code)] impl Wasi { - const MAPPED_CURRENT_DIR_DEFAULT_PATH: &'static str = "/mnt/host"; + pub const MAPPED_CURRENT_DIR_DEFAULT_PATH: &'static str = "/home"; pub fn map_dir(&mut self, alias: &str, target_on_disk: PathBuf) { self.mapped_dirs.push(MappedDirectory { @@ -138,264 +142,97 @@ impl Wasi { self.env_vars.push((key.to_string(), value.to_string())); } - /// Gets the WASI version (if any) for the provided module - pub fn get_versions(module: &Module) -> Option> { - // Get the wasi version in non-strict mode, so multiple wasi versions - // are potentially allowed. - // - // Checking for multiple wasi versions is handled outside this function. - get_wasi_versions(module, false) - } - - /// Checks if a given module has any WASI imports at all. - pub fn has_wasi_imports(module: &Module) -> bool { - // Get the wasi version in non-strict mode, so no other imports - // are allowed - get_wasi_versions(module, false).is_some() - } - - pub fn prepare( - &self, - module: &Module, - program_name: String, - args: Vec, - rt: Arc, - ) -> Result { - let args = args.into_iter().map(|arg| arg.into_bytes()); - - let map_commands = self - .map_commands + pub fn get_fs(&self) -> Result { + let root_fs = RootFileSystemBuilder::new() + .with_tty(Box::new(DeviceFile::new(__WASI_STDIN_FILENO))) + .build(); + let mut mapped_dirs = self.build_mapped_directories()?; + let has_mapped_tmp = mapped_dirs .iter() - .map(|map| map.split_once('=').unwrap()) - .map(|(a, b)| (a.to_string(), b.to_string())) - .collect::>(); - - let mut uses = Vec::new(); - for name in &self.uses { - let specifier = PackageSpecifier::parse(name) - .with_context(|| format!("Unable to parse \"{name}\" as a package specifier"))?; - let pkg = { - let inner_rt = rt.clone(); - rt.task_manager() - .spawn_and_block_on(async move { - BinaryPackage::from_registry(&specifier, &*inner_rt).await - }) - .with_context(|| format!("Unable to load \"{name}\""))? - }; - uses.push(pkg); + .any(|dir| dir.guest == "/tmp" || dir.guest.starts_with("/tmp/")); + if !has_mapped_tmp && self.mount_host_tmp { + let tmp_folder_path = tempfile::Builder::new() + .prefix("wasmer-") + .tempdir()? + .into_path(); + mapped_dirs.push(MappedDirectory { + host: tmp_folder_path, + guest: "/tmp".to_string(), + }); } - - let builder = WasiEnv::builder(program_name) - .runtime(Arc::clone(&rt)) - .args(args) - .envs(self.env_vars.clone()) - .uses(uses) - .map_commands(map_commands); - - let mut builder = { - // If we preopen anything from the host then shallow copy it over - let root_fs = RootFileSystemBuilder::new() - .with_tty(Box::new(DeviceFile::new(__WASI_STDIN_FILENO))) - .build(); - - let mut mapped_dirs = Vec::new(); - - // Process the --dirs flag and merge it with --mapdir. - let mut have_current_dir = false; - for dir in &self.pre_opened_directories { - let mapping = if dir == Path::new(".") { - if have_current_dir { - bail!("Cannot pre-open the current directory twice: --dir=. must only be specified once"); - } - have_current_dir = true; - - let current_dir = - std::env::current_dir().context("could not determine current directory")?; - - MappedDirectory { - host: current_dir, - guest: Self::MAPPED_CURRENT_DIR_DEFAULT_PATH.to_string(), - } - } else { - let resolved = dir.canonicalize().with_context(|| { - format!( - "could not canonicalize path for argument '--dir {}'", - dir.display() + if !mapped_dirs.is_empty() { + let has_root_tmp = false; + for MappedDirectory { host, guest } in mapped_dirs { + tracing::debug!("Mounting host directory {} in {}", host.display(), guest); + let native_fs = HostFileSystem::new(host.canonicalize()?)?; + // Create the parent dirs + if let Some(parent) = PathBuf::from(guest.clone()).parent() { + virtual_fs::ops::create_dir_all(&root_fs, parent)?; + } + let fs: Arc = + Arc::new(native_fs); + root_fs + .mount(guest.clone().into(), &fs, PathBuf::new()) + .map_err(|_e| { + anyhow!( + "There has been a collision. \nA folder might be already mounted in {} or it's parent.", + guest ) + .context(format!( + "Could not mount {} in {}", + host.display(), + guest + )) })?; - - if &resolved != dir { - bail!( - "Invalid argument '--dir {}': path must either be absolute, or '.'", - dir.display(), - ); - } - - let guest = resolved - .to_str() - .with_context(|| { - format!( - "invalid argument '--dir {}': path must be valid utf-8", - dir.display(), - ) - })? - .to_string(); - - MappedDirectory { - host: resolved, - guest, - } - }; - - mapped_dirs.push(mapping); - } - - for MappedDirectory { host, guest } in &self.mapped_dirs { - let resolved_host = host.canonicalize().with_context(|| { - format!( - "could not canonicalize path for argument '--mapdir {}:{}'", - host.display(), - guest, - ) - })?; - - let mapping = if guest == "." { - if have_current_dir { - bail!("Cannot pre-open the current directory twice: '--mapdir=?:.' / '--dir=.' must only be specified once"); - } - have_current_dir = true; - - MappedDirectory { - host: resolved_host, - guest: Self::MAPPED_CURRENT_DIR_DEFAULT_PATH.to_string(), - } - } else { - MappedDirectory { - host: resolved_host, - guest: guest.clone(), - } - }; - mapped_dirs.push(mapping); - } - - if !mapped_dirs.is_empty() { - let fs_backing: Arc = - Arc::new(PassthruFileSystem::new(default_fs_backing())); - for MappedDirectory { host, guest } in self.mapped_dirs.clone() { - let host = if !host.is_absolute() { - Path::new("/").join(host) - } else { - host - }; - root_fs.mount(guest.into(), &fs_backing, host)?; - } - } - - // Open the root of the new filesystem - let b = builder - .sandbox_fs(root_fs) - .preopen_dir(Path::new("/")) - .unwrap(); - - if have_current_dir { - b.map_dir(".", Self::MAPPED_CURRENT_DIR_DEFAULT_PATH)? - } else { - b.map_dir(".", "/")? - } - }; - - *builder.capabilities_mut() = self.capabilities(); - - #[cfg(feature = "experimental-io-devices")] - { - if self.enable_experimental_io_devices { - wasi_state_builder - .setup_fs(Box::new(wasmer_wasi_experimental_io_devices::initialize)); } } - - Ok(builder) + if let Err(e) = root_fs.create_dir(Path::new(Self::MAPPED_CURRENT_DIR_DEFAULT_PATH)) { + tracing::debug!( + "Could not create /home directory, probably the path is already mounted" + ); + } + Ok(root_fs) } - pub fn build_mapped_directories(&self) -> Result, anyhow::Error> { + fn build_mapped_directories(&self) -> Result> { let mut mapped_dirs = Vec::new(); - // Process the --dirs flag and merge it with --mapdir. - let mut have_current_dir = false; + // Process the --dirs flag and merge it with --mapdir flag. for dir in &self.pre_opened_directories { - let mapping = if dir == Path::new(".") { - if have_current_dir { - bail!("Cannot pre-open the current directory twice: --dir=. must only be specified once"); - } - have_current_dir = true; - - let current_dir = - std::env::current_dir().context("could not determine current directory")?; - - MappedDirectory { - host: current_dir, - guest: Self::MAPPED_CURRENT_DIR_DEFAULT_PATH.to_string(), - } - } else { - let resolved = dir.canonicalize().with_context(|| { - format!( - "could not canonicalize path for argument '--dir {}'", - dir.display() - ) - })?; - - if &resolved != dir { - bail!( - "Invalid argument '--dir {}': path must either be absolute, or '.'", - dir.display(), - ); - } - - let guest = resolved - .to_str() - .with_context(|| { - format!( - "invalid argument '--dir {}': path must be valid utf-8", - dir.display(), - ) - })? - .to_string(); - - MappedDirectory { - host: resolved, - guest, - } - }; - - mapped_dirs.push(mapping); + if !dir.is_relative() { + bail!( + "Invalid argument '--dir {}': path must be relative", + dir.display(), + ); + } + let guest = PathBuf::from(Self::MAPPED_CURRENT_DIR_DEFAULT_PATH) + .join(dir) + .display() + .to_string(); + let host = dir.canonicalize().with_context(|| { + format!( + "could not canonicalize path for argument '--dir {}'", + dir.display() + ) + })?; + mapped_dirs.push(MappedDirectory { host, guest }); } + // Process the --mapdir flag. for MappedDirectory { host, guest } in &self.mapped_dirs { - let resolved_host = host.canonicalize().with_context(|| { + let host = host.canonicalize().with_context(|| { format!( "could not canonicalize path for argument '--mapdir {}:{}'", host.display(), guest, ) })?; + let guest = PathBuf::from(Self::MAPPED_CURRENT_DIR_DEFAULT_PATH) + .join(guest) + .display() + .to_string(); - let mapping = if guest == "." { - if have_current_dir { - bail!("Cannot pre-open the current directory twice: '--mapdir=?:.' / '--dir=.' must only be specified once"); - } - have_current_dir = true; - - MappedDirectory { - host: resolved_host, - guest: Self::MAPPED_CURRENT_DIR_DEFAULT_PATH.to_string(), - } - } else { - MappedDirectory { - host: resolved_host, - guest: guest.clone(), - } - }; - mapped_dirs.push(mapping); + mapped_dirs.push(MappedDirectory { host, guest }); } Ok(mapped_dirs) @@ -487,21 +324,6 @@ impl Wasi { Ok(rt) } - /// Helper function for instantiating a module with Wasi imports for the `Run` command. - pub fn instantiate( - &self, - module: &Module, - program_name: String, - args: Vec, - runtime: Arc, - store: &mut Store, - ) -> Result<(WasiFunctionEnv, Instance)> { - let builder = self.prepare(module, program_name, args, runtime)?; - let (instance, wasi_env) = builder.instantiate(module.clone(), store)?; - - Ok((wasi_env, instance)) - } - pub fn for_binfmt_interpreter() -> Result { let dir = std::env::var_os("WASMER_BINFMT_MISC_PREOPEN") .map(Into::into) diff --git a/lib/compiler/Cargo.toml b/lib/compiler/Cargo.toml index e32eeaf3a13..19b895e1572 100644 --- a/lib/compiler/Cargo.toml +++ b/lib/compiler/Cargo.toml @@ -35,7 +35,7 @@ enum-iterator = "0.7.0" bytes = "1.0" self_cell = "1.0" rkyv = { version = "0.7.40", features = ["indexmap", "validation", "strict"] } -shared-buffer = "0.1" +shared-buffer.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] wasmer-vm = { path = "../vm", version = "=4.2.3" } diff --git a/lib/emscripten/src/time.rs b/lib/emscripten/src/time.rs index d4c62c60f66..eef62941b8b 100644 --- a/lib/emscripten/src/time.rs +++ b/lib/emscripten/src/time.rs @@ -426,7 +426,8 @@ pub fn _strftime( ) else { return 0; }; - let Ok(rust_time) = time::Time::from_hms(tm.tm_hour as u8, tm.tm_min as u8, tm.tm_sec as u8) else { + let Ok(rust_time) = time::Time::from_hms(tm.tm_hour as u8, tm.tm_min as u8, tm.tm_sec as u8) + else { return 0; }; let rust_datetime = time::PrimitiveDateTime::new(rust_date, rust_time); diff --git a/lib/registry/Cargo.toml b/lib/registry/Cargo.toml index 1e2711eef9c..eabdf1e6117 100644 --- a/lib/registry/Cargo.toml +++ b/lib/registry/Cargo.toml @@ -37,7 +37,7 @@ semver = "1.0.14" serde = { version = "1.0.145", features = ["derive"] } serde_json = "1.0.85" tar = "0.4.38" -tempfile = "3.6.0" +tempfile.workspace = true thiserror = "1.0.37" time = { version = "0.3.17", default-features = false, features = ["parsing", "std", "formatting"], optional = true } tldextract = "0.6.0" diff --git a/lib/virtual-fs/Cargo.toml b/lib/virtual-fs/Cargo.toml index c22527bb988..8105096bbdd 100644 --- a/lib/virtual-fs/Cargo.toml +++ b/lib/virtual-fs/Cargo.toml @@ -28,6 +28,7 @@ tokio = { version = "1", features = ["io-util", "sync", "macros"], default_featu pin-project-lite = "0.2.9" indexmap = "1.9.2" replace_with = "0.1.7" +tempfile.workspace = true [target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies] getrandom = { version = "0.2" } @@ -37,8 +38,9 @@ getrandom = { version = "0.2", features = [ "js" ] } [dev-dependencies] pretty_assertions = "1.3.0" -tempfile = "3.6.0" +tempfile.workspace = true tokio = { version = "1", features = ["io-util", "rt"], default_features = false } +tracing-test = "0.2" [features] default = ["host-fs", "webc-fs", "static-fs"] diff --git a/lib/virtual-fs/src/arc_fs.rs b/lib/virtual-fs/src/arc_fs.rs deleted file mode 100644 index 734774fc16c..00000000000 --- a/lib/virtual-fs/src/arc_fs.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Wraps a clonable Arc of a file system - in practice this is useful so you -//! can pass clonable file systems with a `Box` to other -//! interfaces - -use std::{path::Path, sync::Arc}; - -use crate::*; - -#[derive(Debug)] -pub struct ArcFileSystem { - fs: Arc, -} - -impl ArcFileSystem { - pub fn new(inner: Arc) -> Self { - Self { fs: inner } - } -} - -impl FileSystem for ArcFileSystem { - fn read_dir(&self, path: &Path) -> Result { - self.fs.read_dir(path) - } - - fn create_dir(&self, path: &Path) -> Result<()> { - self.fs.create_dir(path) - } - - fn remove_dir(&self, path: &Path) -> Result<()> { - self.fs.remove_dir(path) - } - - fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> { - Box::pin(async { self.fs.rename(from, to).await }) - } - - fn metadata(&self, path: &Path) -> Result { - self.fs.metadata(path) - } - - fn symlink_metadata(&self, path: &Path) -> Result { - self.fs.symlink_metadata(path) - } - - fn remove_file(&self, path: &Path) -> Result<()> { - self.fs.remove_file(path) - } - - fn new_open_options(&self) -> OpenOptions { - self.fs.new_open_options() - } -} diff --git a/lib/virtual-fs/src/builder.rs b/lib/virtual-fs/src/builder.rs index f583834d88e..7fbdd611b2f 100644 --- a/lib/virtual-fs/src/builder.rs +++ b/lib/virtual-fs/src/builder.rs @@ -61,51 +61,54 @@ impl RootFileSystemBuilder { self } - pub fn build(self) -> TmpFileSystem { - let tmp = TmpFileSystem::new(); + pub fn build_into(self, fs: TmpFileSystem) -> TmpFileSystem { if self.default_root_dirs { for root_dir in &["/.app", "/.private", "/bin", "/dev", "/etc", "/tmp"] { - if let Err(err) = tmp.create_dir(Path::new(root_dir)) { + if let Err(err) = fs.create_dir(Path::new(root_dir)) { debug!("failed to create dir [{}] - {}", root_dir, err); } } } if self.add_wasmer_command { - let _ = tmp + let _ = fs .new_open_options_ext() .insert_device_file(PathBuf::from("/bin/wasmer"), Box::::default()); } if self.default_dev_files { - let _ = tmp + let _ = fs .new_open_options_ext() .insert_device_file(PathBuf::from("/dev/null"), Box::::default()); - let _ = tmp + let _ = fs .new_open_options_ext() .insert_device_file(PathBuf::from("/dev/zero"), Box::::default()); - let _ = tmp + let _ = fs .new_open_options_ext() .insert_device_file(PathBuf::from("/dev/urandom"), Box::::default()); - let _ = tmp.new_open_options_ext().insert_device_file( + let _ = fs.new_open_options_ext().insert_device_file( PathBuf::from("/dev/stdin"), self.stdin .unwrap_or_else(|| Box::new(DeviceFile::new(DeviceFile::STDIN))), ); - let _ = tmp.new_open_options_ext().insert_device_file( + let _ = fs.new_open_options_ext().insert_device_file( PathBuf::from("/dev/stdout"), self.stdout .unwrap_or_else(|| Box::new(DeviceFile::new(DeviceFile::STDOUT))), ); - let _ = tmp.new_open_options_ext().insert_device_file( + let _ = fs.new_open_options_ext().insert_device_file( PathBuf::from("/dev/stderr"), self.stderr .unwrap_or_else(|| Box::new(DeviceFile::new(DeviceFile::STDERR))), ); - let _ = tmp.new_open_options_ext().insert_device_file( + let _ = fs.new_open_options_ext().insert_device_file( PathBuf::from("/dev/tty"), self.tty.unwrap_or_else(|| Box::::default()), ); } - tmp + fs + } + pub fn build(self) -> TmpFileSystem { + let tmp = TmpFileSystem::new(); + self.build_into(tmp) } } diff --git a/lib/virtual-fs/src/static_file.rs b/lib/virtual-fs/src/files/_static.rs similarity index 100% rename from lib/virtual-fs/src/static_file.rs rename to lib/virtual-fs/src/files/_static.rs diff --git a/lib/virtual-fs/src/arc_file.rs b/lib/virtual-fs/src/files/arc.rs similarity index 100% rename from lib/virtual-fs/src/arc_file.rs rename to lib/virtual-fs/src/files/arc.rs diff --git a/lib/virtual-fs/src/arc_box_file.rs b/lib/virtual-fs/src/files/arc_box.rs similarity index 100% rename from lib/virtual-fs/src/arc_box_file.rs rename to lib/virtual-fs/src/files/arc_box.rs diff --git a/lib/virtual-fs/src/buffer_file.rs b/lib/virtual-fs/src/files/buffer.rs similarity index 100% rename from lib/virtual-fs/src/buffer_file.rs rename to lib/virtual-fs/src/files/buffer.rs diff --git a/lib/virtual-fs/src/combine_file.rs b/lib/virtual-fs/src/files/combine.rs similarity index 99% rename from lib/virtual-fs/src/combine_file.rs rename to lib/virtual-fs/src/files/combine.rs index 4880545fc84..1f87997017b 100644 --- a/lib/virtual-fs/src/combine_file.rs +++ b/lib/virtual-fs/src/files/combine.rs @@ -1,6 +1,6 @@ use derivative::Derivative; -use super::*; +use crate::*; use crate::VirtualFile; diff --git a/lib/virtual-fs/src/cow_file.rs b/lib/virtual-fs/src/files/cow.rs similarity index 100% rename from lib/virtual-fs/src/cow_file.rs rename to lib/virtual-fs/src/files/cow.rs diff --git a/lib/virtual-fs/src/dual_write_file.rs b/lib/virtual-fs/src/files/dual_write.rs similarity index 99% rename from lib/virtual-fs/src/dual_write_file.rs rename to lib/virtual-fs/src/files/dual_write.rs index f2c0aca0198..b556e6fe99d 100644 --- a/lib/virtual-fs/src/dual_write_file.rs +++ b/lib/virtual-fs/src/files/dual_write.rs @@ -1,6 +1,6 @@ use derivative::Derivative; -use super::*; +use crate::*; use crate::VirtualFile; diff --git a/lib/virtual-fs/src/files/mod.rs b/lib/virtual-fs/src/files/mod.rs new file mode 100644 index 00000000000..37b7ddf3abc --- /dev/null +++ b/lib/virtual-fs/src/files/mod.rs @@ -0,0 +1,11 @@ +pub mod _static; +pub mod arc; +pub mod arc_box; +pub mod buffer; +pub mod combine; +pub mod cow; +pub mod dual_write; +pub mod null; +pub mod random; +pub mod special; +pub mod zero; diff --git a/lib/virtual-fs/src/null_file.rs b/lib/virtual-fs/src/files/null.rs similarity index 100% rename from lib/virtual-fs/src/null_file.rs rename to lib/virtual-fs/src/files/null.rs diff --git a/lib/virtual-fs/src/random_file.rs b/lib/virtual-fs/src/files/random.rs similarity index 100% rename from lib/virtual-fs/src/random_file.rs rename to lib/virtual-fs/src/files/random.rs diff --git a/lib/virtual-fs/src/special_file.rs b/lib/virtual-fs/src/files/special.rs similarity index 100% rename from lib/virtual-fs/src/special_file.rs rename to lib/virtual-fs/src/files/special.rs diff --git a/lib/virtual-fs/src/zero_file.rs b/lib/virtual-fs/src/files/zero.rs similarity index 100% rename from lib/virtual-fs/src/zero_file.rs rename to lib/virtual-fs/src/files/zero.rs diff --git a/lib/virtual-fs/src/empty_fs.rs b/lib/virtual-fs/src/fs/empty.rs similarity index 69% rename from lib/virtual-fs/src/empty_fs.rs rename to lib/virtual-fs/src/fs/empty.rs index ce5be69637c..11223bce26d 100644 --- a/lib/virtual-fs/src/empty_fs.rs +++ b/lib/virtual-fs/src/fs/empty.rs @@ -2,16 +2,20 @@ //! as the name suggests it always returns file not found. use std::path::Path; +use std::sync::Mutex; #[allow(unused_imports, dead_code)] use tracing::{debug, error, info, trace, warn}; use crate::*; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct EmptyFileSystem {} #[allow(unused_variables)] impl FileSystem for EmptyFileSystem { + fn as_dir(&self) -> Box { + Box::new(self.clone()) + } fn read_dir(&self, path: &Path) -> Result { // Special-case the root path by returning an empty iterator. // An empty file system should still be readable, just not contain @@ -65,6 +69,34 @@ impl FileSystem for EmptyFileSystem { } } +impl crate::Directory for EmptyFileSystem { + fn unique_id(&self) -> usize { + unimplemented!(); + } + + fn get_child(&self, _name: OsString) -> Result { + Err(FsError::EntryNotFound) + } + + fn iter(&self) -> ReaddirIterator { + ReaddirIterator(Mutex::new(Box::new(vec![].into_iter()))) + } + fn absolute_path(&self) -> PathBuf { + // let guard = self.fs.inner.read().unwrap(); + // let node = guard.get_node(self.inode).unwrap(); + // guard.absolute_path(node) + PathBuf::from("/") + } + + fn walk_to<'a>(&self, _to: PathBuf) -> Result> { + Err(FsError::EntryNotFound) + } + + fn parent(&self) -> Option> { + unimplemented!(); + } +} + impl FileOpener for EmptyFileSystem { #[allow(unused_variables)] fn open( diff --git a/lib/virtual-fs/src/host_fs.rs b/lib/virtual-fs/src/fs/host.rs similarity index 84% rename from lib/virtual-fs/src/host_fs.rs rename to lib/virtual-fs/src/fs/host.rs index da7b845eb1b..c5ed67c732c 100644 --- a/lib/virtual-fs/src/host_fs.rs +++ b/lib/virtual-fs/src/fs/host.rs @@ -1,3 +1,4 @@ +use crate::ops::PathClean; use crate::{ DirEntry, FileType, FsError, Metadata, OpenOptions, OpenOptionsConfig, ReadDir, Result, VirtualFile, @@ -20,37 +21,40 @@ use tokio::runtime::Handle; #[derive(Debug, Clone)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -pub struct FileSystem(Handle); - -impl Default for FileSystem { - fn default() -> Self { - Self(Handle::current()) - } -} -impl FileSystem { - pub fn new(handle: Handle) -> Self { - FileSystem(handle) - } +pub struct FileSystem { + handle: Handle, + base: PathBuf, + parent: Option>, } impl FileSystem { - pub fn canonicalize(&self, path: &Path) -> Result { - if !path.exists() { - return Err(FsError::InvalidInput); - } - fs::canonicalize(path).map_err(Into::into) + pub fn new(base: PathBuf) -> Result { + Ok(FileSystem { + handle: Handle::current(), + base: base.canonicalize()?, + parent: None, + }) } } impl crate::FileSystem for FileSystem { + fn set_parent(&mut self, directory: Arc) -> Result<()> { + self.parent = Some(directory); + Ok(()) + } + fn parent(&self) -> Option> { + self.parent.clone() + } fn read_dir(&self, path: &Path) -> Result { + let mut base = self.base.clone(); + let path = self.base.join(path.clean_safely()?); let read_dir = fs::read_dir(path)?; let mut data = read_dir .map(|entry| { let entry = entry?; let metadata = entry.metadata()?; Ok(DirEntry { - path: entry.path(), + path: entry.path().strip_prefix(&mut base).unwrap().to_owned(), metadata: Ok(metadata.try_into()?), }) }) @@ -61,35 +65,45 @@ impl crate::FileSystem for FileSystem { } fn create_dir(&self, path: &Path) -> Result<()> { - if path.parent().is_none() { - return Err(FsError::BaseNotDirectory); + let path: PathBuf = self.base.join(path.clean_safely()?); + if path == PathBuf::from(".") { + // Creating the root should always work + return Ok(()); } fs::create_dir(path).map_err(Into::into) } fn remove_dir(&self, path: &Path) -> Result<()> { - if path.parent().is_none() { + let path: PathBuf = self.base.join(path.clean_safely()?); + if path == PathBuf::from(".") { return Err(FsError::BaseNotDirectory); } // https://github.com/rust-lang/rust/issues/86442 // DirectoryNotEmpty is not implemented consistently - if path.is_dir() && self.read_dir(path).map(|s| !s.is_empty()).unwrap_or(false) { + if path.is_dir() + && fs::read_dir(&path) + .map(|mut s| s.next().is_some()) + .unwrap_or(false) + { return Err(FsError::DirectoryNotEmpty); } fs::remove_dir(path).map_err(Into::into) } fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> { - let from = from.to_owned(); - let to = to.to_owned(); Box::pin(async move { + let from = from.to_owned().clean_safely()?; + let to = to.to_owned().clean_safely()?; use filetime::{set_file_mtime, FileTime}; - if from.parent().is_none() { + if from == PathBuf::from(".") { return Err(FsError::BaseNotDirectory); } - if to.parent().is_none() { + if to == PathBuf::from(".") { return Err(FsError::BaseNotDirectory); } + let from: PathBuf = self.base.join(&from); + let to: PathBuf = self.base.join(&to); + if !from.exists() { return Err(FsError::EntryNotFound); } @@ -129,7 +143,8 @@ impl crate::FileSystem for FileSystem { } fn remove_file(&self, path: &Path) -> Result<()> { - if path.parent().is_none() { + let path: PathBuf = self.base.join(path.clean_safely()?); + if path == PathBuf::from(".") { return Err(FsError::BaseNotDirectory); } fs::remove_file(path).map_err(Into::into) @@ -140,6 +155,7 @@ impl crate::FileSystem for FileSystem { } fn metadata(&self, path: &Path) -> Result { + let path: PathBuf = self.base.join(path.clean_safely()?); fs::metadata(path) .and_then(TryInto::try_into) .map_err(Into::into) @@ -210,6 +226,8 @@ impl crate::FileOpener for FileSystem { path: &Path, conf: &OpenOptionsConfig, ) -> Result> { + let path = self.base.join(path.clean_safely()?); + // TODO: handle create implying write, etc. let read = conf.read(); let write = conf.write(); @@ -221,11 +239,11 @@ impl crate::FileOpener for FileSystem { .create(conf.create()) .append(conf.append()) .truncate(conf.truncate()) - .open(path) + .open(&path) .map_err(Into::into) .map(|file| { Box::new(File::new( - self.0.clone(), + self.handle.clone(), file, path.to_owned(), read, @@ -247,6 +265,7 @@ pub struct File { pub host_path: PathBuf, #[cfg(feature = "enable-serde")] flags: u16, + unique_id: usize, } #[cfg(feature = "enable-serde")] @@ -371,6 +390,7 @@ impl File { inner_std: file, inner: async_file, host_path, + unique_id: crate::generate_next_unique_id(), #[cfg(feature = "enable-serde")] flags: _flags, } @@ -385,6 +405,10 @@ impl File { //#[cfg_attr(feature = "enable-serde", typetag::serde)] #[async_trait::async_trait] impl VirtualFile for File { + fn unique_id(&self) -> usize { + self.unique_id + } + fn last_accessed(&self) -> u64 { self.metadata() .accessed() @@ -920,22 +944,26 @@ impl VirtualFile for Stdin { mod tests { use tempfile::TempDir; - use crate::host_fs::FileSystem; + use super::FileSystem; use crate::FileSystem as FileSystemTrait; use crate::FsError; use std::path::Path; + use std::path::PathBuf; #[tokio::test] async fn test_new_filesystem() { let temp = TempDir::new().unwrap(); std::fs::write(temp.path().join("foo2.txt"), b"").unwrap(); - let fs = FileSystem::default(); - assert!(fs.read_dir(Path::new("/")).is_ok(), "hostfs can read root"); + let fs = FileSystem::new(temp.path().into()).expect("get filesystem"); + assert!( + fs.read_dir(Path::new("/")).is_ok(), + "NativeFS can read root" + ); assert!( fs.new_open_options() .read(true) - .open(temp.path().join("foo2.txt")) + .open(Path::new("/foo2.txt")) .is_ok(), "created foo2.txt" ); @@ -943,17 +971,17 @@ mod tests { #[tokio::test] async fn test_create_dir() { - let temp = TempDir::new().unwrap(); - let fs = FileSystem::default(); + let temp: TempDir = TempDir::new().unwrap(); + let fs = FileSystem::new(temp.path().into()).expect("get filesystem"); assert_eq!( - fs.create_dir(Path::new("/")), - Err(FsError::BaseNotDirectory), - "creating a directory that has no parent", + fs.create_dir(Path::new("../")), + Err(FsError::InvalidInput), + "creating a directory out of bounds", ); assert_eq!( - fs.create_dir(&temp.path().join("foo")), + fs.create_dir(Path::new("/foo")), Ok(()), "creating a directory", ); @@ -963,7 +991,7 @@ mod tests { "foo dir exists in host_fs" ); - let cur_dir = read_dir_names(&fs, temp.path()); + let cur_dir = read_dir_names(&fs, "/"); if !cur_dir.contains(&"foo".to_string()) { panic!("cur_dir does not contain foo: {:#?}", cur_dir); @@ -975,7 +1003,7 @@ mod tests { ); assert_eq!( - fs.create_dir(&temp.path().join("foo/bar")), + fs.create_dir(Path::new("foo/bar")), Ok(()), "creating a sub-directory", ); @@ -985,14 +1013,14 @@ mod tests { "foo dir exists in host_fs" ); - let foo_dir = read_dir_names(&fs, temp.path().join("foo")); + let foo_dir = read_dir_names(&fs, Path::new("/foo")); assert!( foo_dir.contains(&"bar".to_string()), "the foo directory is updated and well-defined" ); - let bar_dir = read_dir_names(&fs, temp.path().join("foo/bar")); + let bar_dir = read_dir_names(&fs, Path::new("/foo/bar")); assert!( bar_dir.is_empty(), @@ -1002,8 +1030,8 @@ mod tests { #[tokio::test] async fn test_remove_dir() { - let temp = TempDir::new().unwrap(); - let fs = FileSystem::default(); + let temp: TempDir = TempDir::new().unwrap(); + let fs = FileSystem::new(temp.path().into()).expect("get filesystem"); assert_eq!( fs.remove_dir(Path::new("/foo")), @@ -1012,13 +1040,13 @@ mod tests { ); assert_eq!( - fs.create_dir(&temp.path().join("foo")), + fs.create_dir(Path::new("foo")), Ok(()), "creating a directory", ); assert_eq!( - fs.create_dir(&temp.path().join("foo/bar")), + fs.create_dir(Path::new("foo/bar")), Ok(()), "creating a sub-directory", ); @@ -1026,24 +1054,24 @@ mod tests { assert!(temp.path().join("foo/bar").exists(), "./foo/bar exists"); assert_eq!( - fs.remove_dir(&temp.path().join("foo")), + fs.remove_dir(Path::new("foo")), Err(FsError::DirectoryNotEmpty), "removing a directory that has children", ); assert_eq!( - fs.remove_dir(&temp.path().join("foo/bar")), + fs.remove_dir(Path::new("foo/bar")), Ok(()), "removing a sub-directory", ); assert_eq!( - fs.remove_dir(&temp.path().join("foo")), + fs.remove_dir(Path::new("foo")), Ok(()), "removing a directory", ); - let cur_dir = read_dir_names(&fs, temp.path()); + let cur_dir = read_dir_names(&fs, "/"); assert!( !cur_dir.contains(&"foo".to_string()), @@ -1060,11 +1088,13 @@ mod tests { #[tokio::test] async fn test_rename() { - let temp = TempDir::new().unwrap(); - let fs = FileSystem::default(); + let temp: TempDir = TempDir::new().unwrap(); + let fs = FileSystem::new(temp.path().into()).expect("get filesystem"); std::fs::create_dir_all(temp.path().join("foo").join("qux")).unwrap(); - let foo = temp.path().join("foo"); - let bar = temp.path().join("bar"); + let foo = Path::new("foo"); + let bar = Path::new("bar"); + let foo_realpath = temp.path().join(foo); + let bar_realpath = temp.path().join(bar); assert_eq!( fs.rename(Path::new("/"), Path::new("/bar")).await, @@ -1114,7 +1144,7 @@ mod tests { "creating a new file (`hello2.txt`)", ); - let cur_dir = read_dir_names(&fs, temp.path()); + let cur_dir = read_dir_names(&fs, Path::new("/")); assert!( !cur_dir.contains(&"foo".to_string()), @@ -1137,12 +1167,12 @@ mod tests { assert!(qux_dir.is_empty(), "the qux directory is empty"); assert!( - bar.join("hello1.txt").exists(), + bar_realpath.join("hello1.txt").exists(), "the /bar/hello1.txt file exists" ); assert!( - bar.join("hello2.txt").exists(), + bar_realpath.join("hello2.txt").exists(), "the /bar/hello2.txt file exists" ); @@ -1168,21 +1198,27 @@ mod tests { "renaming a file (in the same directory)", ); - assert!(bar.exists(), "./bar exists"); - assert!(bar.join("baz").exists(), "./bar/baz exists"); - assert!(!foo.exists(), "foo does not exist anymore"); + assert!(bar_realpath.exists(), "./bar exists"); + assert!(bar_realpath.join("baz").exists(), "./bar/baz exists"); + assert!(!foo_realpath.exists(), "foo does not exist anymore"); assert!( - bar.join("baz/world2.txt").exists(), + bar_realpath.join("baz/world2.txt").exists(), "/bar/baz/world2.txt exists" ); assert!( - bar.join("world1.txt").exists(), + bar_realpath.join("world1.txt").exists(), "/bar/world1.txt (ex hello1.txt) exists" ); - assert!(!bar.join("hello1.txt").exists(), "hello1.txt was moved"); - assert!(!bar.join("hello2.txt").exists(), "hello2.txt was moved"); assert!( - bar.join("baz/world2.txt").exists(), + !bar_realpath.join("hello1.txt").exists(), + "hello1.txt was moved" + ); + assert!( + !bar_realpath.join("hello2.txt").exists(), + "hello2.txt was moved" + ); + assert!( + bar_realpath.join("baz/world2.txt").exists(), "world2.txt was moved to the correct place" ); } @@ -1194,9 +1230,9 @@ mod tests { let temp = TempDir::new().unwrap(); - let fs = FileSystem::default(); + let fs = FileSystem::new(temp.path().into()).expect("get filesystem"); - let root_metadata = fs.metadata(temp.path()).unwrap(); + let root_metadata = fs.metadata(Path::new("/")).unwrap(); assert!(root_metadata.ft.dir); // it seems created is not evailable on musl, at least on CI testing. @@ -1206,7 +1242,8 @@ mod tests { assert_eq!(root_metadata.modified, root_metadata.created); assert!(root_metadata.modified > 0); - let foo = temp.path().join("foo"); + let foo = Path::new("foo"); + let foo_realpath = temp.path().join(foo); assert_eq!(fs.create_dir(&foo), Ok(())); @@ -1223,7 +1260,8 @@ mod tests { sleep(Duration::from_secs(3)); - let bar = temp.path().join("bar"); + let bar = Path::new("bar"); + let bar_realpath = temp.path().join(bar); assert_eq!(fs.rename(&foo, &bar).await, Ok(())); @@ -1242,26 +1280,26 @@ mod tests { #[tokio::test] async fn test_remove_file() { - let fs = FileSystem::default(); let temp = TempDir::new().unwrap(); + let fs = FileSystem::new(temp.path().into()).expect("get filesystem"); assert!( matches!( fs.new_open_options() .write(true) .create_new(true) - .open(temp.path().join("foo.txt")), + .open(Path::new("foo.txt")), Ok(_) ), "creating a new file", ); - assert!(read_dir_names(&fs, temp.path()).contains(&"foo.txt".to_string())); + assert!(read_dir_names(&fs, Path::new("/")).contains(&"foo.txt".to_string())); assert!(temp.path().join("foo.txt").is_file()); assert_eq!( - fs.remove_file(&temp.path().join("foo.txt")), + fs.remove_file(&Path::new("foo.txt")), Ok(()), "removing a file that exists", ); @@ -1269,7 +1307,7 @@ mod tests { assert!(!temp.path().join("foo.txt").exists()); assert_eq!( - fs.remove_file(&temp.path().join("foo.txt")), + fs.remove_file(&Path::new("foo.txt")), Err(FsError::EntryNotFound), "removing a file that doesn't exists", ); @@ -1278,34 +1316,22 @@ mod tests { #[tokio::test] async fn test_readdir() { let temp = TempDir::new().unwrap(); - let fs = FileSystem::default(); + let fs = FileSystem::new(temp.path().into()).expect("get filesystem"); + assert_eq!(fs.create_dir(&Path::new("foo")), Ok(()), "creating `foo`"); assert_eq!( - fs.create_dir(&temp.path().join("foo")), - Ok(()), - "creating `foo`" - ); - assert_eq!( - fs.create_dir(&temp.path().join("foo/sub")), + fs.create_dir(&Path::new("foo/sub")), Ok(()), "creating `sub`" ); - assert_eq!( - fs.create_dir(&temp.path().join("bar")), - Ok(()), - "creating `bar`" - ); - assert_eq!( - fs.create_dir(&temp.path().join("baz")), - Ok(()), - "creating `bar`" - ); + assert_eq!(fs.create_dir(&Path::new("bar")), Ok(()), "creating `bar`"); + assert_eq!(fs.create_dir(&Path::new("baz")), Ok(()), "creating `bar`"); assert!( matches!( fs.new_open_options() .write(true) .create_new(true) - .open(temp.path().join("a.txt")), + .open(Path::new("a.txt")), Ok(_) ), "creating `a.txt`", @@ -1315,109 +1341,44 @@ mod tests { fs.new_open_options() .write(true) .create_new(true) - .open(&temp.path().join("b.txt")), + .open(&Path::new("b.txt")), Ok(_) ), "creating `b.txt`", ); - let readdir = fs.read_dir(temp.path()); + let readdir = fs.read_dir(Path::new("/")); assert!( readdir.is_ok(), "reading the directory `{}`", - temp.path().display() + Path::new("/").display() ); let mut readdir = readdir.unwrap(); let next = readdir.next().unwrap().unwrap(); assert!(next.path.ends_with("a.txt"), "checking entry #1"); - assert!(next.path.is_file(), "checking entry #1"); + assert!(next.metadata().unwrap().is_file(), "checking entry #1"); let next = readdir.next().unwrap().unwrap(); assert!(next.path.ends_with("b.txt"), "checking entry #2"); - assert!(next.path.is_file(), "checking entry #2"); + assert!(next.metadata().unwrap().is_file(), "checking entry #2"); let next = readdir.next().unwrap().unwrap(); assert!(next.path.ends_with("bar"), "checking entry #3"); - assert!(next.path.is_dir(), "checking entry #3"); + assert!(next.metadata().unwrap().is_dir(), "checking entry #3"); let next = readdir.next().unwrap().unwrap(); assert!(next.path.ends_with("baz"), "checking entry #4"); - assert!(next.path.is_dir(), "checking entry #4"); + assert!(next.metadata().unwrap().is_dir(), "checking entry #4"); let next = readdir.next().unwrap().unwrap(); assert!(next.path.ends_with("foo"), "checking entry #5"); - assert!(next.path.is_dir(), "checking entry #5"); + assert!(next.metadata().unwrap().is_dir(), "checking entry #5"); if let Some(s) = readdir.next() { panic!("next: {:?}", s); } } - - #[tokio::test] - async fn test_canonicalize() { - let temp = TempDir::new().unwrap(); - std::fs::create_dir_all(temp.path().join("foo/bar/baz/qux")).unwrap(); - std::fs::write(temp.path().join("foo/bar/baz/qux/hello.txt"), b"").unwrap(); - - let fs = FileSystem::default(); - let root_dir = temp.path().canonicalize().unwrap(); - - assert_eq!( - fs.canonicalize(temp.path()), - Ok(root_dir.clone()), - "canonicalizing `/`", - ); - assert_eq!( - fs.canonicalize(Path::new("foo")), - Err(FsError::InvalidInput), - "canonicalizing `foo`", - ); - assert_eq!( - fs.canonicalize(&temp.path().join("././././foo/")), - Ok(root_dir.join("foo")), - "canonicalizing `/././././foo/`", - ); - assert_eq!( - fs.canonicalize(&temp.path().join("foo/bar//")), - Ok(root_dir.join("foo").join("bar")), - "canonicalizing `/foo/bar//`", - ); - assert_eq!( - fs.canonicalize(&temp.path().join("foo/bar/../bar")), - Ok(root_dir.join("foo").join("bar")), - "canonicalizing `/foo/bar/../bar`", - ); - assert_eq!( - fs.canonicalize(&temp.path().join("foo/bar/../..")), - Ok(root_dir.clone()), - "canonicalizing `/foo/bar/../..`", - ); - // temp.path().join("/foo/bar/../../..").exists() gives true on windows - #[cfg(not(target_os = "windows"))] - assert_eq!( - fs.canonicalize(&root_dir.join("/foo/bar/../../..")), - Err(FsError::InvalidInput), - "canonicalizing `/foo/bar/../../..`", - ); - assert_eq!( - fs.canonicalize(&root_dir.join("C:/foo/")), - Err(FsError::InvalidInput), - "canonicalizing `C:/foo/`", - ); - assert_eq!( - fs.canonicalize(&root_dir.join( - "foo/./../foo/bar/../../foo/bar/./baz/./../baz/qux/../../baz/./qux/hello.txt" - )), - Ok(root_dir - .join("foo") - .join("bar") - .join("baz") - .join("qux") - .join("hello.txt")), - "canonicalizing a crazily stupid path name", - ); - } } diff --git a/lib/virtual-fs/src/fs/mod.rs b/lib/virtual-fs/src/fs/mod.rs new file mode 100644 index 00000000000..50b117a8291 --- /dev/null +++ b/lib/virtual-fs/src/fs/mod.rs @@ -0,0 +1,9 @@ +pub mod empty; +#[cfg(feature = "host-fs")] +pub mod host; +pub mod overlay; +pub mod tmp; +pub mod trace; +pub mod webc; +pub mod webc_static; +pub mod webc_volume; diff --git a/lib/virtual-fs/src/overlay_fs.rs b/lib/virtual-fs/src/fs/overlay.rs similarity index 90% rename from lib/virtual-fs/src/overlay_fs.rs rename to lib/virtual-fs/src/fs/overlay.rs index 464b2cca111..948f2f5d7b6 100644 --- a/lib/virtual-fs/src/overlay_fs.rs +++ b/lib/virtual-fs/src/fs/overlay.rs @@ -1,5 +1,6 @@ use std::{ collections::HashSet, + ffi::OsString, fmt::Debug, io::{self, SeekFrom}, path::{Path, PathBuf}, @@ -13,8 +14,8 @@ use replace_with::replace_with_or_abort; use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf}; use crate::{ - ops, FileOpener, FileSystem, FileSystems, FsError, Metadata, OpenOptions, OpenOptionsConfig, - ReadDir, VirtualFile, + ops, Descriptor, FileOpener, FileSystem, FileSystems, FsError, Metadata, OpenOptions, + OpenOptionsConfig, ReadDir, ReaddirIterator, VirtualFile, }; /// A primary filesystem and chain of secondary filesystems that are overlayed @@ -38,6 +39,7 @@ use crate::{ /// might do something like this: /// /// ```rust +/// use std::path::PathBuf; /// use virtual_fs::{ /// mem_fs::FileSystem as MemFS, /// host_fs::FileSystem as HostFS, @@ -50,21 +52,24 @@ use crate::{ /// .unwrap(); /// let _guard = runtime.enter(); /// -/// let fs = OverlayFileSystem::new(MemFS::default(), [HostFS::default()]); -/// -/// // This also has the benefit of storing the two values in-line with no extra -/// // overhead or indirection. -/// assert_eq!( -/// std::mem::size_of_val(&fs), -/// std::mem::size_of::<(MemFS, HostFS)>(), -/// ); +/// let fs = OverlayFileSystem::new(MemFS::default(), [HostFS::new(PathBuf::from("/tmp")).unwrap()]); /// ``` /// /// A more complex example is -#[derive(Clone, PartialEq, Eq)] pub struct OverlayFileSystem { - primary: Arc

, - secondaries: S, + pub primary: Arc

, + secondaries: Arc, + parent: Option>, +} + +impl Clone for OverlayFileSystem { + fn clone(&self) -> Self { + Self { + primary: self.primary.clone(), + secondaries: self.secondaries.clone(), + parent: self.parent.clone(), + } + } } impl OverlayFileSystem @@ -77,7 +82,8 @@ where pub fn new(primary: P, secondaries: S) -> Self { OverlayFileSystem { primary: Arc::new(primary), - secondaries, + secondaries: Arc::new(secondaries), + parent: None, } } @@ -91,11 +97,6 @@ where &self.secondaries } - /// Get a mutable reference to the secondary filesystems. - pub fn secondaries_mut(&mut self) -> &mut S { - &mut self.secondaries - } - fn permission_error_or_not_found(&self, path: &Path) -> Result<(), FsError> { for fs in self.secondaries.filesystems() { if ops::exists(fs, path) { @@ -113,6 +114,22 @@ where S: for<'a> FileSystems<'a> + Send + Sync + 'static, for<'a> <>::Iter as IntoIterator>::IntoIter: Send, { + fn set_parent( + &mut self, + directory: Arc, + ) -> Result<(), FsError> { + self.parent = Some(directory); + Ok(()) + } + fn parent(&self) -> Option> { + self.parent.clone() + } + + fn as_dir(&self) -> Box { + let dir = OverlayDirectory::new(PathBuf::new(), self.clone()); + Box::new(dir) + } + #[tracing::instrument(level = "debug", skip_all, fields(path=%path.display()))] fn read_dir(&self, path: &Path) -> Result { let mut entries = Vec::new(); @@ -359,6 +376,100 @@ where } } +#[derive(Clone)] +pub struct OverlayDirectory { + path: PathBuf, + unique_id: usize, + fs: OverlayFileSystem, +} + +impl Debug for OverlayDirectory +where + P: FileSystem, + S: for<'a> FileSystems<'a>, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("OverlayDirectory") + .field("path", &self.path) + .field("fs", &self.fs) + .finish() + } +} + +impl OverlayDirectory +where + P: FileSystem + Send + Sync + 'static, + S: for<'a> FileSystems<'a> + Send + Sync + 'static, +{ + pub fn new(path: PathBuf, fs: OverlayFileSystem) -> Self { + Self { + path, + fs, + unique_id: crate::generate_next_unique_id(), + } + } +} + +impl crate::Directory for OverlayDirectory +where + P: FileSystem + Send + 'static, + S: for<'a> FileSystems<'a> + Send + Sync + 'static, + for<'a> <>::Iter as IntoIterator>::IntoIter: Send, +{ + fn get_child(&self, name: OsString) -> Result { + if let Ok(primary) = self.fs.primary.as_dir().walk_to(self.path.clone()) { + if let Ok(child) = primary.get_child(name.clone()) { + return Ok(child); + } + } + for secondary in self.fs.secondaries.filesystems() { + if let Ok(secondary) = secondary.as_dir().walk_to(self.path.clone()) { + if let Ok(child) = secondary.get_child(name.clone()) { + return Ok(child); + } + } + } + Err(FsError::EntryNotFound) + } + + fn absolute_path(&self) -> PathBuf { + if let Some(parent) = &self.fs.parent { + parent.absolute_path().join(&self.path) + } else { + self.path.clone() + } + } + + fn unique_id(&self) -> usize { + self.unique_id + } + + fn iter(&self) -> ReaddirIterator { + unimplemented!(); + } + + fn walk_to<'a>(&self, to: PathBuf) -> Result, FsError> { + // TODO: Manage whiteouts + let to_path = self.path.join(to); + let primary_dir = self.fs.primary.as_dir().walk_to(to_path.clone()); + if primary_dir.is_ok() { + return primary_dir; + } + + for secondary in self.fs.secondaries.filesystems() { + let secondary_dir = secondary.as_dir().walk_to(to_path.clone()); + if secondary_dir.is_ok() { + return secondary_dir; + } + } + Err(FsError::EntryNotFound) + } + + fn parent(&self) -> Option> { + unimplemented!(); + } +} + impl FileOpener for OverlayFileSystem where P: FileSystem + Send + 'static, @@ -1013,25 +1124,25 @@ where S: for<'a> FileSystems<'a>, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - struct IterFilesystems<'a, S>(&'a S); - impl<'a, S> Debug for IterFilesystems<'a, S> - where - S: for<'b> FileSystems<'b>, - { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut f = f.debug_list(); - - for fs in self.0.filesystems() { - f.entry(&fs); - } - - f.finish() - } - } + // struct IterFilesystems<'a, S>(&'a S); + // impl<'a, S> Debug for IterFilesystems<'a, S> + // where + // S: for<'b> FileSystems<'b>, + // { + // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // let mut f = f.debug_list(); + + // for fs in self.0.filesystems() { + // f.entry(&fs); + // } + + // f.finish() + // } + // } f.debug_struct("OverlayFileSystem") .field("primary", &self.primary) - .field("secondaries", &IterFilesystems(&self.secondaries)) + // .field("secondaries", &IterFilesystems(&self.secondaries)) .finish() } } @@ -1059,7 +1170,7 @@ mod tests { use super::*; use crate::{mem_fs::FileSystem as MemFS, webc_fs::WebcFileSystem, RootFileSystemBuilder}; - const PYTHON: &[u8] = include_bytes!("../../c-api/examples/assets/python-0.1.0.wasmer"); + const PYTHON: &[u8] = include_bytes!("../../../c-api/examples/assets/python-0.1.0.wasmer"); #[tokio::test] async fn remove_directory() { @@ -1197,6 +1308,35 @@ mod tests { ); } + use crate::{EmptyFileSystem, TmpFileSystem, TraceFileSystem}; + use tracing_test::traced_test; + + #[tokio::test] + #[traced_test] + async fn wasi_challenge_example() { + type TypeWebC = OverlayFileSystem; + let primary = TraceFileSystem::new(RootFileSystemBuilder::new().build()); + let other = crate::mem_fs::FileSystem::default(); + let webc = OverlayFileSystem::new(EmptyFileSystem::default(), [other]); + // let fs: OverlayFileSystem = OverlayFileSystem::new(primary, []); + let fs = OverlayFileSystem::new(primary, [webc]); + // let fs = primary; + fs.create_dir(&Path::new("/tmp-dir/")).unwrap(); + dbg!(fs.read_dir(&Path::new("/tmp-dir/"))); + let mut file = fs + .new_open_options() + .write(true) + .create(true) + .open("/tmp-dir/a") + .unwrap(); + file.write("a".as_bytes()).await.unwrap(); + drop(file); + fs.rename(&Path::new("/tmp-dir/a"), &Path::new("/tmp-dir/b")) + .await + .unwrap(); + // file.write("b".as_bytes()).await.unwrap(); + } + #[tokio::test] async fn wasi_runner_use_case() { // Set up some dummy files on the host @@ -1211,16 +1351,17 @@ mod tests { // (initialized with a set of unix-like folders), but certain folders // are first to the host. let primary = RootFileSystemBuilder::new().build(); - let host_fs: Arc = - Arc::new(crate::host_fs::FileSystem::default()); let first_dirs = [(&first, "/first"), (&second, "/second")]; for (host, guest) in first_dirs { + let host_fs: Arc = + Arc::new(crate::host_fs::FileSystem::new(host.to_owned()).unwrap()); primary - .mount(PathBuf::from(guest), &host_fs, host.clone()) + .mount(PathBuf::from(guest), &host_fs, PathBuf::new()) .unwrap(); } // Set up the secondary file systems - let webc = WebCOwned::parse(Bytes::from_static(PYTHON), &ParseOptions::default()).unwrap(); + let webc: WebCOwned = + WebCOwned::parse(Bytes::from_static(PYTHON), &ParseOptions::default()).unwrap(); let webc = WebcFileSystem::init_all(Arc::new(webc)); let fs = OverlayFileSystem::new(primary, [webc]); diff --git a/lib/virtual-fs/src/tmp_fs.rs b/lib/virtual-fs/src/fs/tmp.rs similarity index 82% rename from lib/virtual-fs/src/tmp_fs.rs rename to lib/virtual-fs/src/fs/tmp.rs index 46e47f0fe53..cd06cd085af 100644 --- a/lib/virtual-fs/src/tmp_fs.rs +++ b/lib/virtual-fs/src/fs/tmp.rs @@ -30,21 +30,6 @@ impl TmpFileSystem { self.fs.new_open_options_ext() } - pub fn union(&self, other: &Arc) { - self.fs.union(other) - } - - /// See [`mem_fs::FileSystem::mount_directory_entries`]. - pub fn mount_directory_entries( - &self, - target_path: &Path, - other: &Arc, - source_path: &Path, - ) -> Result<()> { - self.fs - .mount_directory_entries(target_path, other, source_path) - } - pub fn mount( &self, src_path: PathBuf, @@ -61,6 +46,10 @@ impl TmpFileSystem { } impl FileSystem for TmpFileSystem { + fn as_dir(&self) -> Box { + self.fs.as_dir() + } + fn read_dir(&self, path: &Path) -> Result { self.fs.read_dir(path) } diff --git a/lib/virtual-fs/src/trace_fs.rs b/lib/virtual-fs/src/fs/trace.rs similarity index 96% rename from lib/virtual-fs/src/trace_fs.rs rename to lib/virtual-fs/src/fs/trace.rs index 53db3db90b6..e8df933b645 100644 --- a/lib/virtual-fs/src/trace_fs.rs +++ b/lib/virtual-fs/src/fs/trace.rs @@ -39,6 +39,11 @@ impl FileSystem for TraceFileSystem where F: FileSystem, { + #[tracing::instrument(level = "trace", skip(self))] + fn as_dir(&self) -> Box { + self.0.as_dir() + } + #[tracing::instrument(level = "trace", skip(self), err)] fn read_dir(&self, path: &std::path::Path) -> crate::Result { self.0.read_dir(path) @@ -92,6 +97,7 @@ where let file = self.0.new_open_options().options(conf.clone()).open(path)?; Ok(Box::new(TraceFile { file, + unique_id: crate::generate_next_unique_id(), path: path.to_owned(), })) } @@ -100,10 +106,15 @@ where #[derive(Debug)] struct TraceFile { path: PathBuf, + unique_id: usize, file: Box, } impl VirtualFile for TraceFile { + fn unique_id(&self) -> usize { + self.unique_id + } + #[tracing::instrument(level = "trace", skip(self), fields(path=%self.path.display()))] fn last_accessed(&self) -> u64 { self.file.last_accessed() diff --git a/lib/virtual-fs/src/webc_fs.rs b/lib/virtual-fs/src/fs/webc.rs similarity index 74% rename from lib/virtual-fs/src/webc_fs.rs rename to lib/virtual-fs/src/fs/webc.rs index 0a67c739bfa..14562352ef2 100644 --- a/lib/virtual-fs/src/webc_fs.rs +++ b/lib/virtual-fs/src/fs/webc.rs @@ -14,8 +14,7 @@ use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite}; use webc::v1::{FsEntry, FsEntryType, OwnedFsEntryFile, WebC}; use crate::{ - mem_fs::FileSystem as MemFileSystem, FileOpener, FileSystem, FsError, Metadata, OpenOptions, - OpenOptionsConfig, ReadDir, VirtualFile, + FileOpener, FileSystem, FsError, Metadata, OpenOptions, OpenOptionsConfig, ReadDir, VirtualFile, }; /// Custom file system wrapper to map requested file paths @@ -25,7 +24,6 @@ where T: std::fmt::Debug + Send + Sync + 'static, { pub webc: Arc, - pub memory: Arc, top_level_dirs: Vec, volumes: Vec>, } @@ -38,7 +36,6 @@ where pub fn init(webc: Arc, package: &str) -> Self { let mut fs = Self { webc: webc.clone(), - memory: Arc::new(MemFileSystem::default()), top_level_dirs: Vec::new(), volumes: Vec::new(), }; @@ -58,7 +55,6 @@ where pub fn init_all(webc: Arc) -> Self { let mut fs = Self { webc: webc.clone(), - memory: Arc::new(MemFileSystem::default()), top_level_dirs: Vec::new(), volumes: webc.volumes.clone().into_values().collect(), }; @@ -99,6 +95,7 @@ where Ok(Box::new(WebCFile { volume, + unique_id: crate::generate_next_unique_id(), webc: self.webc.clone(), path: path.to_path_buf(), entry: file, @@ -119,13 +116,14 @@ where return Ok(Box::new(WebCFile { volume: volume.clone(), + unique_id: crate::generate_next_unique_id(), webc: self.webc.clone(), path: path.to_path_buf(), entry, cursor: 0, })); } - self.memory.new_open_options().open(path) + Err(FsError::EntryNotFound) } } } @@ -137,6 +135,7 @@ where T: std::fmt::Debug + Send + Sync + 'static, { pub webc: Arc, + unique_id: usize, pub volume: String, #[allow(dead_code)] pub path: PathBuf, @@ -149,6 +148,10 @@ where T: std::fmt::Debug + Send + Sync + 'static, T: Deref>, { + fn unique_id(&self) -> usize { + self.unique_id + } + fn last_accessed(&self) -> u64 { 0 } @@ -314,120 +317,48 @@ where .map(|o| transform_into_read_dir(Path::new(&path), o.as_ref())) .ok_or(FsError::EntryNotFound); - match read_dir_result { - Ok(o) => Ok(o), - Err(_) => self.memory.read_dir(Path::new(&path)), - } + read_dir_result } - fn create_dir(&self, path: &Path) -> Result<(), FsError> { - let path = normalizes_path(path); - let result = self.memory.create_dir(Path::new(&path)); - result + fn create_dir(&self, _path: &Path) -> Result<(), FsError> { + Err(FsError::PermissionDenied) } - fn remove_dir(&self, path: &Path) -> Result<(), FsError> { - let path = normalizes_path(path); - let result = self.memory.remove_dir(Path::new(&path)); - if self.volumes.iter().any(|v| v.get_file_entry(&path).is_ok()) { - Ok(()) - } else { - result - } + fn remove_dir(&self, _path: &Path) -> Result<(), FsError> { + Err(FsError::PermissionDenied) } - fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<(), FsError>> { - Box::pin(async { - let from = normalizes_path(from); - let to = normalizes_path(to); - let result = self.memory.rename(Path::new(&from), Path::new(&to)).await; - if self.volumes.iter().any(|v| v.get_file_entry(&from).is_ok()) { - Ok(()) - } else { - result - } - }) + fn rename<'a>(&'a self, _from: &'a Path, _to: &'a Path) -> BoxFuture<'a, Result<(), FsError>> { + Box::pin(async { Err(FsError::PermissionDenied) }) } fn metadata(&self, path: &Path) -> Result { let path = normalizes_path(path); - if let Some(fs_entry) = self - .volumes - .iter() - .filter_map(|v| v.get_file_entry(&path).ok()) - .next() - { - Ok(Metadata { - ft: translate_file_type(FsEntryType::File), - accessed: 0, - created: 0, - modified: 0, - len: fs_entry.get_len(), - }) - } else if self - .volumes - .iter() - .filter_map(|v| v.read_dir(&path).ok()) - .next() - .is_some() - { - Ok(Metadata { - ft: translate_file_type(FsEntryType::Dir), - accessed: 0, - created: 0, - modified: 0, - len: 0, - }) - } else { - self.memory.metadata(Path::new(&path)) + for volume in self.volumes.iter() { + if let Ok(fs_entry) = volume.get_file_entry(&path) { + return Ok(Metadata { + ft: translate_file_type(FsEntryType::File), + accessed: 0, + created: 0, + modified: 0, + len: fs_entry.get_len(), + }); + } else if let Ok(_fs_entry) = volume.read_dir(&path) { + return Ok(Metadata { + ft: translate_file_type(FsEntryType::Dir), + accessed: 0, + created: 0, + modified: 0, + len: 0, + }); + } } + Err(FsError::EntryNotFound) } - fn remove_file(&self, path: &Path) -> Result<(), FsError> { - let path = normalizes_path(path); - let result = self.memory.remove_file(Path::new(&path)); - if self - .volumes - .iter() - .filter_map(|v| v.get_file_entry(&path).ok()) - .next() - .is_some() - { - Ok(()) - } else { - result - } + fn remove_file(&self, _path: &Path) -> Result<(), FsError> { + Err(FsError::PermissionDenied) } fn new_open_options(&self) -> OpenOptions { OpenOptions::new(self) } fn symlink_metadata(&self, path: &Path) -> Result { - let path = normalizes_path(path); - if let Some(fs_entry) = self - .volumes - .iter() - .filter_map(|v| v.get_file_entry(&path).ok()) - .next() - { - Ok(Metadata { - ft: translate_file_type(FsEntryType::File), - accessed: 0, - created: 0, - modified: 0, - len: fs_entry.get_len(), - }) - } else if self - .volumes - .iter() - .filter_map(|v| v.read_dir(&path).ok()) - .next() - .is_some() - { - Ok(Metadata { - ft: translate_file_type(FsEntryType::Dir), - accessed: 0, - created: 0, - modified: 0, - len: 0, - }) - } else { - self.memory.symlink_metadata(Path::new(&path)) - } + self.metadata(path) } } @@ -462,13 +393,13 @@ mod tests { #[tokio::test] async fn read_a_file_from_the_webc_fs() { - let webc: &[u8] = include_bytes!("../../c-api/examples/assets/python-0.1.0.wasmer"); + let webc: &[u8] = include_bytes!("../../../c-api/examples/assets/python-0.1.0.wasmer"); let options = ParseOptions::default(); let webc = WebCOwned::parse(Bytes::from_static(webc), &options).unwrap(); let fs = WebcFileSystem::init_all(Arc::new(webc)); - let mut f = fs + let mut f: Box = fs .new_open_options() .read(true) .open(Path::new("/lib/python3.6/collections/abc.py")) diff --git a/lib/virtual-fs/src/static_fs.rs b/lib/virtual-fs/src/fs/webc_static.rs similarity index 97% rename from lib/virtual-fs/src/static_fs.rs rename to lib/virtual-fs/src/fs/webc_static.rs index e18da882ce0..66ea179056d 100644 --- a/lib/virtual-fs/src/static_fs.rs +++ b/lib/virtual-fs/src/fs/webc_static.rs @@ -19,13 +19,13 @@ use webc::v1::{FsEntry, FsEntryType, OwnedFsEntryFile}; /// Custom file system wrapper to map requested file paths #[derive(Debug)] -pub struct StaticFileSystem { +pub struct WebCStaticFileSystem { pub package: String, pub volumes: Arc>>, pub memory: Arc, } -impl StaticFileSystem { +impl WebCStaticFileSystem { pub fn init(bytes: &'static [u8], package: &str) -> Option { let volumes = Arc::new(webc::v1::WebC::parse_volumes_from_fileblock(bytes).ok()?); let fs = Self { @@ -45,7 +45,7 @@ impl StaticFileSystem { } /// Custom file opener, returns a WebCFile -impl FileOpener for StaticFileSystem { +impl FileOpener for WebCStaticFileSystem { fn open( &self, path: &Path, @@ -61,6 +61,7 @@ impl FileOpener for StaticFileSystem { Ok(Box::new(WebCFile { package: self.package.clone(), + unique_id: crate::generate_next_unique_id(), volume, volumes: self.volumes.clone(), path: path.to_path_buf(), @@ -77,6 +78,7 @@ impl FileOpener for StaticFileSystem { return Ok(Box::new(WebCFile { package: self.package.clone(), + unique_id: crate::generate_next_unique_id(), volume: volume.clone(), volumes: self.volumes.clone(), path: path.to_path_buf(), @@ -93,6 +95,7 @@ impl FileOpener for StaticFileSystem { #[derive(Debug)] pub struct WebCFile { pub volumes: Arc>>, + unique_id: usize, pub package: String, pub volume: String, pub path: PathBuf, @@ -102,6 +105,10 @@ pub struct WebCFile { #[async_trait::async_trait] impl VirtualFile for WebCFile { + fn unique_id(&self) -> usize { + self.unique_id + } + fn last_accessed(&self) -> u64 { 0 } @@ -237,7 +244,7 @@ fn transform_into_read_dir(path: &Path, fs_entries: &[FsEntry<'_>]) -> crate::Re crate::ReadDir::new(entries) } -impl FileSystem for StaticFileSystem { +impl FileSystem for WebCStaticFileSystem { fn read_dir(&self, path: &Path) -> Result { let path = normalizes_path(path); for volume in self.volumes.values() { diff --git a/lib/virtual-fs/src/webc_volume_fs.rs b/lib/virtual-fs/src/fs/webc_volume.rs similarity index 79% rename from lib/virtual-fs/src/webc_volume_fs.rs rename to lib/virtual-fs/src/fs/webc_volume.rs index 56d0a43907f..6416029fe85 100644 --- a/lib/virtual-fs/src/webc_volume_fs.rs +++ b/lib/virtual-fs/src/fs/webc_volume.rs @@ -1,5 +1,6 @@ use std::{ convert::{TryFrom, TryInto}, + ffi::OsString, io::Cursor, path::{Path, PathBuf}, pin::Pin, @@ -7,26 +8,31 @@ use std::{ task::Poll, }; +use crate::{ + Descriptor, DescriptorType, DirEntry, DirectoryEntry, EmptyFileSystem, FileOpener, FileSystem, + FileType, FsError, Metadata, OpenOptionsConfig, OverlayFileSystem, ReadDir, ReaddirIterator, + VirtualFile, +}; use futures::future::BoxFuture; +use std::sync::{Arc, Mutex}; use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite}; use webc::{ compat::{Container, SharedBytes, Volume}, PathSegmentError, PathSegments, ToPathSegments, }; -use crate::{ - DirEntry, EmptyFileSystem, FileOpener, FileSystem, FileType, FsError, Metadata, - OpenOptionsConfig, OverlayFileSystem, ReadDir, VirtualFile, -}; - #[derive(Debug, Clone)] pub struct WebcVolumeFileSystem { volume: Volume, + parent: Option>, } impl WebcVolumeFileSystem { pub fn new(volume: Volume) -> Self { - WebcVolumeFileSystem { volume } + WebcVolumeFileSystem { + volume, + parent: None, + } } pub fn volume(&self) -> &Volume { @@ -49,6 +55,19 @@ impl WebcVolumeFileSystem { } impl FileSystem for WebcVolumeFileSystem { + fn set_parent( + &mut self, + directory: Arc, + ) -> Result<(), FsError> { + self.parent = Some(directory); + Ok(()) + } + fn parent(&self) -> Option> { + self.parent.clone() + } + fn as_dir(&self) -> Box { + Box::new(WebcDirectory::new(PathBuf::from("/"), self.clone())) + } fn read_dir(&self, path: &Path) -> Result { let meta = self.metadata(path)?; @@ -149,6 +168,98 @@ impl FileSystem for WebcVolumeFileSystem { } } +#[derive(Clone, Debug)] +pub struct WebcDirectory { + path: PathBuf, + unique_id: usize, + fs: WebcVolumeFileSystem, +} + +impl WebcDirectory { + pub fn new(path: PathBuf, fs: WebcVolumeFileSystem) -> Self { + Self { + path, + fs, + unique_id: crate::generate_next_unique_id(), + } + } +} + +impl crate::Directory for WebcDirectory { + fn unique_id(&self) -> usize { + self.unique_id + } + + fn parent(&self) -> Option> { + unimplemented!(); + } + + fn iter(&self) -> ReaddirIterator { + ReaddirIterator(Mutex::new(Box::new( + self.fs + .volume + .read_dir(&self.path) + .unwrap() + .into_iter() + .map(move |(segment, metadata)| { + Ok(DirectoryEntry { + type_: match metadata { + webc::Metadata::Dir => DescriptorType::Directory, + webc::Metadata::File { .. } => DescriptorType::File, + }, + name: segment.to_string().into(), + }) + }), + ))) + } + + fn absolute_path(&self) -> PathBuf { + if let Some(parent) = &self.fs.parent { + parent.absolute_path().join(&self.path) + } else { + self.path.clone() + } + } + + fn walk_to<'a>(&self, to: PathBuf) -> Result, FsError> { + let to_path = self.path.join(to); + match self.fs.volume.metadata(&to_path) { + Some(m) if m.is_dir() => { + let dir = WebcDirectory::new(to_path, self.fs.clone()); + Ok(Arc::new(dir)) + } + Some(_) => Err(FsError::BaseNotDirectory), + None => Err(FsError::EntryNotFound), + } + } + + fn get_child(&self, name: OsString) -> Result { + let to_path = self.path.join(name); + match self.fs.volume.metadata(&to_path) { + Some(f) if f.is_file() => { + match self.fs.volume().read_file(to_path.clone()) { + Some(bytes) => Ok(Descriptor::File(Arc::new(File( + Cursor::new(bytes), + crate::generate_next_unique_id(), + self.fs.parent.clone(), + to_path, + )))), + None => { + // The metadata() call should guarantee this, so something + // probably went wrong internally + Err(FsError::UnknownError) + } + } + } + Some(d) if d.is_dir() => { + let dir = WebcDirectory::new(to_path, self.fs.clone()); + Ok(Descriptor::Directory(Arc::new(dir))) + } + _ => Err(FsError::NotAFile), + } + } +} + impl FileOpener for WebcVolumeFileSystem { fn open( &self, @@ -173,7 +284,12 @@ impl FileOpener for WebcVolumeFileSystem { } match self.volume().read_file(path) { - Some(bytes) => Ok(Box::new(File(Cursor::new(bytes)))), + Some(bytes) => Ok(Box::new(File( + Cursor::new(bytes), + crate::generate_next_unique_id(), + self.parent.clone(), + path.into(), + ))), None => { // The metadata() call should guarantee this, so something // probably went wrong internally @@ -183,10 +299,27 @@ impl FileOpener for WebcVolumeFileSystem { } } -#[derive(Debug, Clone, PartialEq)] -struct File(Cursor); +#[derive(Debug, Clone)] +struct File( + Cursor, + usize, + Option>, + PathBuf, +); impl VirtualFile for File { + fn absolute_path(&self) -> PathBuf { + if let Some(parent) = &self.2 { + parent.absolute_path().join(self.3.clone()) + } else { + self.3.clone() + } + } + + fn unique_id(&self) -> usize { + self.1 + } + fn last_accessed(&self) -> u64 { 0 } @@ -318,7 +451,7 @@ mod tests { use std::convert::TryFrom; use tokio::io::AsyncReadExt; - const PYTHON_WEBC: &[u8] = include_bytes!("../../c-api/examples/assets/python-0.1.0.wasmer"); + const PYTHON_WEBC: &[u8] = include_bytes!("../../../c-api/examples/assets/python-0.1.0.wasmer"); #[test] fn normalize_paths() { @@ -646,4 +779,16 @@ mod tests { FsError::PermissionDenied, ); } + + #[tokio::test] + async fn webc_overlay_as_dir_iter() -> anyhow::Result<()> { + let container = webc::Container::from_bytes(PYTHON_WEBC).unwrap(); + let volumes = container.volumes(); + let volume = volumes["atom"].clone(); + let fs = WebcVolumeFileSystem::new(volume); + let dir = fs.as_dir().walk_to(PathBuf::from("./"))?; + let file_dirs = dir.iter().into_iter().collect::>(); + // dbg!(volumes.keys()); + Ok(()) + } } diff --git a/lib/virtual-fs/src/lib.rs b/lib/virtual-fs/src/lib.rs index 591f086c44c..f729c492008 100644 --- a/lib/virtual-fs/src/lib.rs +++ b/lib/virtual-fs/src/lib.rs @@ -8,71 +8,110 @@ use futures::future::BoxFuture; use std::any::Any; use std::ffi::OsString; use std::fmt; +use std::hash::{Hash, Hasher}; use std::io; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::pin::Pin; +use std::sync::{ + atomic::{AtomicUsize, Ordering::SeqCst}, + Arc, +}; use std::task::Context; use std::task::Poll; use thiserror::Error; -pub mod arc_box_file; -pub mod arc_file; -pub mod arc_fs; -pub mod buffer_file; +pub mod files; +pub mod arc_box_file { + pub use super::files::arc_box::*; +} +pub mod arc_file { + pub use super::files::arc::*; +} +pub mod fs; +pub mod buffer_file { + pub use super::files::buffer::*; +} pub mod builder; -pub mod combine_file; -pub mod cow_file; -pub mod dual_write_file; -pub mod empty_fs; +pub mod combine_file { + pub use super::files::combine::*; +} +pub mod cow_file { + pub use super::files::cow::*; +} +pub mod dual_write_file { + pub use super::files::dual_write::*; +} +pub mod empty_fs { + pub use super::fs::empty::*; +} #[cfg(feature = "host-fs")] -pub mod host_fs; +pub mod host_fs { + pub use super::fs::host::*; +} pub mod mem_fs; -pub mod null_file; -pub mod passthru_fs; -pub mod random_file; -pub mod special_file; -pub mod tmp_fs; -pub mod union_fs; -pub mod zero_file; +pub mod null_file { + pub use super::files::null::*; +} +pub mod random_file { + pub use super::files::random::*; +} +pub mod special_file { + pub use super::files::special::*; +} +pub mod tmp_fs { + pub use super::fs::tmp::*; +} +pub mod zero_file { + pub use super::files::zero::*; +} // tty_file -> see wasmer_wasi::tty_file mod filesystems; pub(crate) mod ops; -mod overlay_fs; +mod overlay_fs { + pub use super::fs::overlay::*; +} pub mod pipe; -mod static_file; +mod static_file { + pub use super::files::_static::*; +} #[cfg(feature = "static-fs")] -pub mod static_fs; -mod trace_fs; +pub mod static_fs { + pub use super::fs::webc_static::*; +} +mod trace_fs { + pub use super::fs::trace::*; +} #[cfg(feature = "webc-fs")] -pub mod webc_fs; +pub mod webc_fs { + pub use super::fs::webc::*; +} #[cfg(feature = "webc-fs")] -mod webc_volume_fs; +mod webc_volume_fs { + pub use super::fs::webc_volume::*; +} pub mod limiter; pub use arc_box_file::*; pub use arc_file::*; -pub use arc_fs::*; pub use buffer_file::*; pub use builder::*; pub use combine_file::*; pub use cow_file::*; pub use dual_write_file::*; pub use empty_fs::*; +pub use files::zero::*; pub use filesystems::FileSystems; pub use null_file::*; pub use overlay_fs::OverlayFileSystem; -pub use passthru_fs::*; pub use pipe::*; pub use special_file::*; pub use static_file::StaticFile; pub use tmp_fs::*; pub use trace_fs::TraceFileSystem; -pub use union_fs::*; #[cfg(feature = "webc-fs")] pub use webc_volume_fs::WebcVolumeFileSystem; -pub use zero_file::*; pub type Result = std::result::Result; @@ -87,7 +126,21 @@ pub trait ClonableVirtualFile: VirtualFile + Clone {} pub use ops::{copy_reference, copy_reference_ext}; pub trait FileSystem: fmt::Debug + Send + Sync + 'static + Upcastable { + fn set_parent(&mut self, _directory: Arc) -> Result<()> { + unimplemented!(); + } + + fn parent(&self) -> Option> { + unimplemented!(); + } + + fn as_dir(&self) -> Box { + unimplemented!(); + } fn read_dir(&self, path: &Path) -> Result; + fn get_dir(&self, _path: &Path) -> Result> { + unimplemented!(); + } fn create_dir(&self, path: &Path) -> Result<()>; fn remove_dir(&self, path: &Path) -> Result<()>; fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>>; @@ -120,6 +173,10 @@ where D: Deref + std::fmt::Debug + Send + Sync + 'static, F: FileSystem + ?Sized, { + fn as_dir(&self) -> Box { + (**self).as_dir() + } + fn read_dir(&self, path: &Path) -> Result { (**self).read_dir(path) } @@ -318,11 +375,35 @@ impl<'a> OpenOptions<'a> { } } +/// A unique ID generator for virtual files and directories +/// Every `VirtualFile` and `Directory` should have a unique ID +/// associated to it. +/// +/// This can help, for example, to be able to have `PartialEq` and `Hash` +/// over those elements. +static NEXT_ID: AtomicUsize = AtomicUsize::new(0); + +/// Generates a unique next ID for a virtual file or directory +pub(crate) fn generate_next_unique_id() -> usize { + NEXT_ID.fetch_add(1, SeqCst) +} + /// This trait relies on your file closing when it goes out of scope via `Drop` //#[cfg_attr(feature = "enable-serde", typetag::serde)] pub trait VirtualFile: fmt::Debug + AsyncRead + AsyncWrite + AsyncSeek + Unpin + Upcastable + Send { + fn absolute_path(&self) -> PathBuf { + unimplemented!(); + } + + /// The unique id associated to the file. + /// The `virtual-fs` crate assure uniqueness on this ids even + /// accross different `VirtualFile` and `Directory` implementations. + fn unique_id(&self) -> usize { + unimplemented!(); + } + /// the last time the file was accessed in nanoseconds as a UNIX timestamp fn last_accessed(&self) -> u64; @@ -375,6 +456,131 @@ pub trait VirtualFile: /// Polls the file for when it is available for writing fn poll_write_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; } +impl Hash for dyn VirtualFile { + fn hash(&self, state: &mut H) { + self.unique_id().hash(state); + } +} + +pub trait Directory: fmt::Debug + Send + Sync + Upcastable { + /// The unique id associated to the file. + /// The `virtual-fs` crate assure uniqueness on this ids even + /// accross different `VirtualFile` and `Directory` implementations. + fn unique_id(&self) -> usize { + unimplemented!(); + } + + fn get_child(&self, name: OsString) -> Result; + + fn walk_to(&self, _to: PathBuf) -> Result> { + unimplemented!(); + } + + fn parent(&self) -> Option>; + + fn iter(&self) -> ReaddirIterator { + unimplemented!(); + } + + fn absolute_path(&self) -> PathBuf; + // /// The parent directory of this dir + // fn parent(self) -> Option>; + // fn get_dir(&self, path: &Path) -> Result> { + // unimplemented!(); + // } + // fn read_dir(&self, path: &Path) -> Result; + // fn create_dir(&self, path: &Path) -> Result<()>; + // fn remove_dir(&self, path: &Path) -> Result<()>; + // fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>>; + // fn metadata(&self, path: &Path) -> Result; + // /// This method gets metadata without following symlinks in the path. + // /// Currently identical to `metadata` because symlinks aren't implemented + // /// yet. + // fn symlink_metadata(&self, path: &Path) -> Result { + // self.metadata(path) + // } + // fn remove_file(&self, path: &Path) -> Result<()>; + + // fn new_open_options(&self) -> OpenOptions; +} + +impl Directory for D +where + D: Deref + std::fmt::Debug + Send + Sync + 'static, + F: Directory + ?Sized, +{ + fn get_child(&self, name: OsString) -> Result { + (**self).get_child(name) + } + + fn unique_id(&self) -> usize { + (**self).unique_id() + } + + fn walk_to<'a>(&self, to: PathBuf) -> Result> { + (**self).walk_to(to) + } + + fn parent(&self) -> Option> { + (**self).parent() + } + + fn iter(&self) -> ReaddirIterator { + (**self).iter() + } + + fn absolute_path(&self) -> PathBuf { + (**self).absolute_path() + } +} + +impl Hash for dyn Directory { + fn hash(&self, state: &mut H) { + self.unique_id().hash(state); + } +} + +#[derive(Debug, Clone)] +pub enum Descriptor { + File(Arc), + Directory(Arc), +} + +#[derive(Debug, PartialEq, Clone)] +pub enum DescriptorType { + File, + Directory, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct DirectoryEntry { + pub(crate) type_: DescriptorType, + pub(crate) name: OsString, +} + +pub struct ReaddirIterator( + std::sync::Mutex> + Send + 'static>>, +); + +impl ReaddirIterator { + #[allow(dead_code)] + pub(crate) fn new(i: impl Iterator> + Send + 'static) -> Self { + ReaddirIterator(std::sync::Mutex::new(Box::new(i))) + } + #[allow(dead_code)] + pub(crate) fn next(&self) -> Result> { + self.0.lock().unwrap().next().transpose() + } +} + +impl IntoIterator for ReaddirIterator { + type Item = Result; + type IntoIter = Box + Send>; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_inner().unwrap() + } +} // Implementation of `Upcastable` taken from https://users.rust-lang.org/t/why-does-downcasting-not-work-for-subtraits/33286/7 . /// Trait needed to get downcasting from `VirtualFile` to work. @@ -671,7 +877,12 @@ impl FileType { ..Default::default() } } - + pub fn new_file() -> Self { + Self { + file: true, + ..Default::default() + } + } pub fn is_dir(&self) -> bool { self.dir } diff --git a/lib/virtual-fs/src/mem_fs/dir.rs b/lib/virtual-fs/src/mem_fs/dir.rs new file mode 100644 index 00000000000..2a76202eed9 --- /dev/null +++ b/lib/virtual-fs/src/mem_fs/dir.rs @@ -0,0 +1,289 @@ +use super::{ + ArcDirectoryNode, CustomFileNode, DirectoryNode, FileHandle, FileNode, FileSystem, Inode, Node, + ReadOnlyFileNode, +}; +use crate::FileSystem as _; +use crate::{Descriptor, DescriptorType, DirectoryEntry, FsError, ReaddirIterator, Result}; +use std::ffi::OsString; +use std::path::{Component, PathBuf}; +use std::sync::{Arc, Mutex}; + +#[derive(Debug, Clone)] +pub struct Directory { + inode: Inode, + unique_id: usize, + fs: FileSystem, +} + +impl Directory { + pub fn new(inode: Inode, fs: FileSystem) -> Self { + Self { + inode, + fs, + unique_id: crate::generate_next_unique_id(), + } + } +} + +impl crate::Directory for Directory { + fn unique_id(&self) -> usize { + self.unique_id + } + + fn get_child(&self, name: OsString) -> Result { + let guard = self.fs.inner.read().unwrap(); + let node = guard.get_node_directory(self.inode).unwrap(); + let found_node = node + .children + .iter() + .find_map(|inode| { + guard.storage.get(*inode).and_then(|node| { + if node.name() == name { + Some(node) + } else { + None + } + }) + }) + .ok_or(FsError::EntryNotFound)?; + match found_node { + Node::Directory(DirectoryNode { inode, .. }) => { + let directory = Directory::new(*inode, self.fs.clone()); + Ok(Descriptor::Directory(Arc::new(directory))) + } + Node::File(FileNode { inode, .. }) + | Node::ReadOnlyFile(ReadOnlyFileNode { inode, .. }) + | Node::CustomFile(CustomFileNode { inode, .. }) => { + let file = FileHandle::new(*inode, self.fs.clone(), false, false, false, 0); + Ok(Descriptor::File(Arc::new(file))) + } + Node::ArcDirectory(ArcDirectoryNode { fs, .. }) => { + Ok(Descriptor::Directory(Arc::new(fs.as_dir()))) + } + } + } + + fn iter(&self) -> ReaddirIterator { + let guard = self.fs.inner.read().unwrap(); + let node = guard.get_node_directory(self.inode).unwrap(); + let fs = self.fs.clone(); + ReaddirIterator(Mutex::new(Box::new(node.children.clone().into_iter().map( + move |child_inode| { + let guard = fs.inner.read().unwrap(); + let node = guard.storage.get(child_inode).unwrap(); + Ok(DirectoryEntry { + type_: match node { + Node::Directory(_) => DescriptorType::Directory, + Node::File(_) => DescriptorType::File, + Node::ReadOnlyFile(_) => DescriptorType::File, + Node::CustomFile(_) => DescriptorType::File, + Node::ArcDirectory(_) => DescriptorType::Directory, + }, + name: node.name().to_owned(), + }) + }, + )))) + } + fn absolute_path(&self) -> PathBuf { + let guard = self.fs.inner.read().unwrap(); + let node = guard.get_node(self.inode).unwrap(); + guard.absolute_path(node) + } + + fn walk_to<'a>(&self, to: PathBuf) -> Result> { + if to == PathBuf::from(".") || to == PathBuf::from("") { + return Ok(Arc::new(self.clone())); + } + let guard = self.fs.inner.read().map_err(|_| FsError::Lock)?; + let mut node = guard.storage.get(self.inode).unwrap(); + + let mut to = to.components(); + while let Some(component) = to.next() { + node = match node { + Node::Directory(DirectoryNode { children, .. }) => match component { + Component::CurDir => node, + Component::ParentDir => { + let parent_inode = node.parent_inode(); + if parent_inode == super::ROOT_INODE { + let remaining_components: PathBuf = to.collect(); + if let Some(parent) = &guard.parent { + return parent.walk_to(remaining_components); + } else { + return Err(FsError::BaseNotDirectory); + } + } else { + guard.storage.get(parent_inode).unwrap() + } + } + Component::Normal(name) => children + .iter() + .find_map(|inode| { + guard.storage.get(*inode).and_then(|node| { + if node.name() == name { + Some(node) + } else { + None + } + }) + }) + .ok_or(FsError::EntryNotFound)?, + _ => return Err(FsError::InvalidData), + }, + // Node::File(FileNode {inode,..}) | Node::ReadOnlyFile(ReadOnlyFileNode { inode, ..}) => { + // // We are trying to get a path from a file + // if to.next().is_some() { + // return Err(FsError::BaseNotDirectory); + // } + // drop(guard); + // let file = FileHandle::new( + // *inode, + // self.fs.clone(), + // false, + // false, + // false, + // 0, + // ); + // return Ok(Descriptor::File(Box::new(file))); + // }, + // Node::CustomFile(CustomFileNode { file, ..}) => { + // drop(guard); + // // We are trying to get a path from a file + // if to.next().is_some() { + // return Err(FsError::BaseNotDirectory); + // } + // return Ok(Descriptor::File(Box::new(file))); + // }, + Node::ArcDirectory(ArcDirectoryNode { fs, .. }) => { + let remaining_components: PathBuf = to.collect(); + return fs.as_dir().walk_to(remaining_components); + } + _ => return Err(FsError::BaseNotDirectory), + }; + } + match node { + Node::Directory(DirectoryNode { inode, .. }) => { + let directory = Directory::new(*inode, self.fs.clone()); + Ok(Arc::new(directory)) + } + _ => Err(FsError::BaseNotDirectory), + } + } + + fn parent(&self) -> Option> { + unimplemented!(); + // let parent_inode = { + // let guard = self.fs.inner.read().ok()?; + // guard.get_node_directory(self.inode).ok()?.parent_inode + // }; + // if parent_inode == super::ROOT_INODE { + // return self.fs.parent.clone(); + // } + // Some(Arc::new(Directory::new(parent_inode, self.fs))) + } + + // fn read_dir(&self, path: &Path) -> Result { + // self.fs.read_dir(path) + // } + + // fn create_dir(&self, path: &Path) -> Result<()> { + // self.fs.create_dir(path) + // } + + // fn remove_dir(&self, path: &Path) -> Result<()> { + // self.fs.remove_dir(path) + // } + + // fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> { + // self.fs.rename(from, to) + // } + + // fn metadata(&self, path: &Path) -> Result { + // self.fs.metadata(path) + // } + + // fn remove_file(&self, path: &Path) -> Result<()> { + // self.fs.remove_file(path) + // } + + // fn new_open_options(&self) -> OpenOptions { + // self.fs.new_open_options() + // } +} + +#[cfg(test)] +mod tests { + use super::FileSystem; + use crate::overlay_fs::OverlayFileSystem; + use crate::WebcVolumeFileSystem; + use crate::{DescriptorType, DirectoryEntry, FileSystem as _, FsError}; + use std::ffi::OsString; + use std::path::{Path, PathBuf}; + + const PYTHON_WEBC: &[u8] = include_bytes!("../../../c-api/examples/assets/python-0.1.0.wasmer"); + + #[tokio::test] + async fn test_create_dir_dot() -> anyhow::Result<()> { + let fs = FileSystem::default(); + // fs.create_dir(".").unwrap(); + assert_eq!( + fs.create_dir(&PathBuf::from("/a")), + Ok(()), + "creating the root which already exists", + ); + + let dir = fs.as_dir(); + let iter_items = dir.iter().into_iter().collect::>(); + assert_eq!(iter_items.len(), 1); + assert_eq!( + iter_items[0].as_ref().unwrap(), + &DirectoryEntry { + type_: DescriptorType::Directory, + name: OsString::from("a"), + } + ); + let dir_a = dir.walk_to(PathBuf::from("a"))?; + + assert_eq!(dir_a.absolute_path(), PathBuf::from("/a")); + assert_eq!(fs.create_dir(&PathBuf::from("/a/b")), Ok(()),); + + assert_eq!(fs.create_dir(&PathBuf::from("/b")), Ok(()),); + + let dir_b = dir.walk_to(PathBuf::from("b"))?; + + let dir_a_b = dir_a.walk_to(PathBuf::from("b"))?; + + fs.rename(&PathBuf::from("/a"), &PathBuf::from("/b/a")) + .await?; + + assert_eq!(dir_a.absolute_path(), PathBuf::from("/b/a")); + assert_eq!(dir_a_b.absolute_path(), PathBuf::from("/b/a/b")); + + Ok(()) + } + + #[tokio::test] + async fn test_create_dir_overlay() -> anyhow::Result<()> { + let fs = FileSystem::default(); + assert_eq!( + fs.create_dir(&PathBuf::from("/a")), + Ok(()), + "creating the root which already exists", + ); + + assert_eq!(fs.create_dir(&PathBuf::from("/a/b")), Ok(()),); + assert_eq!(fs.create_dir(&PathBuf::from("/b")), Ok(()),); + + let fs2 = FileSystem::default(); + assert_eq!(fs2.create_dir(&PathBuf::from("/d")), Ok(()),); + assert_eq!(fs2.create_dir(&PathBuf::from("/e")), Ok(()),); + + let overlay = OverlayFileSystem::new(fs.clone(), [fs2]); + + // let dir = dbg!(overlay.primary.as_dir().walk_to(PathBuf::from("."))); + + let dir = overlay.as_dir().walk_to(PathBuf::from("."))?; + // dbg!(dir.iter().into_iter().collect::>()); + + Ok(()) + } +} diff --git a/lib/virtual-fs/src/mem_fs/file.rs b/lib/virtual-fs/src/mem_fs/file.rs index fe3c5779875..f52649be279 100644 --- a/lib/virtual-fs/src/mem_fs/file.rs +++ b/lib/virtual-fs/src/mem_fs/file.rs @@ -26,24 +26,24 @@ use std::task::{Context, Poll}; /// delegated to the file itself. pub(super) struct FileHandle { inode: Inode, + unique_id: usize, filesystem: FileSystem, readable: bool, writable: bool, append_mode: bool, cursor: u64, - arc_file: Option>>, } impl Clone for FileHandle { fn clone(&self) -> Self { Self { inode: self.inode, + unique_id: self.unique_id, filesystem: self.filesystem.clone(), readable: self.readable, writable: self.writable, append_mode: self.append_mode, cursor: self.cursor, - arc_file: None, } } } @@ -59,48 +59,27 @@ impl FileHandle { ) -> Self { Self { inode, + unique_id: crate::generate_next_unique_id(), filesystem, readable, writable, append_mode, cursor, - arc_file: None, } } +} - fn lazy_load_arc_file_mut(&mut self) -> Result<&mut dyn VirtualFile> { - if self.arc_file.is_none() { - let fs = match self.filesystem.inner.read() { - Ok(fs) => fs, - _ => return Err(FsError::EntryNotFound), - }; +impl VirtualFile for FileHandle { + fn absolute_path(&self) -> PathBuf { + let guard = self.filesystem.inner.read().unwrap(); + let node = guard.get_node(self.inode).unwrap(); + guard.absolute_path(node) + } - let inode = fs.storage.get(self.inode); - match inode { - Some(Node::ArcFile(node)) => { - self.arc_file.replace( - node.fs - .new_open_options() - .read(self.readable) - .write(self.writable) - .append(self.append_mode) - .open(node.path.as_path()), - ); - } - _ => return Err(FsError::EntryNotFound), - } - } - Ok(self - .arc_file - .as_mut() - .unwrap() - .as_mut() - .map_err(|err| *err)? - .as_mut()) + fn unique_id(&self) -> usize { + self.unique_id } -} -impl VirtualFile for FileHandle { fn last_accessed(&self) -> u64 { let fs = match self.filesystem.inner.read() { Ok(fs) => fs, @@ -156,18 +135,6 @@ impl VirtualFile for FileHandle { let file = node.file.lock().unwrap(); file.size() } - Some(Node::ArcFile(node)) => match self.arc_file.as_ref() { - Some(file) => file.as_ref().map(|file| file.size()).unwrap_or(0), - None => node - .fs - .new_open_options() - .read(self.readable) - .write(self.writable) - .append(self.append_mode) - .open(node.path.as_path()) - .map(|file| file.size()) - .unwrap_or(0), - }, _ => 0, } } @@ -188,11 +155,6 @@ impl VirtualFile for FileHandle { node.metadata.len = new_size; } Some(Node::ReadOnlyFile { .. }) => return Err(FsError::PermissionDenied), - Some(Node::ArcFile { .. }) => { - drop(fs); - let file = self.lazy_load_arc_file_mut()?; - file.set_len(new_size)?; - } _ => return Err(FsError::NotAFile), } @@ -262,21 +224,6 @@ impl VirtualFile for FileHandle { let file = node.file.lock().unwrap(); file.get_special_fd() } - Some(Node::ArcFile(node)) => match self.arc_file.as_ref() { - Some(file) => file - .as_ref() - .map(|file| file.get_special_fd()) - .unwrap_or(None), - None => node - .fs - .new_open_options() - .read(self.readable) - .write(self.writable) - .append(self.append_mode) - .open(node.path.as_path()) - .map(|file| file.get_special_fd()) - .unwrap_or(None), - }, _ => None, } } @@ -292,10 +239,7 @@ impl VirtualFile for FileHandle { match inode { Some(inode) => { let metadata = Metadata { - ft: crate::FileType { - file: true, - ..Default::default() - }, + ft: crate::FileType::new_file(), accessed: src.last_accessed(), created: src.created_time(), modified: src.last_modified(), @@ -304,6 +248,7 @@ impl VirtualFile for FileHandle { *inode = Node::CustomFile(CustomFileNode { inode: inode.inode(), + parent_inode: inode.parent_inode(), name: inode.name().to_string_lossy().to_string().into(), file: Mutex::new(Box::new(CopyOnWriteFile::new(src))), metadata, @@ -315,7 +260,7 @@ impl VirtualFile for FileHandle { }) } - fn poll_read_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_read_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { if !self.readable { return Poll::Ready(Err(io::Error::new( io::ErrorKind::PermissionDenied, @@ -346,19 +291,6 @@ impl VirtualFile for FileHandle { let file = Pin::new(file.as_mut()); file.poll_read_ready(cx) } - Some(Node::ArcFile(_)) => { - drop(fs); - match self.lazy_load_arc_file_mut() { - Ok(file) => { - let file = Pin::new(file); - file.poll_read_ready(cx) - } - Err(_) => Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotFound, - format!("inode `{}` doesn't match a file", self.inode), - ))), - } - } _ => Poll::Ready(Err(io::Error::new( io::ErrorKind::NotFound, format!("inode `{}` doesn't match a file", self.inode), @@ -366,7 +298,7 @@ impl VirtualFile for FileHandle { } } - fn poll_write_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_write_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { if !self.readable { return Poll::Ready(Err(io::Error::new( io::ErrorKind::PermissionDenied, @@ -391,19 +323,6 @@ impl VirtualFile for FileHandle { let file = Pin::new(file.as_mut()); file.poll_read_ready(cx) } - Some(Node::ArcFile(_)) => { - drop(fs); - match self.lazy_load_arc_file_mut() { - Ok(file) => { - let file = Pin::new(file); - file.poll_read_ready(cx) - } - Err(_) => Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotFound, - format!("inode `{}` doesn't match a file", self.inode), - ))), - } - } _ => Poll::Ready(Err(io::Error::new( io::ErrorKind::NotFound, format!("inode `{}` doesn't match a file", self.inode), @@ -640,21 +559,6 @@ impl AsyncRead for FileHandle { let file = Pin::new(file.as_mut()); file.poll_read(cx, buf) } - Some(Node::ArcFile(_)) => { - drop(fs); - match self.lazy_load_arc_file_mut() { - Ok(file) => { - let file = Pin::new(file); - file.poll_read(cx, buf) - } - Err(_) => { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotFound, - format!("inode `{}` doesn't match a file", self.inode), - ))) - } - } - } _ => { return Poll::Ready(Err(io::Error::new( io::ErrorKind::NotFound, @@ -695,21 +599,6 @@ impl AsyncSeek for FileHandle { let file = Pin::new(file.as_mut()); file.start_seek(position) } - Some(Node::ArcFile(_)) => { - drop(fs); - match self.lazy_load_arc_file_mut() { - Ok(file) => { - let file = Pin::new(file); - file.start_seek(position) - } - Err(_) => { - return Err(io::Error::new( - io::ErrorKind::NotFound, - format!("inode `{}` doesn't match a file", self.inode), - )); - } - } - } _ => { return Err(io::Error::new( io::ErrorKind::NotFound, @@ -722,7 +611,7 @@ impl AsyncSeek for FileHandle { ret } - fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_complete(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { // In `append` mode, it's not possible to seek in the file. In // [`open(2)`](https://man7.org/linux/man-pages/man2/open.2.html), // the `O_APPEND` option describes this behavior well: @@ -755,19 +644,6 @@ impl AsyncSeek for FileHandle { let file = Pin::new(file.as_mut()); file.poll_complete(cx) } - Some(Node::ArcFile { .. }) => { - drop(fs); - match self.lazy_load_arc_file_mut() { - Ok(file) => { - let file = Pin::new(file); - file.poll_complete(cx) - } - Err(_) => Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotFound, - format!("inode `{}` doesn't match a file", self.inode), - ))), - } - } _ => Poll::Ready(Err(io::Error::new( io::ErrorKind::NotFound, format!("inode `{}` doesn't match a file", self.inode), @@ -831,21 +707,6 @@ impl AsyncWrite for FileHandle { node.metadata.len = guard.size(); bytes_written } - Some(Node::ArcFile(_)) => { - drop(fs); - match self.lazy_load_arc_file_mut() { - Ok(file) => { - let file = Pin::new(file); - return file.poll_write(cx, buf); - } - Err(_) => { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotFound, - format!("inode `{}` doesn't match a file", self.inode), - ))) - } - } - } _ => { return Poll::Ready(Err(io::Error::new( io::ErrorKind::NotFound, @@ -894,19 +755,6 @@ impl AsyncWrite for FileHandle { let file = Pin::new(file.as_mut()); file.poll_write_vectored(cx, bufs) } - Some(Node::ArcFile(_)) => { - drop(fs); - match self.lazy_load_arc_file_mut() { - Ok(file) => { - let file = Pin::new(file); - file.poll_write_vectored(cx, bufs) - } - Err(_) => Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotFound, - format!("inode `{}` doesn't match a file", self.inode), - ))), - } - } _ => Poll::Ready(Err(io::Error::new( io::ErrorKind::NotFound, format!("inode `{}` doesn't match a file", self.inode), @@ -917,7 +765,7 @@ impl AsyncWrite for FileHandle { ret } - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let mut fs = self.filesystem.inner.write().map_err(|_| { io::Error::new(io::ErrorKind::Other, "failed to acquire a write lock") @@ -932,19 +780,6 @@ impl AsyncWrite for FileHandle { let file = Pin::new(file.as_mut()); file.poll_flush(cx) } - Some(Node::ArcFile { .. }) => { - drop(fs); - match self.lazy_load_arc_file_mut() { - Ok(file) => { - let file = Pin::new(file); - file.poll_flush(cx) - } - Err(_) => Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotFound, - format!("inode `{}` doesn't match a file", self.inode), - ))), - } - } _ => Poll::Ready(Err(io::Error::new( io::ErrorKind::NotFound, format!("inode `{}` doesn't match a file", self.inode), @@ -952,7 +787,7 @@ impl AsyncWrite for FileHandle { } } - fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let mut fs = self.filesystem.inner.write().map_err(|_| { io::Error::new(io::ErrorKind::Other, "failed to acquire a write lock") @@ -967,19 +802,6 @@ impl AsyncWrite for FileHandle { let file = Pin::new(file.as_mut()); file.poll_shutdown(cx) } - Some(Node::ArcFile { .. }) => { - drop(fs); - match self.lazy_load_arc_file_mut() { - Ok(file) => { - let file = Pin::new(file); - file.poll_shutdown(cx) - } - Err(_) => Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotFound, - format!("inode `{}` doesn't match a file", self.inode), - ))), - } - } _ => Poll::Ready(Err(io::Error::new( io::ErrorKind::NotFound, format!("inode `{}` doesn't match a file", self.inode), @@ -1001,13 +823,6 @@ impl AsyncWrite for FileHandle { let file = node.file.lock().unwrap(); file.is_write_vectored() } - Some(Node::ArcFile { .. }) => { - drop(fs); - match self.arc_file.as_ref() { - Some(Ok(file)) => file.is_write_vectored(), - _ => false, - } - } _ => false, } } diff --git a/lib/virtual-fs/src/mem_fs/file_opener.rs b/lib/virtual-fs/src/mem_fs/file_opener.rs index 6a070d24486..3774a8adf9a 100644 --- a/lib/virtual-fs/src/mem_fs/file_opener.rs +++ b/lib/virtual-fs/src/mem_fs/file_opener.rs @@ -35,16 +35,14 @@ impl FileSystem { let inode_of_file = fs.storage.vacant_entry().key(); let real_inode_of_file = fs.storage.insert(Node::ReadOnlyFile(ReadOnlyFileNode { inode: inode_of_file, + parent_inode: inode_of_parent, name: name_of_file, file, metadata: { let time = time(); Metadata { - ft: FileType { - file: true, - ..Default::default() - }, + ft: FileType::new_file(), accessed: time, created: time, modified: time, @@ -67,86 +65,6 @@ impl FileSystem { Ok(()) } - /// Inserts a arc file into the file system that references another file - /// in another file system (does not copy the real data) - pub fn insert_arc_file_at( - &self, - target_path: PathBuf, - fs: Arc, - source_path: PathBuf, - ) -> Result<()> { - let _ = crate::FileSystem::remove_file(self, target_path.as_path()); - let (inode_of_parent, maybe_inode_of_file, name_of_file) = - self.insert_inode(target_path.as_path())?; - - let inode_of_parent = match inode_of_parent { - InodeResolution::Found(a) => a, - InodeResolution::Redirect(..) => { - return Err(FsError::InvalidInput); - } - }; - - match maybe_inode_of_file { - // The file already exists, then it can not be inserted. - Some(_inode_of_file) => return Err(FsError::AlreadyExists), - - // The file doesn't already exist; it's OK to create it if - None => { - // Write lock. - let mut fs_lock = self.inner.write().map_err(|_| FsError::Lock)?; - - // Read the metadata or generate a dummy one - let meta = match fs.metadata(&target_path) { - Ok(meta) => meta, - _ => { - let time = time(); - Metadata { - ft: FileType { - file: true, - ..Default::default() - }, - accessed: time, - created: time, - modified: time, - len: 0, - } - } - }; - - // Creating the file in the storage. - let inode_of_file = fs_lock.storage.vacant_entry().key(); - let real_inode_of_file = fs_lock.storage.insert(Node::ArcFile(ArcFileNode { - inode: inode_of_file, - name: name_of_file, - fs, - path: source_path, - metadata: meta, - })); - - assert_eq!( - inode_of_file, real_inode_of_file, - "new file inode should have been correctly calculated", - ); - - // Adding the new directory to its parent. - fs_lock.add_child_to_node(inode_of_parent, inode_of_file)?; - - inode_of_file - } - }; - Ok(()) - } - - /// Inserts a arc file into the file system that references another file - /// in another file system (does not copy the real data) - pub fn insert_arc_file( - &self, - target_path: PathBuf, - fs: Arc, - ) -> Result<()> { - self.insert_arc_file_at(target_path.clone(), fs, target_path) - } - /// Inserts a arc directory into the file system that references another file /// in another file system (does not copy the real data) pub fn insert_arc_directory_at( @@ -179,6 +97,7 @@ impl FileSystem { let inode_of_file = fs_lock.storage.vacant_entry().key(); let real_inode_of_file = fs_lock.storage.insert(Node::ArcDirectory(ArcDirectoryNode { + parent_inode: inode_of_parent, inode: inode_of_file, name: name_of_file, fs: other, @@ -186,10 +105,7 @@ impl FileSystem { metadata: { let time = time(); Metadata { - ft: FileType { - file: true, - ..Default::default() - }, + ft: FileType::new_file(), accessed: time, created: time, modified: time, @@ -252,15 +168,13 @@ impl FileSystem { let inode_of_file = fs_lock.storage.vacant_entry().key(); let real_inode_of_file = fs_lock.storage.insert(Node::CustomFile(CustomFileNode { inode: inode_of_file, + parent_inode: inode_of_parent, name: name_of_file, file: Mutex::new(file), metadata: { let time = time(); Metadata { - ft: FileType { - file: true, - ..Default::default() - }, + ft: FileType::new_file(), accessed: time, created: time, modified: time, @@ -429,33 +343,6 @@ impl crate::FileOpener for FileSystem { } } - Some(Node::ArcFile(node)) => { - // Update the accessed time. - node.metadata.accessed = time(); - - let mut file = node - .fs - .new_open_options() - .read(read) - .write(write) - .append(append) - .truncate(truncate) - .create(create) - .create_new(create_new) - .open(node.path.as_path())?; - - // Truncate if needed. - if truncate { - file.set_len(0)?; - node.metadata.len = 0; - } - - // Move the cursor to the end if needed. - if append { - cursor = file.size(); - } - } - None => return Err(FsError::EntryNotFound), _ => return Err(FsError::NotAFile), } @@ -476,16 +363,14 @@ impl crate::FileOpener for FileSystem { let inode_of_file = fs.storage.vacant_entry().key(); let real_inode_of_file = fs.storage.insert(Node::File(FileNode { inode: inode_of_file, + parent_inode: inode_of_parent, name: name_of_file, file, metadata: { let time = time(); Metadata { - ft: FileType { - file: true, - ..Default::default() - }, + ft: FileType::new_file(), accessed: time, created: time, modified: time, diff --git a/lib/virtual-fs/src/mem_fs/filesystem.rs b/lib/virtual-fs/src/mem_fs/filesystem.rs index 1e344b745e9..365ab84889a 100644 --- a/lib/virtual-fs/src/mem_fs/filesystem.rs +++ b/lib/virtual-fs/src/mem_fs/filesystem.rs @@ -1,11 +1,9 @@ //! This module contains the [`FileSystem`] type itself. use super::*; -use crate::{DirEntry, FileSystem as _, FileType, FsError, Metadata, OpenOptions, ReadDir, Result}; +use crate::{DirEntry, FileType, FsError, Metadata, OpenOptions, ReadDir, Result}; use futures::future::BoxFuture; use slab::Slab; -use std::collections::VecDeque; -use std::convert::identity; use std::ffi::OsString; use std::fmt; use std::path::{Component, Path, PathBuf}; @@ -15,7 +13,7 @@ use std::sync::{Arc, RwLock}; /// /// This `FileSystem` type can be cloned, it's a light copy of the /// `FileSystemInner` (which is behind a `Arc` + `RwLock`). -#[derive(Clone, Default)] +#[derive(Default, Clone)] pub struct FileSystem { pub(super) inner: Arc>, } @@ -35,133 +33,6 @@ impl FileSystem { lock.canonicalize_without_inode(path) } - /// Merge all items from a given source path (directory) of a different file - /// system into this file system. - /// - /// Individual files and directories of the given path are mounted. - /// - /// This function is not recursive, only the items in the source_path are - /// mounted. - /// - /// See [`Self::union`] for mounting all inodes recursively. - pub fn mount_directory_entries( - &self, - target_path: &Path, - other: &Arc, - mut source_path: &Path, - ) -> Result<()> { - let fs_lock = self.inner.read().map_err(|_| FsError::Lock)?; - - if cfg!(windows) { - // We need to take some care here because - // canonicalize_without_inode() doesn't accept Windows paths that - // start with a prefix (drive letters, UNC paths, etc.). If we - // somehow get one of those paths, we'll automatically trim it away. - let mut components = source_path.components(); - - if let Some(Component::Prefix(_)) = components.next() { - source_path = components.as_path(); - } - } - - let (_target_path, root_inode) = match fs_lock.canonicalize(target_path) { - Ok((p, InodeResolution::Found(inode))) => (p, inode), - Ok((_p, InodeResolution::Redirect(..))) => { - return Err(FsError::AlreadyExists); - } - Err(_) => { - // Root directory does not exist, so we can just mount. - return self.mount(target_path.to_path_buf(), other, source_path.to_path_buf()); - } - }; - - let _root_node = match fs_lock.storage.get(root_inode).unwrap() { - Node::Directory(dir) => dir, - _ => { - return Err(FsError::AlreadyExists); - } - }; - - let source_path = fs_lock.canonicalize_without_inode(source_path)?; - - std::mem::drop(fs_lock); - - let source = other.read_dir(&source_path)?; - for entry in source.data { - let meta = entry.metadata?; - - let entry_target_path = target_path.join(entry.path.file_name().unwrap()); - - if meta.is_file() { - self.insert_arc_file_at(entry_target_path, other.clone(), entry.path)?; - } else if meta.is_dir() { - self.insert_arc_directory_at(entry_target_path, other.clone(), entry.path)?; - } - } - - Ok(()) - } - - pub fn union(&self, other: &Arc) { - // Iterate all the directories and files in the other filesystem - // and create references back to them in this filesystem - let mut remaining = VecDeque::new(); - remaining.push_back(PathBuf::from("/")); - while let Some(next) = remaining.pop_back() { - if next - .file_name() - .map(|n| n.to_string_lossy().starts_with(".wh.")) - .unwrap_or(false) - { - let rm = next.to_string_lossy(); - let rm = &rm[".wh.".len()..]; - let rm = PathBuf::from(rm); - let _ = crate::FileSystem::remove_dir(self, rm.as_path()); - let _ = crate::FileSystem::remove_file(self, rm.as_path()); - continue; - } - let _ = crate::FileSystem::create_dir(self, next.as_path()); - - let dir = match other.read_dir(next.as_path()) { - Ok(dir) => dir, - Err(_) => { - // TODO: propagate errors (except NotFound) - continue; - } - }; - - for sub_dir_res in dir { - let sub_dir = match sub_dir_res { - Ok(sub_dir) => sub_dir, - Err(_) => { - // TODO: propagate errors (except NotFound) - continue; - } - }; - - match sub_dir.file_type() { - Ok(t) if t.is_dir() => { - remaining.push_back(sub_dir.path()); - } - Ok(t) if t.is_file() => { - if sub_dir.file_name().to_string_lossy().starts_with(".wh.") { - let rm = next.to_string_lossy(); - let rm = &rm[".wh.".len()..]; - let rm = PathBuf::from(rm); - let _ = crate::FileSystem::remove_dir(self, rm.as_path()); - let _ = crate::FileSystem::remove_file(self, rm.as_path()); - continue; - } - let _ = self - .new_open_options_ext() - .insert_arc_file(sub_dir.path(), other.clone()); - } - _ => {} - } - } - } - } - pub fn mount( &self, target_path: PathBuf, @@ -208,6 +79,7 @@ impl FileSystem { let inode_of_directory = fs.storage.vacant_entry().key(); let real_inode_of_directory = fs.storage.insert(Node::ArcDirectory(ArcDirectoryNode { inode: inode_of_directory, + parent_inode: inode_of_parent, name: name_of_directory, fs: other.clone(), path: source_path, @@ -215,10 +87,7 @@ impl FileSystem { let time = time(); Metadata { - ft: FileType { - dir: true, - ..Default::default() - }, + ft: FileType::new_dir(), accessed: time, created: time, modified: time, @@ -241,44 +110,33 @@ impl FileSystem { } impl crate::FileSystem for FileSystem { + fn set_parent(&mut self, directory: Arc) -> Result<()> { + let mut guard = self.inner.write().map_err(|_| FsError::Lock)?; + guard.parent = Some(directory); + Ok(()) + } + fn parent(&self) -> Option> { + let guard = self.inner.write().ok()?; + guard.parent.clone() + } + + fn as_dir(&self) -> Box { + Box::new(Directory::new(ROOT_INODE, self.clone())) + } + fn read_dir(&self, path: &Path) -> Result { // Read lock. let guard = self.inner.read().map_err(|_| FsError::Lock)?; // Canonicalize the path. - let (path, inode_of_directory) = guard.canonicalize(path)?; + let (_path, inode_of_directory) = guard.canonicalize(path)?; let inode_of_directory = match inode_of_directory { InodeResolution::Found(a) => a, InodeResolution::Redirect(fs, path) => { return fs.read_dir(path.as_path()); } }; - - // Check it's a directory and fetch the immediate children as `DirEntry`. - let inode = guard.storage.get(inode_of_directory); - let children = match inode { - Some(Node::Directory(DirectoryNode { children, .. })) => children - .iter() - .filter_map(|inode| guard.storage.get(*inode)) - .map(|node| DirEntry { - path: { - let mut entry_path = path.to_path_buf(); - entry_path.push(node.name()); - - entry_path - }, - metadata: Ok(node.metadata().clone()), - }) - .collect(), - - Some(Node::ArcDirectory(ArcDirectoryNode { fs, path, .. })) => { - return fs.read_dir(path.as_path()); - } - - _ => return Err(FsError::InvalidInput), - }; - - Ok(ReadDir::new(children)) + guard.read_dir_inode(inode_of_directory) } fn create_dir(&self, path: &Path) -> Result<()> { @@ -315,107 +173,40 @@ impl crate::FileSystem for FileSystem { (inode_of_parent, name_of_directory) }; - - if self.read_dir(path).is_ok() { - return Err(FsError::AlreadyExists); - } - - { - // Write lock. - let mut fs = self.inner.write().map_err(|_| FsError::Lock)?; - - // Creating the directory in the storage. - let inode_of_directory = fs.storage.vacant_entry().key(); - let real_inode_of_directory = fs.storage.insert(Node::Directory(DirectoryNode { - inode: inode_of_directory, - name: name_of_directory, - children: Vec::new(), - metadata: { - let time = time(); - - Metadata { - ft: FileType { - dir: true, - ..Default::default() - }, - accessed: time, - created: time, - modified: time, - len: 0, - } - }, - })); - - assert_eq!( - inode_of_directory, real_inode_of_directory, - "new directory inode should have been correctly calculated", - ); - - // Adding the new directory to its parent. - fs.add_child_to_node(inode_of_parent, inode_of_directory)?; - } - - Ok(()) + let mut guard = self.inner.write().map_err(|_| FsError::Lock)?; + guard.create_dir_inode(inode_of_parent, name_of_directory) } fn remove_dir(&self, path: &Path) -> Result<()> { - let (inode_of_parent, position, inode_of_directory) = { - // Read lock. - let guard = self.inner.read().map_err(|_| FsError::Lock)?; + let mut guard = self.inner.write().map_err(|_| FsError::Lock)?; - // Canonicalize the path. - let (path, _) = guard.canonicalize(path)?; - - // Check the path has a parent. - let parent_of_path = path.parent().ok_or(FsError::BaseNotDirectory)?; - - // Check the directory name. - let name_of_directory = path - .file_name() - .ok_or(FsError::InvalidInput)? - .to_os_string(); - - // Find the parent inode. - let inode_of_parent = match guard.inode_of_parent(parent_of_path)? { - InodeResolution::Found(a) => a, - InodeResolution::Redirect(fs, mut parent_path) => { - drop(guard); - parent_path.push(name_of_directory); - return fs.remove_dir(parent_path.as_path()); - } - }; - - // Get the child index to remove in the parent node, in - // addition to the inode of the directory to remove. - let (position, inode_of_directory) = guard - .as_parent_get_position_and_inode_of_directory( - inode_of_parent, - &name_of_directory, - DirectoryMustBeEmpty::Yes, - )?; - - (inode_of_parent, position, inode_of_directory) - }; + // Canonicalize the path. + let (_path, node) = guard.canonicalize(path)?; - let inode_of_directory = match inode_of_directory { + let inode_of_directory = match node { InodeResolution::Found(a) => a, InodeResolution::Redirect(fs, path) => { return fs.remove_dir(path.as_path()); } }; - { - // Write lock. - let mut fs = self.inner.write().map_err(|_| FsError::Lock)?; + guard.remove_dir_inode(inode_of_directory) + } + + fn remove_file(&self, path: &Path) -> Result<()> { + let mut guard = self.inner.write().map_err(|_| FsError::Lock)?; - // Remove the directory from the storage. - fs.storage.remove(inode_of_directory); + // Canonicalize the path. + let (_path, node) = guard.canonicalize(path)?; - // Remove the child from the parent directory. - fs.remove_child_from_node(inode_of_parent, position)?; - } + let inode_of_file = match node { + InodeResolution::Found(a) => a, + InodeResolution::Redirect(fs, path) => { + return fs.remove_file(path.as_path()); + } + }; - Ok(()) + guard.remove_file_inode(inode_of_file) } fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> { @@ -512,6 +303,12 @@ impl crate::FileSystem for FileSystem { // Add the file to its new parent, and update the modified // time. fs.add_child_to_node(inode_of_to_parent, inode)?; + + // Replace the inode parent + let mut inode = fs.storage.get_mut(inode); + if let Some(inode_mut) = inode.as_mut() { + inode_mut.set_parent_inode(inode_of_to_parent); + }; } // Otherwise, we need to at least update the modified time of the parent. else { @@ -545,63 +342,6 @@ impl crate::FileSystem for FileSystem { } } - fn remove_file(&self, path: &Path) -> Result<()> { - let (inode_of_parent, position, inode_of_file) = { - // Read lock. - let guard = self.inner.read().map_err(|_| FsError::Lock)?; - - // Canonicalize the path. - let path = guard.canonicalize_without_inode(path)?; - - // Check the path has a parent. - let parent_of_path = path.parent().ok_or(FsError::BaseNotDirectory)?; - - // Check the file name. - let name_of_file = path - .file_name() - .ok_or(FsError::InvalidInput)? - .to_os_string(); - - // Find the parent inode. - let inode_of_parent = match guard.inode_of_parent(parent_of_path)? { - InodeResolution::Found(a) => a, - InodeResolution::Redirect(fs, mut parent_path) => { - parent_path.push(name_of_file); - return fs.remove_file(parent_path.as_path()); - } - }; - - // Find the inode of the file if it exists, along with its position. - let maybe_position_and_inode_of_file = - guard.as_parent_get_position_and_inode_of_file(inode_of_parent, &name_of_file)?; - - match maybe_position_and_inode_of_file { - Some((position, inode_of_file)) => (inode_of_parent, position, inode_of_file), - None => return Err(FsError::EntryNotFound), - } - }; - - let inode_of_file = match inode_of_file { - InodeResolution::Found(a) => a, - InodeResolution::Redirect(fs, path) => { - return fs.remove_file(path.as_path()); - } - }; - - { - // Write lock. - let mut fs = self.inner.write().map_err(|_| FsError::Lock)?; - - // Remove the file from the storage. - fs.storage.remove(inode_of_file); - - // Remove the child from the parent directory. - fs.remove_child_from_node(inode_of_parent, position)?; - } - - Ok(()) - } - fn new_open_options(&self) -> OpenOptions { OpenOptions::new(self) } @@ -619,6 +359,7 @@ impl fmt::Debug for FileSystem { /// indexed by their respective `Inode` in a slab. pub(super) struct FileSystemInner { pub(super) storage: Slab, + pub(super) parent: Option>, pub(super) limiter: Option, } @@ -641,6 +382,143 @@ impl InodeResolution { } impl FileSystemInner { + pub(super) fn get_node(&self, inode: Inode) -> Option<&Node> { + self.storage.get(inode) + } + + pub(super) fn get_node_directory(&self, inode: Inode) -> Result<&DirectoryNode> { + let node = self.storage.get(inode); + match node { + Some(Node::Directory(dir_node)) => Ok(dir_node), + _ => Err(FsError::BaseNotDirectory), + } + } + + pub(super) fn get_node_directory_mut(&mut self, inode: Inode) -> Result<&mut DirectoryNode> { + let node = self.storage.get_mut(inode); + match node { + Some(Node::Directory(dir_node)) => Ok(dir_node), + _ => Err(FsError::BaseNotDirectory), + } + } + + #[inline] + pub(super) fn absolute_path(&self, node: &Node) -> PathBuf { + let parent = self.get_node(node.parent_inode()).unwrap(); + if parent.inode() == ROOT_INODE { + if let Some(parent) = &self.parent { + return parent.absolute_path().join(node.name()); + } + return PathBuf::from("/").join(node.name()); + } + self.absolute_path(parent).join(node.name()) + } + + fn read_dir_inode(&self, inode_of_directory: Inode) -> Result { + // Check it's a directory and fetch the immediate children as `DirEntry`. + let inode = self + .storage + .get(inode_of_directory) + .ok_or(FsError::InvalidInput)?; + let base_path = self.absolute_path(inode); + let children = match inode { + Node::Directory(DirectoryNode { children, .. }) => children + .iter() + .filter_map(|inode| self.storage.get(*inode)) + .map(|node| DirEntry { + path: { base_path.join(node.name()) }, + metadata: Ok(node.metadata().clone()), + }) + .collect(), + + Node::ArcDirectory(ArcDirectoryNode { fs, path, .. }) => { + return fs.read_dir(path.as_path()); + } + + _ => return Err(FsError::InvalidInput), + }; + + Ok(ReadDir::new(children)) + } + + fn create_dir_inode(&mut self, inode: Inode, dir_name: OsString) -> Result<()> { + let node = self.get_node_directory(inode)?; + if node.children.iter().any(|child_inode| { + if let Some(node) = self.storage.get(*child_inode) { + return node.name() == dir_name; + } + false + }) { + return Err(FsError::AlreadyExists); + } + + // Creating the directory in the storage. + let inode_of_directory = self.storage.vacant_entry().key(); + let real_inode_of_directory = self.storage.insert(Node::Directory(DirectoryNode { + inode: inode_of_directory, + parent_inode: inode, + name: dir_name, + children: Vec::new(), + metadata: { + let time = time(); + + Metadata { + ft: FileType::new_dir(), + accessed: time, + created: time, + modified: time, + len: 0, + } + }, + })); + + assert_eq!( + inode_of_directory, real_inode_of_directory, + "new directory inode should have been correctly calculated", + ); + + // Adding the new directory to its parent. + self.add_child_to_node(inode, inode_of_directory)?; + + Ok(()) + } + + fn remove_dir_inode(&mut self, inode: Inode) -> Result<()> { + if inode == ROOT_INODE { + // We can't remove the root + return Err(FsError::BaseNotDirectory); + } + let node = self.get_node_directory(inode)?; + if !node.children.is_empty() { + return Err(FsError::DirectoryNotEmpty); + } + self.remove_inode_inside_dir(node.parent_inode, inode) + } + + fn remove_inode_inside_dir(&mut self, inode: Inode, child: Inode) -> Result<()> { + let mut parent_node = self.get_node_directory_mut(inode)?; + let position = parent_node + .children + .iter() + .position(|&r| r == child) + .ok_or(FsError::EntryNotFound)?; + + parent_node.metadata.modified = time(); + + // Remove the child from the parent directory. + self.remove_child_from_node(inode, position)?; + + // Remove the directory from the storage. + self.storage.remove(child); + + Ok(()) + } + + fn remove_file_inode(&mut self, inode: Inode) -> Result<()> { + let node = self.get_node(inode).ok_or(FsError::EntryNotFound)?; + self.remove_inode_inside_dir(node.parent_inode(), inode) + } + /// Get the inode associated to a path if it exists. pub(super) fn inode_of(&self, path: &Path) -> Result { // SAFETY: The root node always exists, so it's safe to unwrap here. @@ -659,14 +537,14 @@ impl FileSystemInner { .filter_map(|inode| self.storage.get(*inode)) .find(|node| node.name() == component.as_os_str()) .ok_or(FsError::EntryNotFound)?, - Node::ArcDirectory(ArcDirectoryNode { - fs, path: fs_path, .. - }) => { - let mut path = fs_path.clone(); + Node::ArcDirectory(ArcDirectoryNode { fs, .. }) => { + let mut path = PathBuf::new(); path.push(PathBuf::from(component.as_os_str())); for component in components.by_ref() { path.push(PathBuf::from(component.as_os_str())); } + // let mut path: PathBuf = components.collect(); + // path.push(component.as_os_str()); return Ok(InodeResolution::Redirect(fs.clone(), path)); } _ => return Err(FsError::BaseNotDirectory), @@ -683,60 +561,16 @@ impl FileSystemInner { InodeResolution::Found(inode_of_parent) => { // Ensure it is a directory. match self.storage.get(inode_of_parent) { - Some(Node::Directory(DirectoryNode { .. })) => { + Some(Node::Directory(DirectoryNode { .. })) | Some(Node::ArcDirectory(_)) => { Ok(InodeResolution::Found(inode_of_parent)) } - Some(Node::ArcDirectory(ArcDirectoryNode { fs, path, .. })) => { - Ok(InodeResolution::Redirect(fs.clone(), path.clone())) - } _ => Err(FsError::BaseNotDirectory), } } - InodeResolution::Redirect(fs, path) => Ok(InodeResolution::Redirect(fs, path)), - } - } - - /// From the inode of a parent node (so, a directory), returns the - /// child index of `name_of_directory` along with its inode. - pub(super) fn as_parent_get_position_and_inode_of_directory( - &self, - inode_of_parent: Inode, - name_of_directory: &OsString, - directory_must_be_empty: DirectoryMustBeEmpty, - ) -> Result<(usize, InodeResolution)> { - match self.storage.get(inode_of_parent) { - Some(Node::Directory(DirectoryNode { children, .. })) => children - .iter() - .enumerate() - .filter_map(|(nth, inode)| self.storage.get(*inode).map(|node| (nth, node))) - .find_map(|(nth, node)| match node { - Node::Directory(DirectoryNode { - inode, - name, - children, - .. - }) if name.as_os_str() == name_of_directory => { - if directory_must_be_empty.no() || children.is_empty() { - Some(Ok((nth, InodeResolution::Found(*inode)))) - } else { - Some(Err(FsError::DirectoryNotEmpty)) - } - } - - _ => None, - }) - .ok_or(FsError::InvalidInput) - .and_then(identity), // flatten - - Some(Node::ArcDirectory(ArcDirectoryNode { - fs, path: fs_path, .. - })) => { - let mut path = fs_path.clone(); - path.push(name_of_directory); - Ok((0, InodeResolution::Redirect(fs.clone(), path))) + InodeResolution::Redirect(fs, path) => { + println!("Inode of parent found -> Redirect: {}", path.display()); + Ok(InodeResolution::Redirect(fs, path)) } - - _ => Err(FsError::BaseNotDirectory), } } @@ -756,7 +590,6 @@ impl FileSystemInner { Node::File(FileNode { inode, name, .. }) | Node::ReadOnlyFile(ReadOnlyFileNode { inode, name, .. }) | Node::CustomFile(CustomFileNode { inode, name, .. }) - | Node::ArcFile(ArcFileNode { inode, name, .. }) if name.as_os_str() == name_of_file => { Some(Some((nth, InodeResolution::Found(*inode)))) @@ -796,7 +629,6 @@ impl FileSystemInner { | Node::Directory(DirectoryNode { inode, name, .. }) | Node::ReadOnlyFile(ReadOnlyFileNode { inode, name, .. }) | Node::CustomFile(CustomFileNode { inode, name, .. }) - | Node::ArcFile(ArcFileNode { inode, name, .. }) if name.as_os_str() == name_of => { Some(Some((nth, InodeResolution::Found(*inode)))) @@ -957,7 +789,6 @@ impl fmt::Debug for FileSystemInner { ty = match node { Node::File { .. } => "file", Node::ReadOnlyFile { .. } => "ro-file", - Node::ArcFile { .. } => "arc-file", Node::CustomFile { .. } => "custom-file", Node::Directory { .. } => "dir", Node::ArcDirectory { .. } => "arc-dir", @@ -999,13 +830,12 @@ impl Default for FileSystemInner { let mut slab = Slab::new(); slab.insert(Node::Directory(DirectoryNode { inode: ROOT_INODE, + // TODO: Fix this + parent_inode: ROOT_INODE, name: OsString::from("/"), children: Vec::new(), metadata: Metadata { - ft: FileType { - dir: true, - ..Default::default() - }, + ft: FileType::new_dir(), accessed: time, created: time, modified: time, @@ -1015,27 +845,12 @@ impl Default for FileSystemInner { Self { storage: slab, + parent: None, limiter: None, } } } -#[allow(dead_code)] // The `No` variant. -pub(super) enum DirectoryMustBeEmpty { - Yes, - No, -} - -impl DirectoryMustBeEmpty { - pub(super) fn yes(&self) -> bool { - matches!(self, Self::Yes) - } - - pub(super) fn no(&self) -> bool { - !self.yes() - } -} - #[cfg(test)] mod test_filesystem { use std::{borrow::Cow, path::Path}; @@ -1074,6 +889,18 @@ mod test_filesystem { ); } + // #[tokio::test] + // async fn test_create_dir_dot() { + // let fs = FileSystem::default(); + // fs.create_dir(".").unwrap(); + + // assert_eq!( + // fs.create_dir(path!(".")), + // Err(FsError::AlreadyExists), + // "creating the root which already exists", + // ); + // } + #[tokio::test] async fn test_create_dir() { let fs = FileSystem::default(); @@ -1307,6 +1134,7 @@ mod test_filesystem { matches!( fs_inner.storage.get(2), Some(Node::Directory(DirectoryNode { + parent_inode: 1, inode: 2, name, children, @@ -1320,6 +1148,7 @@ mod test_filesystem { fs_inner.storage.get(3), Some(Node::Directory(DirectoryNode { inode: 3, + parent_inode: ROOT_INODE, name, children, .. @@ -1332,6 +1161,7 @@ mod test_filesystem { fs_inner.storage.get(4), Some(Node::File(FileNode { inode: 4, + parent_inode: 3, name, .. })) if name == "hello1.txt" @@ -1343,6 +1173,7 @@ mod test_filesystem { fs_inner.storage.get(5), Some(Node::File(FileNode { inode: 5, + parent_inode: 3, name, .. })) if name == "hello2.txt" @@ -1395,8 +1226,9 @@ mod test_filesystem { ); assert!( matches!( - fs_inner.storage.get(1), + dbg!(fs_inner.storage.get(1)), Some(Node::Directory(DirectoryNode { + parent_inode: 3, inode: 1, name, children, @@ -1409,6 +1241,7 @@ mod test_filesystem { matches!( fs_inner.storage.get(2), Some(Node::Directory(DirectoryNode { + parent_inode: 1, inode: 2, name, children, @@ -1421,6 +1254,7 @@ mod test_filesystem { matches!( fs_inner.storage.get(3), Some(Node::Directory(DirectoryNode { + parent_inode: ROOT_INODE, inode: 3, name, children, @@ -1442,9 +1276,10 @@ mod test_filesystem { ); assert!( matches!( - fs_inner.storage.get(5), + dbg!(fs_inner.storage.get(5)), Some(Node::File(FileNode { inode: 5, + parent_inode: 1, name, .. })) if name == "world2.txt" @@ -1835,11 +1670,9 @@ mod test_filesystem { let other: Arc = Arc::new(other); - main.mount_directory_entries(&Path::new("/"), &other, &Path::new("/a")) - .unwrap(); - let mut buf = Vec::new(); + main.mount("/x".into(), &other, "/a/x".into()).unwrap(); let mut f = main .new_open_options() .read(true) diff --git a/lib/virtual-fs/src/mem_fs/mod.rs b/lib/virtual-fs/src/mem_fs/mod.rs index 8d16dd784eb..0bccd18e5fa 100644 --- a/lib/virtual-fs/src/mem_fs/mod.rs +++ b/lib/virtual-fs/src/mem_fs/mod.rs @@ -1,11 +1,13 @@ +mod dir; mod file; mod file_opener; mod filesystem; mod stdio; -use file::{File, FileHandle, ReadOnlyFile}; -pub use filesystem::FileSystem; -pub use stdio::{Stderr, Stdin, Stdout}; +use self::dir::Directory; +use self::file::{File, FileHandle, ReadOnlyFile}; +pub use self::filesystem::FileSystem; +pub use self::stdio::{Stderr, Stdin, Stdout}; use crate::Metadata; use std::{ @@ -20,6 +22,7 @@ const ROOT_INODE: Inode = 0; #[derive(Debug)] struct FileNode { inode: Inode, + parent_inode: Inode, name: OsString, file: File, metadata: Metadata, @@ -28,23 +31,16 @@ struct FileNode { #[derive(Debug)] struct ReadOnlyFileNode { inode: Inode, + parent_inode: Inode, name: OsString, file: ReadOnlyFile, metadata: Metadata, } -#[derive(Debug)] -struct ArcFileNode { - inode: Inode, - name: OsString, - fs: Arc, - path: PathBuf, - metadata: Metadata, -} - #[derive(Debug)] struct CustomFileNode { inode: Inode, + parent_inode: Inode, name: OsString, file: Mutex>, metadata: Metadata, @@ -53,6 +49,7 @@ struct CustomFileNode { #[derive(Debug)] struct DirectoryNode { inode: Inode, + parent_inode: Inode, name: OsString, children: Vec, metadata: Metadata, @@ -61,6 +58,7 @@ struct DirectoryNode { #[derive(Debug)] struct ArcDirectoryNode { inode: Inode, + parent_inode: Inode, name: OsString, fs: Arc, path: PathBuf, @@ -71,7 +69,6 @@ struct ArcDirectoryNode { enum Node { File(FileNode), ReadOnlyFile(ReadOnlyFileNode), - ArcFile(ArcFileNode), CustomFile(CustomFileNode), Directory(DirectoryNode), ArcDirectory(ArcDirectoryNode), @@ -82,18 +79,45 @@ impl Node { *match self { Self::File(FileNode { inode, .. }) => inode, Self::ReadOnlyFile(ReadOnlyFileNode { inode, .. }) => inode, - Self::ArcFile(ArcFileNode { inode, .. }) => inode, Self::CustomFile(CustomFileNode { inode, .. }) => inode, Self::Directory(DirectoryNode { inode, .. }) => inode, Self::ArcDirectory(ArcDirectoryNode { inode, .. }) => inode, } } + fn parent_inode(&self) -> Inode { + *match self { + Self::File(FileNode { parent_inode, .. }) => parent_inode, + Self::ReadOnlyFile(ReadOnlyFileNode { parent_inode, .. }) => parent_inode, + Self::CustomFile(CustomFileNode { parent_inode, .. }) => parent_inode, + Self::Directory(DirectoryNode { parent_inode, .. }) => parent_inode, + Self::ArcDirectory(ArcDirectoryNode { parent_inode, .. }) => parent_inode, + } + } + fn set_parent_inode(&mut self, parent_inode: Inode) { + match self { + Self::File(f) => { + f.parent_inode = parent_inode; + } + Self::ReadOnlyFile(f) => { + f.parent_inode = parent_inode; + } + Self::CustomFile(f) => { + f.parent_inode = parent_inode; + } + Self::Directory(d) => { + d.parent_inode = parent_inode; + } + Self::ArcDirectory(d) => { + d.parent_inode = parent_inode; + } + } + } + fn name(&self) -> &OsStr { match self { Self::File(FileNode { name, .. }) => name.as_os_str(), Self::ReadOnlyFile(ReadOnlyFileNode { name, .. }) => name.as_os_str(), - Self::ArcFile(ArcFileNode { name, .. }) => name.as_os_str(), Self::CustomFile(CustomFileNode { name, .. }) => name.as_os_str(), Self::Directory(DirectoryNode { name, .. }) => name.as_os_str(), Self::ArcDirectory(ArcDirectoryNode { name, .. }) => name.as_os_str(), @@ -104,7 +128,6 @@ impl Node { match self { Self::File(FileNode { metadata, .. }) => metadata, Self::ReadOnlyFile(ReadOnlyFileNode { metadata, .. }) => metadata, - Self::ArcFile(ArcFileNode { metadata, .. }) => metadata, Self::CustomFile(CustomFileNode { metadata, .. }) => metadata, Self::Directory(DirectoryNode { metadata, .. }) => metadata, Self::ArcDirectory(ArcDirectoryNode { metadata, .. }) => metadata, @@ -115,7 +138,6 @@ impl Node { match self { Self::File(FileNode { metadata, .. }) => metadata, Self::ReadOnlyFile(ReadOnlyFileNode { metadata, .. }) => metadata, - Self::ArcFile(ArcFileNode { metadata, .. }) => metadata, Self::CustomFile(CustomFileNode { metadata, .. }) => metadata, Self::Directory(DirectoryNode { metadata, .. }) => metadata, Self::ArcDirectory(ArcDirectoryNode { metadata, .. }) => metadata, @@ -126,7 +148,6 @@ impl Node { match self { Self::File(FileNode { name, .. }) => *name = new_name, Self::ReadOnlyFile(ReadOnlyFileNode { name, .. }) => *name = new_name, - Self::ArcFile(ArcFileNode { name, .. }) => *name = new_name, Self::CustomFile(CustomFileNode { name, .. }) => *name = new_name, Self::Directory(DirectoryNode { name, .. }) => *name = new_name, Self::ArcDirectory(ArcDirectoryNode { name, .. }) => *name = new_name, diff --git a/lib/virtual-fs/src/ops.rs b/lib/virtual-fs/src/ops.rs index 88c9c066808..0ee8e87d0ea 100644 --- a/lib/virtual-fs/src/ops.rs +++ b/lib/virtual-fs/src/ops.rs @@ -3,7 +3,7 @@ use std::{ collections::VecDeque, - path::{Path, PathBuf}, + path::{Component, Path, PathBuf}, }; use futures::future::BoxFuture; @@ -49,10 +49,6 @@ where F: FileSystem + ?Sized, { let path = path.as_ref(); - if let Some(parent) = path.parent() { - create_dir_all(fs, parent)?; - } - if let Ok(metadata) = fs.metadata(path) { if metadata.is_dir() { return Ok(()); @@ -61,7 +57,9 @@ where return Err(FsError::BaseNotDirectory); } } - + if let Some(parent) = path.parent() { + create_dir_all(fs, parent)?; + } fs.create_dir(path) } @@ -329,3 +327,209 @@ mod tests { assert_eq!(super::read(&fs, "/file.txt").await.unwrap(), b""); } } + +/// The Clean trait implements a `clean` method. +pub trait PathClean { + fn clean_safely(&self) -> crate::Result; +} + +/// PathClean implemented for `Path` +impl PathClean for Path { + fn clean_safely(&self) -> crate::Result { + clean_safely(self) + } +} + +/// PathClean implemented for `PathBuf` +impl PathClean for PathBuf { + fn clean_safely(&self) -> crate::Result { + clean_safely(self) + } +} + +/// The core implementation. It performs the following, lexically: +/// 1. Reduce multiple slashes to a single slash. +/// 2. Eliminate `.` path name elements (the current directory). +/// 3. Eliminate `..` path name elements (the parent directory) and the non-`.` non-`..`, element that precedes them. +/// 4. Eliminate `..` elements that begin a rooted path, that is, replace `/..` by `/` at the beginning of a path. +/// 5. Leave intact `..` elements that begin a non-rooted path. +/// +/// If the result of this process is an empty string, return the string `"."`, representing the current directory. +/// +/// Code adapted from: https://github.com/danreeves/path-clean/blob/master/src/lib.rs#L50C1-L87C1 +pub fn clean_safely

(path: P) -> crate::Result +where + P: AsRef, +{ + let mut out = Vec::new(); + + for comp in path.as_ref().components() { + match comp { + Component::CurDir => (), + Component::RootDir => { + if !out.is_empty() { + out.push(Component::RootDir); + } + } + Component::ParentDir => match out.last() { + Some(Component::RootDir) => (), + Some(Component::Normal(_)) => { + out.pop(); + } + None => { + // We tried to go too up the stack + return Err(crate::FsError::InvalidInput); + } + Some(Component::CurDir) + | Some(Component::ParentDir) + | Some(Component::Prefix(_)) => out.push(comp), + }, + comp => out.push(comp), + } + } + + if !out.is_empty() { + if out[0] == Component::RootDir { + return Ok(PathBuf::from(".")); + } + Ok(out.iter().collect()) + } else { + Ok(PathBuf::from(".")) + } +} + +#[cfg(test)] +mod tests_clean { + use super::{clean_safely, PathClean}; + use crate::FsError; + use std::path::{Path, PathBuf}; + + #[test] + fn test_empty_path_is_current_dir() { + assert_eq!(clean_safely(""), Ok(PathBuf::from("."))); + } + + #[test] + fn test_root_is_current_dir() { + assert_eq!(clean_safely("/"), Ok(PathBuf::from("."))); + } + + #[test] + fn test_clean_paths_dont_change() { + let tests = vec![ + (".", Ok(PathBuf::from("."))), + ("..", Err(FsError::InvalidInput)), + ("/", Ok(PathBuf::from("."))), + ]; + + for test in tests { + assert_eq!(clean_safely(test.0), test.1); + } + } + + #[test] + fn test_replace_multiple_slashes() { + let tests = vec![ + ("/", Ok(PathBuf::from("."))), + ("//", Ok(PathBuf::from("."))), + ("///", Ok(PathBuf::from("."))), + (".//", Ok(PathBuf::from("."))), + ("//..", Err(FsError::InvalidInput)), + ("..//", Err(FsError::InvalidInput)), + ("/..//", Err(FsError::InvalidInput)), + ("/.//./", Ok(PathBuf::from("."))), + ("././/./", Ok(PathBuf::from("."))), + ("path//to///thing", Ok(PathBuf::from("path/to/thing"))), + ("/path//to///thing", Ok(PathBuf::from("path/to/thing"))), + ]; + + for test in tests { + assert_eq!(clean_safely(test.0), test.1, "test: {}", test.0); + } + } + + #[test] + fn test_eliminate_current_dir() { + let tests = vec![ + ("./", "."), + ("/./", "."), + ("./test", "test"), + ("./test/./path", "test/path"), + ("/test/./path/", "test/path"), + ("test/path/.", "test/path"), + ]; + + for test in tests { + assert_eq!(clean_safely(test.0), Ok(PathBuf::from(test.1))); + } + } + + #[test] + fn test_eliminate_parent_dir() { + let tests = vec![ + ("/..", Err(FsError::InvalidInput)), + ("/../test", Err(FsError::InvalidInput)), + ("test/..", Ok(PathBuf::from("."))), + ("test/path/..", Ok(PathBuf::from("test"))), + ("test/../path", Ok(PathBuf::from("path"))), + ("/test/../path", Ok(PathBuf::from("path"))), + ("test/path/../../", Ok(PathBuf::from("."))), + ("test/path/../../..", Err(FsError::InvalidInput)), + ("/test/path/../../..", Err(FsError::InvalidInput)), + ("/test/path/../../../..", Err(FsError::InvalidInput)), + ("test/path/../../../..", Err(FsError::InvalidInput)), + ( + "test/path/../../another/path", + Ok(PathBuf::from("another/path")), + ), + ( + "test/path/../../another/path/..", + Ok(PathBuf::from("another")), + ), + ("../test", Err(FsError::InvalidInput)), + ("../test/", Err(FsError::InvalidInput)), + ("../test/path", Err(FsError::InvalidInput)), + ("../test/..", Err(FsError::InvalidInput)), + ]; + + for test in tests { + assert_eq!(clean_safely(test.0), test.1, "test: {}", test.0); + } + } + + #[test] + fn test_pathbuf_trait() { + assert_eq!( + PathBuf::from("/test/../path/").clean_safely(), + Ok(PathBuf::from("path")) + ); + } + + #[test] + fn test_path_trait() { + assert_eq!( + Path::new("/test/../path/").clean_safely(), + Ok(PathBuf::from("path")) + ); + } + + // #[test] + // #[cfg(target_os = "windows")] + // fn test_windows_paths() { + // let tests = vec![ + // ("\\..", "\\"), + // ("\\..\\test", "\\test"), + // ("test\\..", "."), + // ("test\\path\\..\\..\\..", ".."), + // ("test\\path/..\\../another\\path", "another\\path"), // Mixed + // ("test\\path\\my/path", "test\\path\\my\\path"), // Mixed 2 + // ("/dir\\../otherDir/test.json", "/otherDir/test.json"), // User example + // ("c:\\test\\..", "c:\\"), // issue #12 + // ("c:/test/..", "c:/"), // issue #12 + // ]; + + // for test in tests { + // assert_eq!(clean_safely(test.0), PathBuf::from(test.1)); + // } + // } +} diff --git a/lib/virtual-fs/src/passthru_fs.rs b/lib/virtual-fs/src/passthru_fs.rs deleted file mode 100644 index 08a940ed0c5..00000000000 --- a/lib/virtual-fs/src/passthru_fs.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Wraps a boxed file system with an implemented trait VirtualSystem - this is -//! needed so that a `Box` can be wrapped in an Arc and -//! shared - some of the interfaces pass around a `Box` - -use std::path::Path; - -use crate::*; - -#[derive(Debug)] -pub struct PassthruFileSystem { - fs: Box, -} - -impl PassthruFileSystem { - pub fn new(inner: Box) -> Self { - Self { fs: inner } - } -} - -impl FileSystem for PassthruFileSystem { - fn read_dir(&self, path: &Path) -> Result { - self.fs.read_dir(path) - } - - fn create_dir(&self, path: &Path) -> Result<()> { - self.fs.create_dir(path) - } - - fn remove_dir(&self, path: &Path) -> Result<()> { - self.fs.remove_dir(path) - } - - fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> { - Box::pin(async { self.fs.rename(from, to).await }) - } - - fn metadata(&self, path: &Path) -> Result { - self.fs.metadata(path) - } - - fn symlink_metadata(&self, path: &Path) -> Result { - self.fs.symlink_metadata(path) - } - - fn remove_file(&self, path: &Path) -> Result<()> { - self.fs.remove_file(path) - } - - fn new_open_options(&self) -> OpenOptions { - self.fs.new_open_options() - } -} - -#[cfg(test)] -mod test_builder { - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - - use crate::{FileSystem, PassthruFileSystem}; - - #[tokio::test] - async fn test_passthru_fs_2() { - let mem_fs = crate::mem_fs::FileSystem::default(); - - mem_fs - .new_open_options() - .read(true) - .write(true) - .create(true) - .open("/foo.txt") - .unwrap() - .write_all(b"hello") - .await - .unwrap(); - - let mut buf = Vec::new(); - mem_fs - .new_open_options() - .read(true) - .open("/foo.txt") - .unwrap() - .read_to_end(&mut buf) - .await - .unwrap(); - assert_eq!(buf, b"hello"); - - let passthru_fs = PassthruFileSystem::new(Box::new(mem_fs.clone())); - let mut buf = Vec::new(); - passthru_fs - .new_open_options() - .read(true) - .open("/foo.txt") - .unwrap() - .read_to_end(&mut buf) - .await - .unwrap(); - assert_eq!(buf, b"hello"); - } -} diff --git a/lib/virtual-fs/src/union_fs.rs b/lib/virtual-fs/src/union_fs.rs deleted file mode 100644 index 04b6d8eea46..00000000000 --- a/lib/virtual-fs/src/union_fs.rs +++ /dev/null @@ -1,1111 +0,0 @@ -//! Another implementation of the union that uses paths, -//! its not as simple as TmpFs. not currently used but was used by -//! the previoulsy implementation of Deploy - now using TmpFs - -use crate::*; - -use std::{ - path::Path, - sync::{Arc, Mutex, Weak}, -}; - -use tracing::{debug, trace}; - -pub type TempHolding = Arc>>>>; - -#[derive(Debug)] -pub struct MountPoint { - pub path: String, - pub name: String, - pub fs: Option>>, - pub weak_fs: Weak>, - pub temp_holding: TempHolding, - pub should_sanitize: bool, - pub new_path: Option, -} - -impl Clone for MountPoint { - fn clone(&self) -> Self { - Self { - path: self.path.clone(), - name: self.name.clone(), - fs: None, - weak_fs: self.weak_fs.clone(), - temp_holding: self.temp_holding.clone(), - should_sanitize: self.should_sanitize, - new_path: self.new_path.clone(), - } - } -} - -impl MountPoint { - pub fn fs(&self) -> Option>> { - match &self.fs { - Some(a) => Some(a.clone()), - None => self.weak_fs.upgrade(), - } - } - - /// Tries to recover the internal `Weak` to a `Arc` - fn solidify(&mut self) { - if self.fs.is_none() { - self.fs = self.weak_fs.upgrade(); - } - { - let mut guard = self.temp_holding.lock().unwrap(); - let fs = guard.take(); - if self.fs.is_none() { - self.fs = fs; - } - } - } - - /// Returns a strong-referenced copy of the internal `Arc` - fn strong(&self) -> Option { - self.fs().map(|fs| StrongMountPoint { - path: self.path.clone(), - name: self.name.clone(), - fs, - should_sanitize: self.should_sanitize, - new_path: self.new_path.clone(), - }) - } -} - -/// A `strong` mount point holds a strong `Arc` reference to the filesystem -/// mounted at path `path`. -#[derive(Debug)] -pub struct StrongMountPoint { - pub path: String, - pub name: String, - pub fs: Arc>, - pub should_sanitize: bool, - pub new_path: Option, -} - -/// Allows different filesystems of different types -/// to be mounted at various mount points -#[derive(Debug, Default, Clone)] -pub struct UnionFileSystem { - pub mounts: Vec, -} - -impl UnionFileSystem { - pub fn new() -> Self { - Self::default() - } - - pub fn clear(&mut self) { - self.mounts.clear(); - } -} - -impl UnionFileSystem { - pub fn mount( - &mut self, - name: &str, - path: &str, - should_sanitize: bool, - fs: Box, - new_path: Option<&str>, - ) { - self.unmount(path); - let mut path = path.to_string(); - if !path.starts_with('/') { - path.insert(0, '/'); - } - if !path.ends_with('/') { - path += "/"; - } - let new_path = new_path.map(|new_path| { - let mut new_path = new_path.to_string(); - if !new_path.ends_with('/') { - new_path += "/"; - } - new_path - }); - let fs = Arc::new(fs); - - let mount = MountPoint { - path, - name: name.to_string(), - fs: None, - weak_fs: Arc::downgrade(&fs), - temp_holding: Arc::new(Mutex::new(Some(fs.clone()))), - should_sanitize, - new_path, - }; - - self.mounts.push(mount); - } - - pub fn unmount(&mut self, path: &str) { - let path1 = path.to_string(); - let mut path2 = path1; - if !path2.starts_with('/') { - path2.insert(0, '/'); - } - let mut path3 = path2.clone(); - if !path3.ends_with('/') { - path3.push('/') - } - if path2.ends_with('/') { - path2 = (path2[..(path2.len() - 1)]).to_string(); - } - - self.mounts - .retain(|mount| mount.path != path2 && mount.path != path3); - } - - fn read_dir_internal(&self, path: &Path) -> Result { - let path = path.to_string_lossy(); - - let mut ret = None; - for (path, mount) in filter_mounts(&self.mounts, path.as_ref()) { - match mount.fs.read_dir(Path::new(path.as_str())) { - Ok(dir) => { - if ret.is_none() { - ret = Some(Vec::new()); - } - let ret = ret.as_mut().unwrap(); - for sub in dir.flatten() { - ret.push(sub); - } - } - Err(err) => { - debug!("failed to read dir - {}", err); - } - } - } - - match ret { - Some(mut ret) => { - ret.sort_by(|a, b| match (a.metadata.as_ref(), b.metadata.as_ref()) { - (Ok(a), Ok(b)) => a.modified.cmp(&b.modified), - _ => std::cmp::Ordering::Equal, - }); - Ok(ReadDir::new(ret)) - } - None => Err(FsError::EntryNotFound), - } - } - - /// Deletes all mount points that do not have `sanitize` set in the options - pub fn sanitize(mut self) -> Self { - self.solidify(); - self.mounts.retain(|mount| !mount.should_sanitize); - self - } - - /// Tries to recover the internal `Weak` to a `Arc` - pub fn solidify(&mut self) { - for mount in self.mounts.iter_mut() { - mount.solidify(); - } - } -} - -impl FileSystem for UnionFileSystem { - fn read_dir(&self, path: &Path) -> Result { - debug!("read_dir: path={}", path.display()); - self.read_dir_internal(path) - } - fn create_dir(&self, path: &Path) -> Result<()> { - debug!("create_dir: path={}", path.display()); - if path.parent().is_none() { - return Err(FsError::BaseNotDirectory); - } - if self.read_dir_internal(path).is_ok() { - //return Err(FsError::AlreadyExists); - return Ok(()); - } - - let path = path.to_string_lossy(); - let mut ret_error = FsError::EntryNotFound; - for (path, mount) in filter_mounts(&self.mounts, path.as_ref()) { - match mount.fs.create_dir(Path::new(path.as_str())) { - Ok(ret) => { - return Ok(ret); - } - Err(err) => { - ret_error = err; - } - } - } - Err(ret_error) - } - fn remove_dir(&self, path: &Path) -> Result<()> { - debug!("remove_dir: path={}", path.display()); - if path.parent().is_none() { - return Err(FsError::BaseNotDirectory); - } - // https://github.com/rust-lang/rust/issues/86442 - // DirectoryNotEmpty is not implemented consistently - if path.is_dir() && self.read_dir(path).map(|s| !s.is_empty()).unwrap_or(false) { - return Err(FsError::DirectoryNotEmpty); - } - let mut ret_error = FsError::EntryNotFound; - let path = path.to_string_lossy(); - for (path, mount) in filter_mounts(&self.mounts, path.as_ref()) { - match mount.fs.remove_dir(Path::new(path.as_str())) { - Ok(ret) => { - return Ok(ret); - } - Err(err) => { - ret_error = err; - } - } - } - Err(ret_error) - } - fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> { - Box::pin(async { - println!("rename: from={} to={}", from.display(), to.display()); - if from.parent().is_none() { - return Err(FsError::BaseNotDirectory); - } - if to.parent().is_none() { - return Err(FsError::BaseNotDirectory); - } - let mut ret_error = FsError::EntryNotFound; - let from = from.to_string_lossy(); - let to = to.to_string_lossy(); - #[cfg(target_os = "windows")] - let to = to.replace('\\', "/"); - for (path, mount) in filter_mounts(&self.mounts, from.as_ref()) { - let mut to = if to.starts_with(mount.path.as_str()) { - (to[mount.path.len()..]).to_string() - } else { - ret_error = FsError::UnknownError; - continue; - }; - if !to.starts_with('/') { - to = format!("/{}", to); - } - match mount - .fs - .rename(Path::new(&path), Path::new(to.as_str())) - .await - { - Ok(ret) => { - trace!("rename ok"); - return Ok(ret); - } - Err(err) => { - trace!("rename error (from={}, to={}) - {}", from, to, err); - ret_error = err; - } - } - } - trace!("rename failed - {}", ret_error); - Err(ret_error) - }) - } - fn metadata(&self, path: &Path) -> Result { - debug!("metadata: path={}", path.display()); - let mut ret_error = FsError::EntryNotFound; - let path = path.to_string_lossy(); - for (path, mount) in filter_mounts(&self.mounts, path.as_ref()) { - match mount.fs.metadata(Path::new(path.as_str())) { - Ok(ret) => { - return Ok(ret); - } - Err(err) => { - // This fixes a bug when attempting to create the directory /usr when it does not exist - // on the x86 version of memfs - // TODO: patch virtual-fs and remove - if let FsError::NotAFile = &err { - ret_error = FsError::EntryNotFound; - } else { - debug!("metadata failed: (path={}) - {}", path, err); - ret_error = err; - } - } - } - } - Err(ret_error) - } - fn symlink_metadata(&self, path: &Path) -> Result { - debug!("symlink_metadata: path={}", path.display()); - let mut ret_error = FsError::EntryNotFound; - let path = path.to_string_lossy(); - for (path_inner, mount) in filter_mounts(&self.mounts, path.as_ref()) { - match mount.fs.symlink_metadata(Path::new(path_inner.as_str())) { - Ok(ret) => { - return Ok(ret); - } - Err(err) => { - // This fixes a bug when attempting to create the directory /usr when it does not exist - // on the x86 version of memfs - // TODO: patch virtual-fs and remove - if let FsError::NotAFile = &err { - ret_error = FsError::EntryNotFound; - } else { - debug!("metadata failed: (path={}) - {}", path, err); - ret_error = err; - } - } - } - } - debug!("symlink_metadata: failed={}", ret_error); - Err(ret_error) - } - fn remove_file(&self, path: &Path) -> Result<()> { - println!("remove_file: path={}", path.display()); - let mut ret_error = FsError::EntryNotFound; - let path = path.to_string_lossy(); - for (path, mount) in filter_mounts(&self.mounts, path.as_ref()) { - match mount.fs.remove_file(Path::new(path.as_str())) { - Ok(ret) => { - return Ok(ret); - } - Err(err) => { - println!("returning error {err:?}"); - ret_error = err; - } - } - } - Err(ret_error) - } - fn new_open_options(&self) -> OpenOptions { - OpenOptions::new(self) - } -} - -fn filter_mounts( - mounts: &[MountPoint], - target: &str, -) -> impl Iterator { - // On Windows, Path might use \ instead of /, wich mill messup the matching of mount points - #[cfg(target_os = "windows")] - let target = target.replace('\\', "/"); - - let mut biggest_path = 0usize; - let mut ret = Vec::new(); - for mount in mounts.iter().rev() { - let mut test_mount_path1 = mount.path.clone(); - if !test_mount_path1.ends_with('/') { - test_mount_path1.push('/'); - } - - let mut test_mount_path2 = mount.path.clone(); - if test_mount_path2.ends_with('/') { - test_mount_path2 = test_mount_path2[..(test_mount_path2.len() - 1)].to_string(); - } - - if target == test_mount_path1 || target == test_mount_path2 { - if let Some(mount) = mount.strong() { - biggest_path = biggest_path.max(mount.path.len()); - let mut path = "/".to_string(); - if let Some(ref np) = mount.new_path { - path = np.to_string(); - } - ret.push((path, mount)); - } - } else if target.starts_with(test_mount_path1.as_str()) { - if let Some(mount) = mount.strong() { - biggest_path = biggest_path.max(mount.path.len()); - let path = &target[test_mount_path2.len()..]; - let mut path = path.to_string(); - if let Some(ref np) = mount.new_path { - path = format!("{}{}", np, &path[1..]); - } - ret.push((path, mount)); - } - } - } - ret.retain(|(_, b)| b.path.len() >= biggest_path); - ret.into_iter() -} - -impl FileOpener for UnionFileSystem { - fn open( - &self, - path: &Path, - conf: &OpenOptionsConfig, - ) -> Result> { - debug!("open: path={}", path.display()); - let mut ret_err = FsError::EntryNotFound; - let path = path.to_string_lossy(); - - if conf.create() || conf.create_new() { - for (path, mount) in filter_mounts(&self.mounts, path.as_ref()) { - if let Ok(mut ret) = mount - .fs - .new_open_options() - .truncate(conf.truncate()) - .append(conf.append()) - .read(conf.read()) - .write(conf.write()) - .open(path) - { - if conf.create_new() { - ret.unlink(); - continue; - } - return Ok(ret); - } - } - } - for (path, mount) in filter_mounts(&self.mounts, path.as_ref()) { - match mount.fs.new_open_options().options(conf.clone()).open(path) { - Ok(ret) => return Ok(ret), - Err(err) if ret_err == FsError::EntryNotFound => { - ret_err = err; - } - _ => {} - } - } - Err(ret_err) - } -} - -#[cfg(test)] -mod tests { - use std::path::Path; - - use tokio::io::AsyncWriteExt; - - use crate::{mem_fs, ops, FileSystem as FileSystemTrait, FsError, UnionFileSystem}; - - fn gen_filesystem() -> UnionFileSystem { - let mut union = UnionFileSystem::new(); - // fs.mount("/", Box::new(mem_fs::FileSystem::default())); - let a = mem_fs::FileSystem::default(); - let b = mem_fs::FileSystem::default(); - let c = mem_fs::FileSystem::default(); - let d = mem_fs::FileSystem::default(); - let e = mem_fs::FileSystem::default(); - let f = mem_fs::FileSystem::default(); - let g = mem_fs::FileSystem::default(); - let h = mem_fs::FileSystem::default(); - - union.mount("mem_fs_1", "/test_new_filesystem", false, Box::new(a), None); - union.mount("mem_fs_2", "/test_create_dir", false, Box::new(b), None); - union.mount("mem_fs_3", "/test_remove_dir", false, Box::new(c), None); - union.mount("mem_fs_4", "/test_rename", false, Box::new(d), None); - union.mount("mem_fs_5", "/test_metadata", false, Box::new(e), None); - union.mount("mem_fs_6", "/test_remove_file", false, Box::new(f), None); - union.mount("mem_fs_6", "/test_readdir", false, Box::new(g), None); - union.mount("mem_fs_6", "/test_canonicalize", false, Box::new(h), None); - - union - } - - #[tokio::test] - async fn test_new_filesystem() { - let fs = gen_filesystem(); - assert!( - fs.read_dir(Path::new("/test_new_filesystem")).is_ok(), - "hostfs can read root" - ); - let mut file_write = fs - .new_open_options() - .read(true) - .write(true) - .create_new(true) - .open(Path::new("/test_new_filesystem/foo2.txt")) - .unwrap(); - file_write.write_all(b"hello").await.unwrap(); - let _ = std::fs::remove_file("/test_new_filesystem/foo2.txt"); - } - - #[tokio::test] - async fn test_create_dir() { - let fs = gen_filesystem(); - - assert_eq!( - fs.create_dir(Path::new("/")), - Err(FsError::BaseNotDirectory), - "creating a directory that has no parent", - ); - - let _ = fs_extra::remove_items(&["/test_create_dir"]); - - assert_eq!( - fs.create_dir(Path::new("/test_create_dir")), - Ok(()), - "creating a directory", - ); - - assert_eq!( - fs.create_dir(Path::new("/test_create_dir/foo")), - Ok(()), - "creating a directory", - ); - - let cur_dir = read_dir_names(&fs, "/test_create_dir"); - - if !cur_dir.contains(&"foo".to_string()) { - panic!("cur_dir does not contain foo: {:#?}", cur_dir); - } - - assert!( - cur_dir.contains(&"foo".to_string()), - "the root is updated and well-defined" - ); - - assert_eq!( - fs.create_dir(Path::new("/test_create_dir/foo/bar")), - Ok(()), - "creating a sub-directory", - ); - - let foo_dir = read_dir_names(&fs, "/test_create_dir/foo"); - - assert!( - foo_dir.contains(&"bar".to_string()), - "the foo directory is updated and well-defined" - ); - - let bar_dir = read_dir_names(&fs, "/test_create_dir/foo/bar"); - - assert!( - bar_dir.is_empty(), - "the foo directory is updated and well-defined" - ); - let _ = fs_extra::remove_items(&["/test_create_dir"]); - } - - #[tokio::test] - async fn test_remove_dir() { - let fs = gen_filesystem(); - - let _ = fs_extra::remove_items(&["/test_remove_dir"]); - - assert_eq!( - fs.remove_dir(Path::new("/")), - Err(FsError::BaseNotDirectory), - "removing a directory that has no parent", - ); - - assert_eq!( - fs.remove_dir(Path::new("/foo")), - Err(FsError::EntryNotFound), - "cannot remove a directory that doesn't exist", - ); - - assert_eq!( - fs.create_dir(Path::new("/test_remove_dir")), - Ok(()), - "creating a directory", - ); - - assert_eq!( - fs.create_dir(Path::new("/test_remove_dir/foo")), - Ok(()), - "creating a directory", - ); - - assert_eq!( - fs.create_dir(Path::new("/test_remove_dir/foo/bar")), - Ok(()), - "creating a sub-directory", - ); - - assert!( - read_dir_names(&fs, "/test_remove_dir/foo").contains(&"bar".to_string()), - "./foo/bar exists" - ); - - assert_eq!( - fs.remove_dir(Path::new("/test_remove_dir/foo")), - Err(FsError::DirectoryNotEmpty), - "removing a directory that has children", - ); - - assert_eq!( - fs.remove_dir(Path::new("/test_remove_dir/foo/bar")), - Ok(()), - "removing a sub-directory", - ); - - assert_eq!( - fs.remove_dir(Path::new("/test_remove_dir/foo")), - Ok(()), - "removing a directory", - ); - - assert!( - !read_dir_names(&fs, "/test_remove_dir").contains(&"foo".to_string()), - "the foo directory still exists" - ); - - let _ = fs_extra::remove_items(&["/test_remove_dir"]); - } - - fn read_dir_names(fs: &dyn crate::FileSystem, path: &str) -> Vec { - fs.read_dir(Path::new(path)) - .unwrap() - .filter_map(|entry| Some(entry.ok()?.file_name().to_str()?.to_string())) - .collect::>() - } - - #[tokio::test] - async fn test_rename() { - let fs = gen_filesystem(); - - let _ = fs_extra::remove_items(&["./test_rename"]); - - assert_eq!( - fs.rename(Path::new("/"), Path::new("/bar")).await, - Err(FsError::BaseNotDirectory), - "renaming a directory that has no parent", - ); - assert_eq!( - fs.rename(Path::new("/foo"), Path::new("/")).await, - Err(FsError::BaseNotDirectory), - "renaming to a directory that has no parent", - ); - - assert_eq!(fs.create_dir(Path::new("/test_rename")), Ok(())); - assert_eq!(fs.create_dir(Path::new("/test_rename/foo")), Ok(())); - assert_eq!(fs.create_dir(Path::new("/test_rename/foo/qux")), Ok(())); - - assert_eq!( - fs.rename( - Path::new("/test_rename/foo"), - Path::new("/test_rename/bar/baz") - ) - .await, - Err(FsError::EntryNotFound), - "renaming to a directory that has parent that doesn't exist", - ); - - assert_eq!(fs.create_dir(Path::new("/test_rename/bar")), Ok(())); - - assert_eq!( - fs.rename(Path::new("/test_rename/foo"), Path::new("/test_rename/bar")) - .await, - Ok(()), - "renaming to a directory that has parent that exists", - ); - - assert!( - matches!( - fs.new_open_options() - .write(true) - .create_new(true) - .open(Path::new("/test_rename/bar/hello1.txt")), - Ok(_), - ), - "creating a new file (`hello1.txt`)", - ); - assert!( - matches!( - fs.new_open_options() - .write(true) - .create_new(true) - .open(Path::new("/test_rename/bar/hello2.txt")), - Ok(_), - ), - "creating a new file (`hello2.txt`)", - ); - - let cur_dir = read_dir_names(&fs, "/test_rename"); - - assert!( - !cur_dir.contains(&"foo".to_string()), - "the foo directory still exists" - ); - - assert!( - cur_dir.contains(&"bar".to_string()), - "the bar directory still exists" - ); - - let bar_dir = read_dir_names(&fs, "/test_rename/bar"); - - if !bar_dir.contains(&"qux".to_string()) { - println!("qux does not exist: {:?}", bar_dir) - } - - let qux_dir = read_dir_names(&fs, "/test_rename/bar/qux"); - - assert!(qux_dir.is_empty(), "the qux directory is empty"); - - assert!( - read_dir_names(&fs, "/test_rename/bar").contains(&"hello1.txt".to_string()), - "the /bar/hello1.txt file exists" - ); - - assert!( - read_dir_names(&fs, "/test_rename/bar").contains(&"hello2.txt".to_string()), - "the /bar/hello2.txt file exists" - ); - - assert_eq!( - fs.create_dir(Path::new("/test_rename/foo")), - Ok(()), - "create ./foo again", - ); - - assert_eq!( - fs.rename( - Path::new("/test_rename/bar/hello2.txt"), - Path::new("/test_rename/foo/world2.txt") - ) - .await, - Ok(()), - "renaming (and moving) a file", - ); - - assert_eq!( - fs.rename( - Path::new("/test_rename/foo"), - Path::new("/test_rename/bar/baz") - ) - .await, - Ok(()), - "renaming a directory", - ); - - assert_eq!( - fs.rename( - Path::new("/test_rename/bar/hello1.txt"), - Path::new("/test_rename/bar/world1.txt") - ) - .await, - Ok(()), - "renaming a file (in the same directory)", - ); - - assert!( - read_dir_names(&fs, "/test_rename").contains(&"bar".to_string()), - "./bar exists" - ); - - assert!( - read_dir_names(&fs, "/test_rename/bar").contains(&"baz".to_string()), - "/bar/baz exists" - ); - assert!( - !read_dir_names(&fs, "/test_rename").contains(&"foo".to_string()), - "foo does not exist anymore" - ); - assert!( - read_dir_names(&fs, "/test_rename/bar/baz").contains(&"world2.txt".to_string()), - "/bar/baz/world2.txt exists" - ); - assert!( - read_dir_names(&fs, "/test_rename/bar").contains(&"world1.txt".to_string()), - "/bar/world1.txt (ex hello1.txt) exists" - ); - assert!( - !read_dir_names(&fs, "/test_rename/bar").contains(&"hello1.txt".to_string()), - "hello1.txt was moved" - ); - assert!( - !read_dir_names(&fs, "/test_rename/bar").contains(&"hello2.txt".to_string()), - "hello2.txt was moved" - ); - assert!( - read_dir_names(&fs, "/test_rename/bar/baz").contains(&"world2.txt".to_string()), - "world2.txt was moved to the correct place" - ); - - let _ = fs_extra::remove_items(&["/test_rename"]); - } - - #[tokio::test] - async fn test_metadata() { - use std::thread::sleep; - use std::time::Duration; - - let fs = gen_filesystem(); - - let _ = fs_extra::remove_items(&["/test_metadata"]); - - assert_eq!(fs.create_dir(Path::new("/test_metadata")), Ok(())); - - let root_metadata = fs.metadata(Path::new("/test_metadata")).unwrap(); - - assert!(root_metadata.ft.dir); - assert!(root_metadata.accessed == root_metadata.created); - assert!(root_metadata.modified == root_metadata.created); - assert!(root_metadata.modified > 0); - - assert_eq!(fs.create_dir(Path::new("/test_metadata/foo")), Ok(())); - - let foo_metadata = fs.metadata(Path::new("/test_metadata/foo")); - assert!(foo_metadata.is_ok()); - let foo_metadata = foo_metadata.unwrap(); - - assert!(foo_metadata.ft.dir); - assert!(foo_metadata.accessed == foo_metadata.created); - assert!(foo_metadata.modified == foo_metadata.created); - assert!(foo_metadata.modified > 0); - - sleep(Duration::from_secs(3)); - - assert_eq!( - fs.rename( - Path::new("/test_metadata/foo"), - Path::new("/test_metadata/bar") - ) - .await, - Ok(()) - ); - - let bar_metadata = fs.metadata(Path::new("/test_metadata/bar")).unwrap(); - assert!(bar_metadata.ft.dir); - assert!(bar_metadata.accessed == foo_metadata.accessed); - assert!(bar_metadata.created == foo_metadata.created); - assert!(bar_metadata.modified > foo_metadata.modified); - - let root_metadata = fs.metadata(Path::new("/test_metadata/bar")).unwrap(); - assert!( - root_metadata.modified > foo_metadata.modified, - "the parent modified time was updated" - ); - - let _ = fs_extra::remove_items(&["/test_metadata"]); - } - - #[tokio::test] - async fn test_remove_file() { - let fs = gen_filesystem(); - - let _ = fs_extra::remove_items(&["./test_remove_file"]); - - assert!(fs.create_dir(Path::new("/test_remove_file")).is_ok()); - - assert!( - matches!( - fs.new_open_options() - .write(true) - .create_new(true) - .open(Path::new("/test_remove_file/foo.txt")), - Ok(_) - ), - "creating a new file", - ); - - assert!(read_dir_names(&fs, "/test_remove_file").contains(&"foo.txt".to_string())); - - assert_eq!( - fs.remove_file(Path::new("/test_remove_file/foo.txt")), - Ok(()), - "removing a file that exists", - ); - - assert!(!read_dir_names(&fs, "/test_remove_file").contains(&"foo.txt".to_string())); - - assert_eq!( - fs.remove_file(Path::new("/test_remove_file/foo.txt")), - Err(FsError::EntryNotFound), - "removing a file that doesn't exists", - ); - - let _ = fs_extra::remove_items(&["./test_remove_file"]); - } - - #[tokio::test] - async fn test_readdir() { - let fs = gen_filesystem(); - - assert_eq!( - fs.create_dir(Path::new("/test_readdir/foo")), - Ok(()), - "creating `foo`" - ); - assert_eq!( - fs.create_dir(Path::new("/test_readdir/foo/sub")), - Ok(()), - "creating `sub`" - ); - assert_eq!( - fs.create_dir(Path::new("/test_readdir/bar")), - Ok(()), - "creating `bar`" - ); - assert_eq!( - fs.create_dir(Path::new("/test_readdir/baz")), - Ok(()), - "creating `bar`" - ); - assert!( - matches!( - fs.new_open_options() - .write(true) - .create_new(true) - .open(Path::new("/test_readdir/a.txt")), - Ok(_) - ), - "creating `a.txt`", - ); - assert!( - matches!( - fs.new_open_options() - .write(true) - .create_new(true) - .open(Path::new("/test_readdir/b.txt")), - Ok(_) - ), - "creating `b.txt`", - ); - - println!("fs: {:?}", fs); - - let readdir = fs.read_dir(Path::new("/test_readdir")); - - assert!(readdir.is_ok(), "reading the directory `/test_readdir/`"); - - let mut readdir = readdir.unwrap(); - - let next = readdir.next().unwrap().unwrap(); - assert!(next.path.ends_with("foo"), "checking entry #1"); - println!("entry 1: {:#?}", next); - assert!(next.file_type().unwrap().is_dir(), "checking entry #1"); - - let next = readdir.next().unwrap().unwrap(); - assert!(next.path.ends_with("bar"), "checking entry #2"); - assert!(next.file_type().unwrap().is_dir(), "checking entry #2"); - - let next = readdir.next().unwrap().unwrap(); - assert!(next.path.ends_with("baz"), "checking entry #3"); - assert!(next.file_type().unwrap().is_dir(), "checking entry #3"); - - let next = readdir.next().unwrap().unwrap(); - assert!(next.path.ends_with("a.txt"), "checking entry #2"); - assert!(next.file_type().unwrap().is_file(), "checking entry #4"); - - let next = readdir.next().unwrap().unwrap(); - assert!(next.path.ends_with("b.txt"), "checking entry #2"); - assert!(next.file_type().unwrap().is_file(), "checking entry #5"); - - if let Some(s) = readdir.next() { - panic!("next: {:?}", s); - } - - let _ = fs_extra::remove_items(&["./test_readdir"]); - } - - /* - #[tokio::test] - async fn test_canonicalize() { - let fs = gen_filesystem(); - - let root_dir = env!("CARGO_MANIFEST_DIR"); - - let _ = fs_extra::remove_items(&["./test_canonicalize"]); - - assert_eq!( - fs.create_dir(Path::new("./test_canonicalize")), - Ok(()), - "creating `test_canonicalize`" - ); - - assert_eq!( - fs.create_dir(Path::new("./test_canonicalize/foo")), - Ok(()), - "creating `foo`" - ); - assert_eq!( - fs.create_dir(Path::new("./test_canonicalize/foo/bar")), - Ok(()), - "creating `bar`" - ); - assert_eq!( - fs.create_dir(Path::new("./test_canonicalize/foo/bar/baz")), - Ok(()), - "creating `baz`", - ); - assert_eq!( - fs.create_dir(Path::new("./test_canonicalize/foo/bar/baz/qux")), - Ok(()), - "creating `qux`", - ); - assert!( - matches!( - fs.new_open_options() - .write(true) - .create_new(true) - .open(Path::new("./test_canonicalize/foo/bar/baz/qux/hello.txt")), - Ok(_) - ), - "creating `hello.txt`", - ); - - assert_eq!( - fs.canonicalize(Path::new("./test_canonicalize")), - Ok(Path::new(&format!("{root_dir}/test_canonicalize")).to_path_buf()), - "canonicalizing `/`", - ); - assert_eq!( - fs.canonicalize(Path::new("foo")), - Err(FsError::InvalidInput), - "canonicalizing `foo`", - ); - assert_eq!( - fs.canonicalize(Path::new("./test_canonicalize/././././foo/")), - Ok(Path::new(&format!("{root_dir}/test_canonicalize/foo")).to_path_buf()), - "canonicalizing `/././././foo/`", - ); - assert_eq!( - fs.canonicalize(Path::new("./test_canonicalize/foo/bar//")), - Ok(Path::new(&format!("{root_dir}/test_canonicalize/foo/bar")).to_path_buf()), - "canonicalizing `/foo/bar//`", - ); - assert_eq!( - fs.canonicalize(Path::new("./test_canonicalize/foo/bar/../bar")), - Ok(Path::new(&format!("{root_dir}/test_canonicalize/foo/bar")).to_path_buf()), - "canonicalizing `/foo/bar/../bar`", - ); - assert_eq!( - fs.canonicalize(Path::new("./test_canonicalize/foo/bar/../..")), - Ok(Path::new(&format!("{root_dir}/test_canonicalize")).to_path_buf()), - "canonicalizing `/foo/bar/../..`", - ); - assert_eq!( - fs.canonicalize(Path::new("/foo/bar/../../..")), - Err(FsError::InvalidInput), - "canonicalizing `/foo/bar/../../..`", - ); - assert_eq!( - fs.canonicalize(Path::new("C:/foo/")), - Err(FsError::InvalidInput), - "canonicalizing `C:/foo/`", - ); - assert_eq!( - fs.canonicalize(Path::new( - "./test_canonicalize/foo/./../foo/bar/../../foo/bar/./baz/./../baz/qux/../../baz/./qux/hello.txt" - )), - Ok(Path::new(&format!("{root_dir}/test_canonicalize/foo/bar/baz/qux/hello.txt")).to_path_buf()), - "canonicalizing a crazily stupid path name", - ); - - let _ = fs_extra::remove_items(&["./test_canonicalize"]); - } - */ - - #[tokio::test] - #[ignore = "Not yet supported. See https://github.com/wasmerio/wasmer/issues/3678"] - async fn mount_to_overlapping_directories() { - let top_level = mem_fs::FileSystem::default(); - ops::touch(&top_level, "/file.txt").unwrap(); - let nested = mem_fs::FileSystem::default(); - ops::touch(&nested, "/another-file.txt").unwrap(); - - let mut fs = UnionFileSystem::default(); - fs.mount( - "top-level", - "/", - false, - Box::new(top_level), - Some("/top-level"), - ); - fs.mount( - "nested", - "/", - false, - Box::new(nested), - Some("/top-level/nested"), - ); - - assert!(ops::is_dir(&fs, "/top-level")); - assert!(ops::is_file(&fs, "/top-level/file.txt")); - assert!(ops::is_dir(&fs, "/top-level/nested")); - assert!(ops::is_file(&fs, "/top-level/nested/another-file.txt")); - } -} diff --git a/lib/vm/Cargo.toml b/lib/vm/Cargo.toml index 9441d6e27de..5e86d0f20ca 100644 --- a/lib/vm/Cargo.toml +++ b/lib/vm/Cargo.toml @@ -28,7 +28,7 @@ lazy_static = "1.4.0" region = { version = "3.0" } corosensei = { version = "0.1.2" } derivative = { version = "^2" } -dashmap = { version = "5.4" } +dashmap.workspace = true fnv = "1.0.3" # - Optional shared dependencies. tracing = { version = "0.1", optional = true } diff --git a/lib/wasix/Cargo.toml b/lib/wasix/Cargo.toml index 189b55f9c11..60cb948ccd6 100644 --- a/lib/wasix/Cargo.toml +++ b/lib/wasix/Cargo.toml @@ -56,8 +56,8 @@ heapless = "0.7.16" once_cell = "1.17.0" pin-project = "1.0.12" semver = "1.0.17" -dashmap = "5.4.0" -tempfile = "3.6.0" +dashmap.workspace = true +tempfile.workspace = true # Used by the WCGI runner hyper = { version = "0.14", features = ["server", "stream"], optional = true } wcgi = { version = "0.1.2", optional = true } diff --git a/lib/wasix/src/bin_factory/binary_package.rs b/lib/wasix/src/bin_factory/binary_package.rs index 01e76e665fb..72b8517f0e3 100644 --- a/lib/wasix/src/bin_factory/binary_package.rs +++ b/lib/wasix/src/bin_factory/binary_package.rs @@ -99,6 +99,25 @@ impl BinaryPackage { Ok(pkg) } + /// Load a [`BinaryPackage`] and all its dependencies from a registry. + #[tracing::instrument(level = "debug", skip_all)] + pub async fn get_container_from_registry( + specifier: &PackageSpecifier, + runtime: &(dyn Runtime + Send + Sync), + ) -> Result { + let source = runtime.source(); + let root_summary = + source + .latest(specifier) + .await + .map_err(|error| ResolveError::Registry { + package: specifier.clone(), + error, + })?; + let root = runtime.package_loader().load(&root_summary).await?; + Ok(root) + } + /// Load a [`BinaryPackage`] and all its dependencies from a registry. #[tracing::instrument(level = "debug", skip_all)] pub async fn from_registry( diff --git a/lib/wasix/src/bin_factory/exec.rs b/lib/wasix/src/bin_factory/exec.rs index 25da5f1ec2b..e0326a6ce09 100644 --- a/lib/wasix/src/bin_factory/exec.rs +++ b/lib/wasix/src/bin_factory/exec.rs @@ -52,14 +52,14 @@ pub async fn spawn_exec( }; // If the file system has not already been union'ed then do so - env.state - .fs - .conditional_union(&binary) - .await - .map_err(|err| { - tracing::warn!("failed to union file system - {err}"); - SpawnError::FileSystemError - })?; + // env.state + // .fs + // .conditional_union(&binary) + // .await + // .map_err(|err| { + // tracing::warn!("failed to union file system - {err}"); + // SpawnError::FileSystemError + // })?; tracing::debug!("{:?}", env.state.fs); // Now run the module diff --git a/lib/wasix/src/fs/mod.rs b/lib/wasix/src/fs/mod.rs index 671bcfd65b7..48c1cad8c22 100644 --- a/lib/wasix/src/fs/mod.rs +++ b/lib/wasix/src/fs/mod.rs @@ -4,7 +4,7 @@ mod notification; use std::{ borrow::{Borrow, Cow}, - collections::{HashMap, HashSet, VecDeque}, + collections::{HashMap, HashSet}, ops::{Deref, DerefMut}, path::{Component, Path, PathBuf}, pin::Pin, @@ -19,12 +19,12 @@ use crate::{ net::socket::InodeSocketKind, state::{Stderr, Stdin, Stdout}, }; -use futures::{future::BoxFuture, Future, TryStreamExt}; +use futures::Future; #[cfg(feature = "enable-serde")] use serde_derive::{Deserialize, Serialize}; use tokio::io::AsyncWriteExt; use tracing::{debug, trace}; -use virtual_fs::{copy_reference, FileSystem, FsError, OpenOptions, VirtualFile}; +use virtual_fs::{FileSystem, FsError, VirtualFile}; use wasmer_wasix_types::{ types::{__WASI_STDERR_FILENO, __WASI_STDIN_FILENO, __WASI_STDOUT_FILENO}, wasi::{ @@ -40,7 +40,7 @@ pub(crate) use self::inode_guard::{ }; pub use self::notification::NotificationInner; use crate::syscalls::map_io_err; -use crate::{bin_factory::BinaryPackage, state::PreopenedDir, ALL_RIGHTS}; +use crate::{state::PreopenedDir, ALL_RIGHTS}; /// the fd value of the virtual root pub const VIRTUAL_ROOT_FD: WasiFd = 3; @@ -268,148 +268,6 @@ impl Default for WasiInodes { } } -#[derive(Debug, Clone)] -pub enum WasiFsRoot { - Sandbox(Arc), - Backing(Arc>), -} - -impl WasiFsRoot { - /// Merge the contents of a filesystem into this one. - pub(crate) async fn merge( - &self, - other: &Arc, - ) -> Result<(), virtual_fs::FsError> { - match self { - WasiFsRoot::Sandbox(fs) => { - fs.union(other); - Ok(()) - } - WasiFsRoot::Backing(fs) => { - merge_filesystems(other, fs).await?; - Ok(()) - } - } - } -} - -impl FileSystem for WasiFsRoot { - fn read_dir(&self, path: &Path) -> virtual_fs::Result { - match self { - WasiFsRoot::Sandbox(fs) => fs.read_dir(path), - WasiFsRoot::Backing(fs) => fs.read_dir(path), - } - } - fn create_dir(&self, path: &Path) -> virtual_fs::Result<()> { - match self { - WasiFsRoot::Sandbox(fs) => fs.create_dir(path), - WasiFsRoot::Backing(fs) => fs.create_dir(path), - } - } - fn remove_dir(&self, path: &Path) -> virtual_fs::Result<()> { - match self { - WasiFsRoot::Sandbox(fs) => fs.remove_dir(path), - WasiFsRoot::Backing(fs) => fs.remove_dir(path), - } - } - fn rename<'a>(&'a self, from: &Path, to: &Path) -> BoxFuture<'a, virtual_fs::Result<()>> { - let from = from.to_owned(); - let to = to.to_owned(); - let this = self.clone(); - Box::pin(async move { - match this { - WasiFsRoot::Sandbox(fs) => fs.rename(&from, &to).await, - WasiFsRoot::Backing(fs) => fs.rename(&from, &to).await, - } - }) - } - fn metadata(&self, path: &Path) -> virtual_fs::Result { - match self { - WasiFsRoot::Sandbox(fs) => fs.metadata(path), - WasiFsRoot::Backing(fs) => fs.metadata(path), - } - } - fn symlink_metadata(&self, path: &Path) -> virtual_fs::Result { - match self { - WasiFsRoot::Sandbox(fs) => fs.symlink_metadata(path), - WasiFsRoot::Backing(fs) => fs.symlink_metadata(path), - } - } - fn remove_file(&self, path: &Path) -> virtual_fs::Result<()> { - match self { - WasiFsRoot::Sandbox(fs) => fs.remove_file(path), - WasiFsRoot::Backing(fs) => fs.remove_file(path), - } - } - fn new_open_options(&self) -> OpenOptions { - match self { - WasiFsRoot::Sandbox(fs) => fs.new_open_options(), - WasiFsRoot::Backing(fs) => fs.new_open_options(), - } - } -} - -/// Merge the contents of one filesystem into another. -/// -#[tracing::instrument(level = "debug", skip_all)] -async fn merge_filesystems( - source: &dyn FileSystem, - destination: &dyn FileSystem, -) -> Result<(), virtual_fs::FsError> { - tracing::debug!("Falling back to a recursive copy to merge filesystems"); - let files = futures::stream::FuturesUnordered::new(); - - let mut to_check = VecDeque::new(); - to_check.push_back(PathBuf::from("/")); - - while let Some(path) = to_check.pop_front() { - let metadata = match source.metadata(&path) { - Ok(m) => m, - Err(err) => { - tracing::debug!(path=%path.display(), source_fs=?source, ?err, "failed to get metadata for path while merging file systems"); - return Err(err); - } - }; - - if metadata.is_dir() { - create_dir_all(destination, &path)?; - - for entry in source.read_dir(&path)? { - let entry = entry?; - to_check.push_back(entry.path); - } - } else if metadata.is_file() { - files.push(async move { - copy_reference(source, destination, &path) - .await - .map_err(virtual_fs::FsError::from) - }); - } else { - tracing::debug!( - path=%path.display(), - ?metadata, - "Skipping unknown file type while merging" - ); - } - } - - files.try_collect().await -} - -fn create_dir_all(fs: &dyn FileSystem, path: &Path) -> Result<(), virtual_fs::FsError> { - if fs.metadata(path).is_ok() { - return Ok(()); - } - - if let Some(parent) = path.parent() { - create_dir_all(fs, parent)?; - } - - fs.create_dir(path)?; - - Ok(()) -} - /// Warning, modifying these fields directly may cause invariants to break and /// should be considered unsafe. These fields may be made private in a future release #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] @@ -420,7 +278,7 @@ pub struct WasiFs { pub next_fd: AtomicU32, pub current_dir: Mutex, #[cfg_attr(feature = "enable-serde", serde(skip, default))] - pub root_fs: WasiFsRoot, + pub root_fs: Arc, pub root_inode: InodeGuard, pub has_unioned: Arc>>, @@ -487,38 +345,12 @@ impl WasiFs { ); } - /// Will conditionally union the binary file system with this one - /// if it has not already been unioned - pub async fn conditional_union( - &self, - binary: &BinaryPackage, - ) -> Result<(), virtual_fs::FsError> { - let package_name = binary.package_name.clone(); - - let needs_to_be_unioned = self.has_unioned.lock().unwrap().insert(package_name); - - if !needs_to_be_unioned { - return Ok(()); - } - - match self.root_fs { - WasiFsRoot::Sandbox(ref sandbox_fs) => { - sandbox_fs.union(&binary.webc_fs); - } - WasiFsRoot::Backing(ref fs) => { - merge_filesystems(&binary.webc_fs, fs.deref()).await?; - } - } - - Ok(()) - } - /// Created for the builder API. like `new` but with more information pub(crate) fn new_with_preopen( inodes: &WasiInodes, preopens: &[PreopenedDir], vfs_preopens: &[String], - fs_backing: WasiFsRoot, + fs_backing: Arc, ) -> Result { let (wasi_fs, root_inode) = Self::new_init(fs_backing, inodes)?; @@ -694,19 +526,22 @@ impl WasiFs { /// Converts a relative path into an absolute path pub(crate) fn relative_path_to_absolute(&self, mut path: String) -> String { - if path.starts_with("./") { + if !path.starts_with("/") { let current_dir = self.current_dir.lock().unwrap(); - path = format!("{}{}", current_dir.as_str(), &path[1..]); - if path.contains("//") { - path = path.replace("//", "/"); - } + path = PathBuf::from(current_dir.as_str()) + .join(path) + .to_string_lossy() + .to_string(); } path } /// Private helper function to init the filesystem, called in `new` and /// `new_with_preopen` - fn new_init(fs_backing: WasiFsRoot, inodes: &WasiInodes) -> Result<(Self, InodeGuard), String> { + fn new_init( + fs_backing: Arc, + inodes: &WasiInodes, + ) -> Result<(Self, InodeGuard), String> { debug!("Initializing WASI filesystem"); let stat = Filestat { @@ -1398,13 +1233,21 @@ impl WasiFs { follow_symlinks: bool, ) -> Result { let base_inode = self.get_fd_inode(base)?; - let start_inode = - if !base_inode.deref().name.starts_with('/') && self.is_wasix.load(Ordering::Acquire) { - let (cur_inode, _) = self.get_current_dir(inodes, base)?; - cur_inode - } else { - self.get_fd_inode(base)? - }; + println!( + "get_inode_at_path, path: {}, base name: {} (inode: {})", + path, + base_inode.deref().name, + base + ); + let start_inode = if (!base_inode.deref().name.starts_with('/') + || (base_inode.deref().name == "/" && !path.starts_with('/'))) + && self.is_wasix.load(Ordering::Acquire) + { + let (cur_inode, _) = self.get_current_dir(inodes, base)?; + cur_inode + } else { + self.get_fd_inode(base)? + }; self.get_inode_at_path_inner(inodes, start_inode, path, 0, follow_symlinks) } @@ -1901,55 +1744,6 @@ impl std::fmt::Debug for WasiFs { } } -/// Returns the default filesystem backing -pub fn default_fs_backing() -> Box { - cfg_if::cfg_if! { - if #[cfg(feature = "host-fs")] { - Box::::default() - } else if #[cfg(not(feature = "host-fs"))] { - Box::::default() - } else { - Box::::default() - } - } -} - -#[derive(Debug, Default)] -pub struct FallbackFileSystem; - -impl FallbackFileSystem { - fn fail() -> ! { - panic!("No filesystem set for wasmer-wasi, please enable either the `host-fs` or `mem-fs` feature or set your custom filesystem with `WasiEnvBuilder::set_fs`"); - } -} - -impl FileSystem for FallbackFileSystem { - fn read_dir(&self, _path: &Path) -> Result { - Self::fail(); - } - fn create_dir(&self, _path: &Path) -> Result<(), FsError> { - Self::fail(); - } - fn remove_dir(&self, _path: &Path) -> Result<(), FsError> { - Self::fail(); - } - fn rename<'a>(&'a self, _from: &Path, _to: &Path) -> BoxFuture<'a, Result<(), FsError>> { - Self::fail(); - } - fn metadata(&self, _path: &Path) -> Result { - Self::fail(); - } - fn symlink_metadata(&self, _path: &Path) -> Result { - Self::fail(); - } - fn remove_file(&self, _path: &Path) -> Result<(), FsError> { - Self::fail(); - } - fn new_open_options(&self) -> virtual_fs::OpenOptions { - Self::fail(); - } -} - pub fn virtual_file_type_to_wasi_file_type(file_type: virtual_fs::FileType) -> Filetype { // TODO: handle other file types if file_type.is_dir() { diff --git a/lib/wasix/src/lib.rs b/lib/wasix/src/lib.rs index b273a4f5e89..c7b70385dd1 100644 --- a/lib/wasix/src/lib.rs +++ b/lib/wasix/src/lib.rs @@ -84,7 +84,7 @@ pub use virtual_net::{ use wasmer_wasix_types::wasi::{Errno, ExitCode}; pub use crate::{ - fs::{default_fs_backing, Fd, WasiFs, WasiInodes, VIRTUAL_ROOT_FD}, + fs::{Fd, WasiFs, WasiInodes, VIRTUAL_ROOT_FD}, os::{ task::{ control_plane::WasiControlPlane, diff --git a/lib/wasix/src/os/console/mod.rs b/lib/wasix/src/os/console/mod.rs index a56b89d7130..b52bf65e396 100644 --- a/lib/wasix/src/os/console/mod.rs +++ b/lib/wasix/src/os/console/mod.rs @@ -225,13 +225,7 @@ impl Console { .with_stdin(Box::new(self.stdin.clone())) .with_stdout(Box::new(self.stdout.clone())) .with_stderr(Box::new(self.stderr.clone())) - .prepare_webc_env( - prog, - &wasi_opts, - Some(&pkg), - self.runtime.clone(), - Some(root_fs), - ) + .prepare_webc_env(prog, &wasi_opts, Some(&pkg), self.runtime.clone()) // TODO: better error conversion .map_err(|err| SpawnError::Other(err.into()))?; @@ -244,20 +238,6 @@ impl Console { let wasi_process = env.process.clone(); - if let Err(err) = env.uses(self.uses.clone()) { - let mut stderr = self.stderr.clone(); - InlineWaker::block_on(async { - virtual_fs::AsyncWriteExt::write_all( - &mut stderr, - format!("{}\r\n", err).as_bytes(), - ) - .await - .ok(); - }); - tracing::debug!("failed to load used dependency - {}", err); - return Err(SpawnError::BadRequest); - } - // The custom readonly files have to be added after the uses packages // otherwise they will be overriden by their attached file systems for (path, data) in self.ro_files.clone() { diff --git a/lib/wasix/src/runners/wasi.rs b/lib/wasix/src/runners/wasi.rs index f1461315066..0885d443d34 100644 --- a/lib/wasix/src/runners/wasi.rs +++ b/lib/wasix/src/runners/wasi.rs @@ -32,6 +32,12 @@ impl WasiRunner { WasiRunner::default() } + /// Builder method to provide a filesystem to the runner + pub fn with_fs(mut self, fs: TmpFileSystem) -> Self { + self.wasi.fs = Some(fs); + self + } + /// Returns the current arguments for this `WasiRunner` pub fn get_args(&self) -> Vec { self.wasi.args.clone() @@ -64,7 +70,7 @@ impl WasiRunner { /// Provide environment variables to the runner. pub fn set_env(&mut self, key: impl Into, value: impl Into) { - self.wasi.env.insert(key.into(), value.into()); + self.wasi.env.push((key.into(), value.into())); } pub fn with_envs(mut self, envs: I) -> Self @@ -84,7 +90,7 @@ impl WasiRunner { V: Into, { for (key, value) in envs { - self.wasi.env.insert(key.into(), value.into()); + self.wasi.env.push((key.into(), value.into())); } } @@ -112,6 +118,7 @@ impl WasiRunner { self.wasi.current_dir = Some(dir.into()); } + /// Builder method to provide the current Dir pub fn with_current_dir(mut self, dir: impl Into) -> Self { self.set_current_dir(dir); self @@ -220,24 +227,14 @@ impl WasiRunner { #[tracing::instrument(level = "debug", skip_all)] pub(crate) fn prepare_webc_env( - &self, + &mut self, program_name: &str, wasi: &Wasi, pkg: Option<&BinaryPackage>, runtime: Arc, - root_fs: Option, ) -> Result { - let mut builder = WasiEnvBuilder::new(program_name).runtime(runtime); - - let container_fs = if let Some(pkg) = pkg { - builder.add_webc(pkg.clone()); - Some(Arc::clone(&pkg.webc_fs)) - } else { - None - }; - - self.wasi - .prepare_webc_env(&mut builder, container_fs, wasi, root_fs)?; + let mut builder = WasiEnvBuilder::new(program_name); + self.wasi.prepare_webc_env(&mut builder, wasi, pkg)?; if let Some(stdin) = &self.stdin { builder.set_stdin(Box::new(stdin.clone())); @@ -248,20 +245,30 @@ impl WasiRunner { if let Some(stderr) = &self.stderr { builder.set_stderr(Box::new(stderr.clone())); } + if let Some(current_dir) = &self.wasi.current_dir { + builder.set_current_dir(current_dir); + } + + builder.set_runtime(runtime); + + if let Some(root_fs) = self.wasi.fs.take() { + self.wasi.set_filesystem(&mut builder, root_fs)?; + } Ok(builder) } pub fn run_wasm( - &self, + &mut self, runtime: Arc, program_name: &str, module: &Module, + pkg: Option<&BinaryPackage>, asyncify: bool, ) -> Result<(), Error> { let wasi = webc::metadata::annotations::Wasi::new(program_name); let mut store = runtime.new_store(); - let env = self.prepare_webc_env(program_name, &wasi, None, runtime, None)?; + let env = self.prepare_webc_env(program_name, &wasi, pkg, runtime)?; if asyncify { env.run_with_store_async(module.clone(), store)?; @@ -296,7 +303,7 @@ impl crate::runners::Runner for WasiRunner { .unwrap_or_else(|| Wasi::new(command_name)); let env = self - .prepare_webc_env(command_name, &wasi, Some(pkg), Arc::clone(&runtime), None) + .prepare_webc_env(command_name, &wasi, Some(pkg), Arc::clone(&runtime)) .context("Unable to prepare the WASI environment")? .build()?; diff --git a/lib/wasix/src/runners/wasi_common.rs b/lib/wasix/src/runners/wasi_common.rs index d02fa7d2185..7daf815bcaf 100644 --- a/lib/wasix/src/runners/wasi_common.rs +++ b/lib/wasix/src/runners/wasi_common.rs @@ -1,12 +1,8 @@ -use std::{ - collections::HashMap, - path::{Path, PathBuf}, - sync::Arc, -}; +use std::collections::HashMap; +use std::path::PathBuf; -use anyhow::{Context, Error}; -use futures::future::BoxFuture; -use virtual_fs::{FileSystem, FsError, OverlayFileSystem, RootFileSystemBuilder, TmpFileSystem}; +use anyhow::Error; +use virtual_fs::TmpFileSystem; use webc::metadata::annotations::Wasi as WasiAnnotation; use crate::{ @@ -25,12 +21,13 @@ pub struct MappedCommand { #[derive(Debug, Default, Clone)] pub(crate) struct CommonWasiOptions { pub(crate) args: Vec, - pub(crate) env: HashMap, + pub(crate) env: Vec<(String, String)>, pub(crate) forward_host_env: bool, pub(crate) mapped_dirs: Vec, pub(crate) mapped_host_commands: Vec, pub(crate) injected_packages: Vec, pub(crate) capabilities: Capabilities, + pub(crate) fs: Option, pub(crate) current_dir: Option, } @@ -38,22 +35,9 @@ impl CommonWasiOptions { pub(crate) fn prepare_webc_env( &self, builder: &mut WasiEnvBuilder, - container_fs: Option>, wasi: &WasiAnnotation, - root_fs: Option, + base_pkg: Option<&BinaryPackage>, ) -> Result<(), anyhow::Error> { - let root_fs = root_fs.unwrap_or_else(|| RootFileSystemBuilder::default().build()); - let fs = prepare_filesystem(root_fs, &self.mapped_dirs, container_fs, builder)?; - - builder.add_preopen_dir("/")?; - - if self.mapped_dirs.iter().all(|m| m.guest != ".") { - // The user hasn't mounted "." to anything, so let's map it to "/" - builder.add_map_dir(".", "/")?; - } - - builder.set_fs(Box::new(fs)); - for pkg in &self.injected_packages { builder.add_webc(pkg.clone()); } @@ -63,6 +47,9 @@ impl CommonWasiOptions { .iter() .map(|c| (c.alias.as_str(), c.target.as_str())); builder.add_mapped_commands(mapped_cmds); + if let Some(pkg) = base_pkg { + builder.set_package(pkg.clone()); + } self.populate_env(wasi, builder); self.populate_args(wasi, builder); @@ -101,220 +88,22 @@ impl CommonWasiOptions { builder.add_args(&self.args); } -} - -// type ContainerFs = -// OverlayFileSystem>; 1]>; - -fn build_directory_mappings( - builder: &mut WasiEnvBuilder, - root_fs: &mut TmpFileSystem, - host_fs: &Arc, - mapped_dirs: &[MappedDirectory], -) -> Result<(), anyhow::Error> { - for dir in mapped_dirs { - let MappedDirectory { - host: host_path, - guest: guest_path, - } = dir; - let mut guest_path = PathBuf::from(guest_path); - tracing::debug!( - guest=%guest_path.display(), - host=%host_path.display(), - "Mounting host folder", - ); - - if guest_path.is_relative() { - guest_path = apply_relative_path_mounting_hack(&guest_path); - } - - let host_path = std::fs::canonicalize(host_path).with_context(|| { - format!("Unable to canonicalize host path '{}'", host_path.display()) - })?; - - let guest_path = root_fs - .canonicalize_unchecked(&guest_path) - .with_context(|| { - format!( - "Unable to canonicalize guest path '{}'", - guest_path.display() - ) - })?; - - if guest_path == Path::new("/") { - root_fs - .mount_directory_entries(&guest_path, host_fs, &host_path) - .with_context(|| format!("Unable to mount \"{}\" to root", host_path.display(),))?; - } else { - if let Some(parent) = guest_path.parent() { - create_dir_all(root_fs, parent).with_context(|| { - format!("Unable to create the \"{}\" directory", parent.display()) - })?; - } - - root_fs - .mount(guest_path.clone(), host_fs, host_path.clone()) - .with_context(|| { - format!( - "Unable to mount \"{}\" to \"{}\"", - host_path.display(), - guest_path.display() - ) - })?; - - builder - .add_preopen_dir(&guest_path) - .with_context(|| format!("Unable to preopen \"{}\"", guest_path.display()))?; - } - } - - Ok(()) -} - -fn prepare_filesystem( - mut root_fs: TmpFileSystem, - mapped_dirs: &[MappedDirectory], - container_fs: Option>, - builder: &mut WasiEnvBuilder, -) -> Result, Error> { - if !mapped_dirs.is_empty() { - let host_fs: Arc = Arc::new(crate::default_fs_backing()); - build_directory_mappings(builder, &mut root_fs, &host_fs, mapped_dirs)?; - } - - // HACK(Michael-F-Bryan): The WebcVolumeFileSystem only accepts relative - // paths, but our Python executable will try to access its standard library - // with relative paths assuming that it is being run from the root - // directory (i.e. it does `open("lib/python3.6/io.py")` instead of - // `open("/lib/python3.6/io.py")`). - // Until the FileSystem trait figures out whether relative paths should be - // supported or not, we'll add an adapter that automatically retries - // operations using an absolute path if it failed using a relative path. - - let fs = if let Some(container) = container_fs { - let container = RelativeOrAbsolutePathHack(container); - let fs = OverlayFileSystem::new(root_fs, [container]); - Box::new(fs) as Box - } else { - let fs = RelativeOrAbsolutePathHack(root_fs); - Box::new(fs) as Box - }; - - Ok(fs) -} - -/// HACK: We need this so users can mount host directories at relative paths. -/// This assumes that the current directory when a runner starts will be "/", so -/// instead of mounting to a relative path, we just mount to "/$path". -/// -/// This isn't really a long-term solution because there is no guarantee what -/// the current directory will be. The WASI spec also doesn't require the -/// current directory to be part of the "main" filesystem at all, we really -/// *should* be mounting to a relative directory but that isn't supported by our -/// virtual fs layer. -/// -/// See for more. -fn apply_relative_path_mounting_hack(original: &Path) -> PathBuf { - debug_assert!(original.is_relative()); - - let root = Path::new("/"); - let mapped_path = if original == Path::new(".") { - root.to_path_buf() - } else { - root.join(original) - }; - - tracing::debug!( - original_path=%original.display(), - remapped_path=%mapped_path.display(), - "Remapping a relative path" - ); - - mapped_path -} - -fn create_dir_all(fs: &dyn FileSystem, path: &Path) -> Result<(), Error> { - if fs.metadata(path).is_ok() { - return Ok(()); - } - - if let Some(parent) = path.parent() { - create_dir_all(fs, parent)?; - } - - fs.create_dir(path)?; - - Ok(()) -} - -#[derive(Debug)] -struct RelativeOrAbsolutePathHack(F); - -impl RelativeOrAbsolutePathHack { - fn execute(&self, path: &Path, operation: Func) -> Result - where - Func: Fn(&F, &Path) -> Result, - { - // First, try it with the path we were given - let result = operation(&self.0, path); - - if result.is_err() && !path.is_absolute() { - // we were given a relative path, but maybe the operation will work - // using absolute paths instead. - let path = Path::new("/").join(path); - operation(&self.0, &path) - } else { - result - } - } -} -impl virtual_fs::FileSystem for RelativeOrAbsolutePathHack { - fn read_dir(&self, path: &Path) -> virtual_fs::Result { - self.execute(path, |fs, p| fs.read_dir(p)) - } - - fn create_dir(&self, path: &Path) -> virtual_fs::Result<()> { - self.execute(path, |fs, p| fs.create_dir(p)) - } - - fn remove_dir(&self, path: &Path) -> virtual_fs::Result<()> { - self.execute(path, |fs, p| fs.remove_dir(p)) - } - - fn rename<'a>(&'a self, from: &Path, to: &Path) -> BoxFuture<'a, virtual_fs::Result<()>> { - let from = from.to_owned(); - let to = to.to_owned(); - Box::pin(async move { self.0.rename(&from, &to).await }) - } - - fn metadata(&self, path: &Path) -> virtual_fs::Result { - self.execute(path, |fs, p| fs.metadata(p)) - } - - fn remove_file(&self, path: &Path) -> virtual_fs::Result<()> { - self.execute(path, |fs, p| fs.remove_file(p)) - } - - fn new_open_options(&self) -> virtual_fs::OpenOptions { - virtual_fs::OpenOptions::new(self) - } -} - -impl virtual_fs::FileOpener for RelativeOrAbsolutePathHack { - fn open( + pub(crate) fn set_filesystem( &self, - path: &Path, - conf: &virtual_fs::OpenOptionsConfig, - ) -> virtual_fs::Result> { - self.execute(path, |fs, p| { - fs.new_open_options().options(conf.clone()).open(p) - }) + builder: &mut WasiEnvBuilder, + root_fs: TmpFileSystem, + ) -> Result<(), Error> { + builder.set_sandbox_fs(root_fs); + builder.add_preopen_dir("/")?; + // builder.add_preopen_dir("/home")?; + Ok(()) } } #[cfg(test)] mod tests { + use std::sync::Arc; use tempfile::TempDir; use virtual_fs::WebcVolumeFileSystem; @@ -340,7 +129,7 @@ mod tests { "args".to_string(), ]); - args.prepare_webc_env(&mut builder, Some(fs), &annotations, None) + args.prepare_webc_env(&mut builder, &annotations, None) .unwrap(); assert_eq!( @@ -372,7 +161,7 @@ mod tests { let mut annotations = WasiAnnotation::new("python"); annotations.env = Some(vec!["HARD_CODED=env-vars".to_string()]); - args.prepare_webc_env(&mut builder, Some(fs), &annotations, None) + args.prepare_webc_env(&mut builder, &annotations, None) .unwrap(); assert_eq!( @@ -384,33 +173,30 @@ mod tests { ); } - #[tokio::test] - async fn python_use_case() { - let temp = TempDir::new().unwrap(); - let sub_dir = temp.path().join("path").join("to"); - std::fs::create_dir_all(&sub_dir).unwrap(); - std::fs::write(sub_dir.join("file.txt"), b"Hello, World!").unwrap(); - let mapping = [MappedDirectory { - guest: "/home".to_string(), - host: sub_dir, - }]; - let container = Container::from_bytes(PYTHON).unwrap(); - let webc_fs = WebcVolumeFileSystem::mount_all(&container); - let mut builder = WasiEnvBuilder::new(""); - - let root_fs = RootFileSystemBuilder::default().build(); - let fs = - prepare_filesystem(root_fs, &mapping, Some(Arc::new(webc_fs)), &mut builder).unwrap(); - - assert!(fs.metadata("/home/file.txt".as_ref()).unwrap().is_file()); - assert!(fs.metadata("lib".as_ref()).unwrap().is_dir()); - assert!(fs - .metadata("lib/python3.6/collections/__init__.py".as_ref()) - .unwrap() - .is_file()); - assert!(fs - .metadata("lib/python3.6/encodings/__init__.py".as_ref()) - .unwrap() - .is_file()); - } + // #[tokio::test] + // async fn python_use_case() { + // let temp = TempDir::new().unwrap(); + // let sub_dir = temp.path().join("path").join("to"); + // std::fs::create_dir_all(&sub_dir).unwrap(); + // std::fs::write(sub_dir.join("file.txt"), b"Hello, World!").unwrap(); + // let container = Container::from_bytes(PYTHON).unwrap(); + // let webc_fs = WebcVolumeFileSystem::mount_all(&container); + // let mut builder = WasiEnvBuilder::new(""); + + // let mut root_fs = RootFileSystemBuilder::default().build(); + // let home = virtual_fs::host::FileSystem::new(sub_dir); + // root_fs.mount(PathBuf::from("/home"), home, PathBuf::new()); + // let fs = prepare_filesystem(root_fs, Arc::new(webc_fs)).unwrap(); + + // assert!(fs.metadata("/home/file.txt".as_ref()).unwrap().is_file()); + // assert!(fs.metadata("lib".as_ref()).unwrap().is_dir()); + // assert!(fs + // .metadata("lib/python3.6/collections/__init__.py".as_ref()) + // .unwrap() + // .is_file()); + // assert!(fs + // .metadata("lib/python3.6/encodings/__init__.py".as_ref()) + // .unwrap() + // .is_file()); + // } } diff --git a/lib/wasix/src/runners/wcgi/runner.rs b/lib/wasix/src/runners/wcgi/runner.rs index 200481c9425..c45afab9f17 100644 --- a/lib/wasix/src/runners/wcgi/runner.rs +++ b/lib/wasix/src/runners/wcgi/runner.rs @@ -7,6 +7,8 @@ use hyper::Body; use tower::{make::Shared, ServiceBuilder}; use tower_http::{catch_panic::CatchPanicLayer, cors::CorsLayer, trace::TraceLayer}; use tracing::Span; +use virtual_fs::RootFileSystemBuilder; +use virtual_fs::TmpFileSystem; use wcgi_host::CgiDialect; use webc::metadata::{ annotations::{Wasi, Wcgi}, @@ -62,12 +64,18 @@ impl WcgiRunner { None => CgiDialect::Wcgi, }; - let container_fs = Arc::clone(&pkg.webc_fs); - let wasi_common = self.config.wasi.clone(); let rt = Arc::clone(&runtime); + + let root_fs = wasi_common + .fs + .clone() + .unwrap_or_else(|| RootFileSystemBuilder::default().build()); + + let pkg = pkg.clone(); let setup_builder = move |builder: &mut WasiEnvBuilder| { - wasi_common.prepare_webc_env(builder, Some(Arc::clone(&container_fs)), &wasi, None)?; + wasi_common.prepare_webc_env(builder, &wasi, Some(&pkg))?; + wasi_common.set_filesystem(builder, root_fs.clone())?; builder.set_runtime(Arc::clone(&rt)); Ok(()) @@ -157,6 +165,12 @@ pub struct Config { } impl Config { + /// Builder method to provide a filesystem to the runner + pub fn with_fs(&mut self, fs: TmpFileSystem) -> &mut Self { + self.wasi.fs = Some(fs); + self + } + pub fn addr(&mut self, addr: SocketAddr) -> &mut Self { self.addr = addr; self @@ -180,7 +194,7 @@ impl Config { /// Expose an environment variable to the guest. pub fn env(&mut self, name: impl Into, value: impl Into) -> &mut Self { - self.wasi.env.insert(name.into(), value.into()); + self.wasi.env.push((name.into(), value.into())); self } diff --git a/lib/wasix/src/runtime/package_loader/load_package_tree.rs b/lib/wasix/src/runtime/package_loader/load_package_tree.rs index b92337c8845..93d55ddd11a 100644 --- a/lib/wasix/src/runtime/package_loader/load_package_tree.rs +++ b/lib/wasix/src/runtime/package_loader/load_package_tree.rs @@ -291,27 +291,10 @@ fn count_file_system(fs: &dyn FileSystem, path: &Path) -> u64 { /// Given a set of [`ResolvedFileSystemMapping`]s and the [`Container`] for each /// package in a dependency tree, construct the resulting filesystem. /// -/// # Note to future readers -/// -/// Sooo... this code is a bit convoluted because we're constrained by the -/// filesystem implementations we've got available. -/// -/// Ideally, we would create a WebcVolumeFileSystem for each volume we're -/// using, then we'd have a single "union" filesystem which lets you mount -/// filesystem objects under various paths and can deal with conflicts. -/// /// The OverlayFileSystem lets us make files from multiple filesystem /// implementations available at the same time, however all of the /// filesystems will be mounted at "/", when the user wants to mount volumes /// at arbitrary locations. -/// -/// The TmpFileSystem *does* allow mounting at non-root paths, however it can't -/// handle nested paths (e.g. mounting to "/lib" and "/lib/python3.10" - see -/// for more) and you aren't -/// allowed to mount to "/" because it's a special directory that already -/// exists. -/// -/// As a result, we'll duct-tape things together and hope for the best 🤞 fn filesystem( packages: &HashMap, pkg: &ResolvedPackage, @@ -324,9 +307,9 @@ fn filesystem( for ResolvedFileSystemMapping { mount_path, + original_path, volume_name, package, - original_path, } in &pkg.filesystem { // Note: We want to reuse existing Volume instances if we can. That way @@ -346,17 +329,24 @@ fn filesystem( } }; - let volume = container_volumes.get(volume_name).with_context(|| { - format!("The \"{package}\" package doesn't have a \"{volume_name}\" volume") - })?; + let volume = if let Some(volume) = container_volumes.get(volume_name) { + volume + } else { + tracing::debug!("The \"{package}\" package doesn't have a \"{volume_name}\" volume"); + continue; + }; let original_path = PathBuf::from(original_path); - let mount_path = mount_path.clone(); - // Get a filesystem which will map "$mount_dir/some-path" to - // "$original_path/some-path" on the original volume + let mount_path = if mount_path.is_relative() { + PathBuf::from("/home").join(mount_path) + } else { + mount_path.clone() + }; + + // let fs = WebcVolumeFileSystem::new(volume.clone()); let fs = MappedPathFileSystem::new(WebcVolumeFileSystem::new(volume.clone()), move |path| { - let without_mount_dir = path + let without_mount_dir: &Path = path .strip_prefix(&mount_path) .map_err(|_| virtual_fs::FsError::BaseNotDirectory)?; let path_on_original_volume = original_path.join(without_mount_dir); @@ -400,6 +390,9 @@ where F: FileSystem, M: Fn(&Path) -> Result + Send + Sync + 'static, { + fn as_dir(&self) -> Box { + self.inner.as_dir() + } fn read_dir(&self, path: &Path) -> virtual_fs::Result { let path = self.path(path)?; self.inner.read_dir(&path) diff --git a/lib/wasix/src/runtime/resolver/inputs.rs b/lib/wasix/src/runtime/resolver/inputs.rs index a232c46c1bb..904e5dd8c12 100644 --- a/lib/wasix/src/runtime/resolver/inputs.rs +++ b/lib/wasix/src/runtime/resolver/inputs.rs @@ -195,9 +195,10 @@ pub struct PackageInfo { impl PackageInfo { pub fn from_manifest(manifest: &Manifest) -> Result { - let WapmAnnotations { name, version, .. } = manifest + let (name, version) = manifest .wapm()? - .context("Unable to find the \"wapm\" annotations")?; + .map(|WapmAnnotations { name, version, .. }| (name, version)) + .unwrap_or(("unnamed-package".to_owned(), "0.0.0".to_owned())); let dependencies = manifest .use_map diff --git a/lib/wasix/src/state/builder.rs b/lib/wasix/src/state/builder.rs index f3096f5a3fa..c93c85006a1 100644 --- a/lib/wasix/src/state/builder.rs +++ b/lib/wasix/src/state/builder.rs @@ -9,6 +9,7 @@ use std::{ use bytes::Bytes; use rand::Rng; use thiserror::Error; +use virtual_fs::OverlayFileSystem; use virtual_fs::{ArcFile, FileSystem, FsError, TmpFileSystem, VirtualFile}; use wasmer::{AsStoreMut, Instance, Module, RuntimeError, Store}; use wasmer_wasix_types::wasi::{Errno, ExitCode}; @@ -18,7 +19,7 @@ use crate::PluggableRuntime; use crate::{ bin_factory::{BinFactory, BinaryPackage}, capabilities::Capabilities, - fs::{WasiFs, WasiFsRoot, WasiInodes}, + fs::{WasiFs, WasiInodes}, os::task::control_plane::{ControlPlaneConfig, ControlPlaneError, WasiControlPlane}, runtime::task_manager::InlineWaker, state::WasiState, @@ -60,7 +61,8 @@ pub struct WasiEnvBuilder { pub(super) stdout: Option>, pub(super) stderr: Option>, pub(super) stdin: Option>, - pub(super) fs: Option, + pub(super) fs: Option>, + pub(super) pkg: Option, pub(super) runtime: Option>, pub(super) current_dir: Option, @@ -272,6 +274,17 @@ impl WasiEnvBuilder { &mut self.args } + /// Adds the main package to inherit from (useful for the filesystem) + pub fn with_package(mut self, pkg: BinaryPackage) -> Self { + self.set_package(pkg); + self + } + + /// Adds the main package to inherit from (useful for the filesystem) + pub fn set_package(&mut self, pkg: BinaryPackage) { + self.pkg = Some(pkg); + } + /// Adds a container this module inherits from. /// /// This will make all of the container's files and commands available to the @@ -555,17 +568,24 @@ impl WasiEnvBuilder { } pub fn set_fs(&mut self, fs: Box) { - self.fs = Some(WasiFsRoot::Backing(Arc::new(fs))); + self.fs = Some(Arc::new(fs)); } /// Sets a new sandbox FileSystem to be used with this WASI instance. /// /// This is usually used in case a custom `virtual_fs::FileSystem` is needed. pub fn sandbox_fs(mut self, fs: TmpFileSystem) -> Self { - self.fs = Some(WasiFsRoot::Sandbox(Arc::new(fs))); + self.set_sandbox_fs(fs); self } + /// Sets a new sandbox FileSystem to be used with this WASI instance. + /// + /// This is usually used in case a custom `virtual_fs::FileSystem` is needed. + pub fn set_sandbox_fs(&mut self, fs: TmpFileSystem) { + self.fs = Some(Arc::new(fs)); + } + /// Configure the WASI filesystem before running. // TODO: improve ergonomics on this function pub fn setup_fs(mut self, setup_fs_fn: SetupFsFn) -> Self { @@ -671,10 +691,10 @@ impl WasiEnvBuilder { .take() .unwrap_or_else(|| Box::new(ArcFile::new(Box::::default()))); - let fs_backing = self + let mut fs_backing = self .fs .take() - .unwrap_or_else(|| WasiFsRoot::Sandbox(Arc::new(TmpFileSystem::new()))); + .unwrap_or_else(|| Arc::new(TmpFileSystem::new())); if let Some(dir) = &self.current_dir { match fs_backing.read_dir(dir) { @@ -698,6 +718,94 @@ impl WasiEnvBuilder { } } + let envs = self + .envs + .into_iter() + .map(|(key, value)| { + let mut env = Vec::with_capacity(key.len() + value.len() + 1); + env.extend_from_slice(key.as_bytes()); + env.push(b'='); + env.extend_from_slice(&value); + + env + }) + .collect(); + + let runtime = self.runtime.unwrap_or_else(|| { + #[cfg(feature = "sys-thread")] + { + Arc::new(PluggableRuntime::new(Arc::new(crate::runtime::task_manager::tokio::TokioTaskManager::default()))) + } + + #[cfg(not(feature = "sys-thread"))] + { + panic!("this build does not support a default runtime - specify one with WasiEnvBuilder::runtime()"); + } + }); + + let map_commands = self.map_commands; + + let bin_factory = BinFactory::new(runtime.clone()); + + if let Some(pkg) = self.pkg { + // Make all the commands in a [`BinaryPackage`] available to the WASI + // instance. + // + // The [`BinaryPackageCommand::atom()`][cmd-atom] will be saved to + // `/bin/command`. + // + // This will also merge the command's filesystem + // ([`BinaryPackage::webc_fs`][pkg-fs]) into the current filesystem. + // + // [cmd-atom]: crate::bin_factory::BinaryPackageCommand::atom() + // [pkg-fs]: crate::bin_factory::BinaryPackage::webc_fs + let root_fs = &fs_backing; + + // Next, make sure all commands will be available + + if !pkg.commands.is_empty() { + let bin_path = Path::new("/bin"); + let _ = root_fs.create_dir(bin_path); + + for command in &pkg.commands { + let path = bin_path.join(command.name()); + + // FIXME(Michael-F-Bryan): This is pretty sketchy. + // We should be using some sort of reference-counted + // pointer to some bytes that are either on the heap + // or from a memory-mapped file. However, that's not + // possible here because things like memfs and + // WasiEnv are expecting a Cow<'static, [u8]>. It's + // too hard to refactor those at the moment, and we + // were pulling the same trick before by storing an + // "ownership" object in the BinaryPackageCommand, + // so as long as packages aren't removed from the + // module cache it should be fine. + // See https://github.com/wasmerio/wasmer/issues/3875 + let atom: &'static [u8] = unsafe { std::mem::transmute(command.atom()) }; + + let mut f = root_fs + .new_open_options() + .create(true) + .write(true) + .open(&path)?; + f.copy_reference(Box::new(virtual_fs::StaticFile::new(atom.into()))); + + let mut package = pkg.clone(); + package.entrypoint_cmd = Some(command.name().to_string()); + bin_factory.set_binary(path.as_os_str().to_string_lossy().as_ref(), package); + + tracing::debug!( + package=%pkg.package_name, + command_name=command.name(), + path=%path.display(), + "Injected a command into the filesystem", + ); + } + } + fs_backing = Arc::new(OverlayFileSystem::new(fs_backing, [pkg.webc_fs])); + } + // self.preopens are checked in [`PreopenDirBuilder::build`] let inodes = crate::state::WasiInodes::new(); let wasi_fs = { @@ -739,19 +847,6 @@ impl WasiEnvBuilder { wasi_fs.set_current_dir(s); } - let envs = self - .envs - .into_iter() - .map(|(key, value)| { - let mut env = Vec::with_capacity(key.len() + value.len() + 1); - env.extend_from_slice(key.as_bytes()); - env.push(b'='); - env.extend_from_slice(&value); - - env - }) - .collect(); - let state = WasiState { fs: wasi_fs, secret: rand::thread_rng().gen::<[u8; 32]>(), @@ -763,23 +858,6 @@ impl WasiEnvBuilder { envs, }; - let runtime = self.runtime.unwrap_or_else(|| { - #[cfg(feature = "sys-thread")] - { - Arc::new(PluggableRuntime::new(Arc::new(crate::runtime::task_manager::tokio::TokioTaskManager::default()))) - } - - #[cfg(not(feature = "sys-thread"))] - { - panic!("this build does not support a default runtime - specify one with WasiEnvBuilder::runtime()"); - } - }); - - let uses = self.uses; - let map_commands = self.map_commands; - - let bin_factory = BinFactory::new(runtime.clone()); - let capabilities = self.capabilites; let plane_config = ControlPlaneConfig { @@ -791,7 +869,6 @@ impl WasiEnvBuilder { let init = WasiEnvInit { state, runtime, - webc_dependencies: uses, mapped_commands: map_commands, control_plane, bin_factory, diff --git a/lib/wasix/src/state/env.rs b/lib/wasix/src/state/env.rs index 94aa03f4f15..4039cf239eb 100644 --- a/lib/wasix/src/state/env.rs +++ b/lib/wasix/src/state/env.rs @@ -1,15 +1,9 @@ -use std::{ - collections::HashMap, - ops::Deref, - path::{Path, PathBuf}, - sync::Arc, - time::Duration, -}; +use std::{collections::HashMap, ops::Deref, path::PathBuf, sync::Arc, time::Duration}; use derivative::Derivative; use futures::future::BoxFuture; use rand::Rng; -use virtual_fs::{FileSystem, FsError, StaticFile, VirtualFile}; +use virtual_fs::{FileSystem, FsError, VirtualFile}; use virtual_net::DynVirtualNetworking; use wasmer::{ AsStoreMut, AsStoreRef, FunctionEnvMut, Global, Instance, Memory, MemoryType, MemoryView, @@ -21,16 +15,16 @@ use wasmer_wasix_types::{ }; use crate::{ - bin_factory::{BinFactory, BinaryPackage}, + bin_factory::BinFactory, capabilities::Capabilities, - fs::{WasiFsRoot, WasiInodes}, + fs::WasiInodes, import_object_for_all_wasi_versions, os::task::{ control_plane::ControlPlaneError, process::{WasiProcess, WasiProcessId}, thread::{WasiMemoryLayout, WasiThread, WasiThreadHandle, WasiThreadId}, }, - runtime::{resolver::PackageSpecifier, task_manager::InlineWaker, SpawnMemoryType}, + runtime::{task_manager::InlineWaker, SpawnMemoryType}, syscalls::platform_clock_time_get, Runtime, VirtualTaskManager, WasiControlPlane, WasiEnvBuilder, WasiError, WasiFunctionEnv, WasiRuntimeError, WasiStateCreationError, WasiVFork, @@ -210,7 +204,6 @@ impl WasiInstanceHandles { pub struct WasiEnvInit { pub(crate) state: WasiState, pub runtime: Arc, - pub webc_dependencies: Vec, pub mapped_commands: HashMap, pub bin_factory: BinFactory, pub capabilities: Capabilities, @@ -254,7 +247,6 @@ impl WasiEnvInit { preopen: self.state.preopen.clone(), }, runtime: self.runtime.clone(), - webc_dependencies: self.webc_dependencies.clone(), mapped_commands: self.mapped_commands.clone(), bin_factory: self.bin_factory.clone(), capabilities: self.capabilities.clone(), @@ -427,11 +419,6 @@ impl WasiEnv { }; env.owned_handles.push(thread); - // TODO: should not be here - should be callers responsibility! - for pkg in &init.webc_dependencies { - env.use_package(pkg)?; - } - #[cfg(feature = "sys")] env.map_commands(init.mapped_commands.clone())?; @@ -547,7 +534,7 @@ impl WasiEnv { self.runtime.task_manager() } - pub fn fs_root(&self) -> &WasiFsRoot { + pub fn fs_root(&self) -> &dyn FileSystem { &self.state.fs.root_fs } @@ -870,123 +857,6 @@ impl WasiEnv { (state, inodes) } - /// Make all the commands in a [`BinaryPackage`] available to the WASI - /// instance. - /// - /// The [`BinaryPackageCommand::atom()`][cmd-atom] will be saved to - /// `/bin/command`. - /// - /// This will also merge the command's filesystem - /// ([`BinaryPackage::webc_fs`][pkg-fs]) into the current filesystem. - /// - /// [cmd-atom]: crate::bin_factory::BinaryPackageCommand::atom() - /// [pkg-fs]: crate::bin_factory::BinaryPackage::webc_fs - pub fn use_package(&self, pkg: &BinaryPackage) -> Result<(), WasiStateCreationError> { - tracing::trace!(packagae=%pkg.package_name, "merging package dependency into wasi environment"); - let root_fs = &self.state.fs.root_fs; - - // We first need to copy any files in the package over to the - // main file system - if let Err(e) = InlineWaker::block_on(root_fs.merge(&pkg.webc_fs)) { - tracing::warn!( - error = &e as &dyn std::error::Error, - "Unable to merge the package's filesystem into the main one", - ); - } - - // Next, make sure all commands will be available - - if !pkg.commands.is_empty() { - let _ = root_fs.create_dir(Path::new("/bin")); - - for command in &pkg.commands { - let path = format!("/bin/{}", command.name()); - let path = Path::new(path.as_str()); - - // FIXME(Michael-F-Bryan): This is pretty sketchy. - // We should be using some sort of reference-counted - // pointer to some bytes that are either on the heap - // or from a memory-mapped file. However, that's not - // possible here because things like memfs and - // WasiEnv are expecting a Cow<'static, [u8]>. It's - // too hard to refactor those at the moment, and we - // were pulling the same trick before by storing an - // "ownership" object in the BinaryPackageCommand, - // so as long as packages aren't removed from the - // module cache it should be fine. - // See https://github.com/wasmerio/wasmer/issues/3875 - let atom: &'static [u8] = unsafe { std::mem::transmute(command.atom()) }; - - match root_fs { - WasiFsRoot::Sandbox(root_fs) => { - // As a short-cut, when we are using a TmpFileSystem - // we can (unsafely) add the file to the filesystem - // without any copying. - if let Err(err) = root_fs - .new_open_options_ext() - .insert_ro_file(path, atom.into()) - { - tracing::debug!( - "failed to add package [{}] command [{}] - {}", - pkg.package_name, - command.name(), - err - ); - continue; - } - } - WasiFsRoot::Backing(fs) => { - let mut f = fs.new_open_options().create(true).write(true).open(path)?; - f.copy_reference(Box::new(StaticFile::new(atom.into()))); - } - } - - let mut package = pkg.clone(); - package.entrypoint_cmd = Some(command.name().to_string()); - self.bin_factory - .set_binary(path.as_os_str().to_string_lossy().as_ref(), package); - - tracing::debug!( - package=%pkg.package_name, - command_name=command.name(), - path=%path.display(), - "Injected a command into the filesystem", - ); - } - } - - Ok(()) - } - - /// Given a list of packages, load them from the registry and make them - /// available. - pub fn uses(&self, uses: I) -> Result<(), WasiStateCreationError> - where - I: IntoIterator, - { - let rt = self.runtime(); - - for package_name in uses { - let specifier = package_name.parse::().map_err(|e| { - WasiStateCreationError::WasiIncludePackageError(format!( - "package_name={package_name}, {}", - e - )) - })?; - let pkg = InlineWaker::block_on(BinaryPackage::from_registry(&specifier, rt)).map_err( - |e| { - WasiStateCreationError::WasiIncludePackageError(format!( - "package_name={package_name}, {}", - e - )) - }, - )?; - self.use_package(&pkg)?; - } - - Ok(()) - } - #[cfg(feature = "sys")] pub fn map_commands( &self, @@ -1009,21 +879,16 @@ impl WasiEnv { err )) })?; - let file: std::borrow::Cow<'static, [u8]> = file.into(); + let _file: std::borrow::Cow<'static, [u8]> = file.into(); - if let WasiFsRoot::Sandbox(root_fs) = &self.state.fs.root_fs { - let _ = root_fs.create_dir(Path::new("/bin")); + let _ = self.state.fs.root_fs.create_dir(Path::new("/bin")); - let path = format!("/bin/{}", command); - let path = Path::new(path.as_str()); - if let Err(err) = root_fs.new_open_options_ext().insert_ro_file(path, file) { - tracing::debug!("failed to add atom command [{}] - {}", command, err); - continue; - } - } else { - tracing::debug!("failed to add atom command [{}] to the root file system as it is not sandboxed", command); - continue; - } + let path = format!("/bin/{}", command); + let _path = Path::new(path.as_str()); + // if let Err(err) = self.state.fs.root_fs.new_open_options_ext().insert_ro_file(path, file) { + // tracing::debug!("failed to add atom command [{}] - {}", command, err); + // continue; + // } } Ok(()) } diff --git a/lib/wasix/src/state/mod.rs b/lib/wasix/src/state/mod.rs index e18dac9fbbd..1b2202719cf 100644 --- a/lib/wasix/src/state/mod.rs +++ b/lib/wasix/src/state/mod.rs @@ -24,7 +24,7 @@ mod types; use std::{ collections::{BTreeMap, HashMap}, path::Path, - sync::Mutex, + sync::{Arc, Mutex}, task::Waker, time::Duration, }; @@ -42,7 +42,7 @@ pub use self::{ }; pub use crate::fs::{InodeGuard, InodeWeakGuard}; use crate::{ - fs::{fs_error_into_wasi_err, WasiFs, WasiFsRoot, WasiInodes, WasiStateFileGuard}, + fs::{fs_error_into_wasi_err, WasiFs, WasiInodes, WasiStateFileGuard}, syscalls::types::*, utils::WasiParkingLot, }; @@ -52,7 +52,7 @@ pub(crate) use handles::*; pub const ALL_RIGHTS: Rights = Rights::all(); struct WasiStateOpener { - root_fs: WasiFsRoot, + root_fs: Arc, } impl FileOpener for WasiStateOpener { diff --git a/tests/ignores.txt b/tests/ignores.txt index d32e3e1eb56..04e6d97b371 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -186,40 +186,6 @@ wasitests::nightly_2022_10_18::tmp_fs::readlink wasitests::nightly_2022_10_18::tmp_fs::unix_open_special_files wasitests::nightly_2022_10_18::tmp_fs::writing -wasitests::snapshot1::passthru_fs::close_preopen_fd -wasitests::snapshot1::passthru_fs::create_dir -wasitests::snapshot1::passthru_fs::envvar -wasitests::snapshot1::passthru_fs::fd_allocate -wasitests::snapshot1::passthru_fs::fd_close -wasitests::snapshot1::passthru_fs::fd_pread -wasitests::snapshot1::passthru_fs::fd_read -wasitests::snapshot1::passthru_fs::poll_oneoff -wasitests::snapshot1::passthru_fs::readlink -wasitests::snapshot1::passthru_fs::unix_open_special_files -wasitests::snapshot1::passthru_fs::writing -wasitests::unstable::passthru_fs::close_preopen_fd -wasitests::unstable::passthru_fs::create_dir -wasitests::unstable::passthru_fs::envvar -wasitests::unstable::passthru_fs::fd_allocate -wasitests::unstable::passthru_fs::fd_close -wasitests::unstable::passthru_fs::fd_pread -wasitests::unstable::passthru_fs::fd_read -wasitests::unstable::passthru_fs::poll_oneoff -wasitests::unstable::passthru_fs::readlink -wasitests::unstable::passthru_fs::unix_open_special_files -wasitests::unstable::passthru_fs::writing -wasitests::nightly_2022_10_18::passthru_fs::close_preopen_fd -wasitests::nightly_2022_10_18::passthru_fs::create_dir -wasitests::nightly_2022_10_18::passthru_fs::envvar -wasitests::nightly_2022_10_18::passthru_fs::fd_allocate -wasitests::nightly_2022_10_18::passthru_fs::fd_close -wasitests::nightly_2022_10_18::passthru_fs::fd_pread -wasitests::nightly_2022_10_18::passthru_fs::fd_read -wasitests::nightly_2022_10_18::passthru_fs::poll_oneoff -wasitests::nightly_2022_10_18::passthru_fs::readlink -wasitests::nightly_2022_10_18::passthru_fs::unix_open_special_files -wasitests::nightly_2022_10_18::passthru_fs::writing - wasitests::snapshot1::tmp_fs::close_preopen_fd wasitests::snapshot1::tmp_fs::create_dir wasitests::snapshot1::tmp_fs::envvar @@ -323,7 +289,6 @@ wasitests::nightly_2022_10_18::root_fs::unix_open_special_files wasitests::nightly_2022_10_18::root_fs::writing # These tests are failing in CI for some reason, but didn't fail on older compiler versions -wasitests::nightly_2022_10_18::passthru_fs::path_symlink wasitests::nightly_2022_10_18::root_fs::path_symlink wasitests::nightly_2022_10_18::tmp_fs::path_symlink wasitests::nightly_2022_10_18::union_fs::path_symlink @@ -332,7 +297,6 @@ wasitests::nightly_2022_10_18::host_fs::path_symlink wasitests::nightly_2022_10_18::mem_fs::fd_append wasitests::nightly_2022_10_18::host_fs::fd_append -wasitests::nightly_2022_10_18::passthru_fs::fd_append wasitests::nightly_2022_10_18::root_fs::fd_append wasitests::nightly_2022_10_18::tmp_fs::fd_append wasitests::nightly_2022_10_18::union_fs::fd_append diff --git a/tests/integration/cli/Cargo.toml b/tests/integration/cli/Cargo.toml index efdf9202125..5b4af9bc017 100644 --- a/tests/integration/cli/Cargo.toml +++ b/tests/integration/cli/Cargo.toml @@ -27,7 +27,7 @@ libc = "0.2.147" [dependencies] anyhow = "1" -tempfile = "3.6.0" +tempfile.workspace = true target-lexicon = "0.12.5" tar = "0.4.38" flate2 = "1.0.24" diff --git a/tests/integration/cli/tests/snapshots/snapshot__snapshot_bash_ls.snap b/tests/integration/cli/tests/snapshots/snapshot__snapshot_bash_ls.snap index 4a4bd674a4a..c5f0a96297a 100644 --- a/tests/integration/cli/tests/snapshots/snapshot__snapshot_bash_ls.snap +++ b/tests/integration/cli/tests/snapshots/snapshot__snapshot_bash_ls.snap @@ -1,5 +1,6 @@ --- source: tests/integration/cli/tests/snapshot.rs +assertion_line: 1193 expression: snapshot --- { @@ -20,7 +21,7 @@ expression: snapshot }, "result": { "Success": { - "stdout": "bin\ndev\netc\ntmp\nusr\n", + "stdout": "bin\ndev\netc\nhome\ntmp\nusr\n", "stderr": "test.wasm-5.1# test.wasm-5.1# exit\n", "exit_code": 0 } diff --git a/tests/integration/cli/tests/snapshots/snapshot__snapshot_default_file_system_tree.snap b/tests/integration/cli/tests/snapshots/snapshot__snapshot_default_file_system_tree.snap index 9f89403d6b4..041a4b6f792 100644 --- a/tests/integration/cli/tests/snapshots/snapshot__snapshot_default_file_system_tree.snap +++ b/tests/integration/cli/tests/snapshots/snapshot__snapshot_default_file_system_tree.snap @@ -1,5 +1,6 @@ --- source: tests/integration/cli/tests/snapshot.rs +assertion_line: 481 expression: snapshot --- { @@ -15,7 +16,7 @@ expression: snapshot }, "result": { "Success": { - "stdout": "bin\ndev\netc\ntmp\n", + "stdout": "bin\ndev\netc\nhome\ntmp\n", "stderr": "", "exit_code": 0 } diff --git a/tests/integration/cli/tests/snapshots/snapshot__snapshot_readdir_tree.snap b/tests/integration/cli/tests/snapshots/snapshot__snapshot_readdir_tree.snap index 64adb78c961..0816f9d0878 100644 --- a/tests/integration/cli/tests/snapshots/snapshot__snapshot_readdir_tree.snap +++ b/tests/integration/cli/tests/snapshots/snapshot__snapshot_readdir_tree.snap @@ -1,5 +1,6 @@ --- source: tests/integration/cli/tests/snapshot.rs +assertion_line: 566 expression: snapshot --- { @@ -21,7 +22,7 @@ expression: snapshot }, "result": { "Success": { - "stdout": "/\n .app:\n .private:\n bin:\n arch\n base32\n base64\n baseenc\n basename\n cat\n chcon\n chgrp\n chmod\n chown\n chroot\n cksum\n comm\n cp\n csplit\n cut\n date\n dd\n df\n dircolors\n dirname\n du\n echo\n env\n expand\n expr\n factor\n false\n fmt\n fold\n groups\n hashsum\n head\n hostid\n hostname\n id\n install\n join\n kill\n link\n ln\n logname\n ls\n mkdir\n mkfifo\n mknod\n mktemp\n more\n mv\n nice\n nl\n nohup\n nproc\n numfmt\n od\n paste\n pathchk\n pinky\n pr\n printenv\n printf\n ptx\n pwd\n readlink\n realpath\n relpath\n rm\n rmdir\n runcon\n seq\n sh\n shred\n shuf\n sleep\n sort\n split\n stat\n stdbuf\n sum\n sync\n tac\n tail\n tee\n test\n timeout\n touch\n tr\n true\n truncate\n tsort\n tty\n uname\n unexpand\n uniq\n unlink\n uptime\n users\n wasmer\n wc\n who\n whoami\n yes\n dev:\n null\n stderr\n stdin\n stdout\n tty\n urandom\n zero\n etc:\n tmp:\n usr:\n coreutils:\n", + "stdout": "/\n .app:\n .private:\n bin:\n arch\n base32\n base64\n baseenc\n basename\n cat\n chcon\n chgrp\n chmod\n chown\n chroot\n cksum\n comm\n cp\n csplit\n cut\n date\n dd\n df\n dircolors\n dirname\n du\n echo\n env\n expand\n expr\n factor\n false\n fmt\n fold\n groups\n hashsum\n head\n hostid\n hostname\n id\n install\n join\n kill\n link\n ln\n logname\n ls\n mkdir\n mkfifo\n mknod\n mktemp\n more\n mv\n nice\n nl\n nohup\n nproc\n numfmt\n od\n paste\n pathchk\n pinky\n pr\n printenv\n printf\n ptx\n pwd\n readlink\n realpath\n relpath\n rm\n rmdir\n runcon\n seq\n sh\n shred\n shuf\n sleep\n sort\n split\n stat\n stdbuf\n sum\n sync\n tac\n tail\n tee\n test\n timeout\n touch\n tr\n true\n truncate\n tsort\n tty\n uname\n unexpand\n uniq\n unlink\n uptime\n users\n wasmer\n wc\n who\n whoami\n yes\n dev:\n null\n stderr\n stdin\n stdout\n tty\n urandom\n zero\n etc:\n home:\n tmp:\n usr:\n coreutils:\n", "stderr": "", "exit_code": 0 } diff --git a/tests/lib/wast/Cargo.toml b/tests/lib/wast/Cargo.toml index 0ce854340a9..7a8cd9cec1e 100644 --- a/tests/lib/wast/Cargo.toml +++ b/tests/lib/wast/Cargo.toml @@ -17,7 +17,7 @@ wasmer-wasix = { path = "../../../lib/wasix", version = "0.16.0" } virtual-fs = { path = "../../../lib/virtual-fs", version = "0.9.0" } wast = "38.0" serde = "1" -tempfile = "3.6.0" +tempfile.workspace = true thiserror = "1.0" futures = "0.3" tokio = { version = "1", features = [ "io-util", "rt" ], default_features = false } diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 8354ea775da..b1ea4558a1d 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -10,8 +10,8 @@ use std::{ use futures::future::BoxFuture; use virtual_fs::{ - host_fs, mem_fs, passthru_fs, tmp_fs, union_fs, AsyncRead, AsyncSeek, AsyncWrite, - AsyncWriteExt, FileSystem, Pipe, ReadBuf, RootFileSystemBuilder, + host_fs, mem_fs, tmp_fs, AsyncRead, AsyncSeek, AsyncWrite, AsyncWriteExt, FileSystem, Pipe, + ReadBuf, RootFileSystemBuilder, }; use wasmer::{FunctionEnv, Imports, Module, Store}; use wasmer_wasix::runtime::task_manager::{tokio::TokioTaskManager, InlineWaker}; @@ -34,12 +34,6 @@ pub enum WasiFileSystemKind { /// Instruct the test runner to use `virtual_fs::tmp_fs` Tmp, - /// Instruct the test runner to use `virtual_fs::passtru_fs` - PassthruMemory, - - /// Instruct the test runner to use `virtual_fs::union_fs` - UnionHostMemory, - /// Instruct the test runner to use the TempFs returned by `virtual_fs::builder::RootFileSystemBuilder` RootFileSystemBuilder, } @@ -121,7 +115,7 @@ impl<'a> WasiTest<'a> { }; let module = Module::new(store, wasm_bytes)?; - let (builder, _tempdirs, mut stdin_tx, stdout_rx, stderr_rx) = + let (builder, mut stdin_tx, stdout_rx, stderr_rx) = { InlineWaker::block_on(async { self.create_wasi_env(filesystem_kind).await }) }?; let (instance, _wasi_env) = builder.runtime(Arc::new(rt)).instantiate(module, store)?; @@ -179,7 +173,6 @@ impl<'a> WasiTest<'a> { filesystem_kind: WasiFileSystemKind, ) -> anyhow::Result<( WasiEnvBuilder, - Vec, Pipe, mpsc::Receiver>, mpsc::Receiver>, @@ -193,64 +186,42 @@ impl<'a> WasiTest<'a> { builder.add_env(name, value); } - let mut host_temp_dirs_to_not_drop = vec![]; - match filesystem_kind { WasiFileSystemKind::Host => { - let fs = host_fs::FileSystem::default(); + let root_fs = RootFileSystemBuilder::new().build(); + + let base_dir = PathBuf::from(BASE_TEST_DIR); for (alias, real_dir) in &self.mapped_dirs { - let mut dir = PathBuf::from(BASE_TEST_DIR); - dir.push(real_dir); - builder.add_map_dir(alias, dir)?; + let fs: Arc<(dyn virtual_fs::FileSystem + std::marker::Send + Sync + 'static)> = + Arc::new(host_fs::FileSystem::new(base_dir.join(real_dir))?); + root_fs.mount(alias.into(), &fs, PathBuf::new())?; } // due to the structure of our code, all preopen dirs must be mapped now for dir in &self.dirs { - let mut new_dir = PathBuf::from(BASE_TEST_DIR); - new_dir.push(dir); - builder.add_map_dir(dir, new_dir)?; + let fs: Arc<(dyn virtual_fs::FileSystem + std::marker::Send + Sync + 'static)> = + Arc::new(host_fs::FileSystem::new(base_dir.join(dir))?); + root_fs.mount(dir.into(), &fs, PathBuf::new())?; } for alias in &self.temp_dirs { let temp_dir = tempfile::tempdir()?; - builder.add_map_dir(alias, temp_dir.path())?; - host_temp_dirs_to_not_drop.push(temp_dir); + let fs: Arc<(dyn virtual_fs::FileSystem + std::marker::Send + Sync + 'static)> = + Arc::new(host_fs::FileSystem::new(temp_dir.path().to_owned())?); + root_fs.mount(alias.into(), &fs, PathBuf::new())?; } - builder.set_fs(Box::new(fs)); + builder.set_fs(Box::new(root_fs)); } other => { let fs: Box = match other { WasiFileSystemKind::InMemory => Box::::default(), WasiFileSystemKind::Tmp => Box::::default(), - WasiFileSystemKind::PassthruMemory => { - let fs = Box::::default(); - Box::new(passthru_fs::PassthruFileSystem::new(fs)) - } WasiFileSystemKind::RootFileSystemBuilder => { Box::new(RootFileSystemBuilder::new().build()) } - WasiFileSystemKind::UnionHostMemory => { - let a = mem_fs::FileSystem::default(); - let b = mem_fs::FileSystem::default(); - let c = mem_fs::FileSystem::default(); - let d = mem_fs::FileSystem::default(); - let e = mem_fs::FileSystem::default(); - let f = mem_fs::FileSystem::default(); - - let mut union = union_fs::UnionFileSystem::new(); - - union.mount("mem_fs", "/test_fs", false, Box::new(a), None); - union.mount("mem_fs_2", "/snapshot1", false, Box::new(b), None); - union.mount("mem_fs_3", "/tests", false, Box::new(c), None); - union.mount("mem_fs_4", "/nightly_2022_10_18", false, Box::new(d), None); - union.mount("mem_fs_5", "/unstable", false, Box::new(e), None); - union.mount("mem_fs_6", "/.tmp_wasmer_wast_0", false, Box::new(f), None); - - Box::new(union) - } _ => { panic!("unexpected filesystem type {:?}", other); } @@ -296,13 +267,7 @@ impl<'a> WasiTest<'a> { .stdout(Box::new(stdout)) .stderr(Box::new(stderr)); - Ok(( - builder, - host_temp_dirs_to_not_drop, - stdin_tx, - stdout_rx, - stderr_rx, - )) + Ok((builder, stdin_tx, stdout_rx, stderr_rx)) } /// Get the correct [`WasiVersion`] from the Wasm [`Module`]. diff --git a/tests/wasi-wast/Cargo.toml b/tests/wasi-wast/Cargo.toml index f99577da53e..a7f734b3197 100644 --- a/tests/wasi-wast/Cargo.toml +++ b/tests/wasi-wast/Cargo.toml @@ -10,7 +10,7 @@ publish = false [dependencies] glob = "0.3" gumdrop = "0.8" -tempfile = "3.6.0" +tempfile.workspace = true serde = { version = "1", features = ["derive"] } serde_json = "1" wast = "24.0" diff --git a/tests/wasi.fyi/wasi-libstd-test/.gitignore b/tests/wasi.fyi/wasi-libstd-test/.gitignore new file mode 100644 index 00000000000..917660a3481 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/.gitignore @@ -0,0 +1 @@ +*.wasm \ No newline at end of file diff --git a/tests/wasi.fyi/wasi-libstd-test/.gitmodules b/tests/wasi.fyi/wasi-libstd-test/.gitmodules new file mode 100644 index 00000000000..bf415043e67 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tools"] + path = tools + url = https://github.com/caspervonb/wasi-test-tools.git diff --git a/tests/wasi.fyi/wasi-libstd-test/LICENSE b/tests/wasi.fyi/wasi-libstd-test/LICENSE new file mode 100644 index 00000000000..20389713bba --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Casper Beyer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tests/wasi.fyi/wasi-libstd-test/README.md b/tests/wasi.fyi/wasi-libstd-test/README.md new file mode 100644 index 00000000000..ea1dcd9b02d --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/README.md @@ -0,0 +1 @@ +# WebAssembly System Interface tests for libstd diff --git a/tests/wasi.fyi/wasi-libstd-test/build.sh b/tests/wasi.fyi/wasi-libstd-test/build.sh new file mode 100644 index 00000000000..1cea40799bb --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -ueo pipefail + +for input in *.rs; do + output="$(basename $input .rs).wasm" + + echo "Compiling $input" + rustc --target=wasm32-wasi -o "$output" "$input" +done diff --git a/tests/wasi.fyi/wasi-libstd-test/env_args-many.arg b/tests/wasi.fyi/wasi-libstd-test/env_args-many.arg new file mode 100644 index 00000000000..c8b8852871f --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_args-many.arg @@ -0,0 +1,3 @@ +none +some +many diff --git a/tests/wasi.fyi/wasi-libstd-test/env_args-many.rs b/tests/wasi.fyi/wasi-libstd-test/env_args-many.rs new file mode 100644 index 00000000000..8b59fb4e0c3 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_args-many.rs @@ -0,0 +1,10 @@ +use std::env; + +fn main() { + let args = env::args().collect::>(); + assert_eq!(args.len(), 4); + assert_eq!(args[0], "env_args-many.wasm"); + assert_eq!(args[1], "none"); + assert_eq!(args[2], "some"); + assert_eq!(args[3], "many"); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/env_args-none.arg b/tests/wasi.fyi/wasi-libstd-test/env_args-none.arg new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wasi.fyi/wasi-libstd-test/env_args-none.rs b/tests/wasi.fyi/wasi-libstd-test/env_args-none.rs new file mode 100644 index 00000000000..fabcd5dab7e --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_args-none.rs @@ -0,0 +1,7 @@ +use std::env; + +fn main() { + let args = env::args().collect::>(); + assert_eq!(args.len(), 1); + assert_eq!(args[0], "env_args-none.wasm"); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/env_args-some.arg b/tests/wasi.fyi/wasi-libstd-test/env_args-some.arg new file mode 100644 index 00000000000..363ef618d48 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_args-some.arg @@ -0,0 +1 @@ +some diff --git a/tests/wasi.fyi/wasi-libstd-test/env_args-some.rs b/tests/wasi.fyi/wasi-libstd-test/env_args-some.rs new file mode 100644 index 00000000000..a983397278c --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_args-some.rs @@ -0,0 +1,8 @@ +use std::env; + +fn main() { + let args = env::args().collect::>(); + assert_eq!(args.len(), 2); + assert_eq!(args[0], "env_args-some.wasm"); + assert_eq!(args[1], "some"); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/env_vars-many.env b/tests/wasi.fyi/wasi-libstd-test/env_vars-many.env new file mode 100644 index 00000000000..eb5fcb6b4f4 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_vars-many.env @@ -0,0 +1,3 @@ +NONE=none +SOME=some +MANY=many diff --git a/tests/wasi.fyi/wasi-libstd-test/env_vars-many.rs b/tests/wasi.fyi/wasi-libstd-test/env_vars-many.rs new file mode 100644 index 00000000000..a945fbf705c --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_vars-many.rs @@ -0,0 +1,9 @@ +use std::env; + +fn main() { + let vars = env::vars().collect::>(); + assert_eq!(vars.len(), 3); + assert_eq!(vars[0], ("NONE".to_string(), "none".to_string())); + assert_eq!(vars[1], ("SOME".to_string(), "some".to_string())); + assert_eq!(vars[2], ("MANY".to_string(), "many".to_string())); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/env_vars-none.env b/tests/wasi.fyi/wasi-libstd-test/env_vars-none.env new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wasi.fyi/wasi-libstd-test/env_vars-none.rs b/tests/wasi.fyi/wasi-libstd-test/env_vars-none.rs new file mode 100644 index 00000000000..c0eace57a4b --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_vars-none.rs @@ -0,0 +1,6 @@ +use std::env; + +fn main() { + let vars = env::vars().collect::>(); + assert_eq!(vars.len(), 0); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/env_vars-some.env b/tests/wasi.fyi/wasi-libstd-test/env_vars-some.env new file mode 100644 index 00000000000..44156341916 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_vars-some.env @@ -0,0 +1 @@ +SOME=some diff --git a/tests/wasi.fyi/wasi-libstd-test/env_vars-some.rs b/tests/wasi.fyi/wasi-libstd-test/env_vars-some.rs new file mode 100644 index 00000000000..619ee65e605 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/env_vars-some.rs @@ -0,0 +1,7 @@ +use std::env; + +fn main() { + let vars = env::vars().collect::>(); + assert_eq!(vars.len(), 1); + assert_eq!(vars[0], ("SOME".to_string(), "some".to_string())); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-existing-directory.dir/existing_directory/.gitignore b/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-existing-directory.dir/existing_directory/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-existing-directory.rs b/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-existing-directory.rs new file mode 100644 index 00000000000..370beb154ae --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-existing-directory.rs @@ -0,0 +1,5 @@ +use std::fs; + +fn main() { + assert!(fs::create_dir("fs_create_dir-existing-directory.dir/existing_directory").is_err()); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-new-directory.dir/.gitignore b/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-new-directory.dir/.gitignore new file mode 100644 index 00000000000..8d0c781946e --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-new-directory.dir/.gitignore @@ -0,0 +1 @@ +new_directory \ No newline at end of file diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-new-directory.rs b/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-new-directory.rs new file mode 100644 index 00000000000..7bffdbb9a34 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_create_dir-new-directory.rs @@ -0,0 +1,5 @@ +use std::fs; + +fn main() { + assert!(fs::create_dir("fs_create_dir-new-directory.dir/new_directory").is_ok()); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_file_create.dir/.gitignore b/tests/wasi.fyi/wasi-libstd-test/fs_file_create.dir/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_file_create.rs b/tests/wasi.fyi/wasi-libstd-test/fs_file_create.rs new file mode 100644 index 00000000000..458a4bb88a0 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_file_create.rs @@ -0,0 +1,6 @@ +use std::fs; + +fn main() { + assert!(fs::File::create("fs_file_create.dir/new_file").is_ok()); + assert!(fs::metadata("fs_file_create.dir/new_file").unwrap().is_file()); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_metadata-directory.dir/directory/.gitignore b/tests/wasi.fyi/wasi-libstd-test/fs_metadata-directory.dir/directory/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_metadata-directory.rs b/tests/wasi.fyi/wasi-libstd-test/fs_metadata-directory.rs new file mode 100644 index 00000000000..6425be4bb28 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_metadata-directory.rs @@ -0,0 +1,6 @@ +use std::fs; + +fn main() { + let metadata = fs::metadata("fs_metadata-directory.dir/directory").unwrap(); + assert!(metadata.is_dir()); +} \ No newline at end of file diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_metadata-file.dir/file b/tests/wasi.fyi/wasi-libstd-test/fs_metadata-file.dir/file new file mode 100644 index 00000000000..1a010b1c0f0 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_metadata-file.dir/file @@ -0,0 +1 @@ +file \ No newline at end of file diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_metadata-file.rs b/tests/wasi.fyi/wasi-libstd-test/fs_metadata-file.rs new file mode 100644 index 00000000000..2360d0df27f --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_metadata-file.rs @@ -0,0 +1,6 @@ +use std::fs; + +fn main() { + let metadata = fs::metadata("fs_metadata-file.dir/file").unwrap(); + assert!(metadata.is_file()); +} \ No newline at end of file diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_rename-directory.dir/old_directory/.gitignore b/tests/wasi.fyi/wasi-libstd-test/fs_rename-directory.dir/old_directory/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_rename-directory.rs b/tests/wasi.fyi/wasi-libstd-test/fs_rename-directory.rs new file mode 100644 index 00000000000..2901e80b232 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_rename-directory.rs @@ -0,0 +1,8 @@ +use std::fs; + +fn main() { + let old_path = "fs_rename-directory.dir/old_directory"; + let new_path = "fs_rename-directory.dir/new_directory"; + + assert!(fs::rename(old_path, new_path).is_ok()); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_rename-file.dir/.gitignore b/tests/wasi.fyi/wasi-libstd-test/fs_rename-file.dir/.gitignore new file mode 100644 index 00000000000..1501d1ed838 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_rename-file.dir/.gitignore @@ -0,0 +1 @@ +new_file \ No newline at end of file diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_rename-file.dir/old_file b/tests/wasi.fyi/wasi-libstd-test/fs_rename-file.dir/old_file new file mode 100644 index 00000000000..f73f3093ff8 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_rename-file.dir/old_file @@ -0,0 +1 @@ +file diff --git a/tests/wasi.fyi/wasi-libstd-test/fs_rename-file.rs b/tests/wasi.fyi/wasi-libstd-test/fs_rename-file.rs new file mode 100644 index 00000000000..44fcd40f3f0 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/fs_rename-file.rs @@ -0,0 +1,8 @@ +use std::fs; + +fn main() { + let old_path = "fs_rename-file.dir/old_file"; + let new_path = "fs_rename-file.dir/new_file"; + + assert!(fs::rename(old_path, new_path).is_ok()); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stderr-beowulf.rs b/tests/wasi.fyi/wasi-libstd-test/io_stderr-beowulf.rs new file mode 100644 index 00000000000..7d417bff5d1 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stderr-beowulf.rs @@ -0,0 +1,6 @@ +use std::io; +use std::io::Write; + +fn main() { + assert!(io::stderr().write_all(include_bytes!("io_stderr-beowulf.stderr")).is_ok()); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stderr-beowulf.stderr b/tests/wasi.fyi/wasi-libstd-test/io_stderr-beowulf.stderr new file mode 100644 index 00000000000..185668538ac --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stderr-beowulf.stderr @@ -0,0 +1,3182 @@ +Hwæt. We Gardena in geardagum, +þeodcyninga, þrym gefrunon, +hu ða æþelingas ellen fremedon. +Oft Scyld Scefing sceaþena þreatum, +monegum mægþum, meodosetla ofteah, +egsode eorlas. Syððan ærest wearð +feasceaft funden, he þæs frofre gebad, +weox under wolcnum, weorðmyndum þah, +oðþæt him æghwylc þara ymbsittendra +ofer hronrade hyran scolde, +gomban gyldan. þæt wæs god cyning. +ðæm eafera wæs æfter cenned, +geong in geardum, þone god sende +folce to frofre; fyrenðearfe ongeat +þe hie ær drugon aldorlease +lange hwile. Him þæs liffrea, +wuldres wealdend, woroldare forgeaf; +Beowulf wæs breme blæd wide sprang, +Scyldes eafera Scedelandum in. +Swa sceal geong guma gode gewyrcean, +fromum feohgiftum on fæder bearme, +þæt hine on ylde eft gewunigen +wilgesiþas, þonne wig cume, +leode gelæsten; lofdædum sceal +in mægþa gehwære man geþeon. +Him ða Scyld gewat to gescæphwile +felahror feran on frean wære. +Hi hyne þa ætbæron to brimes faroðe, +swæse gesiþas, swa he selfa bæd, +þenden wordum weold wine Scyldinga; +leof landfruma lange ahte. +þær æt hyðe stod hringedstefna, +isig ond utfus, æþelinges fær. +Aledon þa leofne þeoden, +beaga bryttan, on bearm scipes, +mærne be mæste. þær wæs madma fela +of feorwegum, frætwa, gelæded; +ne hyrde ic cymlicor ceol gegyrwan +hildewæpnum ond heaðowædum, +billum ond byrnum; him on bearme læg +madma mænigo, þa him mid scoldon +on flodes æht feor gewitan. +Nalæs hi hine læssan lacum teodan, +þeodgestreonum, þon þa dydon +þe hine æt frumsceafte forð onsendon +ænne ofer yðe umborwesende. +þa gyt hie him asetton segen geldenne +heah ofer heafod, leton holm beran, +geafon on garsecg; him wæs geomor sefa, +murnende mod. Men ne cunnon +secgan to soðe, selerædende, +hæleð under heofenum, hwa þæm hlæste onfeng. +ða wæs on burgum Beowulf Scyldinga, +leof leodcyning, longe þrage +folcum gefræge fæder ellor hwearf, +aldor of earde, oþþæt him eft onwoc +heah Healfdene; heold þenden lifde, +gamol ond guðreouw, glæde Scyldingas. +ðæm feower bearn forð gerimed +in worold wocun, weoroda ræswan, +Heorogar ond Hroðgar ond Halga til; +hyrde ic þæt wæs Onelan cwen, +Heaðoscilfingas healsgebedda. +þa wæs Hroðgare heresped gyfen, +wiges weorðmynd, þæt him his winemagas +georne hyrdon, oðð þæt seo geogoð geweox, +magodriht micel. Him on mod bearn +þæt healreced hatan wolde, +medoærn micel, men gewyrcean +þonne yldo bearn æfre gefrunon, +ond þær on innan eall gedælan +geongum ond ealdum, swylc him god sealde, +buton folcscare ond feorum gumena. +ða ic wide gefrægn weorc gebannan +manigre mægþe geond þisne middangeard, +folcstede frætwan. Him on fyrste gelomp, +ædre mid yldum, þæt hit wearð ealgearo, +healærna mæst; scop him Heort naman +se þe his wordes geweald wide hæfde. +He beot ne aleh, beagas dælde, +sinc æt symle. Sele hlifade, +heah ond horngeap, heaðowylma bad, +laðan liges; ne wæs hit lenge þa gen +þæt se ecghete aþumsweorum, +æfter wælniðe wæcnan scolde. +ða se ellengæst earfoðlice +þrage geþolode, se þe in þystrum bad, +þæt he dogora gehwam dream gehyrde +hludne in healle; þær wæs hearpan sweg, +swutol sang scopes. Sægde se þe cuþe +frumsceaft fira feorran reccan, +cwæð þæt se ælmihtiga eorðan worhte, +wlitebeorhtne wang, swa wæter bebugeð, +gesette sigehreþig sunnan ond monan +leoman to leohte landbuendum +ond gefrætwade foldan sceatas +leomum ond leafum, lif eac gesceop +cynna gehwylcum þara ðe cwice hwyrfaþ. +Swa ða drihtguman dreamum lifdon +eadiglice, oððæt an ongan +fyrene fremman feond on helle. +Wæs se grimma gæst Grendel haten, +mære mearcstapa, se þe moras heold, +fen ond fæsten; fifelcynnes eard +wonsæli wer weardode hwile, +siþðan him scyppend forscrifen hæfde +in Caines cynne. þone cwealm gewræc +ece drihten, þæs þe he Abel slog; +ne gefeah he þære fæhðe, ac he hine feor forwræc, +metod for þy mane, mancynne fram. +þanon untydras ealle onwocon, +eotenas ond ylfe ond orcneas, +swylce gigantas, þa wið gode wunnon +lange þrage; he him ðæs lean forgeald. +Gewat ða neosian, syþðan niht becom, +hean huses, hu hit Hringdene +æfter beorþege gebun hæfdon. +Fand þa ðær inne æþelinga gedriht +swefan æfter symble; sorge ne cuðon, +wonsceaft wera. Wiht unhælo, +grim ond grædig, gearo sona wæs, +reoc ond reþe, ond on ræste genam +þritig þegna, þanon eft gewat +huðe hremig to ham faran, +mid þære wælfylle wica neosan. +ða wæs on uhtan mid ærdæge +Grendles guðcræft gumum undyrne; +þa wæs æfter wiste wop up ahafen, +micel morgensweg. Mære þeoden, +æþeling ærgod, unbliðe sæt, +þolode ðryðswyð, þegnsorge dreah, +syðþan hie þæs laðan last sceawedon, +wergan gastes; wæs þæt gewin to strang, +lað ond longsum. Næs hit lengra fyrst, +ac ymb ane niht eft gefremede +morðbeala mare ond no mearn fore, +fæhðe ond fyrene; wæs to fæst on þam. +þa wæs eaðfynde þe him elles hwær +gerumlicor ræste sohte, +bed æfter burum, ða him gebeacnod wæs, +gesægd soðlice sweotolan tacne +healðegnes hete; heold hyne syðþan +fyr ond fæstor se þæm feonde ætwand. +Swa rixode ond wið rihte wan, +ana wið eallum, oðþæt idel stod +husa selest. Wæs seo hwil micel; +XII wintra tid torn geþolode +wine Scyldinga, weana gehwelcne, +sidra sorga. Forðam secgum wearð, +ylda bearnum, undyrne cuð, +gyddum geomore, þætte Grendel wan +hwile wið Hroþgar, heteniðas wæg, +fyrene ond fæhðe fela missera, +singale sæce, sibbe ne wolde +wið manna hwone mægenes Deniga, +feorhbealo feorran, fea þingian, +ne þær nænig witena wenan þorfte +beorhtre bote to banan folmum, +ac se æglæca ehtende wæs, +deorc deaþscua, duguþe ond geogoþe, +seomade ond syrede, sinnihte heold +mistige moras. men ne cunnon +hwyder helrunan hwyrftum scriþað. +Swa fela fyrena feond mancynnes, +atol angengea, oft gefremede, +heardra hynða. Heorot eardode, +sincfage sel sweartum nihtum; +no he þone gifstol gretan moste, +maþðum for metode, ne his myne wisse. +þæt wæs wræc micel wine Scyldinga, +modes brecða. Monig oft gesæt +rice to rune; ræd eahtedon +hwæt swiðferhðum selest wære +wið færgryrum to gefremmanne. +Hwilum hie geheton æt hærgtrafum +wigweorþunga, wordum bædon +þæt him gastbona geoce gefremede +wið þeodþreaum. Swylc wæs þeaw hyra, +hæþenra hyht; helle gemundon +in modsefan, metod hie ne cuþon, +dæda demend, ne wiston hie drihten god, +ne hie huru heofena helm herian ne cuþon, +wuldres waldend. Wa bið þæm ðe sceal +þurh sliðne nið sawle bescufan +in fyres fæþm, frofre ne wenan, +wihte gewendan; wel bið þæm þe mot +æfter deaðdæge drihten secean +ond to fæder fæþmum freoðo wilnian. +Swa ða mælceare maga Healfdenes +singala seað, ne mihte snotor hæleð +wean onwendan; wæs þæt gewin to swyð, +laþ ond longsum, þe on ða leode becom, +nydwracu niþgrim, nihtbealwa mæst. +þæt fram ham gefrægn Higelaces þegn, +god mid Geatum, Grendles dæda; +se wæs moncynnes mægenes strengest +on þæm dæge þysses lifes, +æþele ond eacen. Het him yðlidan +godne gegyrwan, cwæð, hu guðcyning +ofer swanrade secean wolde, +mærne þeoden, þa him wæs manna þearf. +ðone siðfæt him snotere ceorlas +lythwon logon, þeah he him leof wære; +hwetton higerofne, hæl sceawedon. +Hæfde se goda Geata leoda +cempan gecorone þara þe he cenoste +findan mihte; XVna sum +sundwudu sohte; secg wisade, +lagucræftig mon, landgemyrcu. +Fyrst forð gewat. Flota wæs on yðum, +bat under beorge. Beornas gearwe +on stefn stigon; streamas wundon, +sund wið sande; secgas bæron +on bearm nacan beorhte frætwe, +guðsearo geatolic; guman ut scufon, +weras on wilsið, wudu bundenne. +Gewat þa ofer wægholm, winde gefysed, +flota famiheals fugle gelicost, +oðþæt ymb antid oþres dogores +wundenstefna gewaden hæfde +þæt ða liðende land gesawon, +brimclifu blican, beorgas steape, +side sænæssas; þa wæs sund liden, +eoletes æt ende. þanon up hraðe +Wedera leode on wang stigon, +sæwudu sældon syrcan hrysedon, +guðgewædo, gode þancedon +þæs þe him yþlade eaðe wurdon. +þa of wealle geseah weard Scildinga, +se þe holmclifu healdan scolde, +beran ofer bolcan beorhte randas, +fyrdsearu fuslicu; hine fyrwyt bræc +modgehygdum, hwæt þa men wæron. +Gewat him þa to waroðe wicge ridan +þegn Hroðgares, þrymmum cwehte +mægenwudu mundum, meþelwordum frægn: +Hwæt syndon ge searohæbbendra, +byrnum werede, þe þus brontne ceol +ofer lagustræte lædan cwomon, +hider ofer holmas? le wæs +endesæta, ægwearde heold, +þe on land Dena laðra nænig +mid scipherge sceðþan ne meahte. +No her cuðlicor cuman ongunnon +lindhæbbende; ne ge leafnesword +guðfremmendra gearwe ne wisson, +maga gemedu. Næfre ic maran geseah +eorla ofer eorþan ðonne is eower sum, +secg on searwum; nis þæt seldguma, +wæpnum geweorðad, næfne him his wlite leoge, +ænlic ansyn. Nu ic eower sceal +frumcyn witan, ær ge fyr heonan , +leassceaweras, on land Dena +furþur feran. Nu ge feorbuend, +mereliðende, minne gehyrað +anfealdne geþoht: Ofost is selest +to gecyðanne hwanan eowre cyme syndon. +Him se yldesta ondswarode, +werodes wisa, wordhord onleac: +We synt gumcynnes Geata leode +ond Higelaces heorðgeneatas. +Wæs min fæder folcum gecyþed, +æþele ordfruma, Ecgþeow haten. +Gebad wintra worn, ær he on weg hwurfe, +gamol of geardum; hine gearwe geman +witena welhwylc wide geond eorþan. +We þurh holdne hige hlaford þinne, +sunu Healfdenes, secean cwomon, +leodgebyrgean; wes þu us larena god. +Habbað we to þæm mæran micel ærende, +Deniga frean, ne sceal þær dyrne sum +wesan, þæs ic wene. þu wast gif hit is +swa we soþlice secgan hyrdon +þæt mid Scyldingum sceaðona ic nat hwylc, +deogol dædhata, deorcum nihtum +eaweð þurh egsan uncuðne nið, +hynðu ond hrafyl. Ic þæs Hroðgar mæg +þurh rumne sefan ræd gelæran, +hu he frod ond god feond oferswyðeþ, +gyf him edwendan æfre scolde +bealuwa bisigu, bot eft cuman, +ond þa cearwylmas colran wurðaþ; +oððe a syþðan earfoðþrage, +þreanyd þolað, þenden þær wunað +on heahstede husa selest. +Weard maþelode, ðær on wicge sæt, +ombeht unforht: æghwæþres sceal +scearp scyldwiga gescad witan, +worda ond worca, se þe wel þenceð. +Ic þæt gehyre, þæt þis is hold weorod +frean Scyldinga. Gewitaþ forð beran +wæpen ond gewædu; ic eow wisige. +Swylce ic maguþegnas mine hate +wið feonda gehwone flotan eowerne, +niwtyrwydne nacan on sande +arum healdan, oþðæt eft byreð +ofer lagustreamas leofne mannan +wudu wundenhals to Wedermearce, +godfremmendra swylcum gifeþe bið +þæt þone hilderæs hal gedigeð. +Gewiton him þa feran. Flota stille bad, +seomode on sale sidfæþmed scip, +on ancre fæst. Eoforlic scionon +ofer hleorberan gehroden golde, +fah ond fyrheard; ferhwearde heold +guþmod grimmon. Guman onetton, +sigon ætsomne, oþþæt hy sæl timbred, +geatolic ond goldfah, ongyton mihton; +þæt wæs foremærost foldbuendum +receda under roderum, on þæm se rica bad; +lixte se leoma ofer landa fela. +Him þa hildedeor hof modigra +torht getæhte, þæt hie him to mihton +gegnum gangan; guðbeorna sum +wicg gewende, word æfter cwæð: +Mæl is me to feran; fæder alwalda +mid arstafum eowic gehealde +siða gesunde. Ic to sæ wille +wið wrað werod wearde healdan. +Stræt wæs stanfah, stig wisode +gumum ætgædere. Guðbyrne scan +heard hondlocen, hringiren scir +song in searwum, þa hie to sele furðum +in hyra gryregeatwum gangan cwomon. +Setton sæmeþe side scyldas, +rondas regnhearde, wið þæs recedes weal, +bugon þa to bence. Byrnan hringdon, +guðsearo gumena; garas stodon, +sæmanna searo, samod ætgædere, +æscholt ufan græg; wæs se irenþreat +wæpnum gewurþad. þa ðær wlonc hæleð +oretmecgas æfter æþelum frægn: +Hwanon ferigeað ge fætte scyldas, +græge syrcan ond grimhelmas, +heresceafta heap? Ic eom Hroðgares +ar ond ombiht. Ne seah ic elþeodige +þus manige men modiglicran. +Wen ic þæt ge for wlenco, nalles for wræcsiðum, +ac for higeþrymmum Hroðgar sohton. +Him þa ellenrof andswarode, +wlanc Wedera leod, word æfter spræc, +heard under helme: We synt Higelaces +beodgeneatas; Beowulf is min nama. +Wille ic asecgan sunu Healfdenes, +mærum þeodne, min ærende, +aldre þinum, gif he us geunnan wile +þæt we hine swa godne gretan moton. +Wulfgar maþelode þæt wæs Wendla leod; +wæs his modsefa manegum gecyðed, +wig ond wisdom: Ic þæs wine Deniga, +frean Scildinga, frinan wille, +beaga bryttan, swa þu bena eart, +þeoden mærne, ymb þinne sið, +ond þe þa ondsware ædre gecyðan +ðe me se goda agifan þenceð. +Hwearf þa hrædlice þær Hroðgar sæt +eald ond anhar mid his eorla gedriht; +eode ellenrof, þæt he for eaxlum gestod +Deniga frean; cuþe he duguðe þeaw. +Wulfgar maðelode to his winedrihtne: +Her syndon geferede, feorran cumene +ofer geofenes begang Geata leode; +þone yldestan oretmecgas +Beowulf nemnað. Hy benan synt +þæt hie, þeoden min, wið þe moton +wordum wrixlan. No ðu him wearne geteoh +ðinra gegncwida, glædman Hroðgar. +Hy on wiggetawum wyrðe þinceað +eorla geæhtlan; huru se aldor deah, +se þæm heaðorincum hider wisade. +Hroðgar maþelode, helm Scyldinga: +Ic hine cuðe cnihtwesende. +Wæs his ealdfæder Ecgþeo haten, +ðæm to ham forgeaf Hreþel Geata +angan dohtor; is his eafora nu +heard her cumen, sohte holdne wine. +ðonne sægdon þæt sæliþende, +þa ðe gifsceattas Geata fyredon +þyder to þance, þæt he XXXtiges +manna mægencræft on his mundgripe +heaþorof hæbbe. Hine halig god +for arstafum us onsende, +to Westdenum, þæs ic wen hæbbe, +wið Grendles gryre. Ic þæm godan sceal +for his modþræce madmas beodan. +Beo ðu on ofeste, hat in gan +seon sibbegedriht samod ætgædere; +gesaga him eac wordum þæt hie sint wilcuman +Deniga leodum. +[] word inne abead: +Eow het secgan sigedrihten min, +aldor Eastdena, þæt he eower æþelu can, +ond ge him syndon ofer sæwylmas +heardhicgende hider wilcuman. +Nu ge moton gangan in eowrum guðgeatawum +under heregriman Hroðgar geseon; +lætað hildebord her onbidan, +wudu, wælsceaftas, worda geþinges. +Aras þa se rica, ymb hine rinc manig, +þryðlic þegna heap; sume þær bidon, +heaðoreaf heoldon, swa him se hearda bebead. +Snyredon ætsomne, þa secg wisode, +under Heorotes hrof +heard under helme, þæt he on heoðe gestod. +Beowulf maðelode on him byrne scan, +searonet seowed smiþes orþancum: +Wæs þu, Hroðgar, hal. Ic eom Higelaces +mæg ond magoðegn; hæbbe ic mærða fela +ongunnen on geogoþe. Me wearð Grendles þing +on minre eþeltyrf undyrne cuð; +secgað sæliðend þæt þæs sele stande, +reced selesta, rinca gehwylcum +idel ond unnyt, siððan æfenleoht +under heofenes hador beholen weorþeð. +þa me þæt gelærdon leode mine +þa selestan, snotere ceorlas, +þeoden Hroðgar, þæt ic þe sohte, +forþan hie mægenes cræft minne cuþon, +selfe ofersawon, ða ic of searwum cwom, +fah from feondum. þær ic fife geband, +yðde eotena cyn ond on yðum slog +niceras nihtes, nearoþearfe dreah, +wræc Wedera nið wean ahsodon, +forgrand gramum, ond nu wið Grendel sceal, +wið þam aglæcan, ana gehegan +ðing wið þyrse. Ic þe nu ða, +brego Beorhtdena, biddan wille, +eodor Scyldinga, anre bene, +þæt ðu me ne forwyrne, wigendra hleo, +freowine folca, nu ic þus feorran com, +þæt ic mote ana ond minra eorla gedryht, +þes hearda heap, Heorot fælsian. +Hæbbe ic eac geahsod þæt se æglæca +for his wonhydum wæpna ne recceð. +Ic þæt þonne forhicge swa me Higelac sie, +min mondrihten, modes bliðe, +þæt ic sweord bere oþðe sidne scyld, +geolorand to guþe, ac ic mid grape sceal +fon wið feonde ond ymb feorh sacan, +lað wið laþum; ðær gelyfan sceal +dryhtnes dome se þe hine deað nimeð. +Wen ic þæt he wille, gif he wealdan mot, +in þæm guðsele Geotena leode +etan unforhte, swa he oft dyde, +mægen Hreðmanna. Na þu minne þearft +hafalan hydan, ac he me habban wile +dreore fahne, gif mec deað nimeð. +Byreð blodig wæl, byrgean þenceð, +eteð angenga unmurnlice, +mearcað morhopu; no ðu ymb mines ne þearft +lices feorme leng sorgian. +Onsend Higelace, gif mec hild nime, +beaduscruda betst, þæt mine breost wereð, +hrægla selest; þæt is Hrædlan laf, +Welandes geweorc. Gæð a wyrd swa hio scel. +Hroðgar maþelode, helm Scyldinga: +For gewyrhtum þu, wine min Beowulf, +ond for arstafum usic sohtest. +Gesloh þin fæder fæhðe mæste; +wearþ he Heaþolafe to handbonan +mid Wilfingum; ða hine Wedera cyn +for herebrogan habban ne mihte. +þanon he gesohte Suðdena folc +ofer yða gewealc, Arscyldinga. +ða ic furþum weold folce Deniga +ond on geogoðe heold ginne rice, +hordburh hæleþa; ða wæs Heregar dead, +min yldra mæg unlifigende, +bearn Healfdenes; se wæs betera ðonne ic. +Siððan þa fæhðe feo þingode; +sende ic Wylfingum ofer wæteres hrycg +ealde madmas; he me aþas swor. +Sorh is me to secganne on sefan minum +gumena ængum hwæt me Grendel hafað +hynðo on Heorote mid his heteþancum, +færniða gefremed. Is min fletwerod, +wigheap gewanod; hie wyrd forsweop +on Grendles gryre. God eaþe mæg +þone dolsceaðan dæda getwæfan. +Ful oft gebeotedon beore druncne +ofer ealowæge oretmecgas +þæt hie in beorsele bidan woldon +Grendles guþe mid gryrum ecga. +ðonne wæs þeos medoheal on morgentid, +drihtsele dreorfah, þonne dæg lixte, +eal bencþelu blode bestymed, +heall heorudreore; ahte ic holdra þy læs, +deorre duguðe, þe þa deað fornam. +Site nu to symle ond onsæl meoto, +sigehreð secgum, swa þin sefa hwette. +þa wæs Geatmæcgum geador ætsomne +on beorsele benc gerymed; +þær swiðferhþe sittan eodon, +þryðum dealle. þegn nytte beheold, +se þe on handa bær hroden ealowæge, +scencte scir wered. Scop hwilum sang +hador on Heorote. þær wæs hæleða dream, +duguð unlytel Dena ond Wedera. +Unferð maþelode, Ecglafes bearn, +þe æt fotum sæt frean Scyldinga, +onband beadurune wæs him Beowulfes sið, +modges merefaran, micel æfþunca, +forþon þe he ne uþe þæt ænig oðer man +æfre mærða þon ma middangeardes +gehedde under heofenum þonne he sylfa: +Eart þu se Beowulf, se þe wið Brecan wunne, +on sidne sæ ymb sund flite, +ðær git for wlence wada cunnedon +ond for dolgilpe on deop wæter +aldrum neþdon? Ne inc ænig mon, +ne leof ne lað, belean mihte +sorhfullne sið, þa git on sund reon. +þær git eagorstream earmum þehton, +mæton merestræta, mundum brugdon, +glidon ofer garsecg; geofon yþum weol, +wintrys wylmum. Git on wæteres æht +seofon niht swuncon; he þe æt sunde oferflat, +hæfde mare mægen. þa hine on morgentid +on Heaþoræmas holm up ætbær; +ðonon he gesohte swæsne eþel, +leof his leodum, lond Brondinga, +freoðoburh fægere, þær he folc ahte +burh ond beagas. Beot eal wið þe +sunu Beanstanes soðe gelæste. +ðonne wene ic to þe wyrsan geþingea, +ðeah þu heaðoræsa gehwær dohte, +grimre guðe, gif þu Grendles dearst +nihtlongne fyrst nean bidan. +Beowulf maþelode, bearn Ecgþeowes: +Hwæt. þu worn fela, wine min Unferð, +beore druncen ymb Brecan spræce, +sægdest from his siðe. Soð ic talige, +þæt ic merestrengo maran ahte, +earfeþo on yþum, ðonne ænig oþer man. +Wit þæt gecwædon cnihtwesende +ond gebeotedon wæron begen þa git +on geogoðfeore þæt wit on garsecg ut +aldrum neðdon, ond þæt geæfndon swa. +Hæfdon swurd nacod, þa wit on sund reon, +heard on handa; wit unc wið hronfixas +werian þohton. No he wiht fram me +flodyþum feor fleotan meahte, +hraþor on holme; no ic fram him wolde. +ða wit ætsomne on sæ wæron +fif nihta fyrst, oþþæt unc flod todraf, +wado weallende, wedera cealdost, +nipende niht, ond norþanwind +heaðogrim ondhwearf; hreo wæron yþa. +Wæs merefixa mod onhrered; +þær me wið laðum licsyrce min, +heard, hondlocen, helpe gefremede, +beadohrægl broden on breostum læg +golde gegyrwed. Me to grunde teah +fah feondscaða, fæste hæfde +grim on grape; hwæþre me gyfeþe wearð +þæt ic aglæcan orde geræhte, +hildebille; heaþoræs fornam +mihtig meredeor þurh mine hand. +Swa mec gelome laðgeteonan +þreatedon þearle. Ic him þenode +deoran sweorde, swa hit gedefe wæs. +Næs hie ðære fylle gefean hæfdon, +manfordædlan, þæt hie me þegon, +symbel ymbsæton sægrunde neah; +ac on mergenne mecum wunde +be yðlafe uppe lægon, +sweordum aswefede, þæt syðþan na +ymb brontne ford brimliðende +lade ne letton. Leoht eastan com, +beorht beacen godes; brimu swaþredon, +þæt ic sænæssas geseon mihte, +windige weallas. Wyrd oft nereð +unfægne eorl, þonne his ellen deah. +Hwæþere me gesælde þæt ic mid sweorde ofsloh +niceras nigene. No ic on niht gefrægn +under heofones hwealf heardran feohtan, +ne on egstreamum earmran mannon; +hwaþere ic fara feng feore gedigde, +siþes werig. ða mec sæ oþbær, +flod æfter faroðe on Finna land, +wadu weallendu. No ic wiht fram þe +swylcra searoniða secgan hyrde, +billa brogan. Breca næfre git +æt heaðolace, ne gehwæþer incer, +swa deorlice dæd gefremede +fagum sweordum no ic þæs fela gylpe, +þeah ðu þinum broðrum to banan wurde, +heafodmægum; þæs þu in helle scealt +werhðo dreogan, þeah þin wit duge. +Secge ic þe to soðe, sunu Ecglafes, +þæt næfre Grendel swa fela gryra gefremede, +atol æglæca, ealdre þinum, +hynðo on Heorote, gif þin hige wære, +sefa swa searogrim, swa þu self talast. +Ac he hafað onfunden þæt he þa fæhðe ne þearf, +atole ecgþræce eower leode +swiðe onsittan, Sigescyldinga; +nymeð nydbade, nænegum arað +leode Deniga, ac he lust wigeð, +swefeð ond sendeþ, secce ne weneþ +to Gardenum. Ac ic him Geata sceal +eafoð ond ellen ungeara nu, +guþe gebeodan. Gæþ eft se þe mot +to medo modig, siþþan morgenleoht +ofer ylda bearn oþres dogores, +sunne sweglwered suþan scineð. +þa wæs on salum sinces brytta, +gamolfeax ond guðrof; geoce gelyfde +brego Beorhtdena, gehyrde on Beowulfe +folces hyrde fæstrædne geþoht. +ðær wæs hæleþa hleahtor, hlyn swynsode, +word wæron wynsume. Eode Wealhþeow forð, +cwen Hroðgares, cynna gemyndig, +grette goldhroden guman on healle, +ond þa freolic wif ful gesealde +ærest Eastdena eþelwearde, +bæd hine bliðne æt þære beorþege, +leodum leofne. He on lust geþeah +symbel ond seleful, sigerof kyning. +Ymbeode þa ides Helminga +duguþe ond geogoþe dæl æghwylcne, +sincfato sealde, oþþæt sæl alamp +þæt hio Beowulfe, beaghroden cwen +mode geþungen, medoful ætbær; +grette Geata leod, gode þancode +wisfæst wordum þæs ðe hire se willa gelamp +þæt heo on ænigne eorl gelyfde +fyrena frofre. He þæt ful geþeah, +wælreow wiga, æt Wealhþeon, +ond þa gyddode guþe gefysed; +Beowulf maþelode, bearn Ecgþeowes: +Ic þæt hogode, þa ic on holm gestah, +sæbat gesæt mid minre secga gedriht, +þæt ic anunga eowra leoda +willan geworhte oþðe on wæl crunge, +feondgrapum fæst. Ic gefremman sceal +eorlic ellen, oþðe endedæg +on þisse meoduhealle minne gebidan. +ðam wife þa word wel licodon, +gilpcwide Geates; eode goldhroden +freolicu folccwen to hire frean sittan. +þa wæs eft swa ær inne on healle +þryðword sprecen, ðeod on sælum, +sigefolca sweg, oþþæt semninga +sunu Healfdenes secean wolde +æfenræste; wiste þæm ahlæcan +to þæm heahsele hilde geþinged, +siððan hie sunnan leoht geseon ne meahton, +oðþe nipende niht ofer ealle, +scaduhelma gesceapu scriðan cwoman, +wan under wolcnum. Werod eall aras. +Gegrette þa guma oþerne, +Hroðgar Beowulf, ond him hæl abead, +winærnes geweald, ond þæt word acwæð: +Næfre ic ænegum men ær alyfde, +siþðan ic hond ond rond hebban mihte, +ðryþærn Dena buton þe nu ða. +Hafa nu ond geheald husa selest, +gemyne mærþo, mægenellen cyð, +waca wið wraþum. Ne bið þe wilna gad, +gif þu þæt ellenweorc aldre gedigest. +ða him Hroþgar gewat mid his hæleþa gedryht, +eodur Scyldinga, ut of healle; +wolde wigfruma Wealhþeo secan, +cwen to gebeddan. Hæfde kyningwuldor +Grendle togeanes, swa guman gefrungon, +seleweard aseted; sundornytte beheold +ymb aldor Dena, eotonweard abead. +Huru Geata leod georne truwode +modgan mægnes, metodes hyldo. +ða he him of dyde isernbyrnan, +helm of hafelan, sealde his hyrsted sweord, +irena cyst, ombihtþegne, +ond gehealdan het hildegeatwe. +Gespræc þa se goda gylpworda sum, +Beowulf Geata, ær he on bed stige: +No ic me an herewæsmun hnagran talige, +guþgeweorca, þonne Grendel hine; +forþan ic hine sweorde swebban nelle, +aldre beneotan, þeah ic eal mæge. +Nat he þara goda þæt he me ongean slea, +rand geheawe, þeah ðe he rof sie +niþgeweorca; ac wit on niht sculon +secge ofersittan, gif he gesecean dear +wig ofer wæpen, ond siþðan witig god +on swa hwæþere hond, halig dryhten, +mærðo deme, swa him gemet þince. +Hylde hine þa heaþodeor, hleorbolster onfeng +eorles andwlitan, ond hine ymb monig +snellic særinc selereste gebeah. +Nænig heora þohte þæt he þanon scolde +eft eardlufan æfre gesecean, +folc oþðe freoburh, þær he afeded wæs; +ac hie hæfdon gefrunen þæt hie ær to fela micles +in þæm winsele wældeað fornam, +Denigea leode. Ac him dryhten forgeaf +wigspeda gewiofu, Wedera leodum, +frofor ond fultum, þæt hie feond heora +ðurh anes cræft ealle ofercomon, +selfes mihtum. Soð is gecyþed +þæt mihtig god manna cynnes +weold wideferhð. Com on wanre niht +scriðan sceadugenga. Sceotend swæfon, +þa þæt hornreced healdan scoldon, +ealle buton anum. þæt wæs yldum cuþ +þæt hie ne moste, þa metod nolde, +se scynscaþa under sceadu bregdan; +ac he wæccende wraþum on andan +bad bolgenmod beadwa geþinges. +ða com of more under misthleoþum +Grendel gongan, godes yrre bær; +mynte se manscaða manna cynnes +sumne besyrwan in sele þam hean. +Wod under wolcnum to þæs þe he winreced, +goldsele gumena, gearwost wisse, +fættum fahne. Ne wæs þæt forma sið +þæt he Hroþgares ham gesohte; +næfre he on aldordagum ær ne siþðan +heardran hæle, healðegnas fand. +Com þa to recede rinc siðian, +dreamum bedæled. Duru sona onarn, +fyrbendum fæst, syþðan he hire folmum æthran; +onbræd þa bealohydig, ða he gebolgen wæs, +recedes muþan. Raþe æfter þon +on fagne flor feond treddode, +eode yrremod; him of eagum stod +ligge gelicost leoht unfæger. +Geseah he in recede rinca manige, +swefan sibbegedriht samod ætgædere, +magorinca heap. þa his mod ahlog; +mynte þæt he gedælde, ærþon dæg cwome, +atol aglæca, anra gehwylces +lif wið lice, þa him alumpen wæs +wistfylle wen. Ne wæs þæt wyrd þa gen +þæt he ma moste manna cynnes +ðicgean ofer þa niht. þryðswyð beheold +mæg Higelaces, hu se manscaða +under færgripum gefaran wolde. +Ne þæt se aglæca yldan þohte, +ac he gefeng hraðe forman siðe +slæpendne rinc, slat unwearnum, +bat banlocan, blod edrum dranc, +synsnædum swealh; sona hæfde +unlyfigendes eal gefeormod, +fet ond folma. Forð near ætstop, +nam þa mid handa higeþihtigne +rinc on ræste, ræhte ongean +feond mid folme; he onfeng hraþe +inwitþancum ond wið earm gesæt. +Sona þæt onfunde fyrena hyrde +þæt he ne mette middangeardes, +eorþan sceata, on elran men +mundgripe maran. He on mode wearð +forht on ferhðe; no þy ær fram meahte. +Hyge wæs him hinfus, wolde on heolster fleon, +secan deofla gedræg; ne wæs his drohtoð þær +swylce he on ealderdagum ær gemette. +Gemunde þa se goda, mæg Higelaces, +æfenspræce, uplang astod +ond him fæste wiðfeng; fingras burston. +Eoten wæs utweard; eorl furþur stop. +Mynte se mæra, þær he meahte swa, +widre gewindan ond on weg þanon +fleon on fenhopu; wiste his fingra geweald +on grames grapum. þæt wæs geocor sið +þæt se hearmscaþa to Heorute ateah. +Dryhtsele dynede; Denum eallum wearð, +ceasterbuendum, cenra gehwylcum, +eorlum ealuscerwen. Yrre wæron begen, +reþe renweardas. Reced hlynsode. +þa wæs wundor micel þæt se winsele +wiðhæfde heaþodeorum, þæt he on hrusan ne feol, +fæger foldbold; ac he þæs fæste wæs +innan ond utan irenbendum +searoþoncum besmiþod. þær fram sylle abeag +medubenc monig, mine gefræge, +golde geregnad, þær þa graman wunnon. +þæs ne wendon ær witan Scyldinga +þæt hit a mid gemete manna ænig, +betlic ond banfag, tobrecan meahte, +listum tolucan, nymþe liges fæþm +swulge on swaþule. Sweg up astag +niwe geneahhe; Norðdenum stod +atelic egesa, anra gehwylcum +þara þe of wealle wop gehyrdon, +gryreleoð galan godes ondsacan, +sigeleasne sang, sar wanigean +helle hæfton. Heold hine fæste +se þe manna wæs mægene strengest +on þæm dæge þysses lifes. +Nolde eorla hleo ænige þinga +þone cwealmcuman cwicne forlætan, +ne his lifdagas leoda ænigum +nytte tealde. þær genehost brægd +eorl Beowulfes ealde lafe, +wolde freadrihtnes feorh ealgian, +mæres þeodnes, ðær hie meahton swa. +Hie þæt ne wiston, þa hie gewin drugon, +heardhicgende hildemecgas, +ond on healfa gehwone heawan þohton, +sawle secan, þone synscaðan +ænig ofer eorþan irenna cyst, +guðbilla nan, gretan nolde, +ac he sigewæpnum forsworen hæfde, +ecga gehwylcre. Scolde his aldorgedal +on ðæm dæge þysses lifes +earmlic wurðan, ond se ellorgast +on feonda geweald feor siðian. +ða þæt onfunde se þe fela æror +modes myrðe manna cynne, +fyrene gefremede he wæs fag wið god, +þæt him se lichoma læstan nolde, +ac hine se modega mæg Hygelaces +hæfde be honda; wæs gehwæþer oðrum +lifigende lað. Licsar gebad +atol æglæca; him on eaxle wearð +syndolh sweotol, seonowe onsprungon, +burston banlocan. Beowulfe wearð +guðhreð gyfeþe; scolde Grendel þonan +feorhseoc fleon under fenhleoðu, +secean wynleas wic; wiste þe geornor +þæt his aldres wæs ende gegongen, +dogera dægrim. Denum eallum wearð +æfter þam wælræse willa gelumpen. +Hæfde þa gefælsod se þe ær feorran com, +snotor ond swyðferhð, sele Hroðgares, +genered wið niðe; nihtweorce gefeh, +ellenmærþum. Hæfde Eastdenum +Geatmecga leod gilp gelæsted, +swylce oncyþðe ealle gebette, +inwidsorge, þe hie ær drugon +ond for þreanydum þolian scoldon, +torn unlytel. þæt wæs tacen sweotol, +syþðan hildedeor hond alegde, +earm ond eaxle þær wæs eal geador +Grendles grape under geapne hrof. +ða wæs on morgen mine gefræge +ymb þa gifhealle guðrinc monig; +ferdon folctogan feorran ond nean +geond widwegas wundor sceawian, +laþes lastas. No his lifgedal +sarlic þuhte secga ænegum +þara þe tirleases trode sceawode, +hu he werigmod on weg þanon, +niða ofercumen, on nicera mere +fæge ond geflymed feorhlastas bær. +ðær wæs on blode brim weallende, +atol yða geswing eal gemenged +haton heolfre, heorodreore weol. +Deaðfæge deog, siððan dreama leas +in fenfreoðo feorh alegde, +hæþene sawle; þær him hel onfeng. +þanon eft gewiton ealdgesiðas, +swylce geong manig of gomenwaþe +fram mere modge mearum ridan, +beornas on blancum. ðær wæs Beowulfes +mærðo mæned; monig oft gecwæð +þætte suð ne norð be sæm tweonum +ofer eormengrund oþer nænig +under swegles begong selra nære +rondhæbbendra, rices wyrðra. +Ne hie huru winedrihten wiht ne logon, +glædne Hroðgar, ac þæt wæs god cyning. +Hwilum heaþorofe hleapan leton, +on geflit faran fealwe mearas +ðær him foldwegas fægere þuhton, +cystum cuðe. Hwilum cyninges þegn, +guma gilphlæden, gidda gemyndig, +se ðe ealfela ealdgesegena +worn gemunde, word oþer fand +soðe gebunden; secg eft ongan +sið Beowulfes snyttrum styrian +ond on sped wrecan spel gerade, +wordum wrixlan. Welhwylc gecwæð +þæt he fram Sigemundes secgan hyrde +ellendædum, uncuþes fela, +Wælsinges gewin, wide siðas, +þara þe gumena bearn gearwe ne wiston, +fæhðe ond fyrena, buton Fitela mid hine, +þonne he swulces hwæt secgan wolde, +eam his nefan, swa hie a wæron +æt niða gehwam nydgesteallan; +hæfdon ealfela eotena cynnes +sweordum gesæged. Sigemunde gesprong +æfter deaðdæge dom unlytel, +syþðan wiges heard wyrm acwealde, +hordes hyrde. He under harne stan, +æþelinges bearn, ana geneðde +frecne dæde, ne wæs him Fitela mid. +hwæþre him gesælde ðæt þæt swurd þurhwod +wrætlicne wyrm, þæt hit on wealle ætstod, +dryhtlic iren; draca morðre swealt. +Hæfde aglæca elne gegongen +þæt he beahhordes brucan moste +selfes dome; sæbat gehleod, +bær on bearm scipes beorhte frætwa, +Wælses eafera. Wyrm hat gemealt. +Se wæs wreccena wide mærost +ofer werþeode, wigendra hleo, +ellendædum he þæs ær onðah, +siððan Heremodes hild sweðrode, +eafoð ond ellen. He mid Eotenum wearð +on feonda geweald forð forlacen, +snude forsended. Hine sorhwylmas +lemede to lange; he his leodum wearð, +eallum æþellingum to aldorceare; +swylce oft bemearn ærran mælum +swiðferhþes sið snotor ceorl monig, +se þe him bealwa to bote gelyfde, +þæt þæt ðeodnes bearn geþeon scolde, +fæderæþelum onfon, folc gehealdan, +hord ond hleoburh, hæleþa rice, +eþel Scyldinga. He þær eallum wearð, +mæg Higelaces, manna cynne, +freondum gefægra; hine fyren onwod. +Hwilum flitende fealwe stræte +mearum mæton. ða wæs morgenleoht +scofen ond scynded. Eode scealc monig +swiðhicgende to sele þam hean +searowundor seon; swylce self cyning +of brydbure, beahhorda weard, +tryddode tirfæst getrume micle, +cystum gecyþed, ond his cwen mid him +medostigge mæt mægþa hose. +Hroðgar maþelode he to healle geong, +stod on stapole, geseah steapne hrof, +golde fahne, ond Grendles hond: +ðisse ansyne alwealdan þanc +lungre gelimpe. Fela ic laþes gebad, +grynna æt Grendle; a mæg god wyrcan +wunder æfter wundre, wuldres hyrde. +ðæt wæs ungeara þæt ic ænigra me +weana ne wende to widan feore +bote gebidan, þonne blode fah +husa selest heorodreorig stod, +wea widscofen witena gehwylcum +ðara þe ne wendon þæt hie wideferhð +leoda landgeweorc laþum beweredon +scuccum ond scinnum. Nu scealc hafað +þurh drihtnes miht dæd gefremede ðe +we ealle ær ne meahton +snyttrum besyrwan. Hwæt, þæt secgan mæg +efne swa hwylc mægþa swa ðone magan cende +æfter gumcynnum, gyf heo gyt lyfað, +þæt hyre ealdmetod este wære +bearngebyrdo. Nu ic, Beowulf, þec, +secg betsta, me for sunu wylle +freogan on ferhþe; heald forð tela +niwe sibbe. Ne bið þe nænigra gad +worolde wilna, þe ic geweald hæbbe. +Ful oft ic for læssan lean teohhode, +hordweorþunge hnahran rince, +sæmran æt sæcce. þu þe self hafast +dædum gefremed þæt þin dom lyfað +awa to aldre. Alwalda þec +gode forgylde, swa he nu gyt dyde. +Beowulf maþelode, bearn Ecþeowes: +We þæt ellenweorc estum miclum, +feohtan fremedon, frecne geneðdon +eafoð uncuþes. Uþe ic swiþor +þæt ðu hine selfne geseon moste, +feond on frætewum fylwerigne. +Ic hine hrædlice heardan clammum +on wælbedde wriþan þohte, +þæt he for mundgripe minum scolde +licgean lifbysig, butan his lic swice. +Ic hine ne mihte, þa metod nolde, +ganges getwæman, no ic him þæs georne ætfealh, +feorhgeniðlan; wæs to foremihtig +feond on feþe. Hwæþere he his folme forlet +to lifwraþe last weardian, +earm ond eaxle. No þær ænige swa þeah +feasceaft guma frofre gebohte; +no þy leng leofað laðgeteona, +synnum geswenced, ac hyne sar hafað +mid nydgripe nearwe befongen, +balwon bendum. ðær abidan sceal +maga mane fah miclan domes, +hu him scir metod scrifan wille. +ða wæs swigra secg, sunu Eclafes, +on gylpspræce guðgeweorca, +siþðan æþelingas eorles cræfte +ofer heanne hrof hand sceawedon, +feondes fingras. Foran æghwylc wæs, +stiðra nægla gehwylc, style gelicost, +hæþenes handsporu hilderinces, +egl, unheoru. æghwylc gecwæð +þæt him heardra nan hrinan wolde +iren ærgod, þæt ðæs ahlæcan +blodge beadufolme onberan wolde. +ða wæs haten hreþe Heort innanweard +folmum gefrætwod. Fela þæra wæs, +wera ond wifa, þe þæt winreced, +gestsele gyredon. Goldfag scinon +web æfter wagum, wundorsiona fela +secga gehwylcum þara þe on swylc starað. +Wæs þæt beorhte bold tobrocen swiðe, +eal inneweard irenbendum fæst, +heorras tohlidene. Hrof ana genæs, +ealles ansund, þe se aglæca, +fyrendædum fag, on fleam gewand, +aldres orwena. No þæt yðe byð +to befleonne, fremme se þe wille, +ac gesecan sceal sawlberendra, +nyde genydde, niþða bearna, +grundbuendra gearwe stowe, +þær his lichoma legerbedde fæst +swefeþ æfter symle. þa wæs sæl ond mæl +þæt to healle gang Healfdenes sunu; +wolde self cyning symbel þicgan. +Ne gefrægen ic þa mægþe maran weorode +ymb hyra sincgyfan sel gebæran. +Bugon þa to bence blædagande, +fylle gefægon; fægere geþægon +medoful manig magas þara +swiðhicgende on sele þam hean, +Hroðgar ond Hroþulf. Heorot innan wæs +freondum afylled; nalles facenstafas +|eodscyldingas þenden fremedon. +Forgeaf þa Beowulfe bearn Healfdenes +segen gyldenne sigores to leane; +hroden hildecumbor, helm ond byrnan, +mære maðþumsweord manige gesawon +beforan beorn beran. Beowulf geþah +ful on flette; no he þære feohgyfte +for sceotendum scamigan ðorfte. +Ne gefrægn ic freondlicor feower madmas +golde gegyrede gummanna fela +in ealobence oðrum gesellan. +Ymb þæs helmes hrof heafodbeorge +wirum bewunden walu utan heold, +þæt him fela laf frecne ne meahton +scurheard sceþðan, þonne scyldfreca +ongean gramum gangan scolde. +Heht ða eorla hleo eahta mearas +fætedhleore on flet teon, +in under eoderas. þara anum stod +sadol searwum fah, since gewurþad; +þæt wæs hildesetl heahcyninges, +ðonne sweorda gelac sunu Healfdenes +efnan wolde. Næfre on ore læg +widcuþes wig, ðonne walu feollon. +Ond ða Beowulfe bega gehwæþres +eodor Ingwina onweald geteah, +wicga ond wæpna, het hine wel brucan. +Swa manlice mære þeoden, +hordweard hæleþa, heaþoræsas geald +mearum ond madmum, swa hy næfre man lyhð, +se þe secgan wile soð æfter rihte. +ða gyt æghwylcum eorla drihten +þara þe mid Beowulfe brimlade teah +on þære medubence maþðum gesealde, +yrfelafe, ond þone ænne heht +golde forgyldan, þone ðe Grendel ær +mane acwealde, swa he hyra ma wolde, +nefne him witig god wyrd forstode +ond ðæs mannes mod. Metod eallum weold +gumena cynnes, swa he nu git deð. +Forþan bið andgit æghwær selest, +ferhðes foreþanc. Fela sceal gebidan +leofes ond laþes se þe longe her +on ðyssum windagum worolde bruceð. +þær wæs sang ond sweg samod ætgædere +fore Healfdenes hildewisan, +gomenwudu greted, gid oft wrecen, +ðonne healgamen Hroþgares scop +æfter medobence mænan scolde +be Finnes eaferum, ða hie se fær begeat, +hæleð Healfdena, Hnæf Scyldinga, +in Freswæle feallan scolde. +Ne huru Hildeburh herian þorfte +Eotena treowe; unsynnum wearð +beloren leofum æt þam lindplegan, +bearnum ond broðrum; hie on gebyrd hruron, +gare wunde. þæt wæs geomuru ides. +Nalles holinga Hoces dohtor +meotodsceaft bemearn, syþðan morgen com, +ða heo under swegle geseon meahte +morþorbealo maga, þær heo ær mæste heold +worolde wynne. Wig ealle fornam +Finnes þegnas nemne feaum anum, +þæt he ne mehte on þæm meðelstede +wig Hengeste wiht gefeohtan, +ne þa wealafe wige forþringan +þeodnes ðegna. ac hig him geþingo budon, +þæt hie him oðer flet eal gerymdon, +healle ond heahsetl, þæt hie healfre geweald +wið Eotena bearn agan moston, +ond æt feohgyftum Folcwaldan sunu +dogra gehwylce Dene weorþode, +Hengestes heap hringum wenede +efne swa swiðe sincgestreonum +fættan goldes, swa he Fresena cyn +on beorsele byldan wolde. +ða hie getruwedon on twa healfa +fæste frioðuwære. Fin Hengeste +elne, unflitme aðum benemde +þæt he þa wealafe weotena dome +arum heolde, þæt ðær ænig mon +wordum ne worcum wære ne bræce, +ne þurh inwitsearo æfre gemænden +ðeah hie hira beaggyfan banan folgedon +ðeodenlease, þa him swa geþearfod wæs. +gyf þonne Frysna hwylc frecnan spræce +ðæs morþorhetes myndgiend wære, +þonne hit sweordes ecg seðan scolde. +Ad wæs geæfned ond icge gold +ahæfen of horde. Herescyldinga +betst beadorinca wæs on bæl gearu. +æt þæm ade wæs eþgesyne +swatfah syrce, swyn ealgylden, +eofer irenheard, æþeling manig +wundum awyrded; sume on wæle crungon. +Het ða Hildeburh æt Hnæfes ade +hire selfre sunu sweoloðe befæstan, +banfatu bærnan ond on bæl don +eame on eaxle. Ides gnornode, +geomrode giddum. Guðrinc astah. +Wand to wolcnum wælfyra mæst, +hlynode for hlawe; hafelan multon, +bengeato burston, ðonne blod ætspranc, +laðbite lices. Lig ealle forswealg, +gæsta gifrost, þara ðe þær guð fornam +bega folces; wæs hira blæd scacen. +Gewiton him ða wigend wica neosian, +freondum befeallen, Frysland geseon, +hamas ond heaburh. Hengest ða gyt +wælfagne winter wunode mid Finne +eal unhlitme. Eard gemunde, +þeah þe he ne meahte on mere drifan +hringedstefnan; holm storme weol, +won wið winde, winter yþe beleac +isgebinde, oþðæt oþer com +gear in geardas, swa nu gyt deð, +þa ðe syngales sele bewitiað, +wuldortorhtan weder. ða wæs winter scacen, +fæger foldan bearm. Fundode wrecca, +gist of geardum; he to gyrnwræce +swiðor þohte þonne to sælade, +gif he torngemot þurhteon mihte +þæt he Eotena bearn inne gemunde. +Swa he ne forwyrnde woroldrædenne, +þonne him Hunlafing hildeleoman, +billa selest, on bearm dyde, +þæs wæron mid Eotenum ecge cuðe. +Swylce ferhðfrecan Fin eft begeat +sweordbealo sliðen æt his selfes ham, +siþðan grimne gripe Guðlaf ond Oslaf +æfter sæsiðe, sorge, mændon, +ætwiton weana dæl; ne meahte wæfre mod +forhabban in hreþre. ða wæs heal roden +feonda feorum, swilce Fin slægen, +cyning on corþre, ond seo cwen numen. +Sceotend Scyldinga to scypon feredon +eal ingesteald eorðcyninges, +swylce hie æt Finnes ham findan meahton +sigla, searogimma. Hie on sælade +drihtlice wif to Denum feredon, +læddon to leodum. Leoð wæs asungen, +gleomannes gyd. Gamen eft astah, +beorhtode bencsweg; byrelas sealdon +win of wunderfatum. þa cwom Wealhþeo forð +gan under gyldnum beage, þær þa godan twegen +sæton suhtergefæderan; þa gyt wæs hiera sib ætgædere, +æghwylc oðrum trywe. Swylce þær Unferþ þyle +æt fotum sæt frean Scyldinga; gehwylc hiora his ferhþe treowde, +þæt he hæfde mod micel, þeah þe he his magum nære +arfæst æt ecga gelacum. Spræc ða ides Scyldinga: +Onfoh þissum fulle, freodrihten min, +sinces brytta. þu on sælum wes, +goldwine gumena, ond to Geatum spræc +mildum wordum, swa sceal man don. +Beo wið Geatas glæd, geofena gemyndig, +nean ond feorran þu nu hafast. +Me man sægde þæt þu ðe for sunu wolde +hererinc habban. Heorot is gefælsod, +beahsele beorhta; bruc þenden þu mote +manigra medo, ond þinum magum læf +folc ond rice, þonne ðu forð scyle +metodsceaft seon. Ic minne can +glædne Hroþulf, þæt he þa geogoðe wile +arum healdan, gyf þu ær þonne he, +wine Scildinga, worold oflætest; +wene ic þæt he mid gode gyldan wille +uncran eaferan, gif he þæt eal gemon, +hwæt wit to willan ond to worðmyndum +umborwesendum ær arna gefremedon. +Hwearf þa bi bence þær hyre byre wæron, +Hreðric ond Hroðmund, ond hæleþa bearn, +giogoð ætgædere; þær se goda sæt, +Beowulf Geata, be þæm gebroðrum twæm. +Him wæs ful boren ond freondlaþu +wordum bewægned, ond wunden gold +estum geeawed, earmreade twa, +hrægl ond hringas, healsbeaga mæst +þara þe ic on foldan gefrægen hæbbe. +Nænigne ic under swegle selran hyrde +hordmaððum hæleþa, syþðan Hama ætwæg +to þære byrhtan byrig Brosinga mene, +sigle ond sincfæt; searoniðas fleah +Eormenrices, geceas ecne ræd. +þone hring hæfde Higelac Geata, +nefa Swertinges, nyhstan siðe, +siðþan he under segne sinc ealgode, +wælreaf werede; hyne wyrd fornam, +syþðan he for wlenco wean ahsode, +fæhðe to Frysum. He þa frætwe wæg, +eorclanstanas ofer yða ful, +rice þeoden; he under rande gecranc. +Gehwearf þa in Francna fæþm feorh cyninges, +breostgewædu ond se beah somod; +wyrsan wigfrecan wæl reafedon +æfter guðsceare, Geata leode, +hreawic heoldon. Heal swege onfeng. +Wealhðeo maþelode, heo fore þæm werede spræc: +Bruc ðisses beages, Beowulf leofa, +hyse, mid hæle, ond þisses hrægles neot, +þeodgestreona, ond geþeoh tela, +cen þec mid cræfte ond þyssum cnyhtum wes +lara liðe; ic þe þæs lean geman. +Hafast þu gefered þæt ðe feor ond neah +ealne wideferhþ weras ehtigað, +efne swa side swa sæ bebugeð, +windgeard, weallas. Wes þenden þu lifige, +æþeling, eadig. Ic þe an tela +sincgestreona. Beo þu suna minum +dædum gedefe, dreamhealdende. +Her is æghwylc eorl oþrum getrywe, +modes milde, mandrihtne hold; +þegnas syndon geþwære, þeod ealgearo, +druncne dryhtguman doð swa ic bidde. +Eode þa to setle. þær wæs symbla cyst; +druncon win weras. Wyrd ne cuþon, +geosceaft grimme, swa hit agangen wearð +eorla manegum, syþðan æfen cwom +ond him Hroþgar gewat to hofe sinum, +rice to ræste. Reced weardode +unrim eorla, swa hie oft ær dydon. +Bencþelu beredon; hit geondbræded wearð +beddum ond bolstrum. Beorscealca sum +fus ond fæge fletræste gebeag. +Setton him to heafdon hilderandas, +bordwudu beorhtan; þær on bence wæs +ofer æþelinge yþgesene +heaþosteapa helm, hringed byrne, +þrecwudu þrymlic. Wæs þeaw hyra +þæt hie oft wæron an wig gearwe, +ge æt ham ge on herge, ge gehwæþer þara, +efne swylce mæla swylce hira mandryhtne +þearf gesælde; wæs seo þeod tilu. +Sigon þa to slæpe. Sum sare angeald +æfenræste, swa him ful oft gelamp, +siþðan goldsele Grendel warode, +unriht æfnde, oþþæt ende becwom, +swylt æfter synnum. þæt gesyne wearþ, +widcuþ werum, þætte wrecend þa gyt +lifde æfter laþum, lange þrage, +æfter guðceare. Grendles modor, +ides, aglæcwif, yrmþe gemunde, +se þe wæteregesan wunian scolde, +cealde streamas, siþðan Cain wearð +to ecgbanan angan breþer, +fæderenmæge; he þa fag gewat, +morþre gemearcod, mandream fleon, +westen warode. þanon woc fela +geosceaftgasta; wæs þæra Grendel sum, +heorowearh hetelic, se æt Heorote fand +wæccendne wer wiges bidan. +þær him aglæca ætgræpe wearð; +hwæþre he gemunde mægenes strenge, +gimfæste gife ðe him god sealde, +ond him to anwaldan are gelyfde, +frofre ond fultum; ðy he þone feond ofercwom, +gehnægde helle gast. þa he hean gewat, +dreame bedæled, deaþwic seon, +mancynnes feond, ond his modor þa gyt, +gifre ond galgmod, gegan wolde +sorhfulne sið, sunu deað wrecan. +Com þa to Heorote, ðær Hringdene +geond þæt sæld swæfun. þa ðær sona wearð +edhwyrft eorlum, siþðan inne fealh +Grendles modor. Wæs se gryre læssa +efne swa micle swa bið mægþa cræft, +wiggryre wifes, be wæpnedmen, +þonne heoru bunden, hamere geþuren, +sweord swate fah swin ofer helme +ecgum dyhttig andweard scireð. +þa wæs on healle heardecg togen +sweord ofer setlum, sidrand manig +hafen handa fæst; helm ne gemunde, +byrnan side, þa hine se broga angeat. +Heo wæs on ofste, wolde ut þanon, +feore beorgan, þa heo onfunden wæs. +Hraðe heo æþelinga anne hæfde +fæste befangen, þa heo to fenne gang. +Se wæs Hroþgare hæleþa leofost +on gesiðes had be sæm tweonum, +rice randwiga, þone ðe heo on ræste abreat, +blædfæstne beorn. Næs Beowulf ðær, +ac wæs oþer in ær geteohhod +æfter maþðumgife mærum Geate. +Hream wearð in Heorote; heo under heolfre genam +cuþe folme; cearu wæs geniwod, +geworden in wicun. Ne wæs þæt gewrixle til, +þæt hie on ba healfa bicgan scoldon +freonda feorum. þa wæs frod cyning, +har hilderinc, on hreon mode, +syðþan he aldorþegn unlyfigendne, +þone deorestan deadne wisse. +Hraþe wæs to bure Beowulf fetod, +sigoreadig secg. Samod ærdæge +eode eorla sum, æþele cempa +self mid gesiðum þær se snotera bad, +hwæþer him alwalda æfre wille +æfter weaspelle wyrpe gefremman. +Gang ða æfter flore fyrdwyrðe man +mid his handscale healwudu dynede, +þæt he þone wisan wordum nægde +frean Ingwina, frægn gif him wære +æfter neodlaðum niht getæse. +Hroðgar maþelode, helm Scyldinga: +Ne frin þu æfter sælum. Sorh is geniwod +Denigea leodum. Dead is æschere, +Yrmenlafes yldra broþor, +min runwita ond min rædbora, +eaxlgestealla, ðonne we on orlege +hafelan weredon, þonne hniton feþan, +eoferas cynsedan. Swylc scolde eorl wesan, +æþeling ærgod, swylc æschere wæs. +Wearð him on Heorote to handbanan +wælgæst wæfre; ic ne wat hwæder +atol æse wlanc eftsiðas teah, +fylle gefægnod. Heo þa fæhðe wræc +þe þu gystranniht Grendel cwealdest +þurh hæstne had heardum clammum, +forþan he to lange leode mine +wanode ond wyrde. He æt wige gecrang +ealdres scyldig, ond nu oþer cwom +mihtig manscaða, wolde hyre mæg wrecan, +ge feor hafað fæhðe gestæled +(þæs þe þincean mæg þegne monegum, +se þe æfter sincgyfan on sefan greoteþ), +hreþerbealo hearde; nu seo hand ligeð, +se þe eow welhwylcra wilna dohte. +Ic þæt londbuend, leode mine, +selerædende, secgan hyrde +þæt hie gesawon swylce twegen +micle mearcstapan moras healdan, +ellorgæstas. ðæra oðer wæs, +þæs þe hie gewislicost gewitan meahton, +idese onlicnæs; oðer earmsceapen +on weres wæstmum wræclastas træd, +næfne he wæs mara þonne ænig man oðer; +þone on geardagum Grendel nemdon +foldbuende. No hie fæder cunnon, +hwæþer him ænig wæs ær acenned +dyrnra gasta. Hie dygel lond +warigeað, wulfhleoþu, windige næssas, +frecne fengelad, ðær fyrgenstream +under næssa genipu niþer gewiteð, +flod under foldan. Nis þæt feor heonon +milgemearces þæt se mere standeð; +ofer þæm hongiað hrinde bearwas, +wudu wyrtum fæst wæter oferhelmað. +þær mæg nihta gehwæm niðwundor seon, +fyr on flode. No þæs frod leofað +gumena bearna, þæt þone grund wite; +ðeah þe hæðstapa hundum geswenced, +heorot hornum trum, holtwudu sece, +feorran geflymed, ær he feorh seleð, +aldor on ofre, ær he in wille +hafelan hydan. Nis þæt heoru stow! +þonon yðgeblond up astigeð +won to wolcnum, þonne wind styreþ, +lað gewidru, oðþæt lyft drysmaþ, +roderas reotað. Nu is se ræd gelang +eft æt þe anum. Eard git ne const, +frecne stowe, ðær þu findan miht +felasinnigne secg; sec gif þu dyrre. +Ic þe þa fæhðe feo leanige, +ealdgestreonum, swa ic ær dyde, +wundnum golde, gyf þu on weg cymest." +Beowulf maþelode, bearn Ecgþeowes: +"Ne sorga, snotor guma; selre bið æghwæm +þæt he his freond wrece, þonne he fela murne. +Ure æghwylc sceal ende gebidan +worolde lifes; wyrce se þe mote +domes ær deaþe; þæt bið drihtguman +unlifgendum æfter selest. +Aris, rices weard, uton raþe feran +Grendles magan gang sceawigan. +Ic hit þe gehate, no he on helm losaþ, +ne on foldan fæþm, ne on fyrgenholt, +ne on gyfenes grund, ga þær he wille. +ðys dogor þu geþyld hafa +weana gehwylces, swa ic þe wene to." +Ahleop ða se gomela, gode þancode, +mihtigan drihtne, þæs se man gespræc. +þa wæs Hroðgare hors gebæted, +wicg wundenfeax. Wisa fengel +geatolic gende; gumfeþa stop +lindhæbbendra. Lastas wæron +æfter waldswaþum wide gesyne, +gang ofer grundas, þær heo gegnum for +ofer myrcan mor, magoþegna bær +þone selestan sawolleasne +þara þe mid Hroðgare ham eahtode. +Ofereode þa æþelinga bearn +steap stanhliðo, stige nearwe, +enge anpaðas, uncuð gelad, +neowle næssas, nicorhusa fela. +He feara sum beforan gengde +wisra monna wong sceawian, +oþþæt he færinga fyrgenbeamas +ofer harne stan hleonian funde, +wynleasne wudu; wæter under stod +dreorig ond gedrefed. Denum eallum wæs, +winum Scyldinga, weorce on mode +to geþolianne, ðegne monegum, +oncyð eorla gehwæm, syðþan æscheres +on þam holmclife hafelan metton. +Flod blode weol (folc to sægon), +hatan heolfre. Horn stundum song +fuslic fyrdleoð. Feþa eal gesæt. +Gesawon ða æfter wætere wyrmcynnes fela, +sellice sædracan, sund cunnian, +swylce on næshleoðum nicras licgean, +ða on undernmæl oft bewitigað +sorhfulne sið on seglrade, +wyrmas ond wildeor; hie on weg hruron, +bitere ond gebolgne, bearhtm ongeaton, +guðhorn galan. Sumne Geata leod +of flanbogan feores getwæfde, +yðgewinnes, þæt him on aldre stod +herestræl hearda; he on holme wæs +sundes þe sænra, ðe hyne swylt fornam. +Hræþe wearð on yðum mid eoferspreotum +heorohocyhtum hearde genearwod, +niða genæged, ond on næs togen, +wundorlic wægbora; weras sceawedon +gryrelicne gist. Gyrede hine Beowulf +eorlgewædum, nalles for ealdre mearn. +Scolde herebyrne hondum gebroden, +sid ond searofah, sund cunnian, +seo ðe bancofan beorgan cuþe, +þæt him hildegrap hreþre ne mihte, +eorres inwitfeng, aldre gesceþðan; +ac se hwita helm hafelan werede, +se þe meregrundas mengan scolde, +secan sundgebland since geweorðad, +befongen freawrasnum, swa hine fyrndagum +worhte wæpna smið, wundrum teode, +besette swinlicum, þæt hine syðþan no +brond ne beadomecas bitan ne meahton. +Næs þæt þonne mætost mægenfultuma +þæt him on ðearfe lah ðyle Hroðgares; +wæs þæm hæftmece Hrunting nama. +þæt wæs an foran ealdgestreona; +ecg wæs iren, atertanum fah, +ahyrded heaþoswate; næfre hit æt hilde ne swac +manna ængum þara þe hit mid mundum bewand, +se ðe gryresiðas gegan dorste, +folcstede fara; næs þæt forma sið +þæt hit ellenweorc æfnan scolde. +Huru ne gemunde mago Ecglafes, +eafoþes cræftig, þæt he ær gespræc +wine druncen, þa he þæs wæpnes onlah +selran sweordfrecan. Selfa ne dorste +under yða gewin aldre geneþan, +drihtscype dreogan; þær he dome forleas, +ellenmærðum. Ne wæs þæm oðrum swa, +syðþan he hine to guðe gegyred hæfde. +Beowulf maðelode, bearn Ecgþeowes: +"Geþenc nu, se mæra maga Healfdenes, +snottra fengel, nu ic eom siðes fus, +goldwine gumena, hwæt wit geo spræcon, +gif ic æt þearfe þinre scolde +aldre linnan, þæt ðu me a wære +forðgewitenum on fæder stæle. +Wes þu mundbora minum magoþegnum, +hondgesellum, gif mec hild nime; +swylce þu ða madmas þe þu me sealdest, +Hroðgar leofa, Higelace onsend. +Mæg þonne on þæm golde ongitan Geata dryhten, +geseon sunu Hrædles, þonne he on þæt sinc starað, +þæt ic gumcystum godne funde +beaga bryttan, breac þonne moste. +Ond þu Unferð læt ealde lafe, +wrætlic wægsweord, widcuðne man +heardecg habban; ic me mid Hruntinge +dom gewyrce, oþðe mec deað nimeð." +æfter þæm wordum Wedergeata leod +efste mid elne, nalas ondsware +bidan wolde; brimwylm onfeng +hilderince. ða wæs hwil dæges +ær he þone grundwong ongytan mehte. +Sona þæt onfunde se ðe floda begong +heorogifre beheold hund missera, +grim ond grædig, þæt þær gumena sum +ælwihta eard ufan cunnode. +Grap þa togeanes, guðrinc gefeng +atolan clommum. No þy ær in gescod +halan lice; hring utan ymbbearh, +þæt heo þone fyrdhom ðurhfon ne mihte, +locene leoðosyrcan laþan fingrum. +Bær þa seo brimwylf, þa heo to botme com, +hringa þengel to hofe sinum, +swa he ne mihte, no he þæs modig wæs, +wæpna gewealdan, ac hine wundra þæs fela +swencte on sunde, sædeor monig +hildetuxum heresyrcan bræc, +ehton aglæcan. ða se eorl ongeat +þæt he in niðsele nathwylcum wæs, +þær him nænig wæter wihte ne sceþede, +ne him for hrofsele hrinan ne mehte +færgripe flodes; fyrleoht geseah, +blacne leoman, beorhte scinan. +Ongeat þa se goda grundwyrgenne, +merewif mihtig; mægenræs forgeaf +hildebille, hond sweng ne ofteah, +þæt hire on hafelan hringmæl agol +grædig guðleoð. ða se gist onfand +þæt se beadoleoma bitan nolde, +aldre sceþðan, ac seo ecg geswac +ðeodne æt þearfe; ðolode ær fela +hondgemota, helm oft gescær, +fæges fyrdhrægl; ða wæs forma sið +deorum madme, þæt his dom alæg. +Eft wæs anræd, nalas elnes læt, +mærða gemyndig mæg Hylaces. +Wearp ða wundenmæl wrættum gebunden +yrre oretta, þæt hit on eorðan læg, +stið ond stylecg; strenge getruwode, +mundgripe mægenes. Swa sceal man don, +þonne he æt guðe gegan þenceð +longsumne lof, na ymb his lif cearað. +Gefeng þa be eaxle (nalas for fæhðe mearn) +Guðgeata leod Grendles modor; +brægd þa beadwe heard, þa he gebolgen wæs, +feorhgeniðlan, þæt heo on flet gebeah. +Heo him eft hraþe andlean forgeald +grimman grapum ond him togeanes feng; +oferwearp þa werigmod wigena strengest, +feþecempa, þæt he on fylle wearð. +Ofsæt þa þone selegyst ond hyre seax geteah, +brad ond brunecg, wolde hire bearn wrecan, +angan eaferan. Him on eaxle læg +breostnet broden; þæt gebearh feore, +wið ord ond wið ecge ingang forstod. +Hæfde ða forsiðod sunu Ecgþeowes +under gynne grund, Geata cempa, +nemne him heaðobyrne helpe gefremede, +herenet hearde, ond halig god +geweold wigsigor; witig drihten, +rodera rædend, hit on ryht gesced +yðelice, syþðan he eft astod. +Geseah ða on searwum sigeeadig bil, +eald sweord eotenisc, ecgum þyhtig, +wigena weorðmynd; þæt wæs wæpna cyst, +buton hit wæs mare ðonne ænig mon oðer +to beadulace ætberan meahte, +god ond geatolic, giganta geweorc. +He gefeng þa fetelhilt, freca Scyldinga +hreoh ond heorogrim hringmæl gebrægd, +aldres orwena, yrringa sloh, +þæt hire wið halse heard grapode, +banhringas bræc. Bil eal ðurhwod +fægne flæschoman; heo on flet gecrong. +Sweord wæs swatig, secg weorce gefeh. +Lixte se leoma, leoht inne stod, +efne swa of hefene hadre scineð +rodores candel. He æfter recede wlat; +hwearf þa be wealle, wæpen hafenade +heard be hiltum Higelaces ðegn, +yrre ond anræd. Næs seo ecg fracod +hilderince, ac he hraþe wolde +Grendle forgyldan guðræsa fela +ðara þe he geworhte to Westdenum +oftor micle ðonne on ænne sið, +þonne he Hroðgares heorðgeneatas +sloh on sweofote, slæpende fræt +folces Denigea fyftyne men +ond oðer swylc ut offerede, +laðlicu lac. He him þæs lean forgeald, +reþe cempa, to ðæs þe he on ræste geseah +guðwerigne Grendel licgan +aldorleasne, swa him ær gescod +hild æt Heorote. Hra wide sprong, +syþðan he æfter deaðe drepe þrowade, +heorosweng heardne, ond hine þa heafde becearf. +Sona þæt gesawon snottre ceorlas, +þa ðe mid Hroðgare on holm wliton, +þæt wæs yðgeblond eal gemenged, +brim blode fah. Blondenfeaxe, +gomele ymb godne, ongeador spræcon +þæt hig þæs æðelinges eft ne wendon +þæt he sigehreðig secean come +mærne þeoden; þa ðæs monige gewearð +þæt hine seo brimwylf abroten hæfde. +ða com non dæges. Næs ofgeafon +hwate Scyldingas; gewat him ham þonon +goldwine gumena. Gistas setan +modes seoce ond on mere staredon, +wiston ond ne wendon þæt hie heora winedrihten +selfne gesawon. þa þæt sweord ongan +æfter heaþoswate hildegicelum, +wigbil wanian. þæt wæs wundra sum, +þæt hit eal gemealt ise gelicost, +ðonne forstes bend fæder onlæteð, +onwindeð wælrapas, se geweald hafað +sæla ond mæla; þæt is soð metod. +Ne nom he in þæm wicum, Wedergeata leod, +maðmæhta ma, þeh he þær monige geseah, +buton þone hafelan ond þa hilt somod +since fage. Sweord ær gemealt, +forbarn brodenmæl; wæs þæt blod to þæs hat, +ættren ellorgæst se þær inne swealt. +Sona wæs on sunde se þe ær æt sæcce gebad +wighryre wraðra, wæter up þurhdeaf. +Wæron yðgebland eal gefælsod, +eacne eardas, þa se ellorgast +oflet lifdagas ond þas lænan gesceaft. +Com þa to lande lidmanna helm +swiðmod swymman; sælace gefeah, +mægenbyrþenne þara þe he him mid hæfde. +Eodon him þa togeanes, gode þancodon, +ðryðlic þegna heap, þeodnes gefegon, +þæs þe hi hyne gesundne geseon moston. +ða wæs of þæm hroran helm ond byrne +lungre alysed. Lagu drusade, +wæter under wolcnum, wældreore fag. +Ferdon forð þonon feþelastum +ferhþum fægne, foldweg mæton, +cuþe stræte. Cyningbalde men +from þæm holmclife hafelan bæron +earfoðlice heora æghwæþrum, +felamodigra; feower scoldon +on þæm wælstenge weorcum geferian +to þæm goldsele Grendles heafod, +oþðæt semninga to sele comon +frome fyrdhwate feowertyne +Geata gongan; gumdryhten mid +modig on gemonge meodowongas træd. +ða com in gan ealdor ðegna, +dædcene mon dome gewurþad, +hæle hildedeor, Hroðgar gretan. +þa wæs be feaxe on flet boren +Grendles heafod, þær guman druncon, +egeslic for eorlum ond þære idese mid, +wliteseon wrætlic; weras on sawon. +Beowulf maþelode, bearn Ecgþeowes: +"Hwæt! we þe þas sælac, sunu Healfdenes, +leod Scyldinga, lustum brohton +tires to tacne, þe þu her to locast. +Ic þæt unsofte ealdre gedigde +wigge under wætere, weorc geneþde +earfoðlice; ætrihte wæs +guð getwæfed, nymðe mec god scylde. +Ne meahte ic æt hilde mid Hruntinge +wiht gewyrcan, þeah þæt wæpen duge; +ac me geuðe ylda waldend +þæt ic on wage geseah wlitig hangian +eald sweord eacen (oftost wisode +winigea leasum), þæt ic ðy wæpne gebræd. +Ofsloh ða æt þære sæcce, þa me sæl ageald, +huses hyrdas. þa þæt hildebil +forbarn brogdenmæl, swa þæt blod gesprang, +hatost heaþoswata. Ic þæt hilt þanan +feondum ætferede, fyrendæda wræc, +deaðcwealm Denigea, swa hit gedefe wæs. +Ic hit þe þonne gehate, þæt þu on Heorote most +sorhleas swefan mid þinra secga gedryht +ond þegna gehwylc þinra leoda, +duguðe ond iogoþe, þæt þu him ondrædan ne þearft, +þeoden Scyldinga, on þa healfe, +aldorbealu eorlum, swa þu ær dydest." +ða wæs gylden hilt gamelum rince, +harum hildfruman, on hand gyfen, +enta ærgeweorc; hit on æht gehwearf +æfter deofla hryre Denigea frean, +wundorsmiþa geweorc, ond þa þas worold ofgeaf +gromheort guma, godes ondsaca, +morðres scyldig, ond his modor eac, +on geweald gehwearf woroldcyninga +ðæm selestan be sæm tweonum +ðara þe on Scedenigge sceattas dælde. +Hroðgar maðelode, hylt sceawode, +ealde lafe, on ðæm wæs or writen +fyrngewinnes, syðþan flod ofsloh, +gifen geotende, giganta cyn +(frecne geferdon); þæt wæs fremde þeod +ecean dryhtne; him þæs endelean +þurh wæteres wylm waldend sealde. +Swa wæs on ðæm scennum sciran goldes +þurh runstafas rihte gemearcod, +geseted ond gesæd hwam þæt sweord geworht, +irena cyst, ærest wære, +wreoþenhilt ond wyrmfah. ða se wisa spræc +sunu Healfdenes (swigedon ealle): +"þæt, la, mæg secgan se þe soð ond riht +fremeð on folce, feor eal gemon, +eald OEweard, þæt ðes eorl wære +geboren betera! Blæd is aræred +geond widwegas, wine min Beowulf, +ðin ofer þeoda gehwylce. Eal þu hit geþyldum healdest, +mægen mid modes snyttrum. Ic þe sceal mine gelæstan +freode, swa wit furðum spræcon. ðu scealt to frofre weorþan +eal langtwidig leodum þinum, +hæleðum to helpe. Ne wearð Heremod swa +eaforum Ecgwelan, Arscyldingum; +ne geweox he him to willan, ac to wælfealle +ond to deaðcwalum Deniga leodum; +breat bolgenmod beodgeneatas, +eaxlgesteallan, oþþæt he ana hwearf, +mære þeoden, mondreamum from. +ðeah þe hine mihtig god mægenes wynnum, +eafeþum stepte, ofer ealle men +forð gefremede, hwæþere him on ferhþe greow +breosthord blodreow. Nallas beagas geaf +Denum æfter dome; dreamleas gebad +þæt he þæs gewinnes weorc þrowade, +leodbealo longsum. ðu þe lær be þon, +gumcyste ongit; ic þis gid be þe +awræc wintrum frod. Wundor is to secganne +hu mihtig god manna cynne +þurh sidne sefan snyttru bryttað, +eard ond eorlscipe; he ah ealra geweald. +Hwilum he on lufan læteð hworfan +monnes modgeþonc mæran cynnes, +seleð him on eþle eorþan wynne +to healdanne, hleoburh wera, +gedeð him swa gewealdene worolde dælas, +side rice, þæt he his selfa ne mæg +for his unsnyttrum ende geþencean. +Wunað he on wiste; no hine wiht dweleð +adl ne yldo, ne him inwitsorh +on sefan sweorceð, ne gesacu ohwær +ecghete eoweð, ac him eal worold +wendeð on willan (he þæt wyrse ne con), +oðþæt him on innan oferhygda dæl +weaxeð ond wridað. þonne se weard swefeð, +sawele hyrde; bið se slæp to fæst, +bisgum gebunden, bona swiðe neah, +se þe of flanbogan fyrenum sceoteð. +þonne bið on hreþre under helm drepen +biteran stræle (him bebeorgan ne con), +wom wundorbebodum wergan gastes; +þinceð him to lytel þæt he lange heold, +gytsað gromhydig, nallas on gylp seleð +fædde beagas, ond he þa forðgesceaft +forgyteð ond forgymeð, þæs þe him ær god sealde, +wuldres waldend, weorðmynda dæl. +Hit on endestæf eft gelimpeð +þæt se lichoma læne gedreoseð, +fæge gefealleð; fehð oþer to, +se þe unmurnlice madmas dæleþ, +eorles ærgestreon, egesan ne gymeð. +Bebeorh þe ðone bealonið, Beowulf leofa, +secg betsta, ond þe þæt selre geceos, +ece rædas; oferhyda ne gym, +mære cempa. Nu is þines mægnes blæd +ane hwile. Eft sona bið +þæt þec adl oððe ecg eafoþes getwæfeð, +oððe fyres feng, oððe flodes wylm, +oððe gripe meces, oððe gares fliht, +oððe atol yldo; oððe eagena bearhtm +forsiteð ond forsworceð; semninga bið +þæt ðec, dryhtguma, deað oferswyðeð. +Swa ic Hringdena hund missera +weold under wolcnum ond hig wigge beleac +manigum mægþa geond þysne middangeard, +æscum ond ecgum, þæt ic me ænigne +under swegles begong gesacan ne tealde. +Hwæt, me þæs on eþle edwenden cwom, +gyrn æfter gomene, seoþðan Grendel wearð, +ealdgewinna, ingenga min; +ic þære socne singales wæg +modceare micle. þæs sig metode þanc, +ecean dryhtne, þæs ðe ic on aldre gebad +þæt ic on þone hafelan heorodreorigne +ofer ealdgewin eagum starige! +Ga nu to setle, symbelwynne dreoh +wigge weorþad; unc sceal worn fela +maþma gemænra, siþðan morgen bið." +Geat wæs glædmod, geong sona to +setles neosan, swa se snottra heht. +þa wæs eft swa ær ellenrofum +fletsittendum fægere gereorded +niowan stefne. Nihthelm geswearc +deorc ofer dryhtgumum. Duguð eal aras. +Wolde blondenfeax beddes neosan, +gamela Scylding. Geat unigmetes wel, +rofne randwigan, restan lyste; +sona him seleþegn siðes wergum, +feorrancundum, forð wisade, +se for andrysnum ealle beweotede +þegnes þearfe, swylce þy dogore +heaþoliðende habban scoldon. +Reste hine þa rumheort; reced hliuade +geap ond goldfah; gæst inne swæf +oþþæt hrefn blaca heofones wynne +bliðheort bodode. ða com beorht scacan +scaþan onetton, +wæron æþelingas eft to leodum +fuse to farenne; wolde feor þanon +cuma collenferhð ceoles neosan. +Heht þa se hearda Hrunting beran +sunu Ecglafes, heht his sweord niman, +leoflic iren; sægde him þæs leanes þanc, +cwæð, he þone guðwine godne tealde, +wigcræftigne, nales wordum log +meces ecge; þæt wæs modig secg. +Ond þa siðfrome, searwum gearwe +wigend wæron; eode weorð Denum +æþeling to yppan, þær se oþer wæs, +hæle hildedeor Hroðgar grette. +Beowulf maþelode, bearn Ecgþeowes: +"Nu we sæliðend secgan wyllað, +feorran cumene, þæt we fundiaþ +Higelac secan. Wæron her tela +willum bewenede; þu us wel dohtest. +Gif ic þonne on eorþan owihte mæg +þinre modlufan maran tilian, +gumena dryhten, ðonne ic gyt dyde, +guðgeweorca, ic beo gearo sona. +Gif ic þæt gefricge ofer floda begang, +þæt þec ymbsittend egesan þywað, +swa þec hetende hwilum dydon, +ic ðe þusenda þegna bringe, +hæleþa to helpe. Ic on Higelac wat, +Geata dryhten, þeah ðe he geong sy, +folces hyrde, þæt he mec fremman wile +wordum ond worcum, þæt ic þe wel herige +ond þe to geoce garholt bere, +mægenes fultum, þær ðe bið manna þearf. +Gif him þonne Hreþric to hofum Geata +geþingeð, þeodnes bearn, he mæg þær fela +freonda findan; feorcyþðe beoð +selran gesohte þæm þe him selfa deah." +Hroðgar maþelode him on ondsware: +"þe þa wordcwydas wigtig drihten +on sefan sende; ne hyrde ic snotorlicor +on swa geongum feore guman þingian. +þu eart mægenes strang ond on mode frod, +wis wordcwida. Wen ic talige, +gif þæt gegangeð, þæt ðe gar nymeð, +hild heorugrimme, Hreþles eaferan, +adl oþðe iren ealdor ðinne, +folces hyrde, ond þu þin feorh hafast, +þæt þe Sægeatas selran næbben +to geceosenne cyning ænigne, +hordweard hæleþa, gyf þu healdan wylt +maga rice. Me þin modsefa +licað leng swa wel, leofa Beowulf. +Hafast þu gefered þæt þam folcum sceal, +Geata leodum ond Gardenum, +sib gemæne, ond sacu restan, +inwitniþas, þe hie ær drugon, +wesan, þenden ic wealde widan rices, +maþmas gemæne, manig oþerne +godum gegretan ofer ganotes bæð; +sceal hringnaca ofer heafu bringan +lac ond luftacen. Ic þa leode wat +ge wið feond ge wið freond fæste geworhte, +æghwæs untæle ealde wisan." +ða git him eorla hleo inne gesealde, +mago Healfdenes, maþmas [XII]; +het hine mid þæm lacum leode swæse +secean on gesyntum, snude eft cuman. +Gecyste þa cyning æþelum god, +þeoden Scyldinga, ðegn betstan +ond be healse genam; hruron him tearas, +blondenfeaxum. Him wæs bega wen, +ealdum infrodum, oþres swiðor, +þæt hie seoððan no geseon moston, +modige on meþle. Wæs him se man to þon leof +þæt he þone breostwylm forberan ne mehte, +ac him on hreþre hygebendum fæst +æfter deorum men dyrne langað +beorn wið blode. Him Beowulf þanan, +guðrinc goldwlanc, græsmoldan træd +since hremig; sægenga bad +agendfrean, se þe on ancre rad. +þa wæs on gange gifu Hroðgares +oft geæhted; þæt wæs an cyning, +æghwæs orleahtre, oþþæt hine yldo benam +mægenes wynnum, se þe oft manegum scod. +Cwom þa to flode felamodigra, +hægstealdra heap, hringnet bæron, +locene leoðosyrcan. Landweard onfand +eftsið eorla, swa he ær dyde; +no he mid hearme of hliðes nosan +gæstas grette, ac him togeanes rad, +cwæð þæt wilcuman Wedera leodum +scaþan scirhame to scipe foron. +þa wæs on sande sægeap naca +hladen herewædum, hringedstefna, +mearum ond maðmum; mæst hlifade +ofer Hroðgares hordgestreonum. +He þæm batwearde bunden golde +swurd gesealde, þæt he syðþan wæs +on meodubence maþme þy weorþra, +yrfelafe. Gewat him on naca +drefan deop wæter, Dena land ofgeaf. +þa wæs be mæste merehrægla sum, +segl sale fæst; sundwudu þunede. +No þær wegflotan wind ofer yðum +siðes getwæfde; sægenga for, +fleat famigheals forð ofer yðe, +bundenstefna ofer brimstreamas, +þæt hie Geata clifu ongitan meahton, +cuþe næssas. Ceol up geþrang +lyftgeswenced, on lande stod. +Hraþe wæs æt holme hyðweard geara, +se þe ær lange tid leofra manna +fus æt faroðe feor wlatode; +sælde to sande sidfæþme scip, +oncerbendum fæst, þy læs hym yþa ðrym +wudu wynsuman forwrecan meahte. +Het þa up beran æþelinga gestreon, +frætwe ond fætgold; næs him feor þanon +to gesecanne sinces bryttan, +Higelac Hreþling, þær æt ham wunað +selfa mid gesiðum sæwealle neah. +Bold wæs betlic, bregorof cyning, +heah in healle, Hygd swiðe geong, +wis, welþungen, þeah ðe wintra lyt +under burhlocan gebiden hæbbe, +Hæreþes dohtor; næs hio hnah swa þeah, +ne to gneað gifa Geata leodum, +maþmgestreona. Mod þryðo wæg, +fremu folces cwen, firen ondrysne. +Nænig þæt dorste deor geneþan +swæsra gesiða, nefne sinfrea, +þæt hire an dæges eagum starede, +ac him wælbende weotode tealde +handgewriþene; hraþe seoþðan wæs +æfter mundgripe mece geþinged, +þæt hit sceadenmæl scyran moste, +cwealmbealu cyðan. Ne bið swylc cwenlic þeaw +idese to efnanne, þeah ðe hio ænlicu sy, +þætte freoðuwebbe feores onsæce +æfter ligetorne leofne mannan. +Huru þæt onhohsnode Hemminges mæg; +ealodrincende oðer sædan, +þæt hio leodbealewa læs gefremede, +inwitniða, syððan ærest wearð +gyfen goldhroden geongum cempan, +æðelum diore, syððan hio Offan flet +ofer fealone flod be fæder lare +siðe gesohte; ðær hio syððan well +in gumstole, gode, mære, +lifgesceafta lifigende breac, +hiold heahlufan wið hæleþa brego, +ealles moncynnes mine gefræge +þone selestan bi sæm tweonum, +eormencynnes. Forðam Offa wæs +geofum ond guðum, garcene man, +wide geweorðod, wisdome heold +eðel sinne; þonon Eomer woc +hæleðum to helpe, Hemminges mæg, +nefa Garmundes, niða cræftig. +Gewat him ða se hearda mid his hondscole +sylf æfter sande sæwong tredan, +wide waroðas. Woruldcandel scan, +sigel suðan fus. Hi sið drugon, +elne geeodon, to ðæs ðe eorla hleo, +bonan Ongenþeoes burgum in innan, +geongne guðcyning godne gefrunon +hringas dælan. Higelace wæs +sið Beowulfes snude gecyðed, +þæt ðær on worðig wigendra hleo, +lindgestealla, lifigende cwom, +heaðolaces hal to hofe gongan. +Hraðe wæs gerymed, swa se rica bebead, +feðegestum flet innanweard. +Gesæt þa wið sylfne se ða sæcce genæs, +mæg wið mæge, syððan mandryhten +þurh hleoðorcwyde holdne gegrette, +meaglum wordum. Meoduscencum hwearf +geond þæt healreced Hæreðes dohtor, +lufode ða leode, liðwæge bær +hæleðum to handa. Higelac ongan +sinne geseldan in sele þam hean +fægre fricgcean (hyne fyrwet bræc, +hwylce Sægeata siðas wæron): +"Hu lomp eow on lade, leofa Biowulf, +þa ðu færinga feorr gehogodest +sæcce secean ofer sealt wæter, +hilde to Hiorote? Ac ðu Hroðgare +widcuðne wean wihte gebettest, +mærum ðeodne? Ic ðæs modceare +sorhwylmum seað, siðe ne truwode +leofes mannes; ic ðe lange bæd +þæt ðu þone wælgæst wihte ne grette, +lete Suðdene sylfe geweorðan +guðe wið Grendel. Gode ic þanc secge +þæs ðe ic ðe gesundne geseon moste." +Biowulf maðelode, bearn Ecgðioes: +"þæt is undyrne, dryhten Higelac, +micel gemeting, monegum fira, +hwylc orleghwil uncer Grendles +wearð on ðam wange, þær he worna fela +Sigescyldingum sorge gefremede, +yrmðe to aldre. Ic ðæt eall gewræc, +swa begylpan ne þearf Grendeles maga +ænig ofer eorðan uhthlem þone, +se ðe lengest leofað laðan cynnes, +facne bifongen. Ic ðær furðum cwom +to ðam hringsele Hroðgar gretan; +sona me se mæra mago Healfdenes, +syððan he modsefan minne cuðe, +wið his sylfes sunu setl getæhte. +Weorod wæs on wynne; ne seah ic widan feorh +under heofones hwealf healsittendra +medudream maran. Hwilum mæru cwen, +friðusibb folca, flet eall geondhwearf, +bædde byre geonge; oft hio beahwriðan +secge sealde, ær hie to setle geong. +Hwilum for duguðe dohtor Hroðgares +eorlum on ende ealuwæge bær; +þa ic Freaware fletsittende +nemnan hyrde, þær hio nægled sinc +hæleðum sealde. Sio gehaten is, +geong, goldhroden, gladum suna Frodan; +hafað þæs geworden wine Scyldinga, +rices hyrde, ond þæt ræd talað, +þæt he mid ðy wife wælfæhða dæl, +sæcca gesette. Oft seldan hwær +æfter leodhryre lytle hwile +bongar bugeð, þeah seo bryd duge! +Mæg þæs þonne ofþyncan ðeodne Heaðobeardna +ond þegna gehwam þara leoda, +þonne he mid fæmnan on flett gæð, +dryhtbearn Dena, duguða biwenede; +on him gladiað gomelra lafe, +heard ond hringmæl Heaðabeardna gestreon +þenden hie ðam wæpnum wealdan moston, +oððæt hie forlæddan to ðam lindplegan +swæse gesiðas ond hyra sylfra feorh. +þonne cwið æt beore se ðe beah gesyhð, +eald æscwiga, se ðe eall geman, +garcwealm gumena (him bið grim sefa), +onginneð geomormod geongum cempan +þurh hreðra gehygd higes cunnian, +wigbealu weccean, ond þæt word acwyð: +'Meaht ðu, min wine, mece gecnawan +þone þin fæder to gefeohte bær +under heregriman hindeman siðe, +dyre iren, þær hyne Dene slogon, +weoldon wælstowe, syððan Wiðergyld læg, +æfter hæleþa hryre, hwate Scyldungas? +Nu her þara banena byre nathwylces +frætwum hremig on flet gæð, +morðres gylpeð, ond þone maðþum byreð, +þone þe ðu mid rihte rædan sceoldest.' +Manað swa ond myndgað mæla gehwylce +sarum wordum, oððæt sæl cymeð +þæt se fæmnan þegn fore fæder dædum +æfter billes bite blodfag swefeð, +ealdres scyldig; him se oðer þonan +losað lifigende, con him land geare. +þonne bioð abrocene on ba healfe +aðsweord eorla; syððan Ingelde +weallað wælniðas, ond him wiflufan +æfter cearwælmum colran weorðað. +þy ic Heaðobeardna hyldo ne telge, +dryhtsibbe dæl Denum unfæcne, +freondscipe fæstne. Ic sceal forð sprecan +gen ymbe Grendel, þæt ðu geare cunne, +sinces brytta, to hwan syððan wearð +hondræs hæleða. Syððan heofones gim +glad ofer grundas, gæst yrre cwom, +eatol, æfengrom, user neosan, +ðær we gesunde sæl weardodon. +þær wæs Hondscio hild onsæge, +feorhbealu fægum; he fyrmest læg, +gyrded cempa; him Grendel wearð, +mærum maguþegne to muðbonan, +leofes mannes lic eall forswealg. +No ðy ær ut ða gen idelhende +bona blodigtoð, bealewa gemyndig, +of ðam goldsele gongan wolde, +ac he mægnes rof min costode, +grapode gearofolm. Glof hangode +sid ond syllic, searobendum fæst; +sio wæs orðoncum eall gegyrwed +deofles cræftum ond dracan fellum. +He mec þær on innan unsynnigne, +dior dædfruma, gedon wolde +manigra sumne; hyt ne mihte swa, +syððan ic on yrre uppriht astod. +To lang ys to reccenne hu ic ðam leodsceaðan +yfla gehwylces ondlean forgeald; +þær ic, þeoden min, þine leode +weorðode weorcum. He on weg losade, +lytle hwile lifwynna breac; +hwæþre him sio swiðre swaðe weardade +hand on Hiorte, ond he hean ðonan +modes geomor meregrund gefeoll. +Me þone wælræs wine Scildunga +fættan golde fela leanode, +manegum maðmum, syððan mergen com +ond we to symble geseten hæfdon. +þær wæs gidd ond gleo. Gomela Scilding, +felafricgende, feorran rehte; +hwilum hildedeor hearpan wynne, +gomenwudu grette, hwilum gyd awræc +soð ond sarlic, hwilum syllic spell +rehte æfter rihte rumheort cyning. +Hwilum eft ongan, eldo gebunden, +gomel guðwiga gioguðe cwiðan, +hildestrengo; hreðer inne weoll, +þonne he wintrum frod worn gemunde. +Swa we þær inne ondlangne dæg +niode naman, oððæt niht becwom +oðer to yldum. þa wæs eft hraðe +gearo gyrnwræce Grendeles modor, +siðode sorhfull; sunu deað fornam, +wighete Wedra. Wif unhyre +hyre bearn gewræc, beorn acwealde +ellenlice; þær wæs æschere, +frodan fyrnwitan, feorh uðgenge. +Noðer hy hine ne moston, syððan mergen cwom, +deaðwerigne, Denia leode, +bronde forbærnan, ne on bęl hladan +leofne mannan; hio þæt lic ætbær +feondes fæðmum under firgenstream. +þæt wæs Hroðgare hreowa tornost +þara þe leodfruman lange begeate. +þa se ðeoden mec ðine life +healsode hreohmod, þæt ic on holma geþring +eorlscipe efnde, ealdre geneðde, +mærðo fremede; he me mede gehet. +Ic ða ðæs wælmes, þe is wide cuð, +grimne gryrelicne grundhyrde fond; +þær unc hwile wæs hand gemæne, +holm heolfre weoll, ond ic heafde becearf +in ðam guðsele Grendeles modor +eacnum ecgum, unsofte þonan +feorh oðferede. Næs ic fæge þa gyt, +ac me eorla hleo eft gesealde +maðma menigeo, maga Healfdenes. +Swa se ðeodkyning þeawum lyfde. +Nealles ic ðam leanum forloren hæfde, +mægnes mede, ac he me maðmas geaf, +sunu Healfdenes, on minne sylfes dom; +ða ic ðe, beorncyning, bringan wylle, +estum geywan. Gen is eall æt ðe +lissa gelong; ic lyt hafo +heafodmaga nefne, Hygelac, ðec." +Het ða in beran eaforheafodsegn, +heaðosteapne helm, hare byrnan, +guðsweord geatolic, gyd æfter wræc: +"Me ðis hildesceorp Hroðgar sealde, +snotra fengel, sume worde het +þæt ic his ærest ðe est gesægde; +cwæð þæt hyt hæfde Hiorogar cyning, +leod Scyldunga lange hwile; +no ðy ær suna sinum syllan wolde, +hwatum Heorowearde, þeah he him hold wære, +breostgewædu. Bruc ealles well!" +Hyrde ic þæt þam frætwum feower mearas +lungre, gelice, last weardode, +æppelfealuwe; he him est geteah +meara ond maðma. Swa sceal mæg don, +nealles inwitnet oðrum bregdon +dyrnum cræfte, deað renian +hondgesteallan. Hygelace wæs, +niða heardum, nefa swyðe hold, +ond gehwæðer oðrum hroþra gemyndig. +Hyrde ic þæt he ðone healsbeah Hygde gesealde, +wrætlicne wundurmaððum, ðone þe him Wealhðeo geaf, +ðeodnes dohtor, þrio wicg somod +swancor ond sadolbeorht; hyre syððan wæs +æfter beahðege breost geweorðod. +Swa bealdode bearn Ecgðeowes, +guma guðum cuð, godum dædum, +dreah æfter dome, nealles druncne slog +heorðgeneatas; næs him hreoh sefa, +ac he mancynnes mæste cræfte +ginfæstan gife, þe him god sealde, +heold hildedeor. Hean wæs lange, +swa hyne Geata bearn godne ne tealdon, +ne hyne on medobence micles wyrðne +drihten Wedera gedon wolde; +swyðe wendon þæt he sleac wære, +æðeling unfrom. Edwenden cwom +tireadigum menn torna gehwylces. +Het ða eorla hleo in gefetian, +heaðorof cyning, Hreðles lafe +golde gegyrede; næs mid Geatum ða +sincmaðþum selra on sweordes had; +þæt he on Biowulfes bearm alegde +ond him gesealde seofan þusendo, +bold ond bregostol. Him wæs bam samod +on ðam leodscipe lond gecynde, +eard, eðelriht, oðrum swiðor +side rice þam ðær selra wæs. +Eft þæt geiode ufaran dogrum +hildehlæmmum, syððan Hygelac læg +ond Heardrede hildemeceas +under bordhreoðan to bonan wurdon, +ða hyne gesohtan on sigeþeode +hearde hildefrecan, Heaðoscilfingas, +niða genægdan nefan Hererices, +syððan Beowulfe brade rice +on hand gehwearf; he geheold tela +fiftig wintra (wæs ða frod cyning, +eald eþelweard), oððæt an ongan +deorcum nihtum draca ricsian, +se ðe on heaum hofe hord beweotode, +stanbeorh steapne; stig under læg, +eldum uncuð. þær on innan giong +niða nathwylc, se ðe neh gefeng +hæðnum horde, hond [...], +since fahne. He þæt syððan [...], +þeah ðe he slæpende besyred wurde +þeofes cræfte; þæt sie ðiod onfand, +bufolc beorna, þæt he gebolgen wæs. +Nealles mid gewealdum wyrmhord abræc +sylfes willum, se ðe him sare gesceod, +ac for þreanedlan þeow nathwylces +hæleða bearna heteswengeas fleah, +ærnes þearfa, ond ðær inne fealh, +secg synbysig, sona onfunde +þæt þær ðam gyste gryrebroga stod; +hwæðre earmsceapen +sceapen +þa hyne se fær begeat. +Sincfæt [...]; þær wæs swylcra fela +in ðam eorðhuse ærgestreona, +swa hy on geardagum gumena nathwylc, +eormenlafe æþelan cynnes, +þanchycgende þær gehydde, +deore maðmas. Ealle hie deað fornam +ærran mælum, ond se an ða gen +leoda duguðe, se ðær lengest hwearf, +weard winegeomor, wende þæs ylcan, +þæt he lytel fæc longgestreona +brucan moste. Beorh eallgearo +wunode on wonge wæteryðum neah, +niwe be næsse, nearocræftum fæst. +þær on innan bær eorlgestreona +hringa hyrde hordwyrðne dæl, +fættan goldes, fea worda cwæð: +"Heald þu nu, hruse, nu hæleð ne moston, +eorla æhte! Hwæt, hyt ær on ðe +gode begeaton. Guðdeað fornam, +feorhbealo frecne, fyra gehwylcne +leoda minra, þara ðe þis lif ofgeaf, +gesawon seledream. Ic nah hwa sweord wege +oððe feormie fæted wæge, +dryncfæt deore; duguð ellor sceoc. +Sceal se hearda helm hyrsted golde +fætum befeallen; feormynd swefað, +þa ðe beadogriman bywan sceoldon, +ge swylce seo herepad, sio æt hilde gebad +ofer borda gebræc bite irena, +brosnað æfter beorne. Ne mæg byrnan hring +æfter wigfruman wide feran, +hæleðum be healfe. Næs hearpan wyn, +gomen gleobeames, ne god hafoc +geond sæl swingeð, ne se swifta mearh +burhstede beateð. Bealocwealm hafað +fela feorhcynna forð onsended!" +Swa giomormod giohðo mænde +an æfter eallum, unbliðe hwearf +dæges ond nihtes, oððæt deaðes wylm +hran æt heortan. Hordwynne fond +eald uhtsceaða opene standan, +se ðe byrnende biorgas seceð, +nacod niðdraca, nihtes fleogeð +fyre befangen; hyne foldbuend +swiðe ondrædað. He gesecean sceall +hord on hrusan, þær he hæðen gold +warað wintrum frod, ne byð him wihte ðy sel. +Swa se ðeodsceaða þreo hund wintra +heold on hrusan hordærna sum, +eacencræftig, oððæt hyne an abealch +mon on mode; mandryhtne bær +fæted wæge, frioðowære bæd +hlaford sinne. ða wæs hord rasod, +onboren beaga hord, bene getiðad +feasceaftum men. Frea sceawode +fira fyrngeweorc forman siðe. +þa se wyrm onwoc, wroht wæs geniwad; +stonc ða æfter stane, stearcheort onfand +feondes fotlast; he to forð gestop +dyrnan cræfte dracan heafde neah. +Swa mæg unfæge eaðe gedigan +wean ond wræcsið, se ðe waldendes +hyldo gehealdeþ! Hordweard sohte +georne æfter grunde, wolde guman findan, +þone þe him on sweofote sare geteode, +hat ond hreohmod hlæw oft ymbehwearf +ealne utanweardne, ne ðær ænig mon +on þære westenne; hwæðre wiges gefeh, +beaduwe weorces, hwilum on beorh æthwearf, +sincfæt sohte. He þæt sona onfand +ðæt hæfde gumena sum goldes gefandod, +heahgestreona. Hordweard onbad +earfoðlice oððæt æfen cwom; +wæs ða gebolgen beorges hyrde, +wolde se laða lige forgyldan +drincfæt dyre. þa wæs dæg sceacen +wyrme on willan; no on wealle læg, +bidan wolde, ac mid bæle for, +fyre gefysed. Wæs se fruma egeslic +leodum on lande, swa hyt lungre wearð +on hyra sincgifan sare geendod. +ða se gæst ongan gledum spiwan, +beorht hofu bærnan; bryneleoma stod +eldum on andan. No ðær aht cwices +lað lyftfloga læfan wolde. +Wæs þæs wyrmes wig wide gesyne, +nearofages nið nean ond feorran, +hu se guðsceaða Geata leode +hatode ond hynde; hord eft gesceat, +dryhtsele dyrnne, ær dæges hwile. +Hæfde landwara lige befangen, +bæle ond bronde, beorges getruwode, +wiges ond wealles; him seo wen geleah. +þa wæs Biowulfe broga gecyðed +snude to soðe, þæt his sylfes ham, +bolda selest, brynewylmum mealt, +gifstol Geata. þæt ðam godan wæs +hreow on hreðre, hygesorga mæst; +wende se wisa þæt he wealdende +ofer ealde riht, ecean dryhtne, +bitre gebulge. Breost innan weoll +þeostrum geþoncum, swa him geþywe ne wæs. +Hæfde ligdraca leoda fæsten, +ealond utan, eorðweard ðone +gledum forgrunden; him ðæs guðkyning, +Wedera þioden, wræce leornode. +Heht him þa gewyrcean wigendra hleo +eallirenne, eorla dryhten, +wigbord wrætlic; wisse he gearwe +þæt him holtwudu helpan ne meahte, +lind wið lige. Sceolde lændaga +æþeling ærgod ende gebidan, +worulde lifes, ond se wyrm somod, +þeah ðe hordwelan heolde lange. +Oferhogode ða hringa fengel +þæt he þone widflogan weorode gesohte, +sidan herge; no he him þa sæcce ondred, +ne him þæs wyrmes wig for wiht dyde, +eafoð ond ellen, forðon he ær fela +nearo neðende niða gedigde, +hildehlemma, syððan he Hroðgares, +sigoreadig secg, sele fælsode +ond æt guðe forgrap Grendeles mægum +laðan cynnes. No þæt læsest wæs +hondgemota, þær mon Hygelac sloh, +syððan Geata cyning guðe ræsum, +freawine folca Freslondum on, +Hreðles eafora hiorodryncum swealt, +bille gebeaten. þonan Biowulf com +sylfes cræfte, sundnytte dreah; +hæfde him on earme ana [XXX] +hildegeatwa, þa he to holme beag. +Nealles Hetware hremge þorfton +feðewiges, þe him foran ongean +linde bæron; lyt eft becwom +fram þam hildfrecan hames niosan. +Oferswam ða sioleða bigong sunu Ecgðeowes, +earm anhaga, eft to leodum; +þær him Hygd gebead hord ond rice, +beagas ond bregostol, bearne ne truwode +þæt he wið ælfylcum eþelstolas +healdan cuðe, ða wæs Hygelac dead. +No ðy ær feasceafte findan meahton +æt ðam æðelinge ænige ðinga, +þæt he Heardrede hlaford wære +oððe þone cynedom ciosan wolde; +hwæðre he him on folce freondlarum heold, +estum mid are, oððæt he yldra wearð, +Wedergeatum weold. Hyne wræcmæcgas +ofer sæ sohtan, suna Ohteres; +hæfdon hy forhealden helm Scylfinga, +þone selestan sæcyninga +þara ðe in Swiorice sinc brytnade, +mærne þeoden. Him þæt to mearce wearð; +he þær for feorme feorhwunde hleat +sweordes swengum, sunu Hygelaces, +ond him eft gewat Ongenðioes bearn +hames niosan, syððan Heardred læg, +let ðone bregostol Biowulf healdan, +Geatum wealdan. þæt wæs god cyning! +Se ðæs leodhryres lean gemunde +uferan dogrum, Eadgilse wearð +feasceaftum freond, folce gestepte +ofer sæ side sunu Ohteres, +wigum ond wæpnum; he gewræc syððan +cealdum cearsiðum, cyning ealdre bineat. +Swa he niða gehwane genesen hæfde, +sliðra geslyhta, sunu Ecgðiowes, +ellenweorca, oð ðone anne dæg +þe he wið þam wyrme gewegan sceolde. +Gewat þa [XII]a sum torne gebolgen +dryhten Geata dracan sceawian. +Hæfde þa gefrunen hwanan sio fæhð aras, +bealonið biorna; him to bearme cwom +maðþumfæt mære þurh ðæs meldan hond. +Se wæs on ðam ðreate þreotteoða secg, +se ðæs orleges or onstealde, +hæft hygegiomor, sceolde hean ðonon +wong wisian. He ofer willan giong +to ðæs ðe he eorðsele anne wisse, +hlæw under hrusan holmwylme neh, +yðgewinne; se wæs innan full +wrætta ond wira. Weard unhiore, +gearo guðfreca, goldmaðmas heold, +eald under eorðan. Næs þæt yðe ceap +to gegangenne gumena ænigum! +Gesæt ða on næsse niðheard cyning, +þenden hælo abead heorðgeneatum, +goldwine Geata. Him wæs geomor sefa, +wæfre ond wælfus, wyrd ungemete neah, +se ðone gomelan gretan sceolde, +secean sawle hord, sundur gedælan +lif wið lice, no þon lange wæs +feorh æþelinges flæsce bewunden. +Biowulf maþelade, bearn Ecgðeowes: +"Fela ic on giogoðe guðræsa genæs, +orleghwila; ic þæt eall gemon. +Ic wæs syfanwintre, þa mec sinca baldor, +freawine folca, æt minum fæder genam; +heold mec ond hæfde Hreðel cyning, +geaf me sinc ond symbel, sibbe gemunde. +Næs ic him to life laðra owihte, +beorn in burgum, þonne his bearna hwylc, +Herebeald ond Hæðcyn oððe Hygelac min. +Wæs þam yldestan ungedefelice +mæges dædum morþorbed stred, +syððan hyne Hæðcyn of hornbogan, +his freawine, flane geswencte, +miste mercelses ond his mæg ofscet, +broðor oðerne blodigan gare. +þæt wæs feohleas gefeoht, fyrenum gesyngad, +hreðre hygemeðe; sceolde hwæðre swa þeah +æðeling unwrecen ealdres linnan. +Swa bið geomorlic gomelum ceorle +to gebidanne, þæt his byre ride +giong on galgan, þonne he gyd wrece, +sarigne sang, þonne his sunu hangað +hrefne to hroðre, ond he him helpe ne mæg, +eald ond infrod, ænige gefremman. +Symble bið gemyndgad morna gehwylce +eaforan ellorsið; oðres ne gymeð +to gebidanne burgum in innan +yrfeweardas, þonne se an hafað +þurh deaðes nyd dæda gefondad. +Gesyhð sorhcearig on his suna bure +winsele westne, windge reste +reote berofene. Ridend swefað, +hæleð in hoðman; nis þær hearpan sweg, +gomen in geardum, swylce ðær iu wæron. +Gewiteð þonne on sealman, sorhleoð gæleð +an æfter anum; þuhte him eall to rum, +wongas ond wicstede. Swa Wedra helm +æfter Herebealde heortan sorge +weallende wæg. Wihte ne meahte +on ðam feorhbonan fæghðe gebetan; +no ðy ær he þone heaðorinc hatian ne meahte +laðum dædum, þeah him leof ne wæs. +He ða mid þære sorhge, þe him swa sar belamp, +gumdream ofgeaf, godes leoht geceas, +eaferum læfde, swa deð eadig mon, +lond ond leodbyrig, þa he of life gewat. +þa wæs synn ond sacu Sweona ond Geata +ofer wid wæter, wroht gemæne, +herenið hearda, syððan Hreðel swealt, +oððe him Ongenðeowes eaferan wæran +frome, fyrdhwate, freode ne woldon +ofer heafo healdan, ac ymb Hreosnabeorh +eatolne inwitscear oft gefremedon. +þæt mægwine mine gewræcan, +fæhðe ond fyrene, swa hyt gefræge wæs, +þeah ðe oðer his ealdre gebohte, +heardan ceape; Hæðcynne wearð, +Geata dryhtne, guð onsæge. +þa ic on morgne gefrægn mæg oðerne +billes ecgum on bonan stælan, +þær Ongenþeow Eofores niosað. +Guðhelm toglad, gomela Scylfing +hreas hildeblac; hond gemunde +fæhðo genoge, feorhsweng ne ofteah. +Ic him þa maðmas, þe he me sealde, +geald æt guðe, swa me gifeðe wæs, +leohtan sweorde; he me lond forgeaf, +eard, eðelwyn. Næs him ænig þearf +þæt he to Gifðum oððe to Gardenum +oððe in Swiorice secean þurfe +wyrsan wigfrecan, weorðe gecypan. +Symle ic him on feðan beforan wolde, +ana on orde, ond swa to aldre sceall +sæcce fremman, þenden þis sweord þolað, +þæt mec ær ond sið oft gelæste. +Syððan ic for dugeðum Dæghrefne wearð +to handbonan, Huga cempan; +nalles he ða frætwe Frescyninge, +breostweorðunge, bringan moste, +ac in compe gecrong cumbles hyrde, +æþeling on elne; ne wæs ecg bona, +ac him hildegrap heortan wylmas, +banhus gebræc. Nu sceall billes ecg, +hond ond heard sweord, ymb hord wigan." +Beowulf maðelode, beotwordum spræc +niehstan siðe: "Ic geneðde fela +guða on geogoðe; gyt ic wylle, +frod folces weard, fæhðe secan, +mærðu fremman, gif mec se mansceaða +of eorðsele ut geseceð." +Gegrette ða gumena gehwylcne, +hwate helmberend, hindeman siðe, +swæse gesiðas: "Nolde ic sweord beran, +wæpen to wyrme, gif ic wiste hu +wið ðam aglæcean elles meahte +gylpe wiðgripan, swa ic gio wið Grendle dyde. +Ac ic ðær heaðufyres hates wene, +oreðes ond attres; forðon ic me on hafu +bord ond byrnan. Nelle ic beorges weard +forfleon fotes trem, ac unc furður sceal +weorðan æt wealle, swa unc wyrd geteoð, +metod manna gehwæs. Ic eom on mode from +þæt ic wið þone guðflogan gylp ofersitte. +Gebide ge on beorge byrnum werede, +secgas on searwum, hwæðer sel mæge +æfter wælræse wunde gedygan +uncer twega. Nis þæt eower sið +ne gemet mannes, nefne min anes, +þæt he wið aglæcean eofoðo dæle, +eorlscype efne. Ic mid elne sceall +gold gegangan, oððe guð nimeð, +feorhbealu frecne, frean eowerne!" +Aras ða bi ronde rof oretta, +heard under helme, hiorosercean bær +under stancleofu, strengo getruwode +anes mannes. Ne bið swylc earges sið! +Geseah ða be wealle se ðe worna fela, +gumcystum god, guða gedigde, +hildehlemma, þonne hnitan feðan, +stondan stanbogan, stream ut þonan +brecan of beorge. Wæs þære burnan wælm +heaðofyrum hat; ne meahte horde neah +unbyrnende ænige hwile +deop gedygan for dracan lege. +Let ða of breostum, ða he gebolgen wæs, +Wedergeata leod word ut faran, +stearcheort styrmde; stefn in becom +heaðotorht hlynnan under harne stan. +Hete wæs onhrered, hordweard oncniow +mannes reorde; næs ðær mara fyrst +freode to friclan. From ærest cwom +oruð aglæcean ut of stane, +hat hildeswat. Hruse dynede. +Biorn under beorge bordrand onswaf +wið ðam gryregieste, Geata dryhten; +ða wæs hringbogan heorte gefysed +sæcce to seceanne. Sweord ær gebræd +god guðcyning, gomele lafe, +ecgum unslaw; æghwæðrum wæs +bealohycgendra broga fram oðrum. +Stiðmod gestod wið steapne rond +winia bealdor, ða se wyrm gebeah +snude tosomne; he on searwum bad. +Gewat ða byrnende gebogen scriðan, +to gescipe scyndan. Scyld wel gebearg +life ond lice læssan hwile +mærum þeodne þonne his myne sohte, +ðær he þy fyrste, forman dogore +wealdan moste swa him wyrd ne gescraf +hreð æt hilde. Hond up abræd +Geata dryhten, gryrefahne sloh +incgelafe, þæt sio ecg gewac +brun on bane, bat unswiðor +þonne his ðiodcyning þearfe hæfde, +bysigum gebæded. þa wæs beorges weard +æfter heaðuswenge on hreoum mode, +wearp wælfyre; wide sprungon +hildeleoman. Hreðsigora ne gealp +goldwine Geata; guðbill geswac, +nacod æt niðe, swa hyt no sceolde, +iren ærgod. Ne wæs þæt eðe sið, +þæt se mæra maga Ecgðeowes +grundwong þone ofgyfan wolde; +sceolde ofer willan wic eardian +elles hwergen, swa sceal æghwylc mon +alætan lændagas. Næs ða long to ðon +þæt ða aglæcean hy eft gemetton. +Hyrte hyne hordweard (hreðer æðme weoll) +niwan stefne; nearo ðrowode, +fyre befongen, se ðe ær folce weold. +Nealles him on heape handgesteallan, +æðelinga bearn, ymbe gestodon +hildecystum, ac hy on holt bugon, +ealdre burgan. Hiora in anum weoll +sefa wið sorgum; sibb æfre ne mæg +wiht onwendan þam ðe wel þenceð. +Wiglaf wæs haten Weoxstanes sunu, +leoflic lindwiga, leod Scylfinga, +mæg ælfheres; geseah his mondryhten +under heregriman hat þrowian. +Gemunde ða ða are þe he him ær forgeaf, +wicstede weligne Wægmundinga, +folcrihta gehwylc, swa his fæder ahte. +Ne mihte ða forhabban; hond rond gefeng, +geolwe linde, gomel swyrd geteah, +þæt wæs mid eldum Eanmundes laf, +suna Ohteres. þam æt sæcce wearð, +wræccan wineleasum, Weohstan bana +meces ecgum, ond his magum ætbær +brunfagne helm, hringde byrnan, +eald sweord etonisc; þæt him Onela forgeaf, +his gædelinges guðgewædu, +fyrdsearo fuslic, no ymbe ða fæhðe spræc, +þeah ðe he his broðor bearn abredwade. +He frætwe geheold fela missera, +bill ond byrnan, oððæt his byre mihte +eorlscipe efnan swa his ærfæder; +geaf him ða mid Geatum guðgewæda, +æghwæs unrim, þa he of ealdre gewat, +frod on forðweg. þa wæs forma sið +geongan cempan, þæt he guðe ræs +mid his freodryhtne fremman sceolde. +Ne gemealt him se modsefa, ne his mæges laf +gewac æt wige; þæt se wyrm onfand, +syððan hie togædre gegan hæfdon. +Wiglaf maðelode, wordrihta fela +sægde gesiðum (him wæs sefa geomor): +"Ic ðæt mæl geman, þær we medu þegun, +þonne we geheton ussum hlaforde +in biorsele, ðe us ðas beagas geaf, +þæt we him ða guðgetawa gyldan woldon +gif him þyslicu þearf gelumpe, +helmas ond heard sweord. ðe he usic on herge geceas +to ðyssum siðfate sylfes willum, +onmunde usic mærða, ond me þas maðmas geaf, +þe he usic garwigend gode tealde, +hwate helmberend, þeah ðe hlaford us +þis ellenweorc ana aðohte +to gefremmanne, folces hyrde, +for ðam he manna mæst mærða gefremede, +dæda dollicra. Nu is se dæg cumen +þæt ure mandryhten mægenes behofað, +godra guðrinca; wutun gongan to, +helpan hildfruman, þenden hyt sy, +gledegesa grim. God wat on mec +þæt me is micle leofre þæt minne lichaman +mid minne goldgyfan gled fæðmie. +Ne þynceð me gerysne þæt we rondas beren +eft to earde, nemne we æror mægen +fane gefyllan, feorh ealgian +Wedra ðeodnes. Ic wat geare +þæt næron ealdgewyrht, þæt he ana scyle +Geata duguðe gnorn þrowian, +gesigan æt sæcce; urum sceal sweord ond helm, +byrne ond beaduscrud, bam gemæne." +Wod þa þurh þone wælrec, wigheafolan bær +frean on fultum, fea worda cwæð: +"Leofa Biowulf, læst eall tela, +swa ðu on geoguðfeore geara gecwæde +þæt ðu ne alæte be ðe lifigendum +dom gedreosan. Scealt nu dædum rof, +æðeling anhydig, ealle mægene +feorh ealgian; ic ðe fullæstu." +æfter ðam wordum wyrm yrre cwom, +atol inwitgæst, oðre siðe +fyrwylmum fah fionda niosian, +laðra manna; ligyðum for. +Born bord wið rond, byrne ne meahte +geongum garwigan geoce gefremman, +ac se maga geonga under his mæges scyld +elne geeode, þa his agen wæs +gledum forgrunden. þa gen guðcyning +mærða gemunde, mægenstrengo sloh +hildebille, þæt hyt on heafolan stod +niþe genyded; Nægling forbærst, +geswac æt sæcce sweord Biowulfes, +gomol ond grægmæl. Him þæt gifeðe ne wæs +þæt him irenna ecge mihton +helpan æt hilde; wæs sio hond to strong, +se ðe meca gehwane, mine gefræge, +swenge ofersohte, þonne he to sæcce bær +wæpen wundrum heard; næs him wihte ðe sel. +þa wæs þeodsceaða þriddan siðe, +frecne fyrdraca, fæhða gemyndig, +ræsde on ðone rofan, þa him rum ageald, +hat ond heaðogrim, heals ealne ymbefeng +biteran banum; he geblodegod wearð +sawuldriore, swat yðum weoll. +ða ic æt þearfe gefrægn þeodcyninges +andlongne eorl ellen cyðan, +cræft ond cenðu, swa him gecynde wæs. +Ne hedde he þæs heafolan, ac sio hand gebarn +modiges mannes, þær he his mæges healp, +þæt he þone niðgæst nioðor hwene sloh, +secg on searwum, þæt ðæt sweord gedeaf, +fah ond fæted, þæt ðæt fyr ongon +sweðrian syððan. þa gen sylf cyning +geweold his gewitte, wællseaxe gebræd +biter ond beaduscearp, þæt he on byrnan wæg; +forwrat Wedra helm wyrm on middan. +Feond gefyldan (ferh ellen wræc), +ond hi hyne þa begen abroten hæfdon, +sibæðelingas. Swylc sceolde secg wesan, +þegn æt ðearfe! þæt ðam þeodne wæs +siðast sigehwila sylfes dædum, +worlde geweorces. ða sio wund ongon, +þe him se eorðdraca ær geworhte, +swelan ond swellan; he þæt sona onfand, +þæt him on breostum bealoniðe weoll +attor on innan. ða se æðeling giong +þæt he bi wealle wishycgende +gesæt on sesse; seah on enta geweorc, +hu ða stanbogan stapulum fæste +ece eorðreced innan healde. +Hyne þa mid handa heorodreorigne, +þeoden mærne, þegn ungemete till +winedryhten his wætere gelafede, +hilde sædne, ond his helm onspeon. +Biowulf maþelode (he ofer benne spræc, +wunde wælbleate; wisse he gearwe +þæt he dæghwila gedrogen hæfde, +eorðan wynne; ða wæs eall sceacen +dogorgerimes, deað ungemete neah): +"Nu ic suna minum syllan wolde +guðgewædu, þær me gifeðe swa +ænig yrfeweard æfter wurde +lice gelenge. Ic ðas leode heold +fiftig wintra; næs se folccyning, +ymbesittendra ænig ðara, +þe mec guðwinum gretan dorste, +egesan ðeon. Ic on earde bad +mælgesceafta, heold min tela, +ne sohte searoniðas, ne me swor fela +aða on unriht. Ic ðæs ealles mæg +feorhbennum seoc gefean habban; +for ðam me witan ne ðearf waldend fira +morðorbealo maga, þonne min sceaceð +lif of lice. Nu ðu lungre geong +hord sceawian under harne stan, +Wiglaf leofa, nu se wyrm ligeð, +swefeð sare wund, since bereafod. +Bio nu on ofoste, þæt ic ærwelan, +goldæht ongite, gearo sceawige +swegle searogimmas, þæt ic ðy seft mæge +æfter maððumwelan min alætan +lif ond leodscipe, þone ic longe heold." +ða ic snude gefrægn sunu Wihstanes +æfter wordcwydum wundum dryhtne +hyran heaðosiocum, hringnet beran, +brogdne beadusercean under beorges hrof. +Geseah ða sigehreðig, þa he bi sesse geong, +magoþegn modig maððumsigla fealo, +gold glitinian grunde getenge, +wundur on wealle, ond þæs wyrmes denn, +ealdes uhtflogan, orcas stondan, +fyrnmanna fatu feormendlease, +hyrstum behrorene; þær wæs helm monig +eald ond omig, earmbeaga fela +searwum gesæled. Sinc eaðe mæg, +gold on grunde, gumcynnes gehwone +oferhigian, hyde se ðe wylle. +Swylce he siomian geseah segn eallgylden +heah ofer horde, hondwundra mæst, +gelocen leoðocræftum; of ðam leoma stod, +þæt he þone grundwong ongitan meahte, +wræte giondwlitan. Næs ðæs wyrmes þær +onsyn ænig, ac hyne ecg fornam. +ða ic on hlæwe gefrægn hord reafian, +eald enta geweorc, anne mannan, +him on bearm hladon bunan ond discas +sylfes dome; segn eac genom, +beacna beorhtost. Bill ær gescod +(ecg wæs iren) ealdhlafordes +þam ðara maðma mundbora wæs +longe hwile, ligegesan wæg +hatne for horde, hioroweallende +middelnihtum, oðþæt he morðre swealt. +Ar wæs on ofoste, eftsiðes georn, +frætwum gefyrðred; hyne fyrwet bræc, +hwæðer collenferð cwicne gemette +in ðam wongstede Wedra þeoden +ellensiocne, þær he hine ær forlet. +He ða mid þam maðmum mærne þioden, +dryhten sinne, driorigne fand +ealdres æt ende; he hine eft ongon +wæteres weorpan, oðþæt wordes ord +breosthord þurhbræc. +gomel on giohðe (gold sceawode): +"Ic ðara frætwa frean ealles ðanc, +wuldurcyninge, wordum secge, +ecum dryhtne, þe ic her on starie, +þæs ðe ic moste minum leodum +ær swyltdæge swylc gestrynan. +Nu ic on maðma hord mine bebohte +frode feorhlege, fremmað gena +leoda þearfe; ne mæg ic her leng wesan. +Hatað heaðomære hlæw gewyrcean +beorhtne æfter bæle æt brimes nosan; +se scel to gemyndum minum leodum +heah hlifian on Hronesnæsse, +þæt hit sæliðend syððan hatan +Biowulfes biorh, ða ðe brentingas +ofer floda genipu feorran drifað." +Dyde him of healse hring gyldenne +þioden þristhydig, þegne gesealde, +geongum garwigan, goldfahne helm, +beah ond byrnan, het hyne brucan well: +"þu eart endelaf usses cynnes, +Wægmundinga. Ealle wyrd forsweop +mine magas to metodsceafte, +eorlas on elne; ic him æfter sceal." +þæt wæs þam gomelan gingæste word +breostgehygdum, ær he bæl cure, +hate heaðowylmas; him of hreðre gewat +sawol secean soðfæstra dom. +ða wæs gegongen guman unfrodum +earfoðlice, þæt he on eorðan geseah +þone leofestan lifes æt ende +bleate gebæran. Bona swylce læg, +egeslic eorðdraca ealdre bereafod, +bealwe gebæded. Beahhordum leng +wyrm wohbogen wealdan ne moste, +ac hine irenna ecga fornamon, +hearde, heaðoscearde homera lafe, +þæt se widfloga wundum stille +hreas on hrusan hordærne neah. +Nalles æfter lyfte lacende hwearf +middelnihtum, maðmæhta wlonc +ansyn ywde, ac he eorðan gefeoll +for ðæs hildfruman hondgeweorce. +Huru þæt on lande lyt manna ðah, +mægenagendra, mine gefræge, +þeah ðe he dæda gehwæs dyrstig wære, +þæt he wið attorsceaðan oreðe geræsde, +oððe hringsele hondum styrede, +gif he wæccende weard onfunde +buon on beorge. Biowulfe wearð +dryhtmaðma dæl deaðe forgolden; +hæfde æghwæðer ende gefered +lænan lifes. Næs ða lang to ðon +þæt ða hildlatan holt ofgefan, +tydre treowlogan tyne ætsomne. +ða ne dorston ær dareðum lacan +on hyra mandryhtnes miclan þearfe, +ac hy scamiende scyldas bæran, +guðgewædu, þær se gomela læg, +wlitan on Wilaf. He gewergad sæt, +feðecempa, frean eaxlum neah, +wehte hyne wætre; him wiht ne speow. +Ne meahte he on eorðan, ðeah he uðe wel, +on ðam frumgare feorh gehealdan, +ne ðæs wealdendes wiht oncirran; +wolde dom godes dædum rædan +gumena gehwylcum, swa he nu gen deð. +þa wæs æt ðam geongan grim ondswaru +eðbegete þam ðe ær his elne forleas. +Wiglaf maðelode, Weohstanes sunu, +sec, sarigferð (seah on unleofe): +"þæt, la, mæg secgan se ðe wyle soð specan +þæt se mondryhten se eow ða maðmas geaf, +eoredgeatwe, þe ge þær on standað, +þonne he on ealubence oft gesealde +healsittendum helm ond byrnan, +þeoden his þegnum, swylce he þrydlicost +ower feor oððe neah findan meahte, +þæt he genunga guðgewædu +wraðe forwurpe, ða hyne wig beget. +Nealles folccyning fyrdgesteallum +gylpan þorfte; hwæðre him god uðe, +sigora waldend, þæt he hyne sylfne gewræc +ana mid ecge, þa him wæs elnes þearf. +Ic him lifwraðe lytle meahte +ætgifan æt guðe, ond ongan swa þeah +ofer min gemet mæges helpan; +symle wæs þy sæmra, þonne ic sweorde drep +ferhðgeniðlan, fyr unswiðor +weoll of gewitte. Wergendra to lyt +þrong ymbe þeoden, þa hyne sio þrag becwom. +Nu sceal sincþego ond swyrdgifu, +eall eðelwyn eowrum cynne, +lufen alicgean; londrihtes mot +þære mægburge monna æghwylc +idel hweorfan, syððan æðelingas +feorran gefricgean fleam eowerne, +domleasan dæd. Deað bið sella +eorla gehwylcum þonne edwitlif!" +Heht ða þæt heaðoweorc to hagan biodan +up ofer ecgclif, þær þæt eorlweorod +morgenlongne dæg modgiomor sæt, +bordhæbbende, bega on wenum, +endedogores ond eftcymes +leofes monnes. Lyt swigode +niwra spella se ðe næs gerad, +ac he soðlice sægde ofer ealle: +"Nu is wilgeofa Wedra leoda, +dryhten Geata, deaðbedde fæst, +wunað wælreste wyrmes dædum. +Him on efn ligeð ealdorgewinna +sexbennum seoc; sweorde ne meahte +on ðam aglæcean ænige þinga +wunde gewyrcean. Wiglaf siteð +ofer Biowulfe, byre Wihstanes, +eorl ofer oðrum unlifigendum, +healdeð higemæðum heafodwearde +leofes ond laðes. Nu ys leodum wen +orleghwile, syððan underne +Froncum ond Frysum fyll cyninges +wide weorðeð. Wæs sio wroht scepen +heard wið Hugas, syððan Higelac cwom +faran flotherge on Fresna land, +þær hyne Hetware hilde genægdon, +elne geeodon mid ofermægene, +þæt se byrnwiga bugan sceolde, +feoll on feðan, nalles frætwe geaf +ealdor dugoðe. Us wæs a syððan +Merewioingas milts ungyfeðe. +Ne ic to Sweoðeode sibbe oððe treowe +wihte ne wene, ac wæs wide cuð +þætte Ongenðio ealdre besnyðede +Hæðcen Hreþling wið Hrefnawudu, +þa for onmedlan ærest gesohton +Geata leode Guðscilfingas. +Sona him se froda fæder Ohtheres, +eald ond egesfull, ondslyht ageaf, +abreot brimwisan, bryd ahredde, +gomela iomeowlan golde berofene, +Onelan modor ond Ohtheres, +ond ða folgode feorhgeniðlan, +oððæt hi oðeodon earfoðlice +in Hrefnesholt hlafordlease. +Besæt ða sinherge sweorda lafe, +wundum werge, wean oft gehet +earmre teohhe ondlonge niht, +cwæð, he on mergenne meces ecgum +getan wolde, sum on galgtreowum +fuglum to gamene. Frofor eft gelamp +sarigmodum somod ærdæge, +syððan hie Hygelaces horn ond byman, +gealdor ongeaton, þa se goda com +leoda dugoðe on last faran. +Wæs sio swatswaðu Sweona ond Geata, +wælræs weora wide gesyne, +hu ða folc mid him fæhðe towehton. +Gewat him ða se goda mid his gædelingum, +frod, felageomor, fæsten secean, +eorl Ongenþio, ufor oncirde; +hæfde Higelaces hilde gefrunen, +wlonces wigcræft, wiðres ne truwode, +þæt he sæmannum onsacan mihte, +heaðoliðendum hord forstandan, +bearn ond bryde; beah eft þonan +eald under eorðweall. þa wæs æht boden +Sweona leodum, segn Higelaces +freoðowong þone forð ofereodon, +syððan Hreðlingas to hagan þrungon. +þær wearð Ongenðiow ecgum sweorda, +blondenfexa, on bid wrecen, +þæt se þeodcyning ðafian sceolde +Eafores anne dom. Hyne yrringa +Wulf Wonreding wæpne geræhte, +þæt him for swenge swat ædrum sprong +forð under fexe. Næs he forht swa ðeh, +gomela Scilfing, ac forgeald hraðe +wyrsan wrixle wælhlem þone, +syððan ðeodcyning þyder oncirde. +Ne meahte se snella sunu Wonredes +ealdum ceorle ondslyht giofan, +ac he him on heafde helm ær gescer, +þæt he blode fah bugan sceolde, +feoll on foldan; næs he fæge þa git, +ac he hyne gewyrpte, þeah ðe him wund hrine. +Let se hearda Higelaces þegn +bradne mece, þa his broðor læg, +eald sweord eotonisc, entiscne helm +brecan ofer bordweal; ða gebeah cyning, +folces hyrde, wæs in feorh dropen. +ða wæron monige þe his mæg wriðon, +ricone arærdon, ða him gerymed wearð +þæt hie wælstowe wealdan moston. +þenden reafode rinc oðerne, +nam on Ongenðio irenbyrnan, +heard swyrd hilted ond his helm somod, +hares hyrste Higelace bær. +He ðam frætwum feng ond him fægre gehet +leana mid leodum, ond gelæste swa; +geald þone guðræs Geata dryhten, +Hreðles eafora, þa he to ham becom, +Iofore ond Wulfe mid ofermaðmum, +sealde hiora gehwæðrum hund þusenda +landes ond locenra beaga (ne ðorfte him ða lean oðwitan +mon on middangearde), syððan hie ða mærða geslogon, +ond ða Iofore forgeaf angan dohtor, +hamweorðunge, hyldo to wedde. +þæt ys sio fæhðo ond se feondscipe, +wælnið wera, ðæs ðe ic wen hafo, +þe us seceað to Sweona leoda, +syððan hie gefricgeað frean userne +ealdorleasne, þone ðe ær geheold +wið hettendum hord ond rice +æfter hæleða hryre, hwate Scildingas, +folcred fremede oððe furður gen +eorlscipe efnde. Nu is ofost betost +þæt we þeodcyning þær sceawian +ond þone gebringan, þe us beagas geaf, +on adfære. Ne scel anes hwæt +meltan mid þam modigan, ac þær is maðma hord, +gold unrime grimme geceapod, +ond nu æt siðestan sylfes feore +beagas gebohte. þa sceall brond fretan, +æled þeccean, nalles eorl wegan +maððum to gemyndum, ne mægð scyne +habban on healse hringweorðunge, +ac sceal geomormod, golde bereafod, +oft nalles æne elland tredan, +nu se herewisa hleahtor alegde, +gamen ond gleodream. Forðon sceall gar wesan +monig, morgenceald, mundum bewunden, +hæfen on handa, nalles hearpan sweg +wigend weccean, ac se wonna hrefn +fus ofer fægum fela reordian, +earne secgan hu him æt æte speow, +þenden he wið wulf wæl reafode." +Swa se secg hwata secggende wæs +laðra spella; he ne leag fela +wyrda ne worda. Weorod eall aras; +eodon unbliðe under Earnanæs, +wollenteare wundur sceawian. +Fundon ða on sande sawulleasne +hlimbed healdan þone þe him hringas geaf +ærran mælum; þa wæs endedæg +godum gegongen, þæt se guðcyning, +Wedra þeoden, wundordeaðe swealt. +ær hi þær gesegan syllicran wiht, +wyrm on wonge wiðerræhtes þær +laðne licgean; wæs se legdraca +grimlic, gryrefah, gledum beswæled. +Se wæs fiftiges fotgemearces +lang on legere, lyftwynne heold +nihtes hwilum, nyðer eft gewat +dennes niosian; wæs ða deaðe fæst, +hæfde eorðscrafa ende genyttod. +Him big stodan bunan ond orcas, +discas lagon ond dyre swyrd, +omige, þurhetone, swa hie wið eorðan fæðm +þusend wintra þær eardodon. +þonne wæs þæt yrfe, eacencræftig, +iumonna gold galdre bewunden, +þæt ðam hringsele hrinan ne moste +gumena ænig, nefne god sylfa, +sigora soðcyning, sealde þam ðe he wolde +(he is manna gehyld) hord openian, +efne swa hwylcum manna swa him gemet ðuhte. +þa wæs gesyne þæt se sið ne ðah +þam ðe unrihte inne gehydde +wræte under wealle. Weard ær ofsloh +feara sumne; þa sio fæhð gewearð +gewrecen wraðlice. Wundur hwar þonne +eorl ellenrof ende gefere +lifgesceafta, þonne leng ne mæg +mon mid his magum meduseld buan. +Swa wæs Biowulfe, þa he biorges weard +sohte, searoniðas; seolfa ne cuðe +þurh hwæt his worulde gedal weorðan sceolde. +Swa hit oð domes dæg diope benemdon +þeodnas mære, þa ðæt þær dydon, +þæt se secg wære synnum scildig, +hergum geheaðerod, hellbendum fæst, +wommum gewitnad, se ðone wong strude, +næs he goldhwæte gearwor hæfde +agendes est ær gesceawod. +Wiglaf maðelode, Wihstanes sunu: +"Oft sceall eorl monig anes willan +wræc adreogan, swa us geworden is. +Ne meahton we gelæran leofne þeoden, +rices hyrde, ræd ænigne, +þæt he ne grette goldweard þone, +lete hyne licgean þær he longe wæs, +wicum wunian oð woruldende; +heold on heahgesceap. Hord ys gesceawod, +grimme gegongen; wæs þæt gifeðe to swið +þe ðone þeodcyning þyder ontyhte. +Ic wæs þær inne ond þæt eall geondseh, +recedes geatwa, þa me gerymed wæs, +nealles swæslice sið alyfed +inn under eorðweall. Ic on ofoste gefeng +micle mid mundum mægenbyrðenne +hordgestreona, hider ut ætbær +cyninge minum. Cwico wæs þa gena, +wis ond gewittig; worn eall gespræc +gomol on gehðo ond eowic gretan het, +bæd þæt ge geworhton æfter wines dædum +in bælstede beorh þone hean, +micelne ond mærne, swa he manna wæs +wigend weorðfullost wide geond eorðan, +þenden he burhwelan brucan moste. +Uton nu efstan oðre siðe, +seon ond secean searogimma geþræc, +wundur under wealle; ic eow wisige, +þæt ge genoge neon sceawiað +beagas ond brad gold. Sie sio bær gearo, +ædre geæfned, þonne we ut cymen, +ond þonne geferian frean userne, +leofne mannan, þær he longe sceal +on ðæs waldendes wære geþolian." +Het ða gebeodan byre Wihstanes, +hæle hildedior, hæleða monegum, +boldagendra, þæt hie bælwudu +feorran feredon, folcagende, +godum togenes: "Nu sceal gled fretan, +weaxan wonna leg wigena strengel, +þone ðe oft gebad isernscure, +þonne stræla storm strengum gebæded +scoc ofer scildweall, sceft nytte heold, +feðergearwum fus flane fulleode." +Huru se snotra sunu Wihstanes +acigde of corðre cyninges þegnas +syfone tosomne, þa selestan, +eode eahta sum under inwithrof +hilderinca; sum on handa bær +æledleoman, se ðe on orde geong. +Næs ða on hlytme hwa þæt hord strude, +syððan orwearde ænigne dæl +secgas gesegon on sele wunian, +læne licgan; lyt ænig mearn +þæt hi ofostlice ut geferedon +dyre maðmas. Dracan ec scufun, +wyrm ofer weallclif, leton weg niman, +flod fæðmian frætwa hyrde. +þa wæs wunden gold on wæn hladen, +æghwæs unrim, æþeling boren, +har hilderinc to Hronesnæsse. +Him ða gegiredan Geata leode +ad on eorðan unwaclicne, +helmum behongen, hildebordum, +beorhtum byrnum, swa he bena wæs; +alegdon ða tomiddes mærne þeoden +hæleð hiofende, hlaford leofne. +Ongunnon þa on beorge bælfyra mæst +wigend weccan; wudurec astah, +sweart ofer swioðole, swogende leg +wope bewunden (windblond gelæg), +oðþæt he ða banhus gebrocen hæfde, +hat on hreðre. Higum unrote +modceare mændon, mondryhtnes cwealm; +swylce giomorgyd Geatisc meowle +bundenheorde +song sorgcearig swiðe geneahhe +þæt hio hyre heofungdagas hearde ondrede, +wælfylla worn, werudes egesan, +hynðo ond hæftnyd. Heofon rece swealg. +Geworhton ða Wedra leode +hleo on hoe, se wæs heah ond brad, +wægliðendum wide gesyne, +ond betimbredon on tyn dagum +beadurofes becn, bronda lafe +wealle beworhton, swa hyt weorðlicost +foresnotre men findan mihton. +Hi on beorg dydon beg ond siglu, +eall swylce hyrsta, swylce on horde ær +niðhedige men genumen hæfdon, +forleton eorla gestreon eorðan healdan, +gold on greote, þær hit nu gen lifað +eldum swa unnyt swa hit æror wæs. +þa ymbe hlæw riodan hildediore, +æþelinga bearn, ealra twelfe, +woldon ceare cwiðan ond kyning mænan, +wordgyd wrecan ond ymb wer sprecan; +eahtodan eorlscipe ond his ellenweorc +duguðum demdon, swa hit gedefe bið +þæt mon his winedryhten wordum herge, +ferhðum freoge, þonne he forð scile +of lichaman læded weorðan. +Swa begnornodon Geata leode +hlafordes hryre, heorðgeneatas, +cwædon þæt he wære wyruldcyninga +manna mildust ond monðwærust, +leodum liðost ond lofgeornost. \ No newline at end of file diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stderr-hello.rs b/tests/wasi.fyi/wasi-libstd-test/io_stderr-hello.rs new file mode 100644 index 00000000000..187b7763ea4 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stderr-hello.rs @@ -0,0 +1,6 @@ +use std::io; +use std::io::Write; + +fn main() { + assert!(io::stderr().write_all(include_bytes!("io_stderr-hello.stderr")).is_ok()); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stderr-hello.stderr b/tests/wasi.fyi/wasi-libstd-test/io_stderr-hello.stderr new file mode 100644 index 00000000000..130d52cc176 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stderr-hello.stderr @@ -0,0 +1 @@ +Hello, stderr! diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stdin-beowulf.rs b/tests/wasi.fyi/wasi-libstd-test/io_stdin-beowulf.rs new file mode 100644 index 00000000000..30a2a28272a --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stdin-beowulf.rs @@ -0,0 +1,11 @@ +use std::io; +use std::io::Read; + +fn main() { + let mut stdin = String::new(); + assert!(io::stdin().read_to_string(&mut stdin).is_ok()); + assert_eq!( + stdin, + String::from_utf8_lossy(include_bytes!("io_stdin-beowulf.stdin")) + ); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stdin-beowulf.stdin b/tests/wasi.fyi/wasi-libstd-test/io_stdin-beowulf.stdin new file mode 100644 index 00000000000..185668538ac --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stdin-beowulf.stdin @@ -0,0 +1,3182 @@ +Hwæt. We Gardena in geardagum, +þeodcyninga, þrym gefrunon, +hu ða æþelingas ellen fremedon. +Oft Scyld Scefing sceaþena þreatum, +monegum mægþum, meodosetla ofteah, +egsode eorlas. Syððan ærest wearð +feasceaft funden, he þæs frofre gebad, +weox under wolcnum, weorðmyndum þah, +oðþæt him æghwylc þara ymbsittendra +ofer hronrade hyran scolde, +gomban gyldan. þæt wæs god cyning. +ðæm eafera wæs æfter cenned, +geong in geardum, þone god sende +folce to frofre; fyrenðearfe ongeat +þe hie ær drugon aldorlease +lange hwile. Him þæs liffrea, +wuldres wealdend, woroldare forgeaf; +Beowulf wæs breme blæd wide sprang, +Scyldes eafera Scedelandum in. +Swa sceal geong guma gode gewyrcean, +fromum feohgiftum on fæder bearme, +þæt hine on ylde eft gewunigen +wilgesiþas, þonne wig cume, +leode gelæsten; lofdædum sceal +in mægþa gehwære man geþeon. +Him ða Scyld gewat to gescæphwile +felahror feran on frean wære. +Hi hyne þa ætbæron to brimes faroðe, +swæse gesiþas, swa he selfa bæd, +þenden wordum weold wine Scyldinga; +leof landfruma lange ahte. +þær æt hyðe stod hringedstefna, +isig ond utfus, æþelinges fær. +Aledon þa leofne þeoden, +beaga bryttan, on bearm scipes, +mærne be mæste. þær wæs madma fela +of feorwegum, frætwa, gelæded; +ne hyrde ic cymlicor ceol gegyrwan +hildewæpnum ond heaðowædum, +billum ond byrnum; him on bearme læg +madma mænigo, þa him mid scoldon +on flodes æht feor gewitan. +Nalæs hi hine læssan lacum teodan, +þeodgestreonum, þon þa dydon +þe hine æt frumsceafte forð onsendon +ænne ofer yðe umborwesende. +þa gyt hie him asetton segen geldenne +heah ofer heafod, leton holm beran, +geafon on garsecg; him wæs geomor sefa, +murnende mod. Men ne cunnon +secgan to soðe, selerædende, +hæleð under heofenum, hwa þæm hlæste onfeng. +ða wæs on burgum Beowulf Scyldinga, +leof leodcyning, longe þrage +folcum gefræge fæder ellor hwearf, +aldor of earde, oþþæt him eft onwoc +heah Healfdene; heold þenden lifde, +gamol ond guðreouw, glæde Scyldingas. +ðæm feower bearn forð gerimed +in worold wocun, weoroda ræswan, +Heorogar ond Hroðgar ond Halga til; +hyrde ic þæt wæs Onelan cwen, +Heaðoscilfingas healsgebedda. +þa wæs Hroðgare heresped gyfen, +wiges weorðmynd, þæt him his winemagas +georne hyrdon, oðð þæt seo geogoð geweox, +magodriht micel. Him on mod bearn +þæt healreced hatan wolde, +medoærn micel, men gewyrcean +þonne yldo bearn æfre gefrunon, +ond þær on innan eall gedælan +geongum ond ealdum, swylc him god sealde, +buton folcscare ond feorum gumena. +ða ic wide gefrægn weorc gebannan +manigre mægþe geond þisne middangeard, +folcstede frætwan. Him on fyrste gelomp, +ædre mid yldum, þæt hit wearð ealgearo, +healærna mæst; scop him Heort naman +se þe his wordes geweald wide hæfde. +He beot ne aleh, beagas dælde, +sinc æt symle. Sele hlifade, +heah ond horngeap, heaðowylma bad, +laðan liges; ne wæs hit lenge þa gen +þæt se ecghete aþumsweorum, +æfter wælniðe wæcnan scolde. +ða se ellengæst earfoðlice +þrage geþolode, se þe in þystrum bad, +þæt he dogora gehwam dream gehyrde +hludne in healle; þær wæs hearpan sweg, +swutol sang scopes. Sægde se þe cuþe +frumsceaft fira feorran reccan, +cwæð þæt se ælmihtiga eorðan worhte, +wlitebeorhtne wang, swa wæter bebugeð, +gesette sigehreþig sunnan ond monan +leoman to leohte landbuendum +ond gefrætwade foldan sceatas +leomum ond leafum, lif eac gesceop +cynna gehwylcum þara ðe cwice hwyrfaþ. +Swa ða drihtguman dreamum lifdon +eadiglice, oððæt an ongan +fyrene fremman feond on helle. +Wæs se grimma gæst Grendel haten, +mære mearcstapa, se þe moras heold, +fen ond fæsten; fifelcynnes eard +wonsæli wer weardode hwile, +siþðan him scyppend forscrifen hæfde +in Caines cynne. þone cwealm gewræc +ece drihten, þæs þe he Abel slog; +ne gefeah he þære fæhðe, ac he hine feor forwræc, +metod for þy mane, mancynne fram. +þanon untydras ealle onwocon, +eotenas ond ylfe ond orcneas, +swylce gigantas, þa wið gode wunnon +lange þrage; he him ðæs lean forgeald. +Gewat ða neosian, syþðan niht becom, +hean huses, hu hit Hringdene +æfter beorþege gebun hæfdon. +Fand þa ðær inne æþelinga gedriht +swefan æfter symble; sorge ne cuðon, +wonsceaft wera. Wiht unhælo, +grim ond grædig, gearo sona wæs, +reoc ond reþe, ond on ræste genam +þritig þegna, þanon eft gewat +huðe hremig to ham faran, +mid þære wælfylle wica neosan. +ða wæs on uhtan mid ærdæge +Grendles guðcræft gumum undyrne; +þa wæs æfter wiste wop up ahafen, +micel morgensweg. Mære þeoden, +æþeling ærgod, unbliðe sæt, +þolode ðryðswyð, þegnsorge dreah, +syðþan hie þæs laðan last sceawedon, +wergan gastes; wæs þæt gewin to strang, +lað ond longsum. Næs hit lengra fyrst, +ac ymb ane niht eft gefremede +morðbeala mare ond no mearn fore, +fæhðe ond fyrene; wæs to fæst on þam. +þa wæs eaðfynde þe him elles hwær +gerumlicor ræste sohte, +bed æfter burum, ða him gebeacnod wæs, +gesægd soðlice sweotolan tacne +healðegnes hete; heold hyne syðþan +fyr ond fæstor se þæm feonde ætwand. +Swa rixode ond wið rihte wan, +ana wið eallum, oðþæt idel stod +husa selest. Wæs seo hwil micel; +XII wintra tid torn geþolode +wine Scyldinga, weana gehwelcne, +sidra sorga. Forðam secgum wearð, +ylda bearnum, undyrne cuð, +gyddum geomore, þætte Grendel wan +hwile wið Hroþgar, heteniðas wæg, +fyrene ond fæhðe fela missera, +singale sæce, sibbe ne wolde +wið manna hwone mægenes Deniga, +feorhbealo feorran, fea þingian, +ne þær nænig witena wenan þorfte +beorhtre bote to banan folmum, +ac se æglæca ehtende wæs, +deorc deaþscua, duguþe ond geogoþe, +seomade ond syrede, sinnihte heold +mistige moras. men ne cunnon +hwyder helrunan hwyrftum scriþað. +Swa fela fyrena feond mancynnes, +atol angengea, oft gefremede, +heardra hynða. Heorot eardode, +sincfage sel sweartum nihtum; +no he þone gifstol gretan moste, +maþðum for metode, ne his myne wisse. +þæt wæs wræc micel wine Scyldinga, +modes brecða. Monig oft gesæt +rice to rune; ræd eahtedon +hwæt swiðferhðum selest wære +wið færgryrum to gefremmanne. +Hwilum hie geheton æt hærgtrafum +wigweorþunga, wordum bædon +þæt him gastbona geoce gefremede +wið þeodþreaum. Swylc wæs þeaw hyra, +hæþenra hyht; helle gemundon +in modsefan, metod hie ne cuþon, +dæda demend, ne wiston hie drihten god, +ne hie huru heofena helm herian ne cuþon, +wuldres waldend. Wa bið þæm ðe sceal +þurh sliðne nið sawle bescufan +in fyres fæþm, frofre ne wenan, +wihte gewendan; wel bið þæm þe mot +æfter deaðdæge drihten secean +ond to fæder fæþmum freoðo wilnian. +Swa ða mælceare maga Healfdenes +singala seað, ne mihte snotor hæleð +wean onwendan; wæs þæt gewin to swyð, +laþ ond longsum, þe on ða leode becom, +nydwracu niþgrim, nihtbealwa mæst. +þæt fram ham gefrægn Higelaces þegn, +god mid Geatum, Grendles dæda; +se wæs moncynnes mægenes strengest +on þæm dæge þysses lifes, +æþele ond eacen. Het him yðlidan +godne gegyrwan, cwæð, hu guðcyning +ofer swanrade secean wolde, +mærne þeoden, þa him wæs manna þearf. +ðone siðfæt him snotere ceorlas +lythwon logon, þeah he him leof wære; +hwetton higerofne, hæl sceawedon. +Hæfde se goda Geata leoda +cempan gecorone þara þe he cenoste +findan mihte; XVna sum +sundwudu sohte; secg wisade, +lagucræftig mon, landgemyrcu. +Fyrst forð gewat. Flota wæs on yðum, +bat under beorge. Beornas gearwe +on stefn stigon; streamas wundon, +sund wið sande; secgas bæron +on bearm nacan beorhte frætwe, +guðsearo geatolic; guman ut scufon, +weras on wilsið, wudu bundenne. +Gewat þa ofer wægholm, winde gefysed, +flota famiheals fugle gelicost, +oðþæt ymb antid oþres dogores +wundenstefna gewaden hæfde +þæt ða liðende land gesawon, +brimclifu blican, beorgas steape, +side sænæssas; þa wæs sund liden, +eoletes æt ende. þanon up hraðe +Wedera leode on wang stigon, +sæwudu sældon syrcan hrysedon, +guðgewædo, gode þancedon +þæs þe him yþlade eaðe wurdon. +þa of wealle geseah weard Scildinga, +se þe holmclifu healdan scolde, +beran ofer bolcan beorhte randas, +fyrdsearu fuslicu; hine fyrwyt bræc +modgehygdum, hwæt þa men wæron. +Gewat him þa to waroðe wicge ridan +þegn Hroðgares, þrymmum cwehte +mægenwudu mundum, meþelwordum frægn: +Hwæt syndon ge searohæbbendra, +byrnum werede, þe þus brontne ceol +ofer lagustræte lædan cwomon, +hider ofer holmas? le wæs +endesæta, ægwearde heold, +þe on land Dena laðra nænig +mid scipherge sceðþan ne meahte. +No her cuðlicor cuman ongunnon +lindhæbbende; ne ge leafnesword +guðfremmendra gearwe ne wisson, +maga gemedu. Næfre ic maran geseah +eorla ofer eorþan ðonne is eower sum, +secg on searwum; nis þæt seldguma, +wæpnum geweorðad, næfne him his wlite leoge, +ænlic ansyn. Nu ic eower sceal +frumcyn witan, ær ge fyr heonan , +leassceaweras, on land Dena +furþur feran. Nu ge feorbuend, +mereliðende, minne gehyrað +anfealdne geþoht: Ofost is selest +to gecyðanne hwanan eowre cyme syndon. +Him se yldesta ondswarode, +werodes wisa, wordhord onleac: +We synt gumcynnes Geata leode +ond Higelaces heorðgeneatas. +Wæs min fæder folcum gecyþed, +æþele ordfruma, Ecgþeow haten. +Gebad wintra worn, ær he on weg hwurfe, +gamol of geardum; hine gearwe geman +witena welhwylc wide geond eorþan. +We þurh holdne hige hlaford þinne, +sunu Healfdenes, secean cwomon, +leodgebyrgean; wes þu us larena god. +Habbað we to þæm mæran micel ærende, +Deniga frean, ne sceal þær dyrne sum +wesan, þæs ic wene. þu wast gif hit is +swa we soþlice secgan hyrdon +þæt mid Scyldingum sceaðona ic nat hwylc, +deogol dædhata, deorcum nihtum +eaweð þurh egsan uncuðne nið, +hynðu ond hrafyl. Ic þæs Hroðgar mæg +þurh rumne sefan ræd gelæran, +hu he frod ond god feond oferswyðeþ, +gyf him edwendan æfre scolde +bealuwa bisigu, bot eft cuman, +ond þa cearwylmas colran wurðaþ; +oððe a syþðan earfoðþrage, +þreanyd þolað, þenden þær wunað +on heahstede husa selest. +Weard maþelode, ðær on wicge sæt, +ombeht unforht: æghwæþres sceal +scearp scyldwiga gescad witan, +worda ond worca, se þe wel þenceð. +Ic þæt gehyre, þæt þis is hold weorod +frean Scyldinga. Gewitaþ forð beran +wæpen ond gewædu; ic eow wisige. +Swylce ic maguþegnas mine hate +wið feonda gehwone flotan eowerne, +niwtyrwydne nacan on sande +arum healdan, oþðæt eft byreð +ofer lagustreamas leofne mannan +wudu wundenhals to Wedermearce, +godfremmendra swylcum gifeþe bið +þæt þone hilderæs hal gedigeð. +Gewiton him þa feran. Flota stille bad, +seomode on sale sidfæþmed scip, +on ancre fæst. Eoforlic scionon +ofer hleorberan gehroden golde, +fah ond fyrheard; ferhwearde heold +guþmod grimmon. Guman onetton, +sigon ætsomne, oþþæt hy sæl timbred, +geatolic ond goldfah, ongyton mihton; +þæt wæs foremærost foldbuendum +receda under roderum, on þæm se rica bad; +lixte se leoma ofer landa fela. +Him þa hildedeor hof modigra +torht getæhte, þæt hie him to mihton +gegnum gangan; guðbeorna sum +wicg gewende, word æfter cwæð: +Mæl is me to feran; fæder alwalda +mid arstafum eowic gehealde +siða gesunde. Ic to sæ wille +wið wrað werod wearde healdan. +Stræt wæs stanfah, stig wisode +gumum ætgædere. Guðbyrne scan +heard hondlocen, hringiren scir +song in searwum, þa hie to sele furðum +in hyra gryregeatwum gangan cwomon. +Setton sæmeþe side scyldas, +rondas regnhearde, wið þæs recedes weal, +bugon þa to bence. Byrnan hringdon, +guðsearo gumena; garas stodon, +sæmanna searo, samod ætgædere, +æscholt ufan græg; wæs se irenþreat +wæpnum gewurþad. þa ðær wlonc hæleð +oretmecgas æfter æþelum frægn: +Hwanon ferigeað ge fætte scyldas, +græge syrcan ond grimhelmas, +heresceafta heap? Ic eom Hroðgares +ar ond ombiht. Ne seah ic elþeodige +þus manige men modiglicran. +Wen ic þæt ge for wlenco, nalles for wræcsiðum, +ac for higeþrymmum Hroðgar sohton. +Him þa ellenrof andswarode, +wlanc Wedera leod, word æfter spræc, +heard under helme: We synt Higelaces +beodgeneatas; Beowulf is min nama. +Wille ic asecgan sunu Healfdenes, +mærum þeodne, min ærende, +aldre þinum, gif he us geunnan wile +þæt we hine swa godne gretan moton. +Wulfgar maþelode þæt wæs Wendla leod; +wæs his modsefa manegum gecyðed, +wig ond wisdom: Ic þæs wine Deniga, +frean Scildinga, frinan wille, +beaga bryttan, swa þu bena eart, +þeoden mærne, ymb þinne sið, +ond þe þa ondsware ædre gecyðan +ðe me se goda agifan þenceð. +Hwearf þa hrædlice þær Hroðgar sæt +eald ond anhar mid his eorla gedriht; +eode ellenrof, þæt he for eaxlum gestod +Deniga frean; cuþe he duguðe þeaw. +Wulfgar maðelode to his winedrihtne: +Her syndon geferede, feorran cumene +ofer geofenes begang Geata leode; +þone yldestan oretmecgas +Beowulf nemnað. Hy benan synt +þæt hie, þeoden min, wið þe moton +wordum wrixlan. No ðu him wearne geteoh +ðinra gegncwida, glædman Hroðgar. +Hy on wiggetawum wyrðe þinceað +eorla geæhtlan; huru se aldor deah, +se þæm heaðorincum hider wisade. +Hroðgar maþelode, helm Scyldinga: +Ic hine cuðe cnihtwesende. +Wæs his ealdfæder Ecgþeo haten, +ðæm to ham forgeaf Hreþel Geata +angan dohtor; is his eafora nu +heard her cumen, sohte holdne wine. +ðonne sægdon þæt sæliþende, +þa ðe gifsceattas Geata fyredon +þyder to þance, þæt he XXXtiges +manna mægencræft on his mundgripe +heaþorof hæbbe. Hine halig god +for arstafum us onsende, +to Westdenum, þæs ic wen hæbbe, +wið Grendles gryre. Ic þæm godan sceal +for his modþræce madmas beodan. +Beo ðu on ofeste, hat in gan +seon sibbegedriht samod ætgædere; +gesaga him eac wordum þæt hie sint wilcuman +Deniga leodum. +[] word inne abead: +Eow het secgan sigedrihten min, +aldor Eastdena, þæt he eower æþelu can, +ond ge him syndon ofer sæwylmas +heardhicgende hider wilcuman. +Nu ge moton gangan in eowrum guðgeatawum +under heregriman Hroðgar geseon; +lætað hildebord her onbidan, +wudu, wælsceaftas, worda geþinges. +Aras þa se rica, ymb hine rinc manig, +þryðlic þegna heap; sume þær bidon, +heaðoreaf heoldon, swa him se hearda bebead. +Snyredon ætsomne, þa secg wisode, +under Heorotes hrof +heard under helme, þæt he on heoðe gestod. +Beowulf maðelode on him byrne scan, +searonet seowed smiþes orþancum: +Wæs þu, Hroðgar, hal. Ic eom Higelaces +mæg ond magoðegn; hæbbe ic mærða fela +ongunnen on geogoþe. Me wearð Grendles þing +on minre eþeltyrf undyrne cuð; +secgað sæliðend þæt þæs sele stande, +reced selesta, rinca gehwylcum +idel ond unnyt, siððan æfenleoht +under heofenes hador beholen weorþeð. +þa me þæt gelærdon leode mine +þa selestan, snotere ceorlas, +þeoden Hroðgar, þæt ic þe sohte, +forþan hie mægenes cræft minne cuþon, +selfe ofersawon, ða ic of searwum cwom, +fah from feondum. þær ic fife geband, +yðde eotena cyn ond on yðum slog +niceras nihtes, nearoþearfe dreah, +wræc Wedera nið wean ahsodon, +forgrand gramum, ond nu wið Grendel sceal, +wið þam aglæcan, ana gehegan +ðing wið þyrse. Ic þe nu ða, +brego Beorhtdena, biddan wille, +eodor Scyldinga, anre bene, +þæt ðu me ne forwyrne, wigendra hleo, +freowine folca, nu ic þus feorran com, +þæt ic mote ana ond minra eorla gedryht, +þes hearda heap, Heorot fælsian. +Hæbbe ic eac geahsod þæt se æglæca +for his wonhydum wæpna ne recceð. +Ic þæt þonne forhicge swa me Higelac sie, +min mondrihten, modes bliðe, +þæt ic sweord bere oþðe sidne scyld, +geolorand to guþe, ac ic mid grape sceal +fon wið feonde ond ymb feorh sacan, +lað wið laþum; ðær gelyfan sceal +dryhtnes dome se þe hine deað nimeð. +Wen ic þæt he wille, gif he wealdan mot, +in þæm guðsele Geotena leode +etan unforhte, swa he oft dyde, +mægen Hreðmanna. Na þu minne þearft +hafalan hydan, ac he me habban wile +dreore fahne, gif mec deað nimeð. +Byreð blodig wæl, byrgean þenceð, +eteð angenga unmurnlice, +mearcað morhopu; no ðu ymb mines ne þearft +lices feorme leng sorgian. +Onsend Higelace, gif mec hild nime, +beaduscruda betst, þæt mine breost wereð, +hrægla selest; þæt is Hrædlan laf, +Welandes geweorc. Gæð a wyrd swa hio scel. +Hroðgar maþelode, helm Scyldinga: +For gewyrhtum þu, wine min Beowulf, +ond for arstafum usic sohtest. +Gesloh þin fæder fæhðe mæste; +wearþ he Heaþolafe to handbonan +mid Wilfingum; ða hine Wedera cyn +for herebrogan habban ne mihte. +þanon he gesohte Suðdena folc +ofer yða gewealc, Arscyldinga. +ða ic furþum weold folce Deniga +ond on geogoðe heold ginne rice, +hordburh hæleþa; ða wæs Heregar dead, +min yldra mæg unlifigende, +bearn Healfdenes; se wæs betera ðonne ic. +Siððan þa fæhðe feo þingode; +sende ic Wylfingum ofer wæteres hrycg +ealde madmas; he me aþas swor. +Sorh is me to secganne on sefan minum +gumena ængum hwæt me Grendel hafað +hynðo on Heorote mid his heteþancum, +færniða gefremed. Is min fletwerod, +wigheap gewanod; hie wyrd forsweop +on Grendles gryre. God eaþe mæg +þone dolsceaðan dæda getwæfan. +Ful oft gebeotedon beore druncne +ofer ealowæge oretmecgas +þæt hie in beorsele bidan woldon +Grendles guþe mid gryrum ecga. +ðonne wæs þeos medoheal on morgentid, +drihtsele dreorfah, þonne dæg lixte, +eal bencþelu blode bestymed, +heall heorudreore; ahte ic holdra þy læs, +deorre duguðe, þe þa deað fornam. +Site nu to symle ond onsæl meoto, +sigehreð secgum, swa þin sefa hwette. +þa wæs Geatmæcgum geador ætsomne +on beorsele benc gerymed; +þær swiðferhþe sittan eodon, +þryðum dealle. þegn nytte beheold, +se þe on handa bær hroden ealowæge, +scencte scir wered. Scop hwilum sang +hador on Heorote. þær wæs hæleða dream, +duguð unlytel Dena ond Wedera. +Unferð maþelode, Ecglafes bearn, +þe æt fotum sæt frean Scyldinga, +onband beadurune wæs him Beowulfes sið, +modges merefaran, micel æfþunca, +forþon þe he ne uþe þæt ænig oðer man +æfre mærða þon ma middangeardes +gehedde under heofenum þonne he sylfa: +Eart þu se Beowulf, se þe wið Brecan wunne, +on sidne sæ ymb sund flite, +ðær git for wlence wada cunnedon +ond for dolgilpe on deop wæter +aldrum neþdon? Ne inc ænig mon, +ne leof ne lað, belean mihte +sorhfullne sið, þa git on sund reon. +þær git eagorstream earmum þehton, +mæton merestræta, mundum brugdon, +glidon ofer garsecg; geofon yþum weol, +wintrys wylmum. Git on wæteres æht +seofon niht swuncon; he þe æt sunde oferflat, +hæfde mare mægen. þa hine on morgentid +on Heaþoræmas holm up ætbær; +ðonon he gesohte swæsne eþel, +leof his leodum, lond Brondinga, +freoðoburh fægere, þær he folc ahte +burh ond beagas. Beot eal wið þe +sunu Beanstanes soðe gelæste. +ðonne wene ic to þe wyrsan geþingea, +ðeah þu heaðoræsa gehwær dohte, +grimre guðe, gif þu Grendles dearst +nihtlongne fyrst nean bidan. +Beowulf maþelode, bearn Ecgþeowes: +Hwæt. þu worn fela, wine min Unferð, +beore druncen ymb Brecan spræce, +sægdest from his siðe. Soð ic talige, +þæt ic merestrengo maran ahte, +earfeþo on yþum, ðonne ænig oþer man. +Wit þæt gecwædon cnihtwesende +ond gebeotedon wæron begen þa git +on geogoðfeore þæt wit on garsecg ut +aldrum neðdon, ond þæt geæfndon swa. +Hæfdon swurd nacod, þa wit on sund reon, +heard on handa; wit unc wið hronfixas +werian þohton. No he wiht fram me +flodyþum feor fleotan meahte, +hraþor on holme; no ic fram him wolde. +ða wit ætsomne on sæ wæron +fif nihta fyrst, oþþæt unc flod todraf, +wado weallende, wedera cealdost, +nipende niht, ond norþanwind +heaðogrim ondhwearf; hreo wæron yþa. +Wæs merefixa mod onhrered; +þær me wið laðum licsyrce min, +heard, hondlocen, helpe gefremede, +beadohrægl broden on breostum læg +golde gegyrwed. Me to grunde teah +fah feondscaða, fæste hæfde +grim on grape; hwæþre me gyfeþe wearð +þæt ic aglæcan orde geræhte, +hildebille; heaþoræs fornam +mihtig meredeor þurh mine hand. +Swa mec gelome laðgeteonan +þreatedon þearle. Ic him þenode +deoran sweorde, swa hit gedefe wæs. +Næs hie ðære fylle gefean hæfdon, +manfordædlan, þæt hie me þegon, +symbel ymbsæton sægrunde neah; +ac on mergenne mecum wunde +be yðlafe uppe lægon, +sweordum aswefede, þæt syðþan na +ymb brontne ford brimliðende +lade ne letton. Leoht eastan com, +beorht beacen godes; brimu swaþredon, +þæt ic sænæssas geseon mihte, +windige weallas. Wyrd oft nereð +unfægne eorl, þonne his ellen deah. +Hwæþere me gesælde þæt ic mid sweorde ofsloh +niceras nigene. No ic on niht gefrægn +under heofones hwealf heardran feohtan, +ne on egstreamum earmran mannon; +hwaþere ic fara feng feore gedigde, +siþes werig. ða mec sæ oþbær, +flod æfter faroðe on Finna land, +wadu weallendu. No ic wiht fram þe +swylcra searoniða secgan hyrde, +billa brogan. Breca næfre git +æt heaðolace, ne gehwæþer incer, +swa deorlice dæd gefremede +fagum sweordum no ic þæs fela gylpe, +þeah ðu þinum broðrum to banan wurde, +heafodmægum; þæs þu in helle scealt +werhðo dreogan, þeah þin wit duge. +Secge ic þe to soðe, sunu Ecglafes, +þæt næfre Grendel swa fela gryra gefremede, +atol æglæca, ealdre þinum, +hynðo on Heorote, gif þin hige wære, +sefa swa searogrim, swa þu self talast. +Ac he hafað onfunden þæt he þa fæhðe ne þearf, +atole ecgþræce eower leode +swiðe onsittan, Sigescyldinga; +nymeð nydbade, nænegum arað +leode Deniga, ac he lust wigeð, +swefeð ond sendeþ, secce ne weneþ +to Gardenum. Ac ic him Geata sceal +eafoð ond ellen ungeara nu, +guþe gebeodan. Gæþ eft se þe mot +to medo modig, siþþan morgenleoht +ofer ylda bearn oþres dogores, +sunne sweglwered suþan scineð. +þa wæs on salum sinces brytta, +gamolfeax ond guðrof; geoce gelyfde +brego Beorhtdena, gehyrde on Beowulfe +folces hyrde fæstrædne geþoht. +ðær wæs hæleþa hleahtor, hlyn swynsode, +word wæron wynsume. Eode Wealhþeow forð, +cwen Hroðgares, cynna gemyndig, +grette goldhroden guman on healle, +ond þa freolic wif ful gesealde +ærest Eastdena eþelwearde, +bæd hine bliðne æt þære beorþege, +leodum leofne. He on lust geþeah +symbel ond seleful, sigerof kyning. +Ymbeode þa ides Helminga +duguþe ond geogoþe dæl æghwylcne, +sincfato sealde, oþþæt sæl alamp +þæt hio Beowulfe, beaghroden cwen +mode geþungen, medoful ætbær; +grette Geata leod, gode þancode +wisfæst wordum þæs ðe hire se willa gelamp +þæt heo on ænigne eorl gelyfde +fyrena frofre. He þæt ful geþeah, +wælreow wiga, æt Wealhþeon, +ond þa gyddode guþe gefysed; +Beowulf maþelode, bearn Ecgþeowes: +Ic þæt hogode, þa ic on holm gestah, +sæbat gesæt mid minre secga gedriht, +þæt ic anunga eowra leoda +willan geworhte oþðe on wæl crunge, +feondgrapum fæst. Ic gefremman sceal +eorlic ellen, oþðe endedæg +on þisse meoduhealle minne gebidan. +ðam wife þa word wel licodon, +gilpcwide Geates; eode goldhroden +freolicu folccwen to hire frean sittan. +þa wæs eft swa ær inne on healle +þryðword sprecen, ðeod on sælum, +sigefolca sweg, oþþæt semninga +sunu Healfdenes secean wolde +æfenræste; wiste þæm ahlæcan +to þæm heahsele hilde geþinged, +siððan hie sunnan leoht geseon ne meahton, +oðþe nipende niht ofer ealle, +scaduhelma gesceapu scriðan cwoman, +wan under wolcnum. Werod eall aras. +Gegrette þa guma oþerne, +Hroðgar Beowulf, ond him hæl abead, +winærnes geweald, ond þæt word acwæð: +Næfre ic ænegum men ær alyfde, +siþðan ic hond ond rond hebban mihte, +ðryþærn Dena buton þe nu ða. +Hafa nu ond geheald husa selest, +gemyne mærþo, mægenellen cyð, +waca wið wraþum. Ne bið þe wilna gad, +gif þu þæt ellenweorc aldre gedigest. +ða him Hroþgar gewat mid his hæleþa gedryht, +eodur Scyldinga, ut of healle; +wolde wigfruma Wealhþeo secan, +cwen to gebeddan. Hæfde kyningwuldor +Grendle togeanes, swa guman gefrungon, +seleweard aseted; sundornytte beheold +ymb aldor Dena, eotonweard abead. +Huru Geata leod georne truwode +modgan mægnes, metodes hyldo. +ða he him of dyde isernbyrnan, +helm of hafelan, sealde his hyrsted sweord, +irena cyst, ombihtþegne, +ond gehealdan het hildegeatwe. +Gespræc þa se goda gylpworda sum, +Beowulf Geata, ær he on bed stige: +No ic me an herewæsmun hnagran talige, +guþgeweorca, þonne Grendel hine; +forþan ic hine sweorde swebban nelle, +aldre beneotan, þeah ic eal mæge. +Nat he þara goda þæt he me ongean slea, +rand geheawe, þeah ðe he rof sie +niþgeweorca; ac wit on niht sculon +secge ofersittan, gif he gesecean dear +wig ofer wæpen, ond siþðan witig god +on swa hwæþere hond, halig dryhten, +mærðo deme, swa him gemet þince. +Hylde hine þa heaþodeor, hleorbolster onfeng +eorles andwlitan, ond hine ymb monig +snellic særinc selereste gebeah. +Nænig heora þohte þæt he þanon scolde +eft eardlufan æfre gesecean, +folc oþðe freoburh, þær he afeded wæs; +ac hie hæfdon gefrunen þæt hie ær to fela micles +in þæm winsele wældeað fornam, +Denigea leode. Ac him dryhten forgeaf +wigspeda gewiofu, Wedera leodum, +frofor ond fultum, þæt hie feond heora +ðurh anes cræft ealle ofercomon, +selfes mihtum. Soð is gecyþed +þæt mihtig god manna cynnes +weold wideferhð. Com on wanre niht +scriðan sceadugenga. Sceotend swæfon, +þa þæt hornreced healdan scoldon, +ealle buton anum. þæt wæs yldum cuþ +þæt hie ne moste, þa metod nolde, +se scynscaþa under sceadu bregdan; +ac he wæccende wraþum on andan +bad bolgenmod beadwa geþinges. +ða com of more under misthleoþum +Grendel gongan, godes yrre bær; +mynte se manscaða manna cynnes +sumne besyrwan in sele þam hean. +Wod under wolcnum to þæs þe he winreced, +goldsele gumena, gearwost wisse, +fættum fahne. Ne wæs þæt forma sið +þæt he Hroþgares ham gesohte; +næfre he on aldordagum ær ne siþðan +heardran hæle, healðegnas fand. +Com þa to recede rinc siðian, +dreamum bedæled. Duru sona onarn, +fyrbendum fæst, syþðan he hire folmum æthran; +onbræd þa bealohydig, ða he gebolgen wæs, +recedes muþan. Raþe æfter þon +on fagne flor feond treddode, +eode yrremod; him of eagum stod +ligge gelicost leoht unfæger. +Geseah he in recede rinca manige, +swefan sibbegedriht samod ætgædere, +magorinca heap. þa his mod ahlog; +mynte þæt he gedælde, ærþon dæg cwome, +atol aglæca, anra gehwylces +lif wið lice, þa him alumpen wæs +wistfylle wen. Ne wæs þæt wyrd þa gen +þæt he ma moste manna cynnes +ðicgean ofer þa niht. þryðswyð beheold +mæg Higelaces, hu se manscaða +under færgripum gefaran wolde. +Ne þæt se aglæca yldan þohte, +ac he gefeng hraðe forman siðe +slæpendne rinc, slat unwearnum, +bat banlocan, blod edrum dranc, +synsnædum swealh; sona hæfde +unlyfigendes eal gefeormod, +fet ond folma. Forð near ætstop, +nam þa mid handa higeþihtigne +rinc on ræste, ræhte ongean +feond mid folme; he onfeng hraþe +inwitþancum ond wið earm gesæt. +Sona þæt onfunde fyrena hyrde +þæt he ne mette middangeardes, +eorþan sceata, on elran men +mundgripe maran. He on mode wearð +forht on ferhðe; no þy ær fram meahte. +Hyge wæs him hinfus, wolde on heolster fleon, +secan deofla gedræg; ne wæs his drohtoð þær +swylce he on ealderdagum ær gemette. +Gemunde þa se goda, mæg Higelaces, +æfenspræce, uplang astod +ond him fæste wiðfeng; fingras burston. +Eoten wæs utweard; eorl furþur stop. +Mynte se mæra, þær he meahte swa, +widre gewindan ond on weg þanon +fleon on fenhopu; wiste his fingra geweald +on grames grapum. þæt wæs geocor sið +þæt se hearmscaþa to Heorute ateah. +Dryhtsele dynede; Denum eallum wearð, +ceasterbuendum, cenra gehwylcum, +eorlum ealuscerwen. Yrre wæron begen, +reþe renweardas. Reced hlynsode. +þa wæs wundor micel þæt se winsele +wiðhæfde heaþodeorum, þæt he on hrusan ne feol, +fæger foldbold; ac he þæs fæste wæs +innan ond utan irenbendum +searoþoncum besmiþod. þær fram sylle abeag +medubenc monig, mine gefræge, +golde geregnad, þær þa graman wunnon. +þæs ne wendon ær witan Scyldinga +þæt hit a mid gemete manna ænig, +betlic ond banfag, tobrecan meahte, +listum tolucan, nymþe liges fæþm +swulge on swaþule. Sweg up astag +niwe geneahhe; Norðdenum stod +atelic egesa, anra gehwylcum +þara þe of wealle wop gehyrdon, +gryreleoð galan godes ondsacan, +sigeleasne sang, sar wanigean +helle hæfton. Heold hine fæste +se þe manna wæs mægene strengest +on þæm dæge þysses lifes. +Nolde eorla hleo ænige þinga +þone cwealmcuman cwicne forlætan, +ne his lifdagas leoda ænigum +nytte tealde. þær genehost brægd +eorl Beowulfes ealde lafe, +wolde freadrihtnes feorh ealgian, +mæres þeodnes, ðær hie meahton swa. +Hie þæt ne wiston, þa hie gewin drugon, +heardhicgende hildemecgas, +ond on healfa gehwone heawan þohton, +sawle secan, þone synscaðan +ænig ofer eorþan irenna cyst, +guðbilla nan, gretan nolde, +ac he sigewæpnum forsworen hæfde, +ecga gehwylcre. Scolde his aldorgedal +on ðæm dæge þysses lifes +earmlic wurðan, ond se ellorgast +on feonda geweald feor siðian. +ða þæt onfunde se þe fela æror +modes myrðe manna cynne, +fyrene gefremede he wæs fag wið god, +þæt him se lichoma læstan nolde, +ac hine se modega mæg Hygelaces +hæfde be honda; wæs gehwæþer oðrum +lifigende lað. Licsar gebad +atol æglæca; him on eaxle wearð +syndolh sweotol, seonowe onsprungon, +burston banlocan. Beowulfe wearð +guðhreð gyfeþe; scolde Grendel þonan +feorhseoc fleon under fenhleoðu, +secean wynleas wic; wiste þe geornor +þæt his aldres wæs ende gegongen, +dogera dægrim. Denum eallum wearð +æfter þam wælræse willa gelumpen. +Hæfde þa gefælsod se þe ær feorran com, +snotor ond swyðferhð, sele Hroðgares, +genered wið niðe; nihtweorce gefeh, +ellenmærþum. Hæfde Eastdenum +Geatmecga leod gilp gelæsted, +swylce oncyþðe ealle gebette, +inwidsorge, þe hie ær drugon +ond for þreanydum þolian scoldon, +torn unlytel. þæt wæs tacen sweotol, +syþðan hildedeor hond alegde, +earm ond eaxle þær wæs eal geador +Grendles grape under geapne hrof. +ða wæs on morgen mine gefræge +ymb þa gifhealle guðrinc monig; +ferdon folctogan feorran ond nean +geond widwegas wundor sceawian, +laþes lastas. No his lifgedal +sarlic þuhte secga ænegum +þara þe tirleases trode sceawode, +hu he werigmod on weg þanon, +niða ofercumen, on nicera mere +fæge ond geflymed feorhlastas bær. +ðær wæs on blode brim weallende, +atol yða geswing eal gemenged +haton heolfre, heorodreore weol. +Deaðfæge deog, siððan dreama leas +in fenfreoðo feorh alegde, +hæþene sawle; þær him hel onfeng. +þanon eft gewiton ealdgesiðas, +swylce geong manig of gomenwaþe +fram mere modge mearum ridan, +beornas on blancum. ðær wæs Beowulfes +mærðo mæned; monig oft gecwæð +þætte suð ne norð be sæm tweonum +ofer eormengrund oþer nænig +under swegles begong selra nære +rondhæbbendra, rices wyrðra. +Ne hie huru winedrihten wiht ne logon, +glædne Hroðgar, ac þæt wæs god cyning. +Hwilum heaþorofe hleapan leton, +on geflit faran fealwe mearas +ðær him foldwegas fægere þuhton, +cystum cuðe. Hwilum cyninges þegn, +guma gilphlæden, gidda gemyndig, +se ðe ealfela ealdgesegena +worn gemunde, word oþer fand +soðe gebunden; secg eft ongan +sið Beowulfes snyttrum styrian +ond on sped wrecan spel gerade, +wordum wrixlan. Welhwylc gecwæð +þæt he fram Sigemundes secgan hyrde +ellendædum, uncuþes fela, +Wælsinges gewin, wide siðas, +þara þe gumena bearn gearwe ne wiston, +fæhðe ond fyrena, buton Fitela mid hine, +þonne he swulces hwæt secgan wolde, +eam his nefan, swa hie a wæron +æt niða gehwam nydgesteallan; +hæfdon ealfela eotena cynnes +sweordum gesæged. Sigemunde gesprong +æfter deaðdæge dom unlytel, +syþðan wiges heard wyrm acwealde, +hordes hyrde. He under harne stan, +æþelinges bearn, ana geneðde +frecne dæde, ne wæs him Fitela mid. +hwæþre him gesælde ðæt þæt swurd þurhwod +wrætlicne wyrm, þæt hit on wealle ætstod, +dryhtlic iren; draca morðre swealt. +Hæfde aglæca elne gegongen +þæt he beahhordes brucan moste +selfes dome; sæbat gehleod, +bær on bearm scipes beorhte frætwa, +Wælses eafera. Wyrm hat gemealt. +Se wæs wreccena wide mærost +ofer werþeode, wigendra hleo, +ellendædum he þæs ær onðah, +siððan Heremodes hild sweðrode, +eafoð ond ellen. He mid Eotenum wearð +on feonda geweald forð forlacen, +snude forsended. Hine sorhwylmas +lemede to lange; he his leodum wearð, +eallum æþellingum to aldorceare; +swylce oft bemearn ærran mælum +swiðferhþes sið snotor ceorl monig, +se þe him bealwa to bote gelyfde, +þæt þæt ðeodnes bearn geþeon scolde, +fæderæþelum onfon, folc gehealdan, +hord ond hleoburh, hæleþa rice, +eþel Scyldinga. He þær eallum wearð, +mæg Higelaces, manna cynne, +freondum gefægra; hine fyren onwod. +Hwilum flitende fealwe stræte +mearum mæton. ða wæs morgenleoht +scofen ond scynded. Eode scealc monig +swiðhicgende to sele þam hean +searowundor seon; swylce self cyning +of brydbure, beahhorda weard, +tryddode tirfæst getrume micle, +cystum gecyþed, ond his cwen mid him +medostigge mæt mægþa hose. +Hroðgar maþelode he to healle geong, +stod on stapole, geseah steapne hrof, +golde fahne, ond Grendles hond: +ðisse ansyne alwealdan þanc +lungre gelimpe. Fela ic laþes gebad, +grynna æt Grendle; a mæg god wyrcan +wunder æfter wundre, wuldres hyrde. +ðæt wæs ungeara þæt ic ænigra me +weana ne wende to widan feore +bote gebidan, þonne blode fah +husa selest heorodreorig stod, +wea widscofen witena gehwylcum +ðara þe ne wendon þæt hie wideferhð +leoda landgeweorc laþum beweredon +scuccum ond scinnum. Nu scealc hafað +þurh drihtnes miht dæd gefremede ðe +we ealle ær ne meahton +snyttrum besyrwan. Hwæt, þæt secgan mæg +efne swa hwylc mægþa swa ðone magan cende +æfter gumcynnum, gyf heo gyt lyfað, +þæt hyre ealdmetod este wære +bearngebyrdo. Nu ic, Beowulf, þec, +secg betsta, me for sunu wylle +freogan on ferhþe; heald forð tela +niwe sibbe. Ne bið þe nænigra gad +worolde wilna, þe ic geweald hæbbe. +Ful oft ic for læssan lean teohhode, +hordweorþunge hnahran rince, +sæmran æt sæcce. þu þe self hafast +dædum gefremed þæt þin dom lyfað +awa to aldre. Alwalda þec +gode forgylde, swa he nu gyt dyde. +Beowulf maþelode, bearn Ecþeowes: +We þæt ellenweorc estum miclum, +feohtan fremedon, frecne geneðdon +eafoð uncuþes. Uþe ic swiþor +þæt ðu hine selfne geseon moste, +feond on frætewum fylwerigne. +Ic hine hrædlice heardan clammum +on wælbedde wriþan þohte, +þæt he for mundgripe minum scolde +licgean lifbysig, butan his lic swice. +Ic hine ne mihte, þa metod nolde, +ganges getwæman, no ic him þæs georne ætfealh, +feorhgeniðlan; wæs to foremihtig +feond on feþe. Hwæþere he his folme forlet +to lifwraþe last weardian, +earm ond eaxle. No þær ænige swa þeah +feasceaft guma frofre gebohte; +no þy leng leofað laðgeteona, +synnum geswenced, ac hyne sar hafað +mid nydgripe nearwe befongen, +balwon bendum. ðær abidan sceal +maga mane fah miclan domes, +hu him scir metod scrifan wille. +ða wæs swigra secg, sunu Eclafes, +on gylpspræce guðgeweorca, +siþðan æþelingas eorles cræfte +ofer heanne hrof hand sceawedon, +feondes fingras. Foran æghwylc wæs, +stiðra nægla gehwylc, style gelicost, +hæþenes handsporu hilderinces, +egl, unheoru. æghwylc gecwæð +þæt him heardra nan hrinan wolde +iren ærgod, þæt ðæs ahlæcan +blodge beadufolme onberan wolde. +ða wæs haten hreþe Heort innanweard +folmum gefrætwod. Fela þæra wæs, +wera ond wifa, þe þæt winreced, +gestsele gyredon. Goldfag scinon +web æfter wagum, wundorsiona fela +secga gehwylcum þara þe on swylc starað. +Wæs þæt beorhte bold tobrocen swiðe, +eal inneweard irenbendum fæst, +heorras tohlidene. Hrof ana genæs, +ealles ansund, þe se aglæca, +fyrendædum fag, on fleam gewand, +aldres orwena. No þæt yðe byð +to befleonne, fremme se þe wille, +ac gesecan sceal sawlberendra, +nyde genydde, niþða bearna, +grundbuendra gearwe stowe, +þær his lichoma legerbedde fæst +swefeþ æfter symle. þa wæs sæl ond mæl +þæt to healle gang Healfdenes sunu; +wolde self cyning symbel þicgan. +Ne gefrægen ic þa mægþe maran weorode +ymb hyra sincgyfan sel gebæran. +Bugon þa to bence blædagande, +fylle gefægon; fægere geþægon +medoful manig magas þara +swiðhicgende on sele þam hean, +Hroðgar ond Hroþulf. Heorot innan wæs +freondum afylled; nalles facenstafas +|eodscyldingas þenden fremedon. +Forgeaf þa Beowulfe bearn Healfdenes +segen gyldenne sigores to leane; +hroden hildecumbor, helm ond byrnan, +mære maðþumsweord manige gesawon +beforan beorn beran. Beowulf geþah +ful on flette; no he þære feohgyfte +for sceotendum scamigan ðorfte. +Ne gefrægn ic freondlicor feower madmas +golde gegyrede gummanna fela +in ealobence oðrum gesellan. +Ymb þæs helmes hrof heafodbeorge +wirum bewunden walu utan heold, +þæt him fela laf frecne ne meahton +scurheard sceþðan, þonne scyldfreca +ongean gramum gangan scolde. +Heht ða eorla hleo eahta mearas +fætedhleore on flet teon, +in under eoderas. þara anum stod +sadol searwum fah, since gewurþad; +þæt wæs hildesetl heahcyninges, +ðonne sweorda gelac sunu Healfdenes +efnan wolde. Næfre on ore læg +widcuþes wig, ðonne walu feollon. +Ond ða Beowulfe bega gehwæþres +eodor Ingwina onweald geteah, +wicga ond wæpna, het hine wel brucan. +Swa manlice mære þeoden, +hordweard hæleþa, heaþoræsas geald +mearum ond madmum, swa hy næfre man lyhð, +se þe secgan wile soð æfter rihte. +ða gyt æghwylcum eorla drihten +þara þe mid Beowulfe brimlade teah +on þære medubence maþðum gesealde, +yrfelafe, ond þone ænne heht +golde forgyldan, þone ðe Grendel ær +mane acwealde, swa he hyra ma wolde, +nefne him witig god wyrd forstode +ond ðæs mannes mod. Metod eallum weold +gumena cynnes, swa he nu git deð. +Forþan bið andgit æghwær selest, +ferhðes foreþanc. Fela sceal gebidan +leofes ond laþes se þe longe her +on ðyssum windagum worolde bruceð. +þær wæs sang ond sweg samod ætgædere +fore Healfdenes hildewisan, +gomenwudu greted, gid oft wrecen, +ðonne healgamen Hroþgares scop +æfter medobence mænan scolde +be Finnes eaferum, ða hie se fær begeat, +hæleð Healfdena, Hnæf Scyldinga, +in Freswæle feallan scolde. +Ne huru Hildeburh herian þorfte +Eotena treowe; unsynnum wearð +beloren leofum æt þam lindplegan, +bearnum ond broðrum; hie on gebyrd hruron, +gare wunde. þæt wæs geomuru ides. +Nalles holinga Hoces dohtor +meotodsceaft bemearn, syþðan morgen com, +ða heo under swegle geseon meahte +morþorbealo maga, þær heo ær mæste heold +worolde wynne. Wig ealle fornam +Finnes þegnas nemne feaum anum, +þæt he ne mehte on þæm meðelstede +wig Hengeste wiht gefeohtan, +ne þa wealafe wige forþringan +þeodnes ðegna. ac hig him geþingo budon, +þæt hie him oðer flet eal gerymdon, +healle ond heahsetl, þæt hie healfre geweald +wið Eotena bearn agan moston, +ond æt feohgyftum Folcwaldan sunu +dogra gehwylce Dene weorþode, +Hengestes heap hringum wenede +efne swa swiðe sincgestreonum +fættan goldes, swa he Fresena cyn +on beorsele byldan wolde. +ða hie getruwedon on twa healfa +fæste frioðuwære. Fin Hengeste +elne, unflitme aðum benemde +þæt he þa wealafe weotena dome +arum heolde, þæt ðær ænig mon +wordum ne worcum wære ne bræce, +ne þurh inwitsearo æfre gemænden +ðeah hie hira beaggyfan banan folgedon +ðeodenlease, þa him swa geþearfod wæs. +gyf þonne Frysna hwylc frecnan spræce +ðæs morþorhetes myndgiend wære, +þonne hit sweordes ecg seðan scolde. +Ad wæs geæfned ond icge gold +ahæfen of horde. Herescyldinga +betst beadorinca wæs on bæl gearu. +æt þæm ade wæs eþgesyne +swatfah syrce, swyn ealgylden, +eofer irenheard, æþeling manig +wundum awyrded; sume on wæle crungon. +Het ða Hildeburh æt Hnæfes ade +hire selfre sunu sweoloðe befæstan, +banfatu bærnan ond on bæl don +eame on eaxle. Ides gnornode, +geomrode giddum. Guðrinc astah. +Wand to wolcnum wælfyra mæst, +hlynode for hlawe; hafelan multon, +bengeato burston, ðonne blod ætspranc, +laðbite lices. Lig ealle forswealg, +gæsta gifrost, þara ðe þær guð fornam +bega folces; wæs hira blæd scacen. +Gewiton him ða wigend wica neosian, +freondum befeallen, Frysland geseon, +hamas ond heaburh. Hengest ða gyt +wælfagne winter wunode mid Finne +eal unhlitme. Eard gemunde, +þeah þe he ne meahte on mere drifan +hringedstefnan; holm storme weol, +won wið winde, winter yþe beleac +isgebinde, oþðæt oþer com +gear in geardas, swa nu gyt deð, +þa ðe syngales sele bewitiað, +wuldortorhtan weder. ða wæs winter scacen, +fæger foldan bearm. Fundode wrecca, +gist of geardum; he to gyrnwræce +swiðor þohte þonne to sælade, +gif he torngemot þurhteon mihte +þæt he Eotena bearn inne gemunde. +Swa he ne forwyrnde woroldrædenne, +þonne him Hunlafing hildeleoman, +billa selest, on bearm dyde, +þæs wæron mid Eotenum ecge cuðe. +Swylce ferhðfrecan Fin eft begeat +sweordbealo sliðen æt his selfes ham, +siþðan grimne gripe Guðlaf ond Oslaf +æfter sæsiðe, sorge, mændon, +ætwiton weana dæl; ne meahte wæfre mod +forhabban in hreþre. ða wæs heal roden +feonda feorum, swilce Fin slægen, +cyning on corþre, ond seo cwen numen. +Sceotend Scyldinga to scypon feredon +eal ingesteald eorðcyninges, +swylce hie æt Finnes ham findan meahton +sigla, searogimma. Hie on sælade +drihtlice wif to Denum feredon, +læddon to leodum. Leoð wæs asungen, +gleomannes gyd. Gamen eft astah, +beorhtode bencsweg; byrelas sealdon +win of wunderfatum. þa cwom Wealhþeo forð +gan under gyldnum beage, þær þa godan twegen +sæton suhtergefæderan; þa gyt wæs hiera sib ætgædere, +æghwylc oðrum trywe. Swylce þær Unferþ þyle +æt fotum sæt frean Scyldinga; gehwylc hiora his ferhþe treowde, +þæt he hæfde mod micel, þeah þe he his magum nære +arfæst æt ecga gelacum. Spræc ða ides Scyldinga: +Onfoh þissum fulle, freodrihten min, +sinces brytta. þu on sælum wes, +goldwine gumena, ond to Geatum spræc +mildum wordum, swa sceal man don. +Beo wið Geatas glæd, geofena gemyndig, +nean ond feorran þu nu hafast. +Me man sægde þæt þu ðe for sunu wolde +hererinc habban. Heorot is gefælsod, +beahsele beorhta; bruc þenden þu mote +manigra medo, ond þinum magum læf +folc ond rice, þonne ðu forð scyle +metodsceaft seon. Ic minne can +glædne Hroþulf, þæt he þa geogoðe wile +arum healdan, gyf þu ær þonne he, +wine Scildinga, worold oflætest; +wene ic þæt he mid gode gyldan wille +uncran eaferan, gif he þæt eal gemon, +hwæt wit to willan ond to worðmyndum +umborwesendum ær arna gefremedon. +Hwearf þa bi bence þær hyre byre wæron, +Hreðric ond Hroðmund, ond hæleþa bearn, +giogoð ætgædere; þær se goda sæt, +Beowulf Geata, be þæm gebroðrum twæm. +Him wæs ful boren ond freondlaþu +wordum bewægned, ond wunden gold +estum geeawed, earmreade twa, +hrægl ond hringas, healsbeaga mæst +þara þe ic on foldan gefrægen hæbbe. +Nænigne ic under swegle selran hyrde +hordmaððum hæleþa, syþðan Hama ætwæg +to þære byrhtan byrig Brosinga mene, +sigle ond sincfæt; searoniðas fleah +Eormenrices, geceas ecne ræd. +þone hring hæfde Higelac Geata, +nefa Swertinges, nyhstan siðe, +siðþan he under segne sinc ealgode, +wælreaf werede; hyne wyrd fornam, +syþðan he for wlenco wean ahsode, +fæhðe to Frysum. He þa frætwe wæg, +eorclanstanas ofer yða ful, +rice þeoden; he under rande gecranc. +Gehwearf þa in Francna fæþm feorh cyninges, +breostgewædu ond se beah somod; +wyrsan wigfrecan wæl reafedon +æfter guðsceare, Geata leode, +hreawic heoldon. Heal swege onfeng. +Wealhðeo maþelode, heo fore þæm werede spræc: +Bruc ðisses beages, Beowulf leofa, +hyse, mid hæle, ond þisses hrægles neot, +þeodgestreona, ond geþeoh tela, +cen þec mid cræfte ond þyssum cnyhtum wes +lara liðe; ic þe þæs lean geman. +Hafast þu gefered þæt ðe feor ond neah +ealne wideferhþ weras ehtigað, +efne swa side swa sæ bebugeð, +windgeard, weallas. Wes þenden þu lifige, +æþeling, eadig. Ic þe an tela +sincgestreona. Beo þu suna minum +dædum gedefe, dreamhealdende. +Her is æghwylc eorl oþrum getrywe, +modes milde, mandrihtne hold; +þegnas syndon geþwære, þeod ealgearo, +druncne dryhtguman doð swa ic bidde. +Eode þa to setle. þær wæs symbla cyst; +druncon win weras. Wyrd ne cuþon, +geosceaft grimme, swa hit agangen wearð +eorla manegum, syþðan æfen cwom +ond him Hroþgar gewat to hofe sinum, +rice to ræste. Reced weardode +unrim eorla, swa hie oft ær dydon. +Bencþelu beredon; hit geondbræded wearð +beddum ond bolstrum. Beorscealca sum +fus ond fæge fletræste gebeag. +Setton him to heafdon hilderandas, +bordwudu beorhtan; þær on bence wæs +ofer æþelinge yþgesene +heaþosteapa helm, hringed byrne, +þrecwudu þrymlic. Wæs þeaw hyra +þæt hie oft wæron an wig gearwe, +ge æt ham ge on herge, ge gehwæþer þara, +efne swylce mæla swylce hira mandryhtne +þearf gesælde; wæs seo þeod tilu. +Sigon þa to slæpe. Sum sare angeald +æfenræste, swa him ful oft gelamp, +siþðan goldsele Grendel warode, +unriht æfnde, oþþæt ende becwom, +swylt æfter synnum. þæt gesyne wearþ, +widcuþ werum, þætte wrecend þa gyt +lifde æfter laþum, lange þrage, +æfter guðceare. Grendles modor, +ides, aglæcwif, yrmþe gemunde, +se þe wæteregesan wunian scolde, +cealde streamas, siþðan Cain wearð +to ecgbanan angan breþer, +fæderenmæge; he þa fag gewat, +morþre gemearcod, mandream fleon, +westen warode. þanon woc fela +geosceaftgasta; wæs þæra Grendel sum, +heorowearh hetelic, se æt Heorote fand +wæccendne wer wiges bidan. +þær him aglæca ætgræpe wearð; +hwæþre he gemunde mægenes strenge, +gimfæste gife ðe him god sealde, +ond him to anwaldan are gelyfde, +frofre ond fultum; ðy he þone feond ofercwom, +gehnægde helle gast. þa he hean gewat, +dreame bedæled, deaþwic seon, +mancynnes feond, ond his modor þa gyt, +gifre ond galgmod, gegan wolde +sorhfulne sið, sunu deað wrecan. +Com þa to Heorote, ðær Hringdene +geond þæt sæld swæfun. þa ðær sona wearð +edhwyrft eorlum, siþðan inne fealh +Grendles modor. Wæs se gryre læssa +efne swa micle swa bið mægþa cræft, +wiggryre wifes, be wæpnedmen, +þonne heoru bunden, hamere geþuren, +sweord swate fah swin ofer helme +ecgum dyhttig andweard scireð. +þa wæs on healle heardecg togen +sweord ofer setlum, sidrand manig +hafen handa fæst; helm ne gemunde, +byrnan side, þa hine se broga angeat. +Heo wæs on ofste, wolde ut þanon, +feore beorgan, þa heo onfunden wæs. +Hraðe heo æþelinga anne hæfde +fæste befangen, þa heo to fenne gang. +Se wæs Hroþgare hæleþa leofost +on gesiðes had be sæm tweonum, +rice randwiga, þone ðe heo on ræste abreat, +blædfæstne beorn. Næs Beowulf ðær, +ac wæs oþer in ær geteohhod +æfter maþðumgife mærum Geate. +Hream wearð in Heorote; heo under heolfre genam +cuþe folme; cearu wæs geniwod, +geworden in wicun. Ne wæs þæt gewrixle til, +þæt hie on ba healfa bicgan scoldon +freonda feorum. þa wæs frod cyning, +har hilderinc, on hreon mode, +syðþan he aldorþegn unlyfigendne, +þone deorestan deadne wisse. +Hraþe wæs to bure Beowulf fetod, +sigoreadig secg. Samod ærdæge +eode eorla sum, æþele cempa +self mid gesiðum þær se snotera bad, +hwæþer him alwalda æfre wille +æfter weaspelle wyrpe gefremman. +Gang ða æfter flore fyrdwyrðe man +mid his handscale healwudu dynede, +þæt he þone wisan wordum nægde +frean Ingwina, frægn gif him wære +æfter neodlaðum niht getæse. +Hroðgar maþelode, helm Scyldinga: +Ne frin þu æfter sælum. Sorh is geniwod +Denigea leodum. Dead is æschere, +Yrmenlafes yldra broþor, +min runwita ond min rædbora, +eaxlgestealla, ðonne we on orlege +hafelan weredon, þonne hniton feþan, +eoferas cynsedan. Swylc scolde eorl wesan, +æþeling ærgod, swylc æschere wæs. +Wearð him on Heorote to handbanan +wælgæst wæfre; ic ne wat hwæder +atol æse wlanc eftsiðas teah, +fylle gefægnod. Heo þa fæhðe wræc +þe þu gystranniht Grendel cwealdest +þurh hæstne had heardum clammum, +forþan he to lange leode mine +wanode ond wyrde. He æt wige gecrang +ealdres scyldig, ond nu oþer cwom +mihtig manscaða, wolde hyre mæg wrecan, +ge feor hafað fæhðe gestæled +(þæs þe þincean mæg þegne monegum, +se þe æfter sincgyfan on sefan greoteþ), +hreþerbealo hearde; nu seo hand ligeð, +se þe eow welhwylcra wilna dohte. +Ic þæt londbuend, leode mine, +selerædende, secgan hyrde +þæt hie gesawon swylce twegen +micle mearcstapan moras healdan, +ellorgæstas. ðæra oðer wæs, +þæs þe hie gewislicost gewitan meahton, +idese onlicnæs; oðer earmsceapen +on weres wæstmum wræclastas træd, +næfne he wæs mara þonne ænig man oðer; +þone on geardagum Grendel nemdon +foldbuende. No hie fæder cunnon, +hwæþer him ænig wæs ær acenned +dyrnra gasta. Hie dygel lond +warigeað, wulfhleoþu, windige næssas, +frecne fengelad, ðær fyrgenstream +under næssa genipu niþer gewiteð, +flod under foldan. Nis þæt feor heonon +milgemearces þæt se mere standeð; +ofer þæm hongiað hrinde bearwas, +wudu wyrtum fæst wæter oferhelmað. +þær mæg nihta gehwæm niðwundor seon, +fyr on flode. No þæs frod leofað +gumena bearna, þæt þone grund wite; +ðeah þe hæðstapa hundum geswenced, +heorot hornum trum, holtwudu sece, +feorran geflymed, ær he feorh seleð, +aldor on ofre, ær he in wille +hafelan hydan. Nis þæt heoru stow! +þonon yðgeblond up astigeð +won to wolcnum, þonne wind styreþ, +lað gewidru, oðþæt lyft drysmaþ, +roderas reotað. Nu is se ræd gelang +eft æt þe anum. Eard git ne const, +frecne stowe, ðær þu findan miht +felasinnigne secg; sec gif þu dyrre. +Ic þe þa fæhðe feo leanige, +ealdgestreonum, swa ic ær dyde, +wundnum golde, gyf þu on weg cymest." +Beowulf maþelode, bearn Ecgþeowes: +"Ne sorga, snotor guma; selre bið æghwæm +þæt he his freond wrece, þonne he fela murne. +Ure æghwylc sceal ende gebidan +worolde lifes; wyrce se þe mote +domes ær deaþe; þæt bið drihtguman +unlifgendum æfter selest. +Aris, rices weard, uton raþe feran +Grendles magan gang sceawigan. +Ic hit þe gehate, no he on helm losaþ, +ne on foldan fæþm, ne on fyrgenholt, +ne on gyfenes grund, ga þær he wille. +ðys dogor þu geþyld hafa +weana gehwylces, swa ic þe wene to." +Ahleop ða se gomela, gode þancode, +mihtigan drihtne, þæs se man gespræc. +þa wæs Hroðgare hors gebæted, +wicg wundenfeax. Wisa fengel +geatolic gende; gumfeþa stop +lindhæbbendra. Lastas wæron +æfter waldswaþum wide gesyne, +gang ofer grundas, þær heo gegnum for +ofer myrcan mor, magoþegna bær +þone selestan sawolleasne +þara þe mid Hroðgare ham eahtode. +Ofereode þa æþelinga bearn +steap stanhliðo, stige nearwe, +enge anpaðas, uncuð gelad, +neowle næssas, nicorhusa fela. +He feara sum beforan gengde +wisra monna wong sceawian, +oþþæt he færinga fyrgenbeamas +ofer harne stan hleonian funde, +wynleasne wudu; wæter under stod +dreorig ond gedrefed. Denum eallum wæs, +winum Scyldinga, weorce on mode +to geþolianne, ðegne monegum, +oncyð eorla gehwæm, syðþan æscheres +on þam holmclife hafelan metton. +Flod blode weol (folc to sægon), +hatan heolfre. Horn stundum song +fuslic fyrdleoð. Feþa eal gesæt. +Gesawon ða æfter wætere wyrmcynnes fela, +sellice sædracan, sund cunnian, +swylce on næshleoðum nicras licgean, +ða on undernmæl oft bewitigað +sorhfulne sið on seglrade, +wyrmas ond wildeor; hie on weg hruron, +bitere ond gebolgne, bearhtm ongeaton, +guðhorn galan. Sumne Geata leod +of flanbogan feores getwæfde, +yðgewinnes, þæt him on aldre stod +herestræl hearda; he on holme wæs +sundes þe sænra, ðe hyne swylt fornam. +Hræþe wearð on yðum mid eoferspreotum +heorohocyhtum hearde genearwod, +niða genæged, ond on næs togen, +wundorlic wægbora; weras sceawedon +gryrelicne gist. Gyrede hine Beowulf +eorlgewædum, nalles for ealdre mearn. +Scolde herebyrne hondum gebroden, +sid ond searofah, sund cunnian, +seo ðe bancofan beorgan cuþe, +þæt him hildegrap hreþre ne mihte, +eorres inwitfeng, aldre gesceþðan; +ac se hwita helm hafelan werede, +se þe meregrundas mengan scolde, +secan sundgebland since geweorðad, +befongen freawrasnum, swa hine fyrndagum +worhte wæpna smið, wundrum teode, +besette swinlicum, þæt hine syðþan no +brond ne beadomecas bitan ne meahton. +Næs þæt þonne mætost mægenfultuma +þæt him on ðearfe lah ðyle Hroðgares; +wæs þæm hæftmece Hrunting nama. +þæt wæs an foran ealdgestreona; +ecg wæs iren, atertanum fah, +ahyrded heaþoswate; næfre hit æt hilde ne swac +manna ængum þara þe hit mid mundum bewand, +se ðe gryresiðas gegan dorste, +folcstede fara; næs þæt forma sið +þæt hit ellenweorc æfnan scolde. +Huru ne gemunde mago Ecglafes, +eafoþes cræftig, þæt he ær gespræc +wine druncen, þa he þæs wæpnes onlah +selran sweordfrecan. Selfa ne dorste +under yða gewin aldre geneþan, +drihtscype dreogan; þær he dome forleas, +ellenmærðum. Ne wæs þæm oðrum swa, +syðþan he hine to guðe gegyred hæfde. +Beowulf maðelode, bearn Ecgþeowes: +"Geþenc nu, se mæra maga Healfdenes, +snottra fengel, nu ic eom siðes fus, +goldwine gumena, hwæt wit geo spræcon, +gif ic æt þearfe þinre scolde +aldre linnan, þæt ðu me a wære +forðgewitenum on fæder stæle. +Wes þu mundbora minum magoþegnum, +hondgesellum, gif mec hild nime; +swylce þu ða madmas þe þu me sealdest, +Hroðgar leofa, Higelace onsend. +Mæg þonne on þæm golde ongitan Geata dryhten, +geseon sunu Hrædles, þonne he on þæt sinc starað, +þæt ic gumcystum godne funde +beaga bryttan, breac þonne moste. +Ond þu Unferð læt ealde lafe, +wrætlic wægsweord, widcuðne man +heardecg habban; ic me mid Hruntinge +dom gewyrce, oþðe mec deað nimeð." +æfter þæm wordum Wedergeata leod +efste mid elne, nalas ondsware +bidan wolde; brimwylm onfeng +hilderince. ða wæs hwil dæges +ær he þone grundwong ongytan mehte. +Sona þæt onfunde se ðe floda begong +heorogifre beheold hund missera, +grim ond grædig, þæt þær gumena sum +ælwihta eard ufan cunnode. +Grap þa togeanes, guðrinc gefeng +atolan clommum. No þy ær in gescod +halan lice; hring utan ymbbearh, +þæt heo þone fyrdhom ðurhfon ne mihte, +locene leoðosyrcan laþan fingrum. +Bær þa seo brimwylf, þa heo to botme com, +hringa þengel to hofe sinum, +swa he ne mihte, no he þæs modig wæs, +wæpna gewealdan, ac hine wundra þæs fela +swencte on sunde, sædeor monig +hildetuxum heresyrcan bræc, +ehton aglæcan. ða se eorl ongeat +þæt he in niðsele nathwylcum wæs, +þær him nænig wæter wihte ne sceþede, +ne him for hrofsele hrinan ne mehte +færgripe flodes; fyrleoht geseah, +blacne leoman, beorhte scinan. +Ongeat þa se goda grundwyrgenne, +merewif mihtig; mægenræs forgeaf +hildebille, hond sweng ne ofteah, +þæt hire on hafelan hringmæl agol +grædig guðleoð. ða se gist onfand +þæt se beadoleoma bitan nolde, +aldre sceþðan, ac seo ecg geswac +ðeodne æt þearfe; ðolode ær fela +hondgemota, helm oft gescær, +fæges fyrdhrægl; ða wæs forma sið +deorum madme, þæt his dom alæg. +Eft wæs anræd, nalas elnes læt, +mærða gemyndig mæg Hylaces. +Wearp ða wundenmæl wrættum gebunden +yrre oretta, þæt hit on eorðan læg, +stið ond stylecg; strenge getruwode, +mundgripe mægenes. Swa sceal man don, +þonne he æt guðe gegan þenceð +longsumne lof, na ymb his lif cearað. +Gefeng þa be eaxle (nalas for fæhðe mearn) +Guðgeata leod Grendles modor; +brægd þa beadwe heard, þa he gebolgen wæs, +feorhgeniðlan, þæt heo on flet gebeah. +Heo him eft hraþe andlean forgeald +grimman grapum ond him togeanes feng; +oferwearp þa werigmod wigena strengest, +feþecempa, þæt he on fylle wearð. +Ofsæt þa þone selegyst ond hyre seax geteah, +brad ond brunecg, wolde hire bearn wrecan, +angan eaferan. Him on eaxle læg +breostnet broden; þæt gebearh feore, +wið ord ond wið ecge ingang forstod. +Hæfde ða forsiðod sunu Ecgþeowes +under gynne grund, Geata cempa, +nemne him heaðobyrne helpe gefremede, +herenet hearde, ond halig god +geweold wigsigor; witig drihten, +rodera rædend, hit on ryht gesced +yðelice, syþðan he eft astod. +Geseah ða on searwum sigeeadig bil, +eald sweord eotenisc, ecgum þyhtig, +wigena weorðmynd; þæt wæs wæpna cyst, +buton hit wæs mare ðonne ænig mon oðer +to beadulace ætberan meahte, +god ond geatolic, giganta geweorc. +He gefeng þa fetelhilt, freca Scyldinga +hreoh ond heorogrim hringmæl gebrægd, +aldres orwena, yrringa sloh, +þæt hire wið halse heard grapode, +banhringas bræc. Bil eal ðurhwod +fægne flæschoman; heo on flet gecrong. +Sweord wæs swatig, secg weorce gefeh. +Lixte se leoma, leoht inne stod, +efne swa of hefene hadre scineð +rodores candel. He æfter recede wlat; +hwearf þa be wealle, wæpen hafenade +heard be hiltum Higelaces ðegn, +yrre ond anræd. Næs seo ecg fracod +hilderince, ac he hraþe wolde +Grendle forgyldan guðræsa fela +ðara þe he geworhte to Westdenum +oftor micle ðonne on ænne sið, +þonne he Hroðgares heorðgeneatas +sloh on sweofote, slæpende fræt +folces Denigea fyftyne men +ond oðer swylc ut offerede, +laðlicu lac. He him þæs lean forgeald, +reþe cempa, to ðæs þe he on ræste geseah +guðwerigne Grendel licgan +aldorleasne, swa him ær gescod +hild æt Heorote. Hra wide sprong, +syþðan he æfter deaðe drepe þrowade, +heorosweng heardne, ond hine þa heafde becearf. +Sona þæt gesawon snottre ceorlas, +þa ðe mid Hroðgare on holm wliton, +þæt wæs yðgeblond eal gemenged, +brim blode fah. Blondenfeaxe, +gomele ymb godne, ongeador spræcon +þæt hig þæs æðelinges eft ne wendon +þæt he sigehreðig secean come +mærne þeoden; þa ðæs monige gewearð +þæt hine seo brimwylf abroten hæfde. +ða com non dæges. Næs ofgeafon +hwate Scyldingas; gewat him ham þonon +goldwine gumena. Gistas setan +modes seoce ond on mere staredon, +wiston ond ne wendon þæt hie heora winedrihten +selfne gesawon. þa þæt sweord ongan +æfter heaþoswate hildegicelum, +wigbil wanian. þæt wæs wundra sum, +þæt hit eal gemealt ise gelicost, +ðonne forstes bend fæder onlæteð, +onwindeð wælrapas, se geweald hafað +sæla ond mæla; þæt is soð metod. +Ne nom he in þæm wicum, Wedergeata leod, +maðmæhta ma, þeh he þær monige geseah, +buton þone hafelan ond þa hilt somod +since fage. Sweord ær gemealt, +forbarn brodenmæl; wæs þæt blod to þæs hat, +ættren ellorgæst se þær inne swealt. +Sona wæs on sunde se þe ær æt sæcce gebad +wighryre wraðra, wæter up þurhdeaf. +Wæron yðgebland eal gefælsod, +eacne eardas, þa se ellorgast +oflet lifdagas ond þas lænan gesceaft. +Com þa to lande lidmanna helm +swiðmod swymman; sælace gefeah, +mægenbyrþenne þara þe he him mid hæfde. +Eodon him þa togeanes, gode þancodon, +ðryðlic þegna heap, þeodnes gefegon, +þæs þe hi hyne gesundne geseon moston. +ða wæs of þæm hroran helm ond byrne +lungre alysed. Lagu drusade, +wæter under wolcnum, wældreore fag. +Ferdon forð þonon feþelastum +ferhþum fægne, foldweg mæton, +cuþe stræte. Cyningbalde men +from þæm holmclife hafelan bæron +earfoðlice heora æghwæþrum, +felamodigra; feower scoldon +on þæm wælstenge weorcum geferian +to þæm goldsele Grendles heafod, +oþðæt semninga to sele comon +frome fyrdhwate feowertyne +Geata gongan; gumdryhten mid +modig on gemonge meodowongas træd. +ða com in gan ealdor ðegna, +dædcene mon dome gewurþad, +hæle hildedeor, Hroðgar gretan. +þa wæs be feaxe on flet boren +Grendles heafod, þær guman druncon, +egeslic for eorlum ond þære idese mid, +wliteseon wrætlic; weras on sawon. +Beowulf maþelode, bearn Ecgþeowes: +"Hwæt! we þe þas sælac, sunu Healfdenes, +leod Scyldinga, lustum brohton +tires to tacne, þe þu her to locast. +Ic þæt unsofte ealdre gedigde +wigge under wætere, weorc geneþde +earfoðlice; ætrihte wæs +guð getwæfed, nymðe mec god scylde. +Ne meahte ic æt hilde mid Hruntinge +wiht gewyrcan, þeah þæt wæpen duge; +ac me geuðe ylda waldend +þæt ic on wage geseah wlitig hangian +eald sweord eacen (oftost wisode +winigea leasum), þæt ic ðy wæpne gebræd. +Ofsloh ða æt þære sæcce, þa me sæl ageald, +huses hyrdas. þa þæt hildebil +forbarn brogdenmæl, swa þæt blod gesprang, +hatost heaþoswata. Ic þæt hilt þanan +feondum ætferede, fyrendæda wræc, +deaðcwealm Denigea, swa hit gedefe wæs. +Ic hit þe þonne gehate, þæt þu on Heorote most +sorhleas swefan mid þinra secga gedryht +ond þegna gehwylc þinra leoda, +duguðe ond iogoþe, þæt þu him ondrædan ne þearft, +þeoden Scyldinga, on þa healfe, +aldorbealu eorlum, swa þu ær dydest." +ða wæs gylden hilt gamelum rince, +harum hildfruman, on hand gyfen, +enta ærgeweorc; hit on æht gehwearf +æfter deofla hryre Denigea frean, +wundorsmiþa geweorc, ond þa þas worold ofgeaf +gromheort guma, godes ondsaca, +morðres scyldig, ond his modor eac, +on geweald gehwearf woroldcyninga +ðæm selestan be sæm tweonum +ðara þe on Scedenigge sceattas dælde. +Hroðgar maðelode, hylt sceawode, +ealde lafe, on ðæm wæs or writen +fyrngewinnes, syðþan flod ofsloh, +gifen geotende, giganta cyn +(frecne geferdon); þæt wæs fremde þeod +ecean dryhtne; him þæs endelean +þurh wæteres wylm waldend sealde. +Swa wæs on ðæm scennum sciran goldes +þurh runstafas rihte gemearcod, +geseted ond gesæd hwam þæt sweord geworht, +irena cyst, ærest wære, +wreoþenhilt ond wyrmfah. ða se wisa spræc +sunu Healfdenes (swigedon ealle): +"þæt, la, mæg secgan se þe soð ond riht +fremeð on folce, feor eal gemon, +eald OEweard, þæt ðes eorl wære +geboren betera! Blæd is aræred +geond widwegas, wine min Beowulf, +ðin ofer þeoda gehwylce. Eal þu hit geþyldum healdest, +mægen mid modes snyttrum. Ic þe sceal mine gelæstan +freode, swa wit furðum spræcon. ðu scealt to frofre weorþan +eal langtwidig leodum þinum, +hæleðum to helpe. Ne wearð Heremod swa +eaforum Ecgwelan, Arscyldingum; +ne geweox he him to willan, ac to wælfealle +ond to deaðcwalum Deniga leodum; +breat bolgenmod beodgeneatas, +eaxlgesteallan, oþþæt he ana hwearf, +mære þeoden, mondreamum from. +ðeah þe hine mihtig god mægenes wynnum, +eafeþum stepte, ofer ealle men +forð gefremede, hwæþere him on ferhþe greow +breosthord blodreow. Nallas beagas geaf +Denum æfter dome; dreamleas gebad +þæt he þæs gewinnes weorc þrowade, +leodbealo longsum. ðu þe lær be þon, +gumcyste ongit; ic þis gid be þe +awræc wintrum frod. Wundor is to secganne +hu mihtig god manna cynne +þurh sidne sefan snyttru bryttað, +eard ond eorlscipe; he ah ealra geweald. +Hwilum he on lufan læteð hworfan +monnes modgeþonc mæran cynnes, +seleð him on eþle eorþan wynne +to healdanne, hleoburh wera, +gedeð him swa gewealdene worolde dælas, +side rice, þæt he his selfa ne mæg +for his unsnyttrum ende geþencean. +Wunað he on wiste; no hine wiht dweleð +adl ne yldo, ne him inwitsorh +on sefan sweorceð, ne gesacu ohwær +ecghete eoweð, ac him eal worold +wendeð on willan (he þæt wyrse ne con), +oðþæt him on innan oferhygda dæl +weaxeð ond wridað. þonne se weard swefeð, +sawele hyrde; bið se slæp to fæst, +bisgum gebunden, bona swiðe neah, +se þe of flanbogan fyrenum sceoteð. +þonne bið on hreþre under helm drepen +biteran stræle (him bebeorgan ne con), +wom wundorbebodum wergan gastes; +þinceð him to lytel þæt he lange heold, +gytsað gromhydig, nallas on gylp seleð +fædde beagas, ond he þa forðgesceaft +forgyteð ond forgymeð, þæs þe him ær god sealde, +wuldres waldend, weorðmynda dæl. +Hit on endestæf eft gelimpeð +þæt se lichoma læne gedreoseð, +fæge gefealleð; fehð oþer to, +se þe unmurnlice madmas dæleþ, +eorles ærgestreon, egesan ne gymeð. +Bebeorh þe ðone bealonið, Beowulf leofa, +secg betsta, ond þe þæt selre geceos, +ece rædas; oferhyda ne gym, +mære cempa. Nu is þines mægnes blæd +ane hwile. Eft sona bið +þæt þec adl oððe ecg eafoþes getwæfeð, +oððe fyres feng, oððe flodes wylm, +oððe gripe meces, oððe gares fliht, +oððe atol yldo; oððe eagena bearhtm +forsiteð ond forsworceð; semninga bið +þæt ðec, dryhtguma, deað oferswyðeð. +Swa ic Hringdena hund missera +weold under wolcnum ond hig wigge beleac +manigum mægþa geond þysne middangeard, +æscum ond ecgum, þæt ic me ænigne +under swegles begong gesacan ne tealde. +Hwæt, me þæs on eþle edwenden cwom, +gyrn æfter gomene, seoþðan Grendel wearð, +ealdgewinna, ingenga min; +ic þære socne singales wæg +modceare micle. þæs sig metode þanc, +ecean dryhtne, þæs ðe ic on aldre gebad +þæt ic on þone hafelan heorodreorigne +ofer ealdgewin eagum starige! +Ga nu to setle, symbelwynne dreoh +wigge weorþad; unc sceal worn fela +maþma gemænra, siþðan morgen bið." +Geat wæs glædmod, geong sona to +setles neosan, swa se snottra heht. +þa wæs eft swa ær ellenrofum +fletsittendum fægere gereorded +niowan stefne. Nihthelm geswearc +deorc ofer dryhtgumum. Duguð eal aras. +Wolde blondenfeax beddes neosan, +gamela Scylding. Geat unigmetes wel, +rofne randwigan, restan lyste; +sona him seleþegn siðes wergum, +feorrancundum, forð wisade, +se for andrysnum ealle beweotede +þegnes þearfe, swylce þy dogore +heaþoliðende habban scoldon. +Reste hine þa rumheort; reced hliuade +geap ond goldfah; gæst inne swæf +oþþæt hrefn blaca heofones wynne +bliðheort bodode. ða com beorht scacan +scaþan onetton, +wæron æþelingas eft to leodum +fuse to farenne; wolde feor þanon +cuma collenferhð ceoles neosan. +Heht þa se hearda Hrunting beran +sunu Ecglafes, heht his sweord niman, +leoflic iren; sægde him þæs leanes þanc, +cwæð, he þone guðwine godne tealde, +wigcræftigne, nales wordum log +meces ecge; þæt wæs modig secg. +Ond þa siðfrome, searwum gearwe +wigend wæron; eode weorð Denum +æþeling to yppan, þær se oþer wæs, +hæle hildedeor Hroðgar grette. +Beowulf maþelode, bearn Ecgþeowes: +"Nu we sæliðend secgan wyllað, +feorran cumene, þæt we fundiaþ +Higelac secan. Wæron her tela +willum bewenede; þu us wel dohtest. +Gif ic þonne on eorþan owihte mæg +þinre modlufan maran tilian, +gumena dryhten, ðonne ic gyt dyde, +guðgeweorca, ic beo gearo sona. +Gif ic þæt gefricge ofer floda begang, +þæt þec ymbsittend egesan þywað, +swa þec hetende hwilum dydon, +ic ðe þusenda þegna bringe, +hæleþa to helpe. Ic on Higelac wat, +Geata dryhten, þeah ðe he geong sy, +folces hyrde, þæt he mec fremman wile +wordum ond worcum, þæt ic þe wel herige +ond þe to geoce garholt bere, +mægenes fultum, þær ðe bið manna þearf. +Gif him þonne Hreþric to hofum Geata +geþingeð, þeodnes bearn, he mæg þær fela +freonda findan; feorcyþðe beoð +selran gesohte þæm þe him selfa deah." +Hroðgar maþelode him on ondsware: +"þe þa wordcwydas wigtig drihten +on sefan sende; ne hyrde ic snotorlicor +on swa geongum feore guman þingian. +þu eart mægenes strang ond on mode frod, +wis wordcwida. Wen ic talige, +gif þæt gegangeð, þæt ðe gar nymeð, +hild heorugrimme, Hreþles eaferan, +adl oþðe iren ealdor ðinne, +folces hyrde, ond þu þin feorh hafast, +þæt þe Sægeatas selran næbben +to geceosenne cyning ænigne, +hordweard hæleþa, gyf þu healdan wylt +maga rice. Me þin modsefa +licað leng swa wel, leofa Beowulf. +Hafast þu gefered þæt þam folcum sceal, +Geata leodum ond Gardenum, +sib gemæne, ond sacu restan, +inwitniþas, þe hie ær drugon, +wesan, þenden ic wealde widan rices, +maþmas gemæne, manig oþerne +godum gegretan ofer ganotes bæð; +sceal hringnaca ofer heafu bringan +lac ond luftacen. Ic þa leode wat +ge wið feond ge wið freond fæste geworhte, +æghwæs untæle ealde wisan." +ða git him eorla hleo inne gesealde, +mago Healfdenes, maþmas [XII]; +het hine mid þæm lacum leode swæse +secean on gesyntum, snude eft cuman. +Gecyste þa cyning æþelum god, +þeoden Scyldinga, ðegn betstan +ond be healse genam; hruron him tearas, +blondenfeaxum. Him wæs bega wen, +ealdum infrodum, oþres swiðor, +þæt hie seoððan no geseon moston, +modige on meþle. Wæs him se man to þon leof +þæt he þone breostwylm forberan ne mehte, +ac him on hreþre hygebendum fæst +æfter deorum men dyrne langað +beorn wið blode. Him Beowulf þanan, +guðrinc goldwlanc, græsmoldan træd +since hremig; sægenga bad +agendfrean, se þe on ancre rad. +þa wæs on gange gifu Hroðgares +oft geæhted; þæt wæs an cyning, +æghwæs orleahtre, oþþæt hine yldo benam +mægenes wynnum, se þe oft manegum scod. +Cwom þa to flode felamodigra, +hægstealdra heap, hringnet bæron, +locene leoðosyrcan. Landweard onfand +eftsið eorla, swa he ær dyde; +no he mid hearme of hliðes nosan +gæstas grette, ac him togeanes rad, +cwæð þæt wilcuman Wedera leodum +scaþan scirhame to scipe foron. +þa wæs on sande sægeap naca +hladen herewædum, hringedstefna, +mearum ond maðmum; mæst hlifade +ofer Hroðgares hordgestreonum. +He þæm batwearde bunden golde +swurd gesealde, þæt he syðþan wæs +on meodubence maþme þy weorþra, +yrfelafe. Gewat him on naca +drefan deop wæter, Dena land ofgeaf. +þa wæs be mæste merehrægla sum, +segl sale fæst; sundwudu þunede. +No þær wegflotan wind ofer yðum +siðes getwæfde; sægenga for, +fleat famigheals forð ofer yðe, +bundenstefna ofer brimstreamas, +þæt hie Geata clifu ongitan meahton, +cuþe næssas. Ceol up geþrang +lyftgeswenced, on lande stod. +Hraþe wæs æt holme hyðweard geara, +se þe ær lange tid leofra manna +fus æt faroðe feor wlatode; +sælde to sande sidfæþme scip, +oncerbendum fæst, þy læs hym yþa ðrym +wudu wynsuman forwrecan meahte. +Het þa up beran æþelinga gestreon, +frætwe ond fætgold; næs him feor þanon +to gesecanne sinces bryttan, +Higelac Hreþling, þær æt ham wunað +selfa mid gesiðum sæwealle neah. +Bold wæs betlic, bregorof cyning, +heah in healle, Hygd swiðe geong, +wis, welþungen, þeah ðe wintra lyt +under burhlocan gebiden hæbbe, +Hæreþes dohtor; næs hio hnah swa þeah, +ne to gneað gifa Geata leodum, +maþmgestreona. Mod þryðo wæg, +fremu folces cwen, firen ondrysne. +Nænig þæt dorste deor geneþan +swæsra gesiða, nefne sinfrea, +þæt hire an dæges eagum starede, +ac him wælbende weotode tealde +handgewriþene; hraþe seoþðan wæs +æfter mundgripe mece geþinged, +þæt hit sceadenmæl scyran moste, +cwealmbealu cyðan. Ne bið swylc cwenlic þeaw +idese to efnanne, þeah ðe hio ænlicu sy, +þætte freoðuwebbe feores onsæce +æfter ligetorne leofne mannan. +Huru þæt onhohsnode Hemminges mæg; +ealodrincende oðer sædan, +þæt hio leodbealewa læs gefremede, +inwitniða, syððan ærest wearð +gyfen goldhroden geongum cempan, +æðelum diore, syððan hio Offan flet +ofer fealone flod be fæder lare +siðe gesohte; ðær hio syððan well +in gumstole, gode, mære, +lifgesceafta lifigende breac, +hiold heahlufan wið hæleþa brego, +ealles moncynnes mine gefræge +þone selestan bi sæm tweonum, +eormencynnes. Forðam Offa wæs +geofum ond guðum, garcene man, +wide geweorðod, wisdome heold +eðel sinne; þonon Eomer woc +hæleðum to helpe, Hemminges mæg, +nefa Garmundes, niða cræftig. +Gewat him ða se hearda mid his hondscole +sylf æfter sande sæwong tredan, +wide waroðas. Woruldcandel scan, +sigel suðan fus. Hi sið drugon, +elne geeodon, to ðæs ðe eorla hleo, +bonan Ongenþeoes burgum in innan, +geongne guðcyning godne gefrunon +hringas dælan. Higelace wæs +sið Beowulfes snude gecyðed, +þæt ðær on worðig wigendra hleo, +lindgestealla, lifigende cwom, +heaðolaces hal to hofe gongan. +Hraðe wæs gerymed, swa se rica bebead, +feðegestum flet innanweard. +Gesæt þa wið sylfne se ða sæcce genæs, +mæg wið mæge, syððan mandryhten +þurh hleoðorcwyde holdne gegrette, +meaglum wordum. Meoduscencum hwearf +geond þæt healreced Hæreðes dohtor, +lufode ða leode, liðwæge bær +hæleðum to handa. Higelac ongan +sinne geseldan in sele þam hean +fægre fricgcean (hyne fyrwet bræc, +hwylce Sægeata siðas wæron): +"Hu lomp eow on lade, leofa Biowulf, +þa ðu færinga feorr gehogodest +sæcce secean ofer sealt wæter, +hilde to Hiorote? Ac ðu Hroðgare +widcuðne wean wihte gebettest, +mærum ðeodne? Ic ðæs modceare +sorhwylmum seað, siðe ne truwode +leofes mannes; ic ðe lange bæd +þæt ðu þone wælgæst wihte ne grette, +lete Suðdene sylfe geweorðan +guðe wið Grendel. Gode ic þanc secge +þæs ðe ic ðe gesundne geseon moste." +Biowulf maðelode, bearn Ecgðioes: +"þæt is undyrne, dryhten Higelac, +micel gemeting, monegum fira, +hwylc orleghwil uncer Grendles +wearð on ðam wange, þær he worna fela +Sigescyldingum sorge gefremede, +yrmðe to aldre. Ic ðæt eall gewræc, +swa begylpan ne þearf Grendeles maga +ænig ofer eorðan uhthlem þone, +se ðe lengest leofað laðan cynnes, +facne bifongen. Ic ðær furðum cwom +to ðam hringsele Hroðgar gretan; +sona me se mæra mago Healfdenes, +syððan he modsefan minne cuðe, +wið his sylfes sunu setl getæhte. +Weorod wæs on wynne; ne seah ic widan feorh +under heofones hwealf healsittendra +medudream maran. Hwilum mæru cwen, +friðusibb folca, flet eall geondhwearf, +bædde byre geonge; oft hio beahwriðan +secge sealde, ær hie to setle geong. +Hwilum for duguðe dohtor Hroðgares +eorlum on ende ealuwæge bær; +þa ic Freaware fletsittende +nemnan hyrde, þær hio nægled sinc +hæleðum sealde. Sio gehaten is, +geong, goldhroden, gladum suna Frodan; +hafað þæs geworden wine Scyldinga, +rices hyrde, ond þæt ræd talað, +þæt he mid ðy wife wælfæhða dæl, +sæcca gesette. Oft seldan hwær +æfter leodhryre lytle hwile +bongar bugeð, þeah seo bryd duge! +Mæg þæs þonne ofþyncan ðeodne Heaðobeardna +ond þegna gehwam þara leoda, +þonne he mid fæmnan on flett gæð, +dryhtbearn Dena, duguða biwenede; +on him gladiað gomelra lafe, +heard ond hringmæl Heaðabeardna gestreon +þenden hie ðam wæpnum wealdan moston, +oððæt hie forlæddan to ðam lindplegan +swæse gesiðas ond hyra sylfra feorh. +þonne cwið æt beore se ðe beah gesyhð, +eald æscwiga, se ðe eall geman, +garcwealm gumena (him bið grim sefa), +onginneð geomormod geongum cempan +þurh hreðra gehygd higes cunnian, +wigbealu weccean, ond þæt word acwyð: +'Meaht ðu, min wine, mece gecnawan +þone þin fæder to gefeohte bær +under heregriman hindeman siðe, +dyre iren, þær hyne Dene slogon, +weoldon wælstowe, syððan Wiðergyld læg, +æfter hæleþa hryre, hwate Scyldungas? +Nu her þara banena byre nathwylces +frætwum hremig on flet gæð, +morðres gylpeð, ond þone maðþum byreð, +þone þe ðu mid rihte rædan sceoldest.' +Manað swa ond myndgað mæla gehwylce +sarum wordum, oððæt sæl cymeð +þæt se fæmnan þegn fore fæder dædum +æfter billes bite blodfag swefeð, +ealdres scyldig; him se oðer þonan +losað lifigende, con him land geare. +þonne bioð abrocene on ba healfe +aðsweord eorla; syððan Ingelde +weallað wælniðas, ond him wiflufan +æfter cearwælmum colran weorðað. +þy ic Heaðobeardna hyldo ne telge, +dryhtsibbe dæl Denum unfæcne, +freondscipe fæstne. Ic sceal forð sprecan +gen ymbe Grendel, þæt ðu geare cunne, +sinces brytta, to hwan syððan wearð +hondræs hæleða. Syððan heofones gim +glad ofer grundas, gæst yrre cwom, +eatol, æfengrom, user neosan, +ðær we gesunde sæl weardodon. +þær wæs Hondscio hild onsæge, +feorhbealu fægum; he fyrmest læg, +gyrded cempa; him Grendel wearð, +mærum maguþegne to muðbonan, +leofes mannes lic eall forswealg. +No ðy ær ut ða gen idelhende +bona blodigtoð, bealewa gemyndig, +of ðam goldsele gongan wolde, +ac he mægnes rof min costode, +grapode gearofolm. Glof hangode +sid ond syllic, searobendum fæst; +sio wæs orðoncum eall gegyrwed +deofles cræftum ond dracan fellum. +He mec þær on innan unsynnigne, +dior dædfruma, gedon wolde +manigra sumne; hyt ne mihte swa, +syððan ic on yrre uppriht astod. +To lang ys to reccenne hu ic ðam leodsceaðan +yfla gehwylces ondlean forgeald; +þær ic, þeoden min, þine leode +weorðode weorcum. He on weg losade, +lytle hwile lifwynna breac; +hwæþre him sio swiðre swaðe weardade +hand on Hiorte, ond he hean ðonan +modes geomor meregrund gefeoll. +Me þone wælræs wine Scildunga +fættan golde fela leanode, +manegum maðmum, syððan mergen com +ond we to symble geseten hæfdon. +þær wæs gidd ond gleo. Gomela Scilding, +felafricgende, feorran rehte; +hwilum hildedeor hearpan wynne, +gomenwudu grette, hwilum gyd awræc +soð ond sarlic, hwilum syllic spell +rehte æfter rihte rumheort cyning. +Hwilum eft ongan, eldo gebunden, +gomel guðwiga gioguðe cwiðan, +hildestrengo; hreðer inne weoll, +þonne he wintrum frod worn gemunde. +Swa we þær inne ondlangne dæg +niode naman, oððæt niht becwom +oðer to yldum. þa wæs eft hraðe +gearo gyrnwræce Grendeles modor, +siðode sorhfull; sunu deað fornam, +wighete Wedra. Wif unhyre +hyre bearn gewræc, beorn acwealde +ellenlice; þær wæs æschere, +frodan fyrnwitan, feorh uðgenge. +Noðer hy hine ne moston, syððan mergen cwom, +deaðwerigne, Denia leode, +bronde forbærnan, ne on bęl hladan +leofne mannan; hio þæt lic ætbær +feondes fæðmum under firgenstream. +þæt wæs Hroðgare hreowa tornost +þara þe leodfruman lange begeate. +þa se ðeoden mec ðine life +healsode hreohmod, þæt ic on holma geþring +eorlscipe efnde, ealdre geneðde, +mærðo fremede; he me mede gehet. +Ic ða ðæs wælmes, þe is wide cuð, +grimne gryrelicne grundhyrde fond; +þær unc hwile wæs hand gemæne, +holm heolfre weoll, ond ic heafde becearf +in ðam guðsele Grendeles modor +eacnum ecgum, unsofte þonan +feorh oðferede. Næs ic fæge þa gyt, +ac me eorla hleo eft gesealde +maðma menigeo, maga Healfdenes. +Swa se ðeodkyning þeawum lyfde. +Nealles ic ðam leanum forloren hæfde, +mægnes mede, ac he me maðmas geaf, +sunu Healfdenes, on minne sylfes dom; +ða ic ðe, beorncyning, bringan wylle, +estum geywan. Gen is eall æt ðe +lissa gelong; ic lyt hafo +heafodmaga nefne, Hygelac, ðec." +Het ða in beran eaforheafodsegn, +heaðosteapne helm, hare byrnan, +guðsweord geatolic, gyd æfter wræc: +"Me ðis hildesceorp Hroðgar sealde, +snotra fengel, sume worde het +þæt ic his ærest ðe est gesægde; +cwæð þæt hyt hæfde Hiorogar cyning, +leod Scyldunga lange hwile; +no ðy ær suna sinum syllan wolde, +hwatum Heorowearde, þeah he him hold wære, +breostgewædu. Bruc ealles well!" +Hyrde ic þæt þam frætwum feower mearas +lungre, gelice, last weardode, +æppelfealuwe; he him est geteah +meara ond maðma. Swa sceal mæg don, +nealles inwitnet oðrum bregdon +dyrnum cræfte, deað renian +hondgesteallan. Hygelace wæs, +niða heardum, nefa swyðe hold, +ond gehwæðer oðrum hroþra gemyndig. +Hyrde ic þæt he ðone healsbeah Hygde gesealde, +wrætlicne wundurmaððum, ðone þe him Wealhðeo geaf, +ðeodnes dohtor, þrio wicg somod +swancor ond sadolbeorht; hyre syððan wæs +æfter beahðege breost geweorðod. +Swa bealdode bearn Ecgðeowes, +guma guðum cuð, godum dædum, +dreah æfter dome, nealles druncne slog +heorðgeneatas; næs him hreoh sefa, +ac he mancynnes mæste cræfte +ginfæstan gife, þe him god sealde, +heold hildedeor. Hean wæs lange, +swa hyne Geata bearn godne ne tealdon, +ne hyne on medobence micles wyrðne +drihten Wedera gedon wolde; +swyðe wendon þæt he sleac wære, +æðeling unfrom. Edwenden cwom +tireadigum menn torna gehwylces. +Het ða eorla hleo in gefetian, +heaðorof cyning, Hreðles lafe +golde gegyrede; næs mid Geatum ða +sincmaðþum selra on sweordes had; +þæt he on Biowulfes bearm alegde +ond him gesealde seofan þusendo, +bold ond bregostol. Him wæs bam samod +on ðam leodscipe lond gecynde, +eard, eðelriht, oðrum swiðor +side rice þam ðær selra wæs. +Eft þæt geiode ufaran dogrum +hildehlæmmum, syððan Hygelac læg +ond Heardrede hildemeceas +under bordhreoðan to bonan wurdon, +ða hyne gesohtan on sigeþeode +hearde hildefrecan, Heaðoscilfingas, +niða genægdan nefan Hererices, +syððan Beowulfe brade rice +on hand gehwearf; he geheold tela +fiftig wintra (wæs ða frod cyning, +eald eþelweard), oððæt an ongan +deorcum nihtum draca ricsian, +se ðe on heaum hofe hord beweotode, +stanbeorh steapne; stig under læg, +eldum uncuð. þær on innan giong +niða nathwylc, se ðe neh gefeng +hæðnum horde, hond [...], +since fahne. He þæt syððan [...], +þeah ðe he slæpende besyred wurde +þeofes cræfte; þæt sie ðiod onfand, +bufolc beorna, þæt he gebolgen wæs. +Nealles mid gewealdum wyrmhord abræc +sylfes willum, se ðe him sare gesceod, +ac for þreanedlan þeow nathwylces +hæleða bearna heteswengeas fleah, +ærnes þearfa, ond ðær inne fealh, +secg synbysig, sona onfunde +þæt þær ðam gyste gryrebroga stod; +hwæðre earmsceapen +sceapen +þa hyne se fær begeat. +Sincfæt [...]; þær wæs swylcra fela +in ðam eorðhuse ærgestreona, +swa hy on geardagum gumena nathwylc, +eormenlafe æþelan cynnes, +þanchycgende þær gehydde, +deore maðmas. Ealle hie deað fornam +ærran mælum, ond se an ða gen +leoda duguðe, se ðær lengest hwearf, +weard winegeomor, wende þæs ylcan, +þæt he lytel fæc longgestreona +brucan moste. Beorh eallgearo +wunode on wonge wæteryðum neah, +niwe be næsse, nearocræftum fæst. +þær on innan bær eorlgestreona +hringa hyrde hordwyrðne dæl, +fættan goldes, fea worda cwæð: +"Heald þu nu, hruse, nu hæleð ne moston, +eorla æhte! Hwæt, hyt ær on ðe +gode begeaton. Guðdeað fornam, +feorhbealo frecne, fyra gehwylcne +leoda minra, þara ðe þis lif ofgeaf, +gesawon seledream. Ic nah hwa sweord wege +oððe feormie fæted wæge, +dryncfæt deore; duguð ellor sceoc. +Sceal se hearda helm hyrsted golde +fætum befeallen; feormynd swefað, +þa ðe beadogriman bywan sceoldon, +ge swylce seo herepad, sio æt hilde gebad +ofer borda gebræc bite irena, +brosnað æfter beorne. Ne mæg byrnan hring +æfter wigfruman wide feran, +hæleðum be healfe. Næs hearpan wyn, +gomen gleobeames, ne god hafoc +geond sæl swingeð, ne se swifta mearh +burhstede beateð. Bealocwealm hafað +fela feorhcynna forð onsended!" +Swa giomormod giohðo mænde +an æfter eallum, unbliðe hwearf +dæges ond nihtes, oððæt deaðes wylm +hran æt heortan. Hordwynne fond +eald uhtsceaða opene standan, +se ðe byrnende biorgas seceð, +nacod niðdraca, nihtes fleogeð +fyre befangen; hyne foldbuend +swiðe ondrædað. He gesecean sceall +hord on hrusan, þær he hæðen gold +warað wintrum frod, ne byð him wihte ðy sel. +Swa se ðeodsceaða þreo hund wintra +heold on hrusan hordærna sum, +eacencræftig, oððæt hyne an abealch +mon on mode; mandryhtne bær +fæted wæge, frioðowære bæd +hlaford sinne. ða wæs hord rasod, +onboren beaga hord, bene getiðad +feasceaftum men. Frea sceawode +fira fyrngeweorc forman siðe. +þa se wyrm onwoc, wroht wæs geniwad; +stonc ða æfter stane, stearcheort onfand +feondes fotlast; he to forð gestop +dyrnan cræfte dracan heafde neah. +Swa mæg unfæge eaðe gedigan +wean ond wræcsið, se ðe waldendes +hyldo gehealdeþ! Hordweard sohte +georne æfter grunde, wolde guman findan, +þone þe him on sweofote sare geteode, +hat ond hreohmod hlæw oft ymbehwearf +ealne utanweardne, ne ðær ænig mon +on þære westenne; hwæðre wiges gefeh, +beaduwe weorces, hwilum on beorh æthwearf, +sincfæt sohte. He þæt sona onfand +ðæt hæfde gumena sum goldes gefandod, +heahgestreona. Hordweard onbad +earfoðlice oððæt æfen cwom; +wæs ða gebolgen beorges hyrde, +wolde se laða lige forgyldan +drincfæt dyre. þa wæs dæg sceacen +wyrme on willan; no on wealle læg, +bidan wolde, ac mid bæle for, +fyre gefysed. Wæs se fruma egeslic +leodum on lande, swa hyt lungre wearð +on hyra sincgifan sare geendod. +ða se gæst ongan gledum spiwan, +beorht hofu bærnan; bryneleoma stod +eldum on andan. No ðær aht cwices +lað lyftfloga læfan wolde. +Wæs þæs wyrmes wig wide gesyne, +nearofages nið nean ond feorran, +hu se guðsceaða Geata leode +hatode ond hynde; hord eft gesceat, +dryhtsele dyrnne, ær dæges hwile. +Hæfde landwara lige befangen, +bæle ond bronde, beorges getruwode, +wiges ond wealles; him seo wen geleah. +þa wæs Biowulfe broga gecyðed +snude to soðe, þæt his sylfes ham, +bolda selest, brynewylmum mealt, +gifstol Geata. þæt ðam godan wæs +hreow on hreðre, hygesorga mæst; +wende se wisa þæt he wealdende +ofer ealde riht, ecean dryhtne, +bitre gebulge. Breost innan weoll +þeostrum geþoncum, swa him geþywe ne wæs. +Hæfde ligdraca leoda fæsten, +ealond utan, eorðweard ðone +gledum forgrunden; him ðæs guðkyning, +Wedera þioden, wræce leornode. +Heht him þa gewyrcean wigendra hleo +eallirenne, eorla dryhten, +wigbord wrætlic; wisse he gearwe +þæt him holtwudu helpan ne meahte, +lind wið lige. Sceolde lændaga +æþeling ærgod ende gebidan, +worulde lifes, ond se wyrm somod, +þeah ðe hordwelan heolde lange. +Oferhogode ða hringa fengel +þæt he þone widflogan weorode gesohte, +sidan herge; no he him þa sæcce ondred, +ne him þæs wyrmes wig for wiht dyde, +eafoð ond ellen, forðon he ær fela +nearo neðende niða gedigde, +hildehlemma, syððan he Hroðgares, +sigoreadig secg, sele fælsode +ond æt guðe forgrap Grendeles mægum +laðan cynnes. No þæt læsest wæs +hondgemota, þær mon Hygelac sloh, +syððan Geata cyning guðe ræsum, +freawine folca Freslondum on, +Hreðles eafora hiorodryncum swealt, +bille gebeaten. þonan Biowulf com +sylfes cræfte, sundnytte dreah; +hæfde him on earme ana [XXX] +hildegeatwa, þa he to holme beag. +Nealles Hetware hremge þorfton +feðewiges, þe him foran ongean +linde bæron; lyt eft becwom +fram þam hildfrecan hames niosan. +Oferswam ða sioleða bigong sunu Ecgðeowes, +earm anhaga, eft to leodum; +þær him Hygd gebead hord ond rice, +beagas ond bregostol, bearne ne truwode +þæt he wið ælfylcum eþelstolas +healdan cuðe, ða wæs Hygelac dead. +No ðy ær feasceafte findan meahton +æt ðam æðelinge ænige ðinga, +þæt he Heardrede hlaford wære +oððe þone cynedom ciosan wolde; +hwæðre he him on folce freondlarum heold, +estum mid are, oððæt he yldra wearð, +Wedergeatum weold. Hyne wræcmæcgas +ofer sæ sohtan, suna Ohteres; +hæfdon hy forhealden helm Scylfinga, +þone selestan sæcyninga +þara ðe in Swiorice sinc brytnade, +mærne þeoden. Him þæt to mearce wearð; +he þær for feorme feorhwunde hleat +sweordes swengum, sunu Hygelaces, +ond him eft gewat Ongenðioes bearn +hames niosan, syððan Heardred læg, +let ðone bregostol Biowulf healdan, +Geatum wealdan. þæt wæs god cyning! +Se ðæs leodhryres lean gemunde +uferan dogrum, Eadgilse wearð +feasceaftum freond, folce gestepte +ofer sæ side sunu Ohteres, +wigum ond wæpnum; he gewræc syððan +cealdum cearsiðum, cyning ealdre bineat. +Swa he niða gehwane genesen hæfde, +sliðra geslyhta, sunu Ecgðiowes, +ellenweorca, oð ðone anne dæg +þe he wið þam wyrme gewegan sceolde. +Gewat þa [XII]a sum torne gebolgen +dryhten Geata dracan sceawian. +Hæfde þa gefrunen hwanan sio fæhð aras, +bealonið biorna; him to bearme cwom +maðþumfæt mære þurh ðæs meldan hond. +Se wæs on ðam ðreate þreotteoða secg, +se ðæs orleges or onstealde, +hæft hygegiomor, sceolde hean ðonon +wong wisian. He ofer willan giong +to ðæs ðe he eorðsele anne wisse, +hlæw under hrusan holmwylme neh, +yðgewinne; se wæs innan full +wrætta ond wira. Weard unhiore, +gearo guðfreca, goldmaðmas heold, +eald under eorðan. Næs þæt yðe ceap +to gegangenne gumena ænigum! +Gesæt ða on næsse niðheard cyning, +þenden hælo abead heorðgeneatum, +goldwine Geata. Him wæs geomor sefa, +wæfre ond wælfus, wyrd ungemete neah, +se ðone gomelan gretan sceolde, +secean sawle hord, sundur gedælan +lif wið lice, no þon lange wæs +feorh æþelinges flæsce bewunden. +Biowulf maþelade, bearn Ecgðeowes: +"Fela ic on giogoðe guðræsa genæs, +orleghwila; ic þæt eall gemon. +Ic wæs syfanwintre, þa mec sinca baldor, +freawine folca, æt minum fæder genam; +heold mec ond hæfde Hreðel cyning, +geaf me sinc ond symbel, sibbe gemunde. +Næs ic him to life laðra owihte, +beorn in burgum, þonne his bearna hwylc, +Herebeald ond Hæðcyn oððe Hygelac min. +Wæs þam yldestan ungedefelice +mæges dædum morþorbed stred, +syððan hyne Hæðcyn of hornbogan, +his freawine, flane geswencte, +miste mercelses ond his mæg ofscet, +broðor oðerne blodigan gare. +þæt wæs feohleas gefeoht, fyrenum gesyngad, +hreðre hygemeðe; sceolde hwæðre swa þeah +æðeling unwrecen ealdres linnan. +Swa bið geomorlic gomelum ceorle +to gebidanne, þæt his byre ride +giong on galgan, þonne he gyd wrece, +sarigne sang, þonne his sunu hangað +hrefne to hroðre, ond he him helpe ne mæg, +eald ond infrod, ænige gefremman. +Symble bið gemyndgad morna gehwylce +eaforan ellorsið; oðres ne gymeð +to gebidanne burgum in innan +yrfeweardas, þonne se an hafað +þurh deaðes nyd dæda gefondad. +Gesyhð sorhcearig on his suna bure +winsele westne, windge reste +reote berofene. Ridend swefað, +hæleð in hoðman; nis þær hearpan sweg, +gomen in geardum, swylce ðær iu wæron. +Gewiteð þonne on sealman, sorhleoð gæleð +an æfter anum; þuhte him eall to rum, +wongas ond wicstede. Swa Wedra helm +æfter Herebealde heortan sorge +weallende wæg. Wihte ne meahte +on ðam feorhbonan fæghðe gebetan; +no ðy ær he þone heaðorinc hatian ne meahte +laðum dædum, þeah him leof ne wæs. +He ða mid þære sorhge, þe him swa sar belamp, +gumdream ofgeaf, godes leoht geceas, +eaferum læfde, swa deð eadig mon, +lond ond leodbyrig, þa he of life gewat. +þa wæs synn ond sacu Sweona ond Geata +ofer wid wæter, wroht gemæne, +herenið hearda, syððan Hreðel swealt, +oððe him Ongenðeowes eaferan wæran +frome, fyrdhwate, freode ne woldon +ofer heafo healdan, ac ymb Hreosnabeorh +eatolne inwitscear oft gefremedon. +þæt mægwine mine gewræcan, +fæhðe ond fyrene, swa hyt gefræge wæs, +þeah ðe oðer his ealdre gebohte, +heardan ceape; Hæðcynne wearð, +Geata dryhtne, guð onsæge. +þa ic on morgne gefrægn mæg oðerne +billes ecgum on bonan stælan, +þær Ongenþeow Eofores niosað. +Guðhelm toglad, gomela Scylfing +hreas hildeblac; hond gemunde +fæhðo genoge, feorhsweng ne ofteah. +Ic him þa maðmas, þe he me sealde, +geald æt guðe, swa me gifeðe wæs, +leohtan sweorde; he me lond forgeaf, +eard, eðelwyn. Næs him ænig þearf +þæt he to Gifðum oððe to Gardenum +oððe in Swiorice secean þurfe +wyrsan wigfrecan, weorðe gecypan. +Symle ic him on feðan beforan wolde, +ana on orde, ond swa to aldre sceall +sæcce fremman, þenden þis sweord þolað, +þæt mec ær ond sið oft gelæste. +Syððan ic for dugeðum Dæghrefne wearð +to handbonan, Huga cempan; +nalles he ða frætwe Frescyninge, +breostweorðunge, bringan moste, +ac in compe gecrong cumbles hyrde, +æþeling on elne; ne wæs ecg bona, +ac him hildegrap heortan wylmas, +banhus gebræc. Nu sceall billes ecg, +hond ond heard sweord, ymb hord wigan." +Beowulf maðelode, beotwordum spræc +niehstan siðe: "Ic geneðde fela +guða on geogoðe; gyt ic wylle, +frod folces weard, fæhðe secan, +mærðu fremman, gif mec se mansceaða +of eorðsele ut geseceð." +Gegrette ða gumena gehwylcne, +hwate helmberend, hindeman siðe, +swæse gesiðas: "Nolde ic sweord beran, +wæpen to wyrme, gif ic wiste hu +wið ðam aglæcean elles meahte +gylpe wiðgripan, swa ic gio wið Grendle dyde. +Ac ic ðær heaðufyres hates wene, +oreðes ond attres; forðon ic me on hafu +bord ond byrnan. Nelle ic beorges weard +forfleon fotes trem, ac unc furður sceal +weorðan æt wealle, swa unc wyrd geteoð, +metod manna gehwæs. Ic eom on mode from +þæt ic wið þone guðflogan gylp ofersitte. +Gebide ge on beorge byrnum werede, +secgas on searwum, hwæðer sel mæge +æfter wælræse wunde gedygan +uncer twega. Nis þæt eower sið +ne gemet mannes, nefne min anes, +þæt he wið aglæcean eofoðo dæle, +eorlscype efne. Ic mid elne sceall +gold gegangan, oððe guð nimeð, +feorhbealu frecne, frean eowerne!" +Aras ða bi ronde rof oretta, +heard under helme, hiorosercean bær +under stancleofu, strengo getruwode +anes mannes. Ne bið swylc earges sið! +Geseah ða be wealle se ðe worna fela, +gumcystum god, guða gedigde, +hildehlemma, þonne hnitan feðan, +stondan stanbogan, stream ut þonan +brecan of beorge. Wæs þære burnan wælm +heaðofyrum hat; ne meahte horde neah +unbyrnende ænige hwile +deop gedygan for dracan lege. +Let ða of breostum, ða he gebolgen wæs, +Wedergeata leod word ut faran, +stearcheort styrmde; stefn in becom +heaðotorht hlynnan under harne stan. +Hete wæs onhrered, hordweard oncniow +mannes reorde; næs ðær mara fyrst +freode to friclan. From ærest cwom +oruð aglæcean ut of stane, +hat hildeswat. Hruse dynede. +Biorn under beorge bordrand onswaf +wið ðam gryregieste, Geata dryhten; +ða wæs hringbogan heorte gefysed +sæcce to seceanne. Sweord ær gebræd +god guðcyning, gomele lafe, +ecgum unslaw; æghwæðrum wæs +bealohycgendra broga fram oðrum. +Stiðmod gestod wið steapne rond +winia bealdor, ða se wyrm gebeah +snude tosomne; he on searwum bad. +Gewat ða byrnende gebogen scriðan, +to gescipe scyndan. Scyld wel gebearg +life ond lice læssan hwile +mærum þeodne þonne his myne sohte, +ðær he þy fyrste, forman dogore +wealdan moste swa him wyrd ne gescraf +hreð æt hilde. Hond up abræd +Geata dryhten, gryrefahne sloh +incgelafe, þæt sio ecg gewac +brun on bane, bat unswiðor +þonne his ðiodcyning þearfe hæfde, +bysigum gebæded. þa wæs beorges weard +æfter heaðuswenge on hreoum mode, +wearp wælfyre; wide sprungon +hildeleoman. Hreðsigora ne gealp +goldwine Geata; guðbill geswac, +nacod æt niðe, swa hyt no sceolde, +iren ærgod. Ne wæs þæt eðe sið, +þæt se mæra maga Ecgðeowes +grundwong þone ofgyfan wolde; +sceolde ofer willan wic eardian +elles hwergen, swa sceal æghwylc mon +alætan lændagas. Næs ða long to ðon +þæt ða aglæcean hy eft gemetton. +Hyrte hyne hordweard (hreðer æðme weoll) +niwan stefne; nearo ðrowode, +fyre befongen, se ðe ær folce weold. +Nealles him on heape handgesteallan, +æðelinga bearn, ymbe gestodon +hildecystum, ac hy on holt bugon, +ealdre burgan. Hiora in anum weoll +sefa wið sorgum; sibb æfre ne mæg +wiht onwendan þam ðe wel þenceð. +Wiglaf wæs haten Weoxstanes sunu, +leoflic lindwiga, leod Scylfinga, +mæg ælfheres; geseah his mondryhten +under heregriman hat þrowian. +Gemunde ða ða are þe he him ær forgeaf, +wicstede weligne Wægmundinga, +folcrihta gehwylc, swa his fæder ahte. +Ne mihte ða forhabban; hond rond gefeng, +geolwe linde, gomel swyrd geteah, +þæt wæs mid eldum Eanmundes laf, +suna Ohteres. þam æt sæcce wearð, +wræccan wineleasum, Weohstan bana +meces ecgum, ond his magum ætbær +brunfagne helm, hringde byrnan, +eald sweord etonisc; þæt him Onela forgeaf, +his gædelinges guðgewædu, +fyrdsearo fuslic, no ymbe ða fæhðe spræc, +þeah ðe he his broðor bearn abredwade. +He frætwe geheold fela missera, +bill ond byrnan, oððæt his byre mihte +eorlscipe efnan swa his ærfæder; +geaf him ða mid Geatum guðgewæda, +æghwæs unrim, þa he of ealdre gewat, +frod on forðweg. þa wæs forma sið +geongan cempan, þæt he guðe ræs +mid his freodryhtne fremman sceolde. +Ne gemealt him se modsefa, ne his mæges laf +gewac æt wige; þæt se wyrm onfand, +syððan hie togædre gegan hæfdon. +Wiglaf maðelode, wordrihta fela +sægde gesiðum (him wæs sefa geomor): +"Ic ðæt mæl geman, þær we medu þegun, +þonne we geheton ussum hlaforde +in biorsele, ðe us ðas beagas geaf, +þæt we him ða guðgetawa gyldan woldon +gif him þyslicu þearf gelumpe, +helmas ond heard sweord. ðe he usic on herge geceas +to ðyssum siðfate sylfes willum, +onmunde usic mærða, ond me þas maðmas geaf, +þe he usic garwigend gode tealde, +hwate helmberend, þeah ðe hlaford us +þis ellenweorc ana aðohte +to gefremmanne, folces hyrde, +for ðam he manna mæst mærða gefremede, +dæda dollicra. Nu is se dæg cumen +þæt ure mandryhten mægenes behofað, +godra guðrinca; wutun gongan to, +helpan hildfruman, þenden hyt sy, +gledegesa grim. God wat on mec +þæt me is micle leofre þæt minne lichaman +mid minne goldgyfan gled fæðmie. +Ne þynceð me gerysne þæt we rondas beren +eft to earde, nemne we æror mægen +fane gefyllan, feorh ealgian +Wedra ðeodnes. Ic wat geare +þæt næron ealdgewyrht, þæt he ana scyle +Geata duguðe gnorn þrowian, +gesigan æt sæcce; urum sceal sweord ond helm, +byrne ond beaduscrud, bam gemæne." +Wod þa þurh þone wælrec, wigheafolan bær +frean on fultum, fea worda cwæð: +"Leofa Biowulf, læst eall tela, +swa ðu on geoguðfeore geara gecwæde +þæt ðu ne alæte be ðe lifigendum +dom gedreosan. Scealt nu dædum rof, +æðeling anhydig, ealle mægene +feorh ealgian; ic ðe fullæstu." +æfter ðam wordum wyrm yrre cwom, +atol inwitgæst, oðre siðe +fyrwylmum fah fionda niosian, +laðra manna; ligyðum for. +Born bord wið rond, byrne ne meahte +geongum garwigan geoce gefremman, +ac se maga geonga under his mæges scyld +elne geeode, þa his agen wæs +gledum forgrunden. þa gen guðcyning +mærða gemunde, mægenstrengo sloh +hildebille, þæt hyt on heafolan stod +niþe genyded; Nægling forbærst, +geswac æt sæcce sweord Biowulfes, +gomol ond grægmæl. Him þæt gifeðe ne wæs +þæt him irenna ecge mihton +helpan æt hilde; wæs sio hond to strong, +se ðe meca gehwane, mine gefræge, +swenge ofersohte, þonne he to sæcce bær +wæpen wundrum heard; næs him wihte ðe sel. +þa wæs þeodsceaða þriddan siðe, +frecne fyrdraca, fæhða gemyndig, +ræsde on ðone rofan, þa him rum ageald, +hat ond heaðogrim, heals ealne ymbefeng +biteran banum; he geblodegod wearð +sawuldriore, swat yðum weoll. +ða ic æt þearfe gefrægn þeodcyninges +andlongne eorl ellen cyðan, +cræft ond cenðu, swa him gecynde wæs. +Ne hedde he þæs heafolan, ac sio hand gebarn +modiges mannes, þær he his mæges healp, +þæt he þone niðgæst nioðor hwene sloh, +secg on searwum, þæt ðæt sweord gedeaf, +fah ond fæted, þæt ðæt fyr ongon +sweðrian syððan. þa gen sylf cyning +geweold his gewitte, wællseaxe gebræd +biter ond beaduscearp, þæt he on byrnan wæg; +forwrat Wedra helm wyrm on middan. +Feond gefyldan (ferh ellen wræc), +ond hi hyne þa begen abroten hæfdon, +sibæðelingas. Swylc sceolde secg wesan, +þegn æt ðearfe! þæt ðam þeodne wæs +siðast sigehwila sylfes dædum, +worlde geweorces. ða sio wund ongon, +þe him se eorðdraca ær geworhte, +swelan ond swellan; he þæt sona onfand, +þæt him on breostum bealoniðe weoll +attor on innan. ða se æðeling giong +þæt he bi wealle wishycgende +gesæt on sesse; seah on enta geweorc, +hu ða stanbogan stapulum fæste +ece eorðreced innan healde. +Hyne þa mid handa heorodreorigne, +þeoden mærne, þegn ungemete till +winedryhten his wætere gelafede, +hilde sædne, ond his helm onspeon. +Biowulf maþelode (he ofer benne spræc, +wunde wælbleate; wisse he gearwe +þæt he dæghwila gedrogen hæfde, +eorðan wynne; ða wæs eall sceacen +dogorgerimes, deað ungemete neah): +"Nu ic suna minum syllan wolde +guðgewædu, þær me gifeðe swa +ænig yrfeweard æfter wurde +lice gelenge. Ic ðas leode heold +fiftig wintra; næs se folccyning, +ymbesittendra ænig ðara, +þe mec guðwinum gretan dorste, +egesan ðeon. Ic on earde bad +mælgesceafta, heold min tela, +ne sohte searoniðas, ne me swor fela +aða on unriht. Ic ðæs ealles mæg +feorhbennum seoc gefean habban; +for ðam me witan ne ðearf waldend fira +morðorbealo maga, þonne min sceaceð +lif of lice. Nu ðu lungre geong +hord sceawian under harne stan, +Wiglaf leofa, nu se wyrm ligeð, +swefeð sare wund, since bereafod. +Bio nu on ofoste, þæt ic ærwelan, +goldæht ongite, gearo sceawige +swegle searogimmas, þæt ic ðy seft mæge +æfter maððumwelan min alætan +lif ond leodscipe, þone ic longe heold." +ða ic snude gefrægn sunu Wihstanes +æfter wordcwydum wundum dryhtne +hyran heaðosiocum, hringnet beran, +brogdne beadusercean under beorges hrof. +Geseah ða sigehreðig, þa he bi sesse geong, +magoþegn modig maððumsigla fealo, +gold glitinian grunde getenge, +wundur on wealle, ond þæs wyrmes denn, +ealdes uhtflogan, orcas stondan, +fyrnmanna fatu feormendlease, +hyrstum behrorene; þær wæs helm monig +eald ond omig, earmbeaga fela +searwum gesæled. Sinc eaðe mæg, +gold on grunde, gumcynnes gehwone +oferhigian, hyde se ðe wylle. +Swylce he siomian geseah segn eallgylden +heah ofer horde, hondwundra mæst, +gelocen leoðocræftum; of ðam leoma stod, +þæt he þone grundwong ongitan meahte, +wræte giondwlitan. Næs ðæs wyrmes þær +onsyn ænig, ac hyne ecg fornam. +ða ic on hlæwe gefrægn hord reafian, +eald enta geweorc, anne mannan, +him on bearm hladon bunan ond discas +sylfes dome; segn eac genom, +beacna beorhtost. Bill ær gescod +(ecg wæs iren) ealdhlafordes +þam ðara maðma mundbora wæs +longe hwile, ligegesan wæg +hatne for horde, hioroweallende +middelnihtum, oðþæt he morðre swealt. +Ar wæs on ofoste, eftsiðes georn, +frætwum gefyrðred; hyne fyrwet bræc, +hwæðer collenferð cwicne gemette +in ðam wongstede Wedra þeoden +ellensiocne, þær he hine ær forlet. +He ða mid þam maðmum mærne þioden, +dryhten sinne, driorigne fand +ealdres æt ende; he hine eft ongon +wæteres weorpan, oðþæt wordes ord +breosthord þurhbræc. +gomel on giohðe (gold sceawode): +"Ic ðara frætwa frean ealles ðanc, +wuldurcyninge, wordum secge, +ecum dryhtne, þe ic her on starie, +þæs ðe ic moste minum leodum +ær swyltdæge swylc gestrynan. +Nu ic on maðma hord mine bebohte +frode feorhlege, fremmað gena +leoda þearfe; ne mæg ic her leng wesan. +Hatað heaðomære hlæw gewyrcean +beorhtne æfter bæle æt brimes nosan; +se scel to gemyndum minum leodum +heah hlifian on Hronesnæsse, +þæt hit sæliðend syððan hatan +Biowulfes biorh, ða ðe brentingas +ofer floda genipu feorran drifað." +Dyde him of healse hring gyldenne +þioden þristhydig, þegne gesealde, +geongum garwigan, goldfahne helm, +beah ond byrnan, het hyne brucan well: +"þu eart endelaf usses cynnes, +Wægmundinga. Ealle wyrd forsweop +mine magas to metodsceafte, +eorlas on elne; ic him æfter sceal." +þæt wæs þam gomelan gingæste word +breostgehygdum, ær he bæl cure, +hate heaðowylmas; him of hreðre gewat +sawol secean soðfæstra dom. +ða wæs gegongen guman unfrodum +earfoðlice, þæt he on eorðan geseah +þone leofestan lifes æt ende +bleate gebæran. Bona swylce læg, +egeslic eorðdraca ealdre bereafod, +bealwe gebæded. Beahhordum leng +wyrm wohbogen wealdan ne moste, +ac hine irenna ecga fornamon, +hearde, heaðoscearde homera lafe, +þæt se widfloga wundum stille +hreas on hrusan hordærne neah. +Nalles æfter lyfte lacende hwearf +middelnihtum, maðmæhta wlonc +ansyn ywde, ac he eorðan gefeoll +for ðæs hildfruman hondgeweorce. +Huru þæt on lande lyt manna ðah, +mægenagendra, mine gefræge, +þeah ðe he dæda gehwæs dyrstig wære, +þæt he wið attorsceaðan oreðe geræsde, +oððe hringsele hondum styrede, +gif he wæccende weard onfunde +buon on beorge. Biowulfe wearð +dryhtmaðma dæl deaðe forgolden; +hæfde æghwæðer ende gefered +lænan lifes. Næs ða lang to ðon +þæt ða hildlatan holt ofgefan, +tydre treowlogan tyne ætsomne. +ða ne dorston ær dareðum lacan +on hyra mandryhtnes miclan þearfe, +ac hy scamiende scyldas bæran, +guðgewædu, þær se gomela læg, +wlitan on Wilaf. He gewergad sæt, +feðecempa, frean eaxlum neah, +wehte hyne wætre; him wiht ne speow. +Ne meahte he on eorðan, ðeah he uðe wel, +on ðam frumgare feorh gehealdan, +ne ðæs wealdendes wiht oncirran; +wolde dom godes dædum rædan +gumena gehwylcum, swa he nu gen deð. +þa wæs æt ðam geongan grim ondswaru +eðbegete þam ðe ær his elne forleas. +Wiglaf maðelode, Weohstanes sunu, +sec, sarigferð (seah on unleofe): +"þæt, la, mæg secgan se ðe wyle soð specan +þæt se mondryhten se eow ða maðmas geaf, +eoredgeatwe, þe ge þær on standað, +þonne he on ealubence oft gesealde +healsittendum helm ond byrnan, +þeoden his þegnum, swylce he þrydlicost +ower feor oððe neah findan meahte, +þæt he genunga guðgewædu +wraðe forwurpe, ða hyne wig beget. +Nealles folccyning fyrdgesteallum +gylpan þorfte; hwæðre him god uðe, +sigora waldend, þæt he hyne sylfne gewræc +ana mid ecge, þa him wæs elnes þearf. +Ic him lifwraðe lytle meahte +ætgifan æt guðe, ond ongan swa þeah +ofer min gemet mæges helpan; +symle wæs þy sæmra, þonne ic sweorde drep +ferhðgeniðlan, fyr unswiðor +weoll of gewitte. Wergendra to lyt +þrong ymbe þeoden, þa hyne sio þrag becwom. +Nu sceal sincþego ond swyrdgifu, +eall eðelwyn eowrum cynne, +lufen alicgean; londrihtes mot +þære mægburge monna æghwylc +idel hweorfan, syððan æðelingas +feorran gefricgean fleam eowerne, +domleasan dæd. Deað bið sella +eorla gehwylcum þonne edwitlif!" +Heht ða þæt heaðoweorc to hagan biodan +up ofer ecgclif, þær þæt eorlweorod +morgenlongne dæg modgiomor sæt, +bordhæbbende, bega on wenum, +endedogores ond eftcymes +leofes monnes. Lyt swigode +niwra spella se ðe næs gerad, +ac he soðlice sægde ofer ealle: +"Nu is wilgeofa Wedra leoda, +dryhten Geata, deaðbedde fæst, +wunað wælreste wyrmes dædum. +Him on efn ligeð ealdorgewinna +sexbennum seoc; sweorde ne meahte +on ðam aglæcean ænige þinga +wunde gewyrcean. Wiglaf siteð +ofer Biowulfe, byre Wihstanes, +eorl ofer oðrum unlifigendum, +healdeð higemæðum heafodwearde +leofes ond laðes. Nu ys leodum wen +orleghwile, syððan underne +Froncum ond Frysum fyll cyninges +wide weorðeð. Wæs sio wroht scepen +heard wið Hugas, syððan Higelac cwom +faran flotherge on Fresna land, +þær hyne Hetware hilde genægdon, +elne geeodon mid ofermægene, +þæt se byrnwiga bugan sceolde, +feoll on feðan, nalles frætwe geaf +ealdor dugoðe. Us wæs a syððan +Merewioingas milts ungyfeðe. +Ne ic to Sweoðeode sibbe oððe treowe +wihte ne wene, ac wæs wide cuð +þætte Ongenðio ealdre besnyðede +Hæðcen Hreþling wið Hrefnawudu, +þa for onmedlan ærest gesohton +Geata leode Guðscilfingas. +Sona him se froda fæder Ohtheres, +eald ond egesfull, ondslyht ageaf, +abreot brimwisan, bryd ahredde, +gomela iomeowlan golde berofene, +Onelan modor ond Ohtheres, +ond ða folgode feorhgeniðlan, +oððæt hi oðeodon earfoðlice +in Hrefnesholt hlafordlease. +Besæt ða sinherge sweorda lafe, +wundum werge, wean oft gehet +earmre teohhe ondlonge niht, +cwæð, he on mergenne meces ecgum +getan wolde, sum on galgtreowum +fuglum to gamene. Frofor eft gelamp +sarigmodum somod ærdæge, +syððan hie Hygelaces horn ond byman, +gealdor ongeaton, þa se goda com +leoda dugoðe on last faran. +Wæs sio swatswaðu Sweona ond Geata, +wælræs weora wide gesyne, +hu ða folc mid him fæhðe towehton. +Gewat him ða se goda mid his gædelingum, +frod, felageomor, fæsten secean, +eorl Ongenþio, ufor oncirde; +hæfde Higelaces hilde gefrunen, +wlonces wigcræft, wiðres ne truwode, +þæt he sæmannum onsacan mihte, +heaðoliðendum hord forstandan, +bearn ond bryde; beah eft þonan +eald under eorðweall. þa wæs æht boden +Sweona leodum, segn Higelaces +freoðowong þone forð ofereodon, +syððan Hreðlingas to hagan þrungon. +þær wearð Ongenðiow ecgum sweorda, +blondenfexa, on bid wrecen, +þæt se þeodcyning ðafian sceolde +Eafores anne dom. Hyne yrringa +Wulf Wonreding wæpne geræhte, +þæt him for swenge swat ædrum sprong +forð under fexe. Næs he forht swa ðeh, +gomela Scilfing, ac forgeald hraðe +wyrsan wrixle wælhlem þone, +syððan ðeodcyning þyder oncirde. +Ne meahte se snella sunu Wonredes +ealdum ceorle ondslyht giofan, +ac he him on heafde helm ær gescer, +þæt he blode fah bugan sceolde, +feoll on foldan; næs he fæge þa git, +ac he hyne gewyrpte, þeah ðe him wund hrine. +Let se hearda Higelaces þegn +bradne mece, þa his broðor læg, +eald sweord eotonisc, entiscne helm +brecan ofer bordweal; ða gebeah cyning, +folces hyrde, wæs in feorh dropen. +ða wæron monige þe his mæg wriðon, +ricone arærdon, ða him gerymed wearð +þæt hie wælstowe wealdan moston. +þenden reafode rinc oðerne, +nam on Ongenðio irenbyrnan, +heard swyrd hilted ond his helm somod, +hares hyrste Higelace bær. +He ðam frætwum feng ond him fægre gehet +leana mid leodum, ond gelæste swa; +geald þone guðræs Geata dryhten, +Hreðles eafora, þa he to ham becom, +Iofore ond Wulfe mid ofermaðmum, +sealde hiora gehwæðrum hund þusenda +landes ond locenra beaga (ne ðorfte him ða lean oðwitan +mon on middangearde), syððan hie ða mærða geslogon, +ond ða Iofore forgeaf angan dohtor, +hamweorðunge, hyldo to wedde. +þæt ys sio fæhðo ond se feondscipe, +wælnið wera, ðæs ðe ic wen hafo, +þe us seceað to Sweona leoda, +syððan hie gefricgeað frean userne +ealdorleasne, þone ðe ær geheold +wið hettendum hord ond rice +æfter hæleða hryre, hwate Scildingas, +folcred fremede oððe furður gen +eorlscipe efnde. Nu is ofost betost +þæt we þeodcyning þær sceawian +ond þone gebringan, þe us beagas geaf, +on adfære. Ne scel anes hwæt +meltan mid þam modigan, ac þær is maðma hord, +gold unrime grimme geceapod, +ond nu æt siðestan sylfes feore +beagas gebohte. þa sceall brond fretan, +æled þeccean, nalles eorl wegan +maððum to gemyndum, ne mægð scyne +habban on healse hringweorðunge, +ac sceal geomormod, golde bereafod, +oft nalles æne elland tredan, +nu se herewisa hleahtor alegde, +gamen ond gleodream. Forðon sceall gar wesan +monig, morgenceald, mundum bewunden, +hæfen on handa, nalles hearpan sweg +wigend weccean, ac se wonna hrefn +fus ofer fægum fela reordian, +earne secgan hu him æt æte speow, +þenden he wið wulf wæl reafode." +Swa se secg hwata secggende wæs +laðra spella; he ne leag fela +wyrda ne worda. Weorod eall aras; +eodon unbliðe under Earnanæs, +wollenteare wundur sceawian. +Fundon ða on sande sawulleasne +hlimbed healdan þone þe him hringas geaf +ærran mælum; þa wæs endedæg +godum gegongen, þæt se guðcyning, +Wedra þeoden, wundordeaðe swealt. +ær hi þær gesegan syllicran wiht, +wyrm on wonge wiðerræhtes þær +laðne licgean; wæs se legdraca +grimlic, gryrefah, gledum beswæled. +Se wæs fiftiges fotgemearces +lang on legere, lyftwynne heold +nihtes hwilum, nyðer eft gewat +dennes niosian; wæs ða deaðe fæst, +hæfde eorðscrafa ende genyttod. +Him big stodan bunan ond orcas, +discas lagon ond dyre swyrd, +omige, þurhetone, swa hie wið eorðan fæðm +þusend wintra þær eardodon. +þonne wæs þæt yrfe, eacencræftig, +iumonna gold galdre bewunden, +þæt ðam hringsele hrinan ne moste +gumena ænig, nefne god sylfa, +sigora soðcyning, sealde þam ðe he wolde +(he is manna gehyld) hord openian, +efne swa hwylcum manna swa him gemet ðuhte. +þa wæs gesyne þæt se sið ne ðah +þam ðe unrihte inne gehydde +wræte under wealle. Weard ær ofsloh +feara sumne; þa sio fæhð gewearð +gewrecen wraðlice. Wundur hwar þonne +eorl ellenrof ende gefere +lifgesceafta, þonne leng ne mæg +mon mid his magum meduseld buan. +Swa wæs Biowulfe, þa he biorges weard +sohte, searoniðas; seolfa ne cuðe +þurh hwæt his worulde gedal weorðan sceolde. +Swa hit oð domes dæg diope benemdon +þeodnas mære, þa ðæt þær dydon, +þæt se secg wære synnum scildig, +hergum geheaðerod, hellbendum fæst, +wommum gewitnad, se ðone wong strude, +næs he goldhwæte gearwor hæfde +agendes est ær gesceawod. +Wiglaf maðelode, Wihstanes sunu: +"Oft sceall eorl monig anes willan +wræc adreogan, swa us geworden is. +Ne meahton we gelæran leofne þeoden, +rices hyrde, ræd ænigne, +þæt he ne grette goldweard þone, +lete hyne licgean þær he longe wæs, +wicum wunian oð woruldende; +heold on heahgesceap. Hord ys gesceawod, +grimme gegongen; wæs þæt gifeðe to swið +þe ðone þeodcyning þyder ontyhte. +Ic wæs þær inne ond þæt eall geondseh, +recedes geatwa, þa me gerymed wæs, +nealles swæslice sið alyfed +inn under eorðweall. Ic on ofoste gefeng +micle mid mundum mægenbyrðenne +hordgestreona, hider ut ætbær +cyninge minum. Cwico wæs þa gena, +wis ond gewittig; worn eall gespræc +gomol on gehðo ond eowic gretan het, +bæd þæt ge geworhton æfter wines dædum +in bælstede beorh þone hean, +micelne ond mærne, swa he manna wæs +wigend weorðfullost wide geond eorðan, +þenden he burhwelan brucan moste. +Uton nu efstan oðre siðe, +seon ond secean searogimma geþræc, +wundur under wealle; ic eow wisige, +þæt ge genoge neon sceawiað +beagas ond brad gold. Sie sio bær gearo, +ædre geæfned, þonne we ut cymen, +ond þonne geferian frean userne, +leofne mannan, þær he longe sceal +on ðæs waldendes wære geþolian." +Het ða gebeodan byre Wihstanes, +hæle hildedior, hæleða monegum, +boldagendra, þæt hie bælwudu +feorran feredon, folcagende, +godum togenes: "Nu sceal gled fretan, +weaxan wonna leg wigena strengel, +þone ðe oft gebad isernscure, +þonne stræla storm strengum gebæded +scoc ofer scildweall, sceft nytte heold, +feðergearwum fus flane fulleode." +Huru se snotra sunu Wihstanes +acigde of corðre cyninges þegnas +syfone tosomne, þa selestan, +eode eahta sum under inwithrof +hilderinca; sum on handa bær +æledleoman, se ðe on orde geong. +Næs ða on hlytme hwa þæt hord strude, +syððan orwearde ænigne dæl +secgas gesegon on sele wunian, +læne licgan; lyt ænig mearn +þæt hi ofostlice ut geferedon +dyre maðmas. Dracan ec scufun, +wyrm ofer weallclif, leton weg niman, +flod fæðmian frætwa hyrde. +þa wæs wunden gold on wæn hladen, +æghwæs unrim, æþeling boren, +har hilderinc to Hronesnæsse. +Him ða gegiredan Geata leode +ad on eorðan unwaclicne, +helmum behongen, hildebordum, +beorhtum byrnum, swa he bena wæs; +alegdon ða tomiddes mærne þeoden +hæleð hiofende, hlaford leofne. +Ongunnon þa on beorge bælfyra mæst +wigend weccan; wudurec astah, +sweart ofer swioðole, swogende leg +wope bewunden (windblond gelæg), +oðþæt he ða banhus gebrocen hæfde, +hat on hreðre. Higum unrote +modceare mændon, mondryhtnes cwealm; +swylce giomorgyd Geatisc meowle +bundenheorde +song sorgcearig swiðe geneahhe +þæt hio hyre heofungdagas hearde ondrede, +wælfylla worn, werudes egesan, +hynðo ond hæftnyd. Heofon rece swealg. +Geworhton ða Wedra leode +hleo on hoe, se wæs heah ond brad, +wægliðendum wide gesyne, +ond betimbredon on tyn dagum +beadurofes becn, bronda lafe +wealle beworhton, swa hyt weorðlicost +foresnotre men findan mihton. +Hi on beorg dydon beg ond siglu, +eall swylce hyrsta, swylce on horde ær +niðhedige men genumen hæfdon, +forleton eorla gestreon eorðan healdan, +gold on greote, þær hit nu gen lifað +eldum swa unnyt swa hit æror wæs. +þa ymbe hlæw riodan hildediore, +æþelinga bearn, ealra twelfe, +woldon ceare cwiðan ond kyning mænan, +wordgyd wrecan ond ymb wer sprecan; +eahtodan eorlscipe ond his ellenweorc +duguðum demdon, swa hit gedefe bið +þæt mon his winedryhten wordum herge, +ferhðum freoge, þonne he forð scile +of lichaman læded weorðan. +Swa begnornodon Geata leode +hlafordes hryre, heorðgeneatas, +cwædon þæt he wære wyruldcyninga +manna mildust ond monðwærust, +leodum liðost ond lofgeornost. \ No newline at end of file diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stdin-hello.rs b/tests/wasi.fyi/wasi-libstd-test/io_stdin-hello.rs new file mode 100644 index 00000000000..0ab1139c511 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stdin-hello.rs @@ -0,0 +1,11 @@ +use std::io; +use std::io::Read; + +fn main() { + let mut stdin = String::new(); + assert!(io::stdin().read_to_string(&mut stdin).is_ok()); + assert_eq!( + stdin, + String::from_utf8_lossy(include_bytes!("io_stdin-hello.stdin")) + ); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stdin-hello.stdin b/tests/wasi.fyi/wasi-libstd-test/io_stdin-hello.stdin new file mode 100644 index 00000000000..d8a52ccecec --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stdin-hello.stdin @@ -0,0 +1 @@ +Hello, stdin! diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stdout-beowulf.rs b/tests/wasi.fyi/wasi-libstd-test/io_stdout-beowulf.rs new file mode 100644 index 00000000000..eed90b255fb --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stdout-beowulf.rs @@ -0,0 +1,6 @@ +use std::io; +use std::io::Write; + +fn main() { + assert!(io::stdout().write_all(include_bytes!("io_stdout-beowulf.stdout")).is_ok()); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stdout-beowulf.stdout b/tests/wasi.fyi/wasi-libstd-test/io_stdout-beowulf.stdout new file mode 100644 index 00000000000..185668538ac --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stdout-beowulf.stdout @@ -0,0 +1,3182 @@ +Hwæt. We Gardena in geardagum, +þeodcyninga, þrym gefrunon, +hu ða æþelingas ellen fremedon. +Oft Scyld Scefing sceaþena þreatum, +monegum mægþum, meodosetla ofteah, +egsode eorlas. Syððan ærest wearð +feasceaft funden, he þæs frofre gebad, +weox under wolcnum, weorðmyndum þah, +oðþæt him æghwylc þara ymbsittendra +ofer hronrade hyran scolde, +gomban gyldan. þæt wæs god cyning. +ðæm eafera wæs æfter cenned, +geong in geardum, þone god sende +folce to frofre; fyrenðearfe ongeat +þe hie ær drugon aldorlease +lange hwile. Him þæs liffrea, +wuldres wealdend, woroldare forgeaf; +Beowulf wæs breme blæd wide sprang, +Scyldes eafera Scedelandum in. +Swa sceal geong guma gode gewyrcean, +fromum feohgiftum on fæder bearme, +þæt hine on ylde eft gewunigen +wilgesiþas, þonne wig cume, +leode gelæsten; lofdædum sceal +in mægþa gehwære man geþeon. +Him ða Scyld gewat to gescæphwile +felahror feran on frean wære. +Hi hyne þa ætbæron to brimes faroðe, +swæse gesiþas, swa he selfa bæd, +þenden wordum weold wine Scyldinga; +leof landfruma lange ahte. +þær æt hyðe stod hringedstefna, +isig ond utfus, æþelinges fær. +Aledon þa leofne þeoden, +beaga bryttan, on bearm scipes, +mærne be mæste. þær wæs madma fela +of feorwegum, frætwa, gelæded; +ne hyrde ic cymlicor ceol gegyrwan +hildewæpnum ond heaðowædum, +billum ond byrnum; him on bearme læg +madma mænigo, þa him mid scoldon +on flodes æht feor gewitan. +Nalæs hi hine læssan lacum teodan, +þeodgestreonum, þon þa dydon +þe hine æt frumsceafte forð onsendon +ænne ofer yðe umborwesende. +þa gyt hie him asetton segen geldenne +heah ofer heafod, leton holm beran, +geafon on garsecg; him wæs geomor sefa, +murnende mod. Men ne cunnon +secgan to soðe, selerædende, +hæleð under heofenum, hwa þæm hlæste onfeng. +ða wæs on burgum Beowulf Scyldinga, +leof leodcyning, longe þrage +folcum gefræge fæder ellor hwearf, +aldor of earde, oþþæt him eft onwoc +heah Healfdene; heold þenden lifde, +gamol ond guðreouw, glæde Scyldingas. +ðæm feower bearn forð gerimed +in worold wocun, weoroda ræswan, +Heorogar ond Hroðgar ond Halga til; +hyrde ic þæt wæs Onelan cwen, +Heaðoscilfingas healsgebedda. +þa wæs Hroðgare heresped gyfen, +wiges weorðmynd, þæt him his winemagas +georne hyrdon, oðð þæt seo geogoð geweox, +magodriht micel. Him on mod bearn +þæt healreced hatan wolde, +medoærn micel, men gewyrcean +þonne yldo bearn æfre gefrunon, +ond þær on innan eall gedælan +geongum ond ealdum, swylc him god sealde, +buton folcscare ond feorum gumena. +ða ic wide gefrægn weorc gebannan +manigre mægþe geond þisne middangeard, +folcstede frætwan. Him on fyrste gelomp, +ædre mid yldum, þæt hit wearð ealgearo, +healærna mæst; scop him Heort naman +se þe his wordes geweald wide hæfde. +He beot ne aleh, beagas dælde, +sinc æt symle. Sele hlifade, +heah ond horngeap, heaðowylma bad, +laðan liges; ne wæs hit lenge þa gen +þæt se ecghete aþumsweorum, +æfter wælniðe wæcnan scolde. +ða se ellengæst earfoðlice +þrage geþolode, se þe in þystrum bad, +þæt he dogora gehwam dream gehyrde +hludne in healle; þær wæs hearpan sweg, +swutol sang scopes. Sægde se þe cuþe +frumsceaft fira feorran reccan, +cwæð þæt se ælmihtiga eorðan worhte, +wlitebeorhtne wang, swa wæter bebugeð, +gesette sigehreþig sunnan ond monan +leoman to leohte landbuendum +ond gefrætwade foldan sceatas +leomum ond leafum, lif eac gesceop +cynna gehwylcum þara ðe cwice hwyrfaþ. +Swa ða drihtguman dreamum lifdon +eadiglice, oððæt an ongan +fyrene fremman feond on helle. +Wæs se grimma gæst Grendel haten, +mære mearcstapa, se þe moras heold, +fen ond fæsten; fifelcynnes eard +wonsæli wer weardode hwile, +siþðan him scyppend forscrifen hæfde +in Caines cynne. þone cwealm gewræc +ece drihten, þæs þe he Abel slog; +ne gefeah he þære fæhðe, ac he hine feor forwræc, +metod for þy mane, mancynne fram. +þanon untydras ealle onwocon, +eotenas ond ylfe ond orcneas, +swylce gigantas, þa wið gode wunnon +lange þrage; he him ðæs lean forgeald. +Gewat ða neosian, syþðan niht becom, +hean huses, hu hit Hringdene +æfter beorþege gebun hæfdon. +Fand þa ðær inne æþelinga gedriht +swefan æfter symble; sorge ne cuðon, +wonsceaft wera. Wiht unhælo, +grim ond grædig, gearo sona wæs, +reoc ond reþe, ond on ræste genam +þritig þegna, þanon eft gewat +huðe hremig to ham faran, +mid þære wælfylle wica neosan. +ða wæs on uhtan mid ærdæge +Grendles guðcræft gumum undyrne; +þa wæs æfter wiste wop up ahafen, +micel morgensweg. Mære þeoden, +æþeling ærgod, unbliðe sæt, +þolode ðryðswyð, þegnsorge dreah, +syðþan hie þæs laðan last sceawedon, +wergan gastes; wæs þæt gewin to strang, +lað ond longsum. Næs hit lengra fyrst, +ac ymb ane niht eft gefremede +morðbeala mare ond no mearn fore, +fæhðe ond fyrene; wæs to fæst on þam. +þa wæs eaðfynde þe him elles hwær +gerumlicor ræste sohte, +bed æfter burum, ða him gebeacnod wæs, +gesægd soðlice sweotolan tacne +healðegnes hete; heold hyne syðþan +fyr ond fæstor se þæm feonde ætwand. +Swa rixode ond wið rihte wan, +ana wið eallum, oðþæt idel stod +husa selest. Wæs seo hwil micel; +XII wintra tid torn geþolode +wine Scyldinga, weana gehwelcne, +sidra sorga. Forðam secgum wearð, +ylda bearnum, undyrne cuð, +gyddum geomore, þætte Grendel wan +hwile wið Hroþgar, heteniðas wæg, +fyrene ond fæhðe fela missera, +singale sæce, sibbe ne wolde +wið manna hwone mægenes Deniga, +feorhbealo feorran, fea þingian, +ne þær nænig witena wenan þorfte +beorhtre bote to banan folmum, +ac se æglæca ehtende wæs, +deorc deaþscua, duguþe ond geogoþe, +seomade ond syrede, sinnihte heold +mistige moras. men ne cunnon +hwyder helrunan hwyrftum scriþað. +Swa fela fyrena feond mancynnes, +atol angengea, oft gefremede, +heardra hynða. Heorot eardode, +sincfage sel sweartum nihtum; +no he þone gifstol gretan moste, +maþðum for metode, ne his myne wisse. +þæt wæs wræc micel wine Scyldinga, +modes brecða. Monig oft gesæt +rice to rune; ræd eahtedon +hwæt swiðferhðum selest wære +wið færgryrum to gefremmanne. +Hwilum hie geheton æt hærgtrafum +wigweorþunga, wordum bædon +þæt him gastbona geoce gefremede +wið þeodþreaum. Swylc wæs þeaw hyra, +hæþenra hyht; helle gemundon +in modsefan, metod hie ne cuþon, +dæda demend, ne wiston hie drihten god, +ne hie huru heofena helm herian ne cuþon, +wuldres waldend. Wa bið þæm ðe sceal +þurh sliðne nið sawle bescufan +in fyres fæþm, frofre ne wenan, +wihte gewendan; wel bið þæm þe mot +æfter deaðdæge drihten secean +ond to fæder fæþmum freoðo wilnian. +Swa ða mælceare maga Healfdenes +singala seað, ne mihte snotor hæleð +wean onwendan; wæs þæt gewin to swyð, +laþ ond longsum, þe on ða leode becom, +nydwracu niþgrim, nihtbealwa mæst. +þæt fram ham gefrægn Higelaces þegn, +god mid Geatum, Grendles dæda; +se wæs moncynnes mægenes strengest +on þæm dæge þysses lifes, +æþele ond eacen. Het him yðlidan +godne gegyrwan, cwæð, hu guðcyning +ofer swanrade secean wolde, +mærne þeoden, þa him wæs manna þearf. +ðone siðfæt him snotere ceorlas +lythwon logon, þeah he him leof wære; +hwetton higerofne, hæl sceawedon. +Hæfde se goda Geata leoda +cempan gecorone þara þe he cenoste +findan mihte; XVna sum +sundwudu sohte; secg wisade, +lagucræftig mon, landgemyrcu. +Fyrst forð gewat. Flota wæs on yðum, +bat under beorge. Beornas gearwe +on stefn stigon; streamas wundon, +sund wið sande; secgas bæron +on bearm nacan beorhte frætwe, +guðsearo geatolic; guman ut scufon, +weras on wilsið, wudu bundenne. +Gewat þa ofer wægholm, winde gefysed, +flota famiheals fugle gelicost, +oðþæt ymb antid oþres dogores +wundenstefna gewaden hæfde +þæt ða liðende land gesawon, +brimclifu blican, beorgas steape, +side sænæssas; þa wæs sund liden, +eoletes æt ende. þanon up hraðe +Wedera leode on wang stigon, +sæwudu sældon syrcan hrysedon, +guðgewædo, gode þancedon +þæs þe him yþlade eaðe wurdon. +þa of wealle geseah weard Scildinga, +se þe holmclifu healdan scolde, +beran ofer bolcan beorhte randas, +fyrdsearu fuslicu; hine fyrwyt bræc +modgehygdum, hwæt þa men wæron. +Gewat him þa to waroðe wicge ridan +þegn Hroðgares, þrymmum cwehte +mægenwudu mundum, meþelwordum frægn: +Hwæt syndon ge searohæbbendra, +byrnum werede, þe þus brontne ceol +ofer lagustræte lædan cwomon, +hider ofer holmas? le wæs +endesæta, ægwearde heold, +þe on land Dena laðra nænig +mid scipherge sceðþan ne meahte. +No her cuðlicor cuman ongunnon +lindhæbbende; ne ge leafnesword +guðfremmendra gearwe ne wisson, +maga gemedu. Næfre ic maran geseah +eorla ofer eorþan ðonne is eower sum, +secg on searwum; nis þæt seldguma, +wæpnum geweorðad, næfne him his wlite leoge, +ænlic ansyn. Nu ic eower sceal +frumcyn witan, ær ge fyr heonan , +leassceaweras, on land Dena +furþur feran. Nu ge feorbuend, +mereliðende, minne gehyrað +anfealdne geþoht: Ofost is selest +to gecyðanne hwanan eowre cyme syndon. +Him se yldesta ondswarode, +werodes wisa, wordhord onleac: +We synt gumcynnes Geata leode +ond Higelaces heorðgeneatas. +Wæs min fæder folcum gecyþed, +æþele ordfruma, Ecgþeow haten. +Gebad wintra worn, ær he on weg hwurfe, +gamol of geardum; hine gearwe geman +witena welhwylc wide geond eorþan. +We þurh holdne hige hlaford þinne, +sunu Healfdenes, secean cwomon, +leodgebyrgean; wes þu us larena god. +Habbað we to þæm mæran micel ærende, +Deniga frean, ne sceal þær dyrne sum +wesan, þæs ic wene. þu wast gif hit is +swa we soþlice secgan hyrdon +þæt mid Scyldingum sceaðona ic nat hwylc, +deogol dædhata, deorcum nihtum +eaweð þurh egsan uncuðne nið, +hynðu ond hrafyl. Ic þæs Hroðgar mæg +þurh rumne sefan ræd gelæran, +hu he frod ond god feond oferswyðeþ, +gyf him edwendan æfre scolde +bealuwa bisigu, bot eft cuman, +ond þa cearwylmas colran wurðaþ; +oððe a syþðan earfoðþrage, +þreanyd þolað, þenden þær wunað +on heahstede husa selest. +Weard maþelode, ðær on wicge sæt, +ombeht unforht: æghwæþres sceal +scearp scyldwiga gescad witan, +worda ond worca, se þe wel þenceð. +Ic þæt gehyre, þæt þis is hold weorod +frean Scyldinga. Gewitaþ forð beran +wæpen ond gewædu; ic eow wisige. +Swylce ic maguþegnas mine hate +wið feonda gehwone flotan eowerne, +niwtyrwydne nacan on sande +arum healdan, oþðæt eft byreð +ofer lagustreamas leofne mannan +wudu wundenhals to Wedermearce, +godfremmendra swylcum gifeþe bið +þæt þone hilderæs hal gedigeð. +Gewiton him þa feran. Flota stille bad, +seomode on sale sidfæþmed scip, +on ancre fæst. Eoforlic scionon +ofer hleorberan gehroden golde, +fah ond fyrheard; ferhwearde heold +guþmod grimmon. Guman onetton, +sigon ætsomne, oþþæt hy sæl timbred, +geatolic ond goldfah, ongyton mihton; +þæt wæs foremærost foldbuendum +receda under roderum, on þæm se rica bad; +lixte se leoma ofer landa fela. +Him þa hildedeor hof modigra +torht getæhte, þæt hie him to mihton +gegnum gangan; guðbeorna sum +wicg gewende, word æfter cwæð: +Mæl is me to feran; fæder alwalda +mid arstafum eowic gehealde +siða gesunde. Ic to sæ wille +wið wrað werod wearde healdan. +Stræt wæs stanfah, stig wisode +gumum ætgædere. Guðbyrne scan +heard hondlocen, hringiren scir +song in searwum, þa hie to sele furðum +in hyra gryregeatwum gangan cwomon. +Setton sæmeþe side scyldas, +rondas regnhearde, wið þæs recedes weal, +bugon þa to bence. Byrnan hringdon, +guðsearo gumena; garas stodon, +sæmanna searo, samod ætgædere, +æscholt ufan græg; wæs se irenþreat +wæpnum gewurþad. þa ðær wlonc hæleð +oretmecgas æfter æþelum frægn: +Hwanon ferigeað ge fætte scyldas, +græge syrcan ond grimhelmas, +heresceafta heap? Ic eom Hroðgares +ar ond ombiht. Ne seah ic elþeodige +þus manige men modiglicran. +Wen ic þæt ge for wlenco, nalles for wræcsiðum, +ac for higeþrymmum Hroðgar sohton. +Him þa ellenrof andswarode, +wlanc Wedera leod, word æfter spræc, +heard under helme: We synt Higelaces +beodgeneatas; Beowulf is min nama. +Wille ic asecgan sunu Healfdenes, +mærum þeodne, min ærende, +aldre þinum, gif he us geunnan wile +þæt we hine swa godne gretan moton. +Wulfgar maþelode þæt wæs Wendla leod; +wæs his modsefa manegum gecyðed, +wig ond wisdom: Ic þæs wine Deniga, +frean Scildinga, frinan wille, +beaga bryttan, swa þu bena eart, +þeoden mærne, ymb þinne sið, +ond þe þa ondsware ædre gecyðan +ðe me se goda agifan þenceð. +Hwearf þa hrædlice þær Hroðgar sæt +eald ond anhar mid his eorla gedriht; +eode ellenrof, þæt he for eaxlum gestod +Deniga frean; cuþe he duguðe þeaw. +Wulfgar maðelode to his winedrihtne: +Her syndon geferede, feorran cumene +ofer geofenes begang Geata leode; +þone yldestan oretmecgas +Beowulf nemnað. Hy benan synt +þæt hie, þeoden min, wið þe moton +wordum wrixlan. No ðu him wearne geteoh +ðinra gegncwida, glædman Hroðgar. +Hy on wiggetawum wyrðe þinceað +eorla geæhtlan; huru se aldor deah, +se þæm heaðorincum hider wisade. +Hroðgar maþelode, helm Scyldinga: +Ic hine cuðe cnihtwesende. +Wæs his ealdfæder Ecgþeo haten, +ðæm to ham forgeaf Hreþel Geata +angan dohtor; is his eafora nu +heard her cumen, sohte holdne wine. +ðonne sægdon þæt sæliþende, +þa ðe gifsceattas Geata fyredon +þyder to þance, þæt he XXXtiges +manna mægencræft on his mundgripe +heaþorof hæbbe. Hine halig god +for arstafum us onsende, +to Westdenum, þæs ic wen hæbbe, +wið Grendles gryre. Ic þæm godan sceal +for his modþræce madmas beodan. +Beo ðu on ofeste, hat in gan +seon sibbegedriht samod ætgædere; +gesaga him eac wordum þæt hie sint wilcuman +Deniga leodum. +[] word inne abead: +Eow het secgan sigedrihten min, +aldor Eastdena, þæt he eower æþelu can, +ond ge him syndon ofer sæwylmas +heardhicgende hider wilcuman. +Nu ge moton gangan in eowrum guðgeatawum +under heregriman Hroðgar geseon; +lætað hildebord her onbidan, +wudu, wælsceaftas, worda geþinges. +Aras þa se rica, ymb hine rinc manig, +þryðlic þegna heap; sume þær bidon, +heaðoreaf heoldon, swa him se hearda bebead. +Snyredon ætsomne, þa secg wisode, +under Heorotes hrof +heard under helme, þæt he on heoðe gestod. +Beowulf maðelode on him byrne scan, +searonet seowed smiþes orþancum: +Wæs þu, Hroðgar, hal. Ic eom Higelaces +mæg ond magoðegn; hæbbe ic mærða fela +ongunnen on geogoþe. Me wearð Grendles þing +on minre eþeltyrf undyrne cuð; +secgað sæliðend þæt þæs sele stande, +reced selesta, rinca gehwylcum +idel ond unnyt, siððan æfenleoht +under heofenes hador beholen weorþeð. +þa me þæt gelærdon leode mine +þa selestan, snotere ceorlas, +þeoden Hroðgar, þæt ic þe sohte, +forþan hie mægenes cræft minne cuþon, +selfe ofersawon, ða ic of searwum cwom, +fah from feondum. þær ic fife geband, +yðde eotena cyn ond on yðum slog +niceras nihtes, nearoþearfe dreah, +wræc Wedera nið wean ahsodon, +forgrand gramum, ond nu wið Grendel sceal, +wið þam aglæcan, ana gehegan +ðing wið þyrse. Ic þe nu ða, +brego Beorhtdena, biddan wille, +eodor Scyldinga, anre bene, +þæt ðu me ne forwyrne, wigendra hleo, +freowine folca, nu ic þus feorran com, +þæt ic mote ana ond minra eorla gedryht, +þes hearda heap, Heorot fælsian. +Hæbbe ic eac geahsod þæt se æglæca +for his wonhydum wæpna ne recceð. +Ic þæt þonne forhicge swa me Higelac sie, +min mondrihten, modes bliðe, +þæt ic sweord bere oþðe sidne scyld, +geolorand to guþe, ac ic mid grape sceal +fon wið feonde ond ymb feorh sacan, +lað wið laþum; ðær gelyfan sceal +dryhtnes dome se þe hine deað nimeð. +Wen ic þæt he wille, gif he wealdan mot, +in þæm guðsele Geotena leode +etan unforhte, swa he oft dyde, +mægen Hreðmanna. Na þu minne þearft +hafalan hydan, ac he me habban wile +dreore fahne, gif mec deað nimeð. +Byreð blodig wæl, byrgean þenceð, +eteð angenga unmurnlice, +mearcað morhopu; no ðu ymb mines ne þearft +lices feorme leng sorgian. +Onsend Higelace, gif mec hild nime, +beaduscruda betst, þæt mine breost wereð, +hrægla selest; þæt is Hrædlan laf, +Welandes geweorc. Gæð a wyrd swa hio scel. +Hroðgar maþelode, helm Scyldinga: +For gewyrhtum þu, wine min Beowulf, +ond for arstafum usic sohtest. +Gesloh þin fæder fæhðe mæste; +wearþ he Heaþolafe to handbonan +mid Wilfingum; ða hine Wedera cyn +for herebrogan habban ne mihte. +þanon he gesohte Suðdena folc +ofer yða gewealc, Arscyldinga. +ða ic furþum weold folce Deniga +ond on geogoðe heold ginne rice, +hordburh hæleþa; ða wæs Heregar dead, +min yldra mæg unlifigende, +bearn Healfdenes; se wæs betera ðonne ic. +Siððan þa fæhðe feo þingode; +sende ic Wylfingum ofer wæteres hrycg +ealde madmas; he me aþas swor. +Sorh is me to secganne on sefan minum +gumena ængum hwæt me Grendel hafað +hynðo on Heorote mid his heteþancum, +færniða gefremed. Is min fletwerod, +wigheap gewanod; hie wyrd forsweop +on Grendles gryre. God eaþe mæg +þone dolsceaðan dæda getwæfan. +Ful oft gebeotedon beore druncne +ofer ealowæge oretmecgas +þæt hie in beorsele bidan woldon +Grendles guþe mid gryrum ecga. +ðonne wæs þeos medoheal on morgentid, +drihtsele dreorfah, þonne dæg lixte, +eal bencþelu blode bestymed, +heall heorudreore; ahte ic holdra þy læs, +deorre duguðe, þe þa deað fornam. +Site nu to symle ond onsæl meoto, +sigehreð secgum, swa þin sefa hwette. +þa wæs Geatmæcgum geador ætsomne +on beorsele benc gerymed; +þær swiðferhþe sittan eodon, +þryðum dealle. þegn nytte beheold, +se þe on handa bær hroden ealowæge, +scencte scir wered. Scop hwilum sang +hador on Heorote. þær wæs hæleða dream, +duguð unlytel Dena ond Wedera. +Unferð maþelode, Ecglafes bearn, +þe æt fotum sæt frean Scyldinga, +onband beadurune wæs him Beowulfes sið, +modges merefaran, micel æfþunca, +forþon þe he ne uþe þæt ænig oðer man +æfre mærða þon ma middangeardes +gehedde under heofenum þonne he sylfa: +Eart þu se Beowulf, se þe wið Brecan wunne, +on sidne sæ ymb sund flite, +ðær git for wlence wada cunnedon +ond for dolgilpe on deop wæter +aldrum neþdon? Ne inc ænig mon, +ne leof ne lað, belean mihte +sorhfullne sið, þa git on sund reon. +þær git eagorstream earmum þehton, +mæton merestræta, mundum brugdon, +glidon ofer garsecg; geofon yþum weol, +wintrys wylmum. Git on wæteres æht +seofon niht swuncon; he þe æt sunde oferflat, +hæfde mare mægen. þa hine on morgentid +on Heaþoræmas holm up ætbær; +ðonon he gesohte swæsne eþel, +leof his leodum, lond Brondinga, +freoðoburh fægere, þær he folc ahte +burh ond beagas. Beot eal wið þe +sunu Beanstanes soðe gelæste. +ðonne wene ic to þe wyrsan geþingea, +ðeah þu heaðoræsa gehwær dohte, +grimre guðe, gif þu Grendles dearst +nihtlongne fyrst nean bidan. +Beowulf maþelode, bearn Ecgþeowes: +Hwæt. þu worn fela, wine min Unferð, +beore druncen ymb Brecan spræce, +sægdest from his siðe. Soð ic talige, +þæt ic merestrengo maran ahte, +earfeþo on yþum, ðonne ænig oþer man. +Wit þæt gecwædon cnihtwesende +ond gebeotedon wæron begen þa git +on geogoðfeore þæt wit on garsecg ut +aldrum neðdon, ond þæt geæfndon swa. +Hæfdon swurd nacod, þa wit on sund reon, +heard on handa; wit unc wið hronfixas +werian þohton. No he wiht fram me +flodyþum feor fleotan meahte, +hraþor on holme; no ic fram him wolde. +ða wit ætsomne on sæ wæron +fif nihta fyrst, oþþæt unc flod todraf, +wado weallende, wedera cealdost, +nipende niht, ond norþanwind +heaðogrim ondhwearf; hreo wæron yþa. +Wæs merefixa mod onhrered; +þær me wið laðum licsyrce min, +heard, hondlocen, helpe gefremede, +beadohrægl broden on breostum læg +golde gegyrwed. Me to grunde teah +fah feondscaða, fæste hæfde +grim on grape; hwæþre me gyfeþe wearð +þæt ic aglæcan orde geræhte, +hildebille; heaþoræs fornam +mihtig meredeor þurh mine hand. +Swa mec gelome laðgeteonan +þreatedon þearle. Ic him þenode +deoran sweorde, swa hit gedefe wæs. +Næs hie ðære fylle gefean hæfdon, +manfordædlan, þæt hie me þegon, +symbel ymbsæton sægrunde neah; +ac on mergenne mecum wunde +be yðlafe uppe lægon, +sweordum aswefede, þæt syðþan na +ymb brontne ford brimliðende +lade ne letton. Leoht eastan com, +beorht beacen godes; brimu swaþredon, +þæt ic sænæssas geseon mihte, +windige weallas. Wyrd oft nereð +unfægne eorl, þonne his ellen deah. +Hwæþere me gesælde þæt ic mid sweorde ofsloh +niceras nigene. No ic on niht gefrægn +under heofones hwealf heardran feohtan, +ne on egstreamum earmran mannon; +hwaþere ic fara feng feore gedigde, +siþes werig. ða mec sæ oþbær, +flod æfter faroðe on Finna land, +wadu weallendu. No ic wiht fram þe +swylcra searoniða secgan hyrde, +billa brogan. Breca næfre git +æt heaðolace, ne gehwæþer incer, +swa deorlice dæd gefremede +fagum sweordum no ic þæs fela gylpe, +þeah ðu þinum broðrum to banan wurde, +heafodmægum; þæs þu in helle scealt +werhðo dreogan, þeah þin wit duge. +Secge ic þe to soðe, sunu Ecglafes, +þæt næfre Grendel swa fela gryra gefremede, +atol æglæca, ealdre þinum, +hynðo on Heorote, gif þin hige wære, +sefa swa searogrim, swa þu self talast. +Ac he hafað onfunden þæt he þa fæhðe ne þearf, +atole ecgþræce eower leode +swiðe onsittan, Sigescyldinga; +nymeð nydbade, nænegum arað +leode Deniga, ac he lust wigeð, +swefeð ond sendeþ, secce ne weneþ +to Gardenum. Ac ic him Geata sceal +eafoð ond ellen ungeara nu, +guþe gebeodan. Gæþ eft se þe mot +to medo modig, siþþan morgenleoht +ofer ylda bearn oþres dogores, +sunne sweglwered suþan scineð. +þa wæs on salum sinces brytta, +gamolfeax ond guðrof; geoce gelyfde +brego Beorhtdena, gehyrde on Beowulfe +folces hyrde fæstrædne geþoht. +ðær wæs hæleþa hleahtor, hlyn swynsode, +word wæron wynsume. Eode Wealhþeow forð, +cwen Hroðgares, cynna gemyndig, +grette goldhroden guman on healle, +ond þa freolic wif ful gesealde +ærest Eastdena eþelwearde, +bæd hine bliðne æt þære beorþege, +leodum leofne. He on lust geþeah +symbel ond seleful, sigerof kyning. +Ymbeode þa ides Helminga +duguþe ond geogoþe dæl æghwylcne, +sincfato sealde, oþþæt sæl alamp +þæt hio Beowulfe, beaghroden cwen +mode geþungen, medoful ætbær; +grette Geata leod, gode þancode +wisfæst wordum þæs ðe hire se willa gelamp +þæt heo on ænigne eorl gelyfde +fyrena frofre. He þæt ful geþeah, +wælreow wiga, æt Wealhþeon, +ond þa gyddode guþe gefysed; +Beowulf maþelode, bearn Ecgþeowes: +Ic þæt hogode, þa ic on holm gestah, +sæbat gesæt mid minre secga gedriht, +þæt ic anunga eowra leoda +willan geworhte oþðe on wæl crunge, +feondgrapum fæst. Ic gefremman sceal +eorlic ellen, oþðe endedæg +on þisse meoduhealle minne gebidan. +ðam wife þa word wel licodon, +gilpcwide Geates; eode goldhroden +freolicu folccwen to hire frean sittan. +þa wæs eft swa ær inne on healle +þryðword sprecen, ðeod on sælum, +sigefolca sweg, oþþæt semninga +sunu Healfdenes secean wolde +æfenræste; wiste þæm ahlæcan +to þæm heahsele hilde geþinged, +siððan hie sunnan leoht geseon ne meahton, +oðþe nipende niht ofer ealle, +scaduhelma gesceapu scriðan cwoman, +wan under wolcnum. Werod eall aras. +Gegrette þa guma oþerne, +Hroðgar Beowulf, ond him hæl abead, +winærnes geweald, ond þæt word acwæð: +Næfre ic ænegum men ær alyfde, +siþðan ic hond ond rond hebban mihte, +ðryþærn Dena buton þe nu ða. +Hafa nu ond geheald husa selest, +gemyne mærþo, mægenellen cyð, +waca wið wraþum. Ne bið þe wilna gad, +gif þu þæt ellenweorc aldre gedigest. +ða him Hroþgar gewat mid his hæleþa gedryht, +eodur Scyldinga, ut of healle; +wolde wigfruma Wealhþeo secan, +cwen to gebeddan. Hæfde kyningwuldor +Grendle togeanes, swa guman gefrungon, +seleweard aseted; sundornytte beheold +ymb aldor Dena, eotonweard abead. +Huru Geata leod georne truwode +modgan mægnes, metodes hyldo. +ða he him of dyde isernbyrnan, +helm of hafelan, sealde his hyrsted sweord, +irena cyst, ombihtþegne, +ond gehealdan het hildegeatwe. +Gespræc þa se goda gylpworda sum, +Beowulf Geata, ær he on bed stige: +No ic me an herewæsmun hnagran talige, +guþgeweorca, þonne Grendel hine; +forþan ic hine sweorde swebban nelle, +aldre beneotan, þeah ic eal mæge. +Nat he þara goda þæt he me ongean slea, +rand geheawe, þeah ðe he rof sie +niþgeweorca; ac wit on niht sculon +secge ofersittan, gif he gesecean dear +wig ofer wæpen, ond siþðan witig god +on swa hwæþere hond, halig dryhten, +mærðo deme, swa him gemet þince. +Hylde hine þa heaþodeor, hleorbolster onfeng +eorles andwlitan, ond hine ymb monig +snellic særinc selereste gebeah. +Nænig heora þohte þæt he þanon scolde +eft eardlufan æfre gesecean, +folc oþðe freoburh, þær he afeded wæs; +ac hie hæfdon gefrunen þæt hie ær to fela micles +in þæm winsele wældeað fornam, +Denigea leode. Ac him dryhten forgeaf +wigspeda gewiofu, Wedera leodum, +frofor ond fultum, þæt hie feond heora +ðurh anes cræft ealle ofercomon, +selfes mihtum. Soð is gecyþed +þæt mihtig god manna cynnes +weold wideferhð. Com on wanre niht +scriðan sceadugenga. Sceotend swæfon, +þa þæt hornreced healdan scoldon, +ealle buton anum. þæt wæs yldum cuþ +þæt hie ne moste, þa metod nolde, +se scynscaþa under sceadu bregdan; +ac he wæccende wraþum on andan +bad bolgenmod beadwa geþinges. +ða com of more under misthleoþum +Grendel gongan, godes yrre bær; +mynte se manscaða manna cynnes +sumne besyrwan in sele þam hean. +Wod under wolcnum to þæs þe he winreced, +goldsele gumena, gearwost wisse, +fættum fahne. Ne wæs þæt forma sið +þæt he Hroþgares ham gesohte; +næfre he on aldordagum ær ne siþðan +heardran hæle, healðegnas fand. +Com þa to recede rinc siðian, +dreamum bedæled. Duru sona onarn, +fyrbendum fæst, syþðan he hire folmum æthran; +onbræd þa bealohydig, ða he gebolgen wæs, +recedes muþan. Raþe æfter þon +on fagne flor feond treddode, +eode yrremod; him of eagum stod +ligge gelicost leoht unfæger. +Geseah he in recede rinca manige, +swefan sibbegedriht samod ætgædere, +magorinca heap. þa his mod ahlog; +mynte þæt he gedælde, ærþon dæg cwome, +atol aglæca, anra gehwylces +lif wið lice, þa him alumpen wæs +wistfylle wen. Ne wæs þæt wyrd þa gen +þæt he ma moste manna cynnes +ðicgean ofer þa niht. þryðswyð beheold +mæg Higelaces, hu se manscaða +under færgripum gefaran wolde. +Ne þæt se aglæca yldan þohte, +ac he gefeng hraðe forman siðe +slæpendne rinc, slat unwearnum, +bat banlocan, blod edrum dranc, +synsnædum swealh; sona hæfde +unlyfigendes eal gefeormod, +fet ond folma. Forð near ætstop, +nam þa mid handa higeþihtigne +rinc on ræste, ræhte ongean +feond mid folme; he onfeng hraþe +inwitþancum ond wið earm gesæt. +Sona þæt onfunde fyrena hyrde +þæt he ne mette middangeardes, +eorþan sceata, on elran men +mundgripe maran. He on mode wearð +forht on ferhðe; no þy ær fram meahte. +Hyge wæs him hinfus, wolde on heolster fleon, +secan deofla gedræg; ne wæs his drohtoð þær +swylce he on ealderdagum ær gemette. +Gemunde þa se goda, mæg Higelaces, +æfenspræce, uplang astod +ond him fæste wiðfeng; fingras burston. +Eoten wæs utweard; eorl furþur stop. +Mynte se mæra, þær he meahte swa, +widre gewindan ond on weg þanon +fleon on fenhopu; wiste his fingra geweald +on grames grapum. þæt wæs geocor sið +þæt se hearmscaþa to Heorute ateah. +Dryhtsele dynede; Denum eallum wearð, +ceasterbuendum, cenra gehwylcum, +eorlum ealuscerwen. Yrre wæron begen, +reþe renweardas. Reced hlynsode. +þa wæs wundor micel þæt se winsele +wiðhæfde heaþodeorum, þæt he on hrusan ne feol, +fæger foldbold; ac he þæs fæste wæs +innan ond utan irenbendum +searoþoncum besmiþod. þær fram sylle abeag +medubenc monig, mine gefræge, +golde geregnad, þær þa graman wunnon. +þæs ne wendon ær witan Scyldinga +þæt hit a mid gemete manna ænig, +betlic ond banfag, tobrecan meahte, +listum tolucan, nymþe liges fæþm +swulge on swaþule. Sweg up astag +niwe geneahhe; Norðdenum stod +atelic egesa, anra gehwylcum +þara þe of wealle wop gehyrdon, +gryreleoð galan godes ondsacan, +sigeleasne sang, sar wanigean +helle hæfton. Heold hine fæste +se þe manna wæs mægene strengest +on þæm dæge þysses lifes. +Nolde eorla hleo ænige þinga +þone cwealmcuman cwicne forlætan, +ne his lifdagas leoda ænigum +nytte tealde. þær genehost brægd +eorl Beowulfes ealde lafe, +wolde freadrihtnes feorh ealgian, +mæres þeodnes, ðær hie meahton swa. +Hie þæt ne wiston, þa hie gewin drugon, +heardhicgende hildemecgas, +ond on healfa gehwone heawan þohton, +sawle secan, þone synscaðan +ænig ofer eorþan irenna cyst, +guðbilla nan, gretan nolde, +ac he sigewæpnum forsworen hæfde, +ecga gehwylcre. Scolde his aldorgedal +on ðæm dæge þysses lifes +earmlic wurðan, ond se ellorgast +on feonda geweald feor siðian. +ða þæt onfunde se þe fela æror +modes myrðe manna cynne, +fyrene gefremede he wæs fag wið god, +þæt him se lichoma læstan nolde, +ac hine se modega mæg Hygelaces +hæfde be honda; wæs gehwæþer oðrum +lifigende lað. Licsar gebad +atol æglæca; him on eaxle wearð +syndolh sweotol, seonowe onsprungon, +burston banlocan. Beowulfe wearð +guðhreð gyfeþe; scolde Grendel þonan +feorhseoc fleon under fenhleoðu, +secean wynleas wic; wiste þe geornor +þæt his aldres wæs ende gegongen, +dogera dægrim. Denum eallum wearð +æfter þam wælræse willa gelumpen. +Hæfde þa gefælsod se þe ær feorran com, +snotor ond swyðferhð, sele Hroðgares, +genered wið niðe; nihtweorce gefeh, +ellenmærþum. Hæfde Eastdenum +Geatmecga leod gilp gelæsted, +swylce oncyþðe ealle gebette, +inwidsorge, þe hie ær drugon +ond for þreanydum þolian scoldon, +torn unlytel. þæt wæs tacen sweotol, +syþðan hildedeor hond alegde, +earm ond eaxle þær wæs eal geador +Grendles grape under geapne hrof. +ða wæs on morgen mine gefræge +ymb þa gifhealle guðrinc monig; +ferdon folctogan feorran ond nean +geond widwegas wundor sceawian, +laþes lastas. No his lifgedal +sarlic þuhte secga ænegum +þara þe tirleases trode sceawode, +hu he werigmod on weg þanon, +niða ofercumen, on nicera mere +fæge ond geflymed feorhlastas bær. +ðær wæs on blode brim weallende, +atol yða geswing eal gemenged +haton heolfre, heorodreore weol. +Deaðfæge deog, siððan dreama leas +in fenfreoðo feorh alegde, +hæþene sawle; þær him hel onfeng. +þanon eft gewiton ealdgesiðas, +swylce geong manig of gomenwaþe +fram mere modge mearum ridan, +beornas on blancum. ðær wæs Beowulfes +mærðo mæned; monig oft gecwæð +þætte suð ne norð be sæm tweonum +ofer eormengrund oþer nænig +under swegles begong selra nære +rondhæbbendra, rices wyrðra. +Ne hie huru winedrihten wiht ne logon, +glædne Hroðgar, ac þæt wæs god cyning. +Hwilum heaþorofe hleapan leton, +on geflit faran fealwe mearas +ðær him foldwegas fægere þuhton, +cystum cuðe. Hwilum cyninges þegn, +guma gilphlæden, gidda gemyndig, +se ðe ealfela ealdgesegena +worn gemunde, word oþer fand +soðe gebunden; secg eft ongan +sið Beowulfes snyttrum styrian +ond on sped wrecan spel gerade, +wordum wrixlan. Welhwylc gecwæð +þæt he fram Sigemundes secgan hyrde +ellendædum, uncuþes fela, +Wælsinges gewin, wide siðas, +þara þe gumena bearn gearwe ne wiston, +fæhðe ond fyrena, buton Fitela mid hine, +þonne he swulces hwæt secgan wolde, +eam his nefan, swa hie a wæron +æt niða gehwam nydgesteallan; +hæfdon ealfela eotena cynnes +sweordum gesæged. Sigemunde gesprong +æfter deaðdæge dom unlytel, +syþðan wiges heard wyrm acwealde, +hordes hyrde. He under harne stan, +æþelinges bearn, ana geneðde +frecne dæde, ne wæs him Fitela mid. +hwæþre him gesælde ðæt þæt swurd þurhwod +wrætlicne wyrm, þæt hit on wealle ætstod, +dryhtlic iren; draca morðre swealt. +Hæfde aglæca elne gegongen +þæt he beahhordes brucan moste +selfes dome; sæbat gehleod, +bær on bearm scipes beorhte frætwa, +Wælses eafera. Wyrm hat gemealt. +Se wæs wreccena wide mærost +ofer werþeode, wigendra hleo, +ellendædum he þæs ær onðah, +siððan Heremodes hild sweðrode, +eafoð ond ellen. He mid Eotenum wearð +on feonda geweald forð forlacen, +snude forsended. Hine sorhwylmas +lemede to lange; he his leodum wearð, +eallum æþellingum to aldorceare; +swylce oft bemearn ærran mælum +swiðferhþes sið snotor ceorl monig, +se þe him bealwa to bote gelyfde, +þæt þæt ðeodnes bearn geþeon scolde, +fæderæþelum onfon, folc gehealdan, +hord ond hleoburh, hæleþa rice, +eþel Scyldinga. He þær eallum wearð, +mæg Higelaces, manna cynne, +freondum gefægra; hine fyren onwod. +Hwilum flitende fealwe stræte +mearum mæton. ða wæs morgenleoht +scofen ond scynded. Eode scealc monig +swiðhicgende to sele þam hean +searowundor seon; swylce self cyning +of brydbure, beahhorda weard, +tryddode tirfæst getrume micle, +cystum gecyþed, ond his cwen mid him +medostigge mæt mægþa hose. +Hroðgar maþelode he to healle geong, +stod on stapole, geseah steapne hrof, +golde fahne, ond Grendles hond: +ðisse ansyne alwealdan þanc +lungre gelimpe. Fela ic laþes gebad, +grynna æt Grendle; a mæg god wyrcan +wunder æfter wundre, wuldres hyrde. +ðæt wæs ungeara þæt ic ænigra me +weana ne wende to widan feore +bote gebidan, þonne blode fah +husa selest heorodreorig stod, +wea widscofen witena gehwylcum +ðara þe ne wendon þæt hie wideferhð +leoda landgeweorc laþum beweredon +scuccum ond scinnum. Nu scealc hafað +þurh drihtnes miht dæd gefremede ðe +we ealle ær ne meahton +snyttrum besyrwan. Hwæt, þæt secgan mæg +efne swa hwylc mægþa swa ðone magan cende +æfter gumcynnum, gyf heo gyt lyfað, +þæt hyre ealdmetod este wære +bearngebyrdo. Nu ic, Beowulf, þec, +secg betsta, me for sunu wylle +freogan on ferhþe; heald forð tela +niwe sibbe. Ne bið þe nænigra gad +worolde wilna, þe ic geweald hæbbe. +Ful oft ic for læssan lean teohhode, +hordweorþunge hnahran rince, +sæmran æt sæcce. þu þe self hafast +dædum gefremed þæt þin dom lyfað +awa to aldre. Alwalda þec +gode forgylde, swa he nu gyt dyde. +Beowulf maþelode, bearn Ecþeowes: +We þæt ellenweorc estum miclum, +feohtan fremedon, frecne geneðdon +eafoð uncuþes. Uþe ic swiþor +þæt ðu hine selfne geseon moste, +feond on frætewum fylwerigne. +Ic hine hrædlice heardan clammum +on wælbedde wriþan þohte, +þæt he for mundgripe minum scolde +licgean lifbysig, butan his lic swice. +Ic hine ne mihte, þa metod nolde, +ganges getwæman, no ic him þæs georne ætfealh, +feorhgeniðlan; wæs to foremihtig +feond on feþe. Hwæþere he his folme forlet +to lifwraþe last weardian, +earm ond eaxle. No þær ænige swa þeah +feasceaft guma frofre gebohte; +no þy leng leofað laðgeteona, +synnum geswenced, ac hyne sar hafað +mid nydgripe nearwe befongen, +balwon bendum. ðær abidan sceal +maga mane fah miclan domes, +hu him scir metod scrifan wille. +ða wæs swigra secg, sunu Eclafes, +on gylpspræce guðgeweorca, +siþðan æþelingas eorles cræfte +ofer heanne hrof hand sceawedon, +feondes fingras. Foran æghwylc wæs, +stiðra nægla gehwylc, style gelicost, +hæþenes handsporu hilderinces, +egl, unheoru. æghwylc gecwæð +þæt him heardra nan hrinan wolde +iren ærgod, þæt ðæs ahlæcan +blodge beadufolme onberan wolde. +ða wæs haten hreþe Heort innanweard +folmum gefrætwod. Fela þæra wæs, +wera ond wifa, þe þæt winreced, +gestsele gyredon. Goldfag scinon +web æfter wagum, wundorsiona fela +secga gehwylcum þara þe on swylc starað. +Wæs þæt beorhte bold tobrocen swiðe, +eal inneweard irenbendum fæst, +heorras tohlidene. Hrof ana genæs, +ealles ansund, þe se aglæca, +fyrendædum fag, on fleam gewand, +aldres orwena. No þæt yðe byð +to befleonne, fremme se þe wille, +ac gesecan sceal sawlberendra, +nyde genydde, niþða bearna, +grundbuendra gearwe stowe, +þær his lichoma legerbedde fæst +swefeþ æfter symle. þa wæs sæl ond mæl +þæt to healle gang Healfdenes sunu; +wolde self cyning symbel þicgan. +Ne gefrægen ic þa mægþe maran weorode +ymb hyra sincgyfan sel gebæran. +Bugon þa to bence blædagande, +fylle gefægon; fægere geþægon +medoful manig magas þara +swiðhicgende on sele þam hean, +Hroðgar ond Hroþulf. Heorot innan wæs +freondum afylled; nalles facenstafas +|eodscyldingas þenden fremedon. +Forgeaf þa Beowulfe bearn Healfdenes +segen gyldenne sigores to leane; +hroden hildecumbor, helm ond byrnan, +mære maðþumsweord manige gesawon +beforan beorn beran. Beowulf geþah +ful on flette; no he þære feohgyfte +for sceotendum scamigan ðorfte. +Ne gefrægn ic freondlicor feower madmas +golde gegyrede gummanna fela +in ealobence oðrum gesellan. +Ymb þæs helmes hrof heafodbeorge +wirum bewunden walu utan heold, +þæt him fela laf frecne ne meahton +scurheard sceþðan, þonne scyldfreca +ongean gramum gangan scolde. +Heht ða eorla hleo eahta mearas +fætedhleore on flet teon, +in under eoderas. þara anum stod +sadol searwum fah, since gewurþad; +þæt wæs hildesetl heahcyninges, +ðonne sweorda gelac sunu Healfdenes +efnan wolde. Næfre on ore læg +widcuþes wig, ðonne walu feollon. +Ond ða Beowulfe bega gehwæþres +eodor Ingwina onweald geteah, +wicga ond wæpna, het hine wel brucan. +Swa manlice mære þeoden, +hordweard hæleþa, heaþoræsas geald +mearum ond madmum, swa hy næfre man lyhð, +se þe secgan wile soð æfter rihte. +ða gyt æghwylcum eorla drihten +þara þe mid Beowulfe brimlade teah +on þære medubence maþðum gesealde, +yrfelafe, ond þone ænne heht +golde forgyldan, þone ðe Grendel ær +mane acwealde, swa he hyra ma wolde, +nefne him witig god wyrd forstode +ond ðæs mannes mod. Metod eallum weold +gumena cynnes, swa he nu git deð. +Forþan bið andgit æghwær selest, +ferhðes foreþanc. Fela sceal gebidan +leofes ond laþes se þe longe her +on ðyssum windagum worolde bruceð. +þær wæs sang ond sweg samod ætgædere +fore Healfdenes hildewisan, +gomenwudu greted, gid oft wrecen, +ðonne healgamen Hroþgares scop +æfter medobence mænan scolde +be Finnes eaferum, ða hie se fær begeat, +hæleð Healfdena, Hnæf Scyldinga, +in Freswæle feallan scolde. +Ne huru Hildeburh herian þorfte +Eotena treowe; unsynnum wearð +beloren leofum æt þam lindplegan, +bearnum ond broðrum; hie on gebyrd hruron, +gare wunde. þæt wæs geomuru ides. +Nalles holinga Hoces dohtor +meotodsceaft bemearn, syþðan morgen com, +ða heo under swegle geseon meahte +morþorbealo maga, þær heo ær mæste heold +worolde wynne. Wig ealle fornam +Finnes þegnas nemne feaum anum, +þæt he ne mehte on þæm meðelstede +wig Hengeste wiht gefeohtan, +ne þa wealafe wige forþringan +þeodnes ðegna. ac hig him geþingo budon, +þæt hie him oðer flet eal gerymdon, +healle ond heahsetl, þæt hie healfre geweald +wið Eotena bearn agan moston, +ond æt feohgyftum Folcwaldan sunu +dogra gehwylce Dene weorþode, +Hengestes heap hringum wenede +efne swa swiðe sincgestreonum +fættan goldes, swa he Fresena cyn +on beorsele byldan wolde. +ða hie getruwedon on twa healfa +fæste frioðuwære. Fin Hengeste +elne, unflitme aðum benemde +þæt he þa wealafe weotena dome +arum heolde, þæt ðær ænig mon +wordum ne worcum wære ne bræce, +ne þurh inwitsearo æfre gemænden +ðeah hie hira beaggyfan banan folgedon +ðeodenlease, þa him swa geþearfod wæs. +gyf þonne Frysna hwylc frecnan spræce +ðæs morþorhetes myndgiend wære, +þonne hit sweordes ecg seðan scolde. +Ad wæs geæfned ond icge gold +ahæfen of horde. Herescyldinga +betst beadorinca wæs on bæl gearu. +æt þæm ade wæs eþgesyne +swatfah syrce, swyn ealgylden, +eofer irenheard, æþeling manig +wundum awyrded; sume on wæle crungon. +Het ða Hildeburh æt Hnæfes ade +hire selfre sunu sweoloðe befæstan, +banfatu bærnan ond on bæl don +eame on eaxle. Ides gnornode, +geomrode giddum. Guðrinc astah. +Wand to wolcnum wælfyra mæst, +hlynode for hlawe; hafelan multon, +bengeato burston, ðonne blod ætspranc, +laðbite lices. Lig ealle forswealg, +gæsta gifrost, þara ðe þær guð fornam +bega folces; wæs hira blæd scacen. +Gewiton him ða wigend wica neosian, +freondum befeallen, Frysland geseon, +hamas ond heaburh. Hengest ða gyt +wælfagne winter wunode mid Finne +eal unhlitme. Eard gemunde, +þeah þe he ne meahte on mere drifan +hringedstefnan; holm storme weol, +won wið winde, winter yþe beleac +isgebinde, oþðæt oþer com +gear in geardas, swa nu gyt deð, +þa ðe syngales sele bewitiað, +wuldortorhtan weder. ða wæs winter scacen, +fæger foldan bearm. Fundode wrecca, +gist of geardum; he to gyrnwræce +swiðor þohte þonne to sælade, +gif he torngemot þurhteon mihte +þæt he Eotena bearn inne gemunde. +Swa he ne forwyrnde woroldrædenne, +þonne him Hunlafing hildeleoman, +billa selest, on bearm dyde, +þæs wæron mid Eotenum ecge cuðe. +Swylce ferhðfrecan Fin eft begeat +sweordbealo sliðen æt his selfes ham, +siþðan grimne gripe Guðlaf ond Oslaf +æfter sæsiðe, sorge, mændon, +ætwiton weana dæl; ne meahte wæfre mod +forhabban in hreþre. ða wæs heal roden +feonda feorum, swilce Fin slægen, +cyning on corþre, ond seo cwen numen. +Sceotend Scyldinga to scypon feredon +eal ingesteald eorðcyninges, +swylce hie æt Finnes ham findan meahton +sigla, searogimma. Hie on sælade +drihtlice wif to Denum feredon, +læddon to leodum. Leoð wæs asungen, +gleomannes gyd. Gamen eft astah, +beorhtode bencsweg; byrelas sealdon +win of wunderfatum. þa cwom Wealhþeo forð +gan under gyldnum beage, þær þa godan twegen +sæton suhtergefæderan; þa gyt wæs hiera sib ætgædere, +æghwylc oðrum trywe. Swylce þær Unferþ þyle +æt fotum sæt frean Scyldinga; gehwylc hiora his ferhþe treowde, +þæt he hæfde mod micel, þeah þe he his magum nære +arfæst æt ecga gelacum. Spræc ða ides Scyldinga: +Onfoh þissum fulle, freodrihten min, +sinces brytta. þu on sælum wes, +goldwine gumena, ond to Geatum spræc +mildum wordum, swa sceal man don. +Beo wið Geatas glæd, geofena gemyndig, +nean ond feorran þu nu hafast. +Me man sægde þæt þu ðe for sunu wolde +hererinc habban. Heorot is gefælsod, +beahsele beorhta; bruc þenden þu mote +manigra medo, ond þinum magum læf +folc ond rice, þonne ðu forð scyle +metodsceaft seon. Ic minne can +glædne Hroþulf, þæt he þa geogoðe wile +arum healdan, gyf þu ær þonne he, +wine Scildinga, worold oflætest; +wene ic þæt he mid gode gyldan wille +uncran eaferan, gif he þæt eal gemon, +hwæt wit to willan ond to worðmyndum +umborwesendum ær arna gefremedon. +Hwearf þa bi bence þær hyre byre wæron, +Hreðric ond Hroðmund, ond hæleþa bearn, +giogoð ætgædere; þær se goda sæt, +Beowulf Geata, be þæm gebroðrum twæm. +Him wæs ful boren ond freondlaþu +wordum bewægned, ond wunden gold +estum geeawed, earmreade twa, +hrægl ond hringas, healsbeaga mæst +þara þe ic on foldan gefrægen hæbbe. +Nænigne ic under swegle selran hyrde +hordmaððum hæleþa, syþðan Hama ætwæg +to þære byrhtan byrig Brosinga mene, +sigle ond sincfæt; searoniðas fleah +Eormenrices, geceas ecne ræd. +þone hring hæfde Higelac Geata, +nefa Swertinges, nyhstan siðe, +siðþan he under segne sinc ealgode, +wælreaf werede; hyne wyrd fornam, +syþðan he for wlenco wean ahsode, +fæhðe to Frysum. He þa frætwe wæg, +eorclanstanas ofer yða ful, +rice þeoden; he under rande gecranc. +Gehwearf þa in Francna fæþm feorh cyninges, +breostgewædu ond se beah somod; +wyrsan wigfrecan wæl reafedon +æfter guðsceare, Geata leode, +hreawic heoldon. Heal swege onfeng. +Wealhðeo maþelode, heo fore þæm werede spræc: +Bruc ðisses beages, Beowulf leofa, +hyse, mid hæle, ond þisses hrægles neot, +þeodgestreona, ond geþeoh tela, +cen þec mid cræfte ond þyssum cnyhtum wes +lara liðe; ic þe þæs lean geman. +Hafast þu gefered þæt ðe feor ond neah +ealne wideferhþ weras ehtigað, +efne swa side swa sæ bebugeð, +windgeard, weallas. Wes þenden þu lifige, +æþeling, eadig. Ic þe an tela +sincgestreona. Beo þu suna minum +dædum gedefe, dreamhealdende. +Her is æghwylc eorl oþrum getrywe, +modes milde, mandrihtne hold; +þegnas syndon geþwære, þeod ealgearo, +druncne dryhtguman doð swa ic bidde. +Eode þa to setle. þær wæs symbla cyst; +druncon win weras. Wyrd ne cuþon, +geosceaft grimme, swa hit agangen wearð +eorla manegum, syþðan æfen cwom +ond him Hroþgar gewat to hofe sinum, +rice to ræste. Reced weardode +unrim eorla, swa hie oft ær dydon. +Bencþelu beredon; hit geondbræded wearð +beddum ond bolstrum. Beorscealca sum +fus ond fæge fletræste gebeag. +Setton him to heafdon hilderandas, +bordwudu beorhtan; þær on bence wæs +ofer æþelinge yþgesene +heaþosteapa helm, hringed byrne, +þrecwudu þrymlic. Wæs þeaw hyra +þæt hie oft wæron an wig gearwe, +ge æt ham ge on herge, ge gehwæþer þara, +efne swylce mæla swylce hira mandryhtne +þearf gesælde; wæs seo þeod tilu. +Sigon þa to slæpe. Sum sare angeald +æfenræste, swa him ful oft gelamp, +siþðan goldsele Grendel warode, +unriht æfnde, oþþæt ende becwom, +swylt æfter synnum. þæt gesyne wearþ, +widcuþ werum, þætte wrecend þa gyt +lifde æfter laþum, lange þrage, +æfter guðceare. Grendles modor, +ides, aglæcwif, yrmþe gemunde, +se þe wæteregesan wunian scolde, +cealde streamas, siþðan Cain wearð +to ecgbanan angan breþer, +fæderenmæge; he þa fag gewat, +morþre gemearcod, mandream fleon, +westen warode. þanon woc fela +geosceaftgasta; wæs þæra Grendel sum, +heorowearh hetelic, se æt Heorote fand +wæccendne wer wiges bidan. +þær him aglæca ætgræpe wearð; +hwæþre he gemunde mægenes strenge, +gimfæste gife ðe him god sealde, +ond him to anwaldan are gelyfde, +frofre ond fultum; ðy he þone feond ofercwom, +gehnægde helle gast. þa he hean gewat, +dreame bedæled, deaþwic seon, +mancynnes feond, ond his modor þa gyt, +gifre ond galgmod, gegan wolde +sorhfulne sið, sunu deað wrecan. +Com þa to Heorote, ðær Hringdene +geond þæt sæld swæfun. þa ðær sona wearð +edhwyrft eorlum, siþðan inne fealh +Grendles modor. Wæs se gryre læssa +efne swa micle swa bið mægþa cræft, +wiggryre wifes, be wæpnedmen, +þonne heoru bunden, hamere geþuren, +sweord swate fah swin ofer helme +ecgum dyhttig andweard scireð. +þa wæs on healle heardecg togen +sweord ofer setlum, sidrand manig +hafen handa fæst; helm ne gemunde, +byrnan side, þa hine se broga angeat. +Heo wæs on ofste, wolde ut þanon, +feore beorgan, þa heo onfunden wæs. +Hraðe heo æþelinga anne hæfde +fæste befangen, þa heo to fenne gang. +Se wæs Hroþgare hæleþa leofost +on gesiðes had be sæm tweonum, +rice randwiga, þone ðe heo on ræste abreat, +blædfæstne beorn. Næs Beowulf ðær, +ac wæs oþer in ær geteohhod +æfter maþðumgife mærum Geate. +Hream wearð in Heorote; heo under heolfre genam +cuþe folme; cearu wæs geniwod, +geworden in wicun. Ne wæs þæt gewrixle til, +þæt hie on ba healfa bicgan scoldon +freonda feorum. þa wæs frod cyning, +har hilderinc, on hreon mode, +syðþan he aldorþegn unlyfigendne, +þone deorestan deadne wisse. +Hraþe wæs to bure Beowulf fetod, +sigoreadig secg. Samod ærdæge +eode eorla sum, æþele cempa +self mid gesiðum þær se snotera bad, +hwæþer him alwalda æfre wille +æfter weaspelle wyrpe gefremman. +Gang ða æfter flore fyrdwyrðe man +mid his handscale healwudu dynede, +þæt he þone wisan wordum nægde +frean Ingwina, frægn gif him wære +æfter neodlaðum niht getæse. +Hroðgar maþelode, helm Scyldinga: +Ne frin þu æfter sælum. Sorh is geniwod +Denigea leodum. Dead is æschere, +Yrmenlafes yldra broþor, +min runwita ond min rædbora, +eaxlgestealla, ðonne we on orlege +hafelan weredon, þonne hniton feþan, +eoferas cynsedan. Swylc scolde eorl wesan, +æþeling ærgod, swylc æschere wæs. +Wearð him on Heorote to handbanan +wælgæst wæfre; ic ne wat hwæder +atol æse wlanc eftsiðas teah, +fylle gefægnod. Heo þa fæhðe wræc +þe þu gystranniht Grendel cwealdest +þurh hæstne had heardum clammum, +forþan he to lange leode mine +wanode ond wyrde. He æt wige gecrang +ealdres scyldig, ond nu oþer cwom +mihtig manscaða, wolde hyre mæg wrecan, +ge feor hafað fæhðe gestæled +(þæs þe þincean mæg þegne monegum, +se þe æfter sincgyfan on sefan greoteþ), +hreþerbealo hearde; nu seo hand ligeð, +se þe eow welhwylcra wilna dohte. +Ic þæt londbuend, leode mine, +selerædende, secgan hyrde +þæt hie gesawon swylce twegen +micle mearcstapan moras healdan, +ellorgæstas. ðæra oðer wæs, +þæs þe hie gewislicost gewitan meahton, +idese onlicnæs; oðer earmsceapen +on weres wæstmum wræclastas træd, +næfne he wæs mara þonne ænig man oðer; +þone on geardagum Grendel nemdon +foldbuende. No hie fæder cunnon, +hwæþer him ænig wæs ær acenned +dyrnra gasta. Hie dygel lond +warigeað, wulfhleoþu, windige næssas, +frecne fengelad, ðær fyrgenstream +under næssa genipu niþer gewiteð, +flod under foldan. Nis þæt feor heonon +milgemearces þæt se mere standeð; +ofer þæm hongiað hrinde bearwas, +wudu wyrtum fæst wæter oferhelmað. +þær mæg nihta gehwæm niðwundor seon, +fyr on flode. No þæs frod leofað +gumena bearna, þæt þone grund wite; +ðeah þe hæðstapa hundum geswenced, +heorot hornum trum, holtwudu sece, +feorran geflymed, ær he feorh seleð, +aldor on ofre, ær he in wille +hafelan hydan. Nis þæt heoru stow! +þonon yðgeblond up astigeð +won to wolcnum, þonne wind styreþ, +lað gewidru, oðþæt lyft drysmaþ, +roderas reotað. Nu is se ræd gelang +eft æt þe anum. Eard git ne const, +frecne stowe, ðær þu findan miht +felasinnigne secg; sec gif þu dyrre. +Ic þe þa fæhðe feo leanige, +ealdgestreonum, swa ic ær dyde, +wundnum golde, gyf þu on weg cymest." +Beowulf maþelode, bearn Ecgþeowes: +"Ne sorga, snotor guma; selre bið æghwæm +þæt he his freond wrece, þonne he fela murne. +Ure æghwylc sceal ende gebidan +worolde lifes; wyrce se þe mote +domes ær deaþe; þæt bið drihtguman +unlifgendum æfter selest. +Aris, rices weard, uton raþe feran +Grendles magan gang sceawigan. +Ic hit þe gehate, no he on helm losaþ, +ne on foldan fæþm, ne on fyrgenholt, +ne on gyfenes grund, ga þær he wille. +ðys dogor þu geþyld hafa +weana gehwylces, swa ic þe wene to." +Ahleop ða se gomela, gode þancode, +mihtigan drihtne, þæs se man gespræc. +þa wæs Hroðgare hors gebæted, +wicg wundenfeax. Wisa fengel +geatolic gende; gumfeþa stop +lindhæbbendra. Lastas wæron +æfter waldswaþum wide gesyne, +gang ofer grundas, þær heo gegnum for +ofer myrcan mor, magoþegna bær +þone selestan sawolleasne +þara þe mid Hroðgare ham eahtode. +Ofereode þa æþelinga bearn +steap stanhliðo, stige nearwe, +enge anpaðas, uncuð gelad, +neowle næssas, nicorhusa fela. +He feara sum beforan gengde +wisra monna wong sceawian, +oþþæt he færinga fyrgenbeamas +ofer harne stan hleonian funde, +wynleasne wudu; wæter under stod +dreorig ond gedrefed. Denum eallum wæs, +winum Scyldinga, weorce on mode +to geþolianne, ðegne monegum, +oncyð eorla gehwæm, syðþan æscheres +on þam holmclife hafelan metton. +Flod blode weol (folc to sægon), +hatan heolfre. Horn stundum song +fuslic fyrdleoð. Feþa eal gesæt. +Gesawon ða æfter wætere wyrmcynnes fela, +sellice sædracan, sund cunnian, +swylce on næshleoðum nicras licgean, +ða on undernmæl oft bewitigað +sorhfulne sið on seglrade, +wyrmas ond wildeor; hie on weg hruron, +bitere ond gebolgne, bearhtm ongeaton, +guðhorn galan. Sumne Geata leod +of flanbogan feores getwæfde, +yðgewinnes, þæt him on aldre stod +herestræl hearda; he on holme wæs +sundes þe sænra, ðe hyne swylt fornam. +Hræþe wearð on yðum mid eoferspreotum +heorohocyhtum hearde genearwod, +niða genæged, ond on næs togen, +wundorlic wægbora; weras sceawedon +gryrelicne gist. Gyrede hine Beowulf +eorlgewædum, nalles for ealdre mearn. +Scolde herebyrne hondum gebroden, +sid ond searofah, sund cunnian, +seo ðe bancofan beorgan cuþe, +þæt him hildegrap hreþre ne mihte, +eorres inwitfeng, aldre gesceþðan; +ac se hwita helm hafelan werede, +se þe meregrundas mengan scolde, +secan sundgebland since geweorðad, +befongen freawrasnum, swa hine fyrndagum +worhte wæpna smið, wundrum teode, +besette swinlicum, þæt hine syðþan no +brond ne beadomecas bitan ne meahton. +Næs þæt þonne mætost mægenfultuma +þæt him on ðearfe lah ðyle Hroðgares; +wæs þæm hæftmece Hrunting nama. +þæt wæs an foran ealdgestreona; +ecg wæs iren, atertanum fah, +ahyrded heaþoswate; næfre hit æt hilde ne swac +manna ængum þara þe hit mid mundum bewand, +se ðe gryresiðas gegan dorste, +folcstede fara; næs þæt forma sið +þæt hit ellenweorc æfnan scolde. +Huru ne gemunde mago Ecglafes, +eafoþes cræftig, þæt he ær gespræc +wine druncen, þa he þæs wæpnes onlah +selran sweordfrecan. Selfa ne dorste +under yða gewin aldre geneþan, +drihtscype dreogan; þær he dome forleas, +ellenmærðum. Ne wæs þæm oðrum swa, +syðþan he hine to guðe gegyred hæfde. +Beowulf maðelode, bearn Ecgþeowes: +"Geþenc nu, se mæra maga Healfdenes, +snottra fengel, nu ic eom siðes fus, +goldwine gumena, hwæt wit geo spræcon, +gif ic æt þearfe þinre scolde +aldre linnan, þæt ðu me a wære +forðgewitenum on fæder stæle. +Wes þu mundbora minum magoþegnum, +hondgesellum, gif mec hild nime; +swylce þu ða madmas þe þu me sealdest, +Hroðgar leofa, Higelace onsend. +Mæg þonne on þæm golde ongitan Geata dryhten, +geseon sunu Hrædles, þonne he on þæt sinc starað, +þæt ic gumcystum godne funde +beaga bryttan, breac þonne moste. +Ond þu Unferð læt ealde lafe, +wrætlic wægsweord, widcuðne man +heardecg habban; ic me mid Hruntinge +dom gewyrce, oþðe mec deað nimeð." +æfter þæm wordum Wedergeata leod +efste mid elne, nalas ondsware +bidan wolde; brimwylm onfeng +hilderince. ða wæs hwil dæges +ær he þone grundwong ongytan mehte. +Sona þæt onfunde se ðe floda begong +heorogifre beheold hund missera, +grim ond grædig, þæt þær gumena sum +ælwihta eard ufan cunnode. +Grap þa togeanes, guðrinc gefeng +atolan clommum. No þy ær in gescod +halan lice; hring utan ymbbearh, +þæt heo þone fyrdhom ðurhfon ne mihte, +locene leoðosyrcan laþan fingrum. +Bær þa seo brimwylf, þa heo to botme com, +hringa þengel to hofe sinum, +swa he ne mihte, no he þæs modig wæs, +wæpna gewealdan, ac hine wundra þæs fela +swencte on sunde, sædeor monig +hildetuxum heresyrcan bræc, +ehton aglæcan. ða se eorl ongeat +þæt he in niðsele nathwylcum wæs, +þær him nænig wæter wihte ne sceþede, +ne him for hrofsele hrinan ne mehte +færgripe flodes; fyrleoht geseah, +blacne leoman, beorhte scinan. +Ongeat þa se goda grundwyrgenne, +merewif mihtig; mægenræs forgeaf +hildebille, hond sweng ne ofteah, +þæt hire on hafelan hringmæl agol +grædig guðleoð. ða se gist onfand +þæt se beadoleoma bitan nolde, +aldre sceþðan, ac seo ecg geswac +ðeodne æt þearfe; ðolode ær fela +hondgemota, helm oft gescær, +fæges fyrdhrægl; ða wæs forma sið +deorum madme, þæt his dom alæg. +Eft wæs anræd, nalas elnes læt, +mærða gemyndig mæg Hylaces. +Wearp ða wundenmæl wrættum gebunden +yrre oretta, þæt hit on eorðan læg, +stið ond stylecg; strenge getruwode, +mundgripe mægenes. Swa sceal man don, +þonne he æt guðe gegan þenceð +longsumne lof, na ymb his lif cearað. +Gefeng þa be eaxle (nalas for fæhðe mearn) +Guðgeata leod Grendles modor; +brægd þa beadwe heard, þa he gebolgen wæs, +feorhgeniðlan, þæt heo on flet gebeah. +Heo him eft hraþe andlean forgeald +grimman grapum ond him togeanes feng; +oferwearp þa werigmod wigena strengest, +feþecempa, þæt he on fylle wearð. +Ofsæt þa þone selegyst ond hyre seax geteah, +brad ond brunecg, wolde hire bearn wrecan, +angan eaferan. Him on eaxle læg +breostnet broden; þæt gebearh feore, +wið ord ond wið ecge ingang forstod. +Hæfde ða forsiðod sunu Ecgþeowes +under gynne grund, Geata cempa, +nemne him heaðobyrne helpe gefremede, +herenet hearde, ond halig god +geweold wigsigor; witig drihten, +rodera rædend, hit on ryht gesced +yðelice, syþðan he eft astod. +Geseah ða on searwum sigeeadig bil, +eald sweord eotenisc, ecgum þyhtig, +wigena weorðmynd; þæt wæs wæpna cyst, +buton hit wæs mare ðonne ænig mon oðer +to beadulace ætberan meahte, +god ond geatolic, giganta geweorc. +He gefeng þa fetelhilt, freca Scyldinga +hreoh ond heorogrim hringmæl gebrægd, +aldres orwena, yrringa sloh, +þæt hire wið halse heard grapode, +banhringas bræc. Bil eal ðurhwod +fægne flæschoman; heo on flet gecrong. +Sweord wæs swatig, secg weorce gefeh. +Lixte se leoma, leoht inne stod, +efne swa of hefene hadre scineð +rodores candel. He æfter recede wlat; +hwearf þa be wealle, wæpen hafenade +heard be hiltum Higelaces ðegn, +yrre ond anræd. Næs seo ecg fracod +hilderince, ac he hraþe wolde +Grendle forgyldan guðræsa fela +ðara þe he geworhte to Westdenum +oftor micle ðonne on ænne sið, +þonne he Hroðgares heorðgeneatas +sloh on sweofote, slæpende fræt +folces Denigea fyftyne men +ond oðer swylc ut offerede, +laðlicu lac. He him þæs lean forgeald, +reþe cempa, to ðæs þe he on ræste geseah +guðwerigne Grendel licgan +aldorleasne, swa him ær gescod +hild æt Heorote. Hra wide sprong, +syþðan he æfter deaðe drepe þrowade, +heorosweng heardne, ond hine þa heafde becearf. +Sona þæt gesawon snottre ceorlas, +þa ðe mid Hroðgare on holm wliton, +þæt wæs yðgeblond eal gemenged, +brim blode fah. Blondenfeaxe, +gomele ymb godne, ongeador spræcon +þæt hig þæs æðelinges eft ne wendon +þæt he sigehreðig secean come +mærne þeoden; þa ðæs monige gewearð +þæt hine seo brimwylf abroten hæfde. +ða com non dæges. Næs ofgeafon +hwate Scyldingas; gewat him ham þonon +goldwine gumena. Gistas setan +modes seoce ond on mere staredon, +wiston ond ne wendon þæt hie heora winedrihten +selfne gesawon. þa þæt sweord ongan +æfter heaþoswate hildegicelum, +wigbil wanian. þæt wæs wundra sum, +þæt hit eal gemealt ise gelicost, +ðonne forstes bend fæder onlæteð, +onwindeð wælrapas, se geweald hafað +sæla ond mæla; þæt is soð metod. +Ne nom he in þæm wicum, Wedergeata leod, +maðmæhta ma, þeh he þær monige geseah, +buton þone hafelan ond þa hilt somod +since fage. Sweord ær gemealt, +forbarn brodenmæl; wæs þæt blod to þæs hat, +ættren ellorgæst se þær inne swealt. +Sona wæs on sunde se þe ær æt sæcce gebad +wighryre wraðra, wæter up þurhdeaf. +Wæron yðgebland eal gefælsod, +eacne eardas, þa se ellorgast +oflet lifdagas ond þas lænan gesceaft. +Com þa to lande lidmanna helm +swiðmod swymman; sælace gefeah, +mægenbyrþenne þara þe he him mid hæfde. +Eodon him þa togeanes, gode þancodon, +ðryðlic þegna heap, þeodnes gefegon, +þæs þe hi hyne gesundne geseon moston. +ða wæs of þæm hroran helm ond byrne +lungre alysed. Lagu drusade, +wæter under wolcnum, wældreore fag. +Ferdon forð þonon feþelastum +ferhþum fægne, foldweg mæton, +cuþe stræte. Cyningbalde men +from þæm holmclife hafelan bæron +earfoðlice heora æghwæþrum, +felamodigra; feower scoldon +on þæm wælstenge weorcum geferian +to þæm goldsele Grendles heafod, +oþðæt semninga to sele comon +frome fyrdhwate feowertyne +Geata gongan; gumdryhten mid +modig on gemonge meodowongas træd. +ða com in gan ealdor ðegna, +dædcene mon dome gewurþad, +hæle hildedeor, Hroðgar gretan. +þa wæs be feaxe on flet boren +Grendles heafod, þær guman druncon, +egeslic for eorlum ond þære idese mid, +wliteseon wrætlic; weras on sawon. +Beowulf maþelode, bearn Ecgþeowes: +"Hwæt! we þe þas sælac, sunu Healfdenes, +leod Scyldinga, lustum brohton +tires to tacne, þe þu her to locast. +Ic þæt unsofte ealdre gedigde +wigge under wætere, weorc geneþde +earfoðlice; ætrihte wæs +guð getwæfed, nymðe mec god scylde. +Ne meahte ic æt hilde mid Hruntinge +wiht gewyrcan, þeah þæt wæpen duge; +ac me geuðe ylda waldend +þæt ic on wage geseah wlitig hangian +eald sweord eacen (oftost wisode +winigea leasum), þæt ic ðy wæpne gebræd. +Ofsloh ða æt þære sæcce, þa me sæl ageald, +huses hyrdas. þa þæt hildebil +forbarn brogdenmæl, swa þæt blod gesprang, +hatost heaþoswata. Ic þæt hilt þanan +feondum ætferede, fyrendæda wræc, +deaðcwealm Denigea, swa hit gedefe wæs. +Ic hit þe þonne gehate, þæt þu on Heorote most +sorhleas swefan mid þinra secga gedryht +ond þegna gehwylc þinra leoda, +duguðe ond iogoþe, þæt þu him ondrædan ne þearft, +þeoden Scyldinga, on þa healfe, +aldorbealu eorlum, swa þu ær dydest." +ða wæs gylden hilt gamelum rince, +harum hildfruman, on hand gyfen, +enta ærgeweorc; hit on æht gehwearf +æfter deofla hryre Denigea frean, +wundorsmiþa geweorc, ond þa þas worold ofgeaf +gromheort guma, godes ondsaca, +morðres scyldig, ond his modor eac, +on geweald gehwearf woroldcyninga +ðæm selestan be sæm tweonum +ðara þe on Scedenigge sceattas dælde. +Hroðgar maðelode, hylt sceawode, +ealde lafe, on ðæm wæs or writen +fyrngewinnes, syðþan flod ofsloh, +gifen geotende, giganta cyn +(frecne geferdon); þæt wæs fremde þeod +ecean dryhtne; him þæs endelean +þurh wæteres wylm waldend sealde. +Swa wæs on ðæm scennum sciran goldes +þurh runstafas rihte gemearcod, +geseted ond gesæd hwam þæt sweord geworht, +irena cyst, ærest wære, +wreoþenhilt ond wyrmfah. ða se wisa spræc +sunu Healfdenes (swigedon ealle): +"þæt, la, mæg secgan se þe soð ond riht +fremeð on folce, feor eal gemon, +eald OEweard, þæt ðes eorl wære +geboren betera! Blæd is aræred +geond widwegas, wine min Beowulf, +ðin ofer þeoda gehwylce. Eal þu hit geþyldum healdest, +mægen mid modes snyttrum. Ic þe sceal mine gelæstan +freode, swa wit furðum spræcon. ðu scealt to frofre weorþan +eal langtwidig leodum þinum, +hæleðum to helpe. Ne wearð Heremod swa +eaforum Ecgwelan, Arscyldingum; +ne geweox he him to willan, ac to wælfealle +ond to deaðcwalum Deniga leodum; +breat bolgenmod beodgeneatas, +eaxlgesteallan, oþþæt he ana hwearf, +mære þeoden, mondreamum from. +ðeah þe hine mihtig god mægenes wynnum, +eafeþum stepte, ofer ealle men +forð gefremede, hwæþere him on ferhþe greow +breosthord blodreow. Nallas beagas geaf +Denum æfter dome; dreamleas gebad +þæt he þæs gewinnes weorc þrowade, +leodbealo longsum. ðu þe lær be þon, +gumcyste ongit; ic þis gid be þe +awræc wintrum frod. Wundor is to secganne +hu mihtig god manna cynne +þurh sidne sefan snyttru bryttað, +eard ond eorlscipe; he ah ealra geweald. +Hwilum he on lufan læteð hworfan +monnes modgeþonc mæran cynnes, +seleð him on eþle eorþan wynne +to healdanne, hleoburh wera, +gedeð him swa gewealdene worolde dælas, +side rice, þæt he his selfa ne mæg +for his unsnyttrum ende geþencean. +Wunað he on wiste; no hine wiht dweleð +adl ne yldo, ne him inwitsorh +on sefan sweorceð, ne gesacu ohwær +ecghete eoweð, ac him eal worold +wendeð on willan (he þæt wyrse ne con), +oðþæt him on innan oferhygda dæl +weaxeð ond wridað. þonne se weard swefeð, +sawele hyrde; bið se slæp to fæst, +bisgum gebunden, bona swiðe neah, +se þe of flanbogan fyrenum sceoteð. +þonne bið on hreþre under helm drepen +biteran stræle (him bebeorgan ne con), +wom wundorbebodum wergan gastes; +þinceð him to lytel þæt he lange heold, +gytsað gromhydig, nallas on gylp seleð +fædde beagas, ond he þa forðgesceaft +forgyteð ond forgymeð, þæs þe him ær god sealde, +wuldres waldend, weorðmynda dæl. +Hit on endestæf eft gelimpeð +þæt se lichoma læne gedreoseð, +fæge gefealleð; fehð oþer to, +se þe unmurnlice madmas dæleþ, +eorles ærgestreon, egesan ne gymeð. +Bebeorh þe ðone bealonið, Beowulf leofa, +secg betsta, ond þe þæt selre geceos, +ece rædas; oferhyda ne gym, +mære cempa. Nu is þines mægnes blæd +ane hwile. Eft sona bið +þæt þec adl oððe ecg eafoþes getwæfeð, +oððe fyres feng, oððe flodes wylm, +oððe gripe meces, oððe gares fliht, +oððe atol yldo; oððe eagena bearhtm +forsiteð ond forsworceð; semninga bið +þæt ðec, dryhtguma, deað oferswyðeð. +Swa ic Hringdena hund missera +weold under wolcnum ond hig wigge beleac +manigum mægþa geond þysne middangeard, +æscum ond ecgum, þæt ic me ænigne +under swegles begong gesacan ne tealde. +Hwæt, me þæs on eþle edwenden cwom, +gyrn æfter gomene, seoþðan Grendel wearð, +ealdgewinna, ingenga min; +ic þære socne singales wæg +modceare micle. þæs sig metode þanc, +ecean dryhtne, þæs ðe ic on aldre gebad +þæt ic on þone hafelan heorodreorigne +ofer ealdgewin eagum starige! +Ga nu to setle, symbelwynne dreoh +wigge weorþad; unc sceal worn fela +maþma gemænra, siþðan morgen bið." +Geat wæs glædmod, geong sona to +setles neosan, swa se snottra heht. +þa wæs eft swa ær ellenrofum +fletsittendum fægere gereorded +niowan stefne. Nihthelm geswearc +deorc ofer dryhtgumum. Duguð eal aras. +Wolde blondenfeax beddes neosan, +gamela Scylding. Geat unigmetes wel, +rofne randwigan, restan lyste; +sona him seleþegn siðes wergum, +feorrancundum, forð wisade, +se for andrysnum ealle beweotede +þegnes þearfe, swylce þy dogore +heaþoliðende habban scoldon. +Reste hine þa rumheort; reced hliuade +geap ond goldfah; gæst inne swæf +oþþæt hrefn blaca heofones wynne +bliðheort bodode. ða com beorht scacan +scaþan onetton, +wæron æþelingas eft to leodum +fuse to farenne; wolde feor þanon +cuma collenferhð ceoles neosan. +Heht þa se hearda Hrunting beran +sunu Ecglafes, heht his sweord niman, +leoflic iren; sægde him þæs leanes þanc, +cwæð, he þone guðwine godne tealde, +wigcræftigne, nales wordum log +meces ecge; þæt wæs modig secg. +Ond þa siðfrome, searwum gearwe +wigend wæron; eode weorð Denum +æþeling to yppan, þær se oþer wæs, +hæle hildedeor Hroðgar grette. +Beowulf maþelode, bearn Ecgþeowes: +"Nu we sæliðend secgan wyllað, +feorran cumene, þæt we fundiaþ +Higelac secan. Wæron her tela +willum bewenede; þu us wel dohtest. +Gif ic þonne on eorþan owihte mæg +þinre modlufan maran tilian, +gumena dryhten, ðonne ic gyt dyde, +guðgeweorca, ic beo gearo sona. +Gif ic þæt gefricge ofer floda begang, +þæt þec ymbsittend egesan þywað, +swa þec hetende hwilum dydon, +ic ðe þusenda þegna bringe, +hæleþa to helpe. Ic on Higelac wat, +Geata dryhten, þeah ðe he geong sy, +folces hyrde, þæt he mec fremman wile +wordum ond worcum, þæt ic þe wel herige +ond þe to geoce garholt bere, +mægenes fultum, þær ðe bið manna þearf. +Gif him þonne Hreþric to hofum Geata +geþingeð, þeodnes bearn, he mæg þær fela +freonda findan; feorcyþðe beoð +selran gesohte þæm þe him selfa deah." +Hroðgar maþelode him on ondsware: +"þe þa wordcwydas wigtig drihten +on sefan sende; ne hyrde ic snotorlicor +on swa geongum feore guman þingian. +þu eart mægenes strang ond on mode frod, +wis wordcwida. Wen ic talige, +gif þæt gegangeð, þæt ðe gar nymeð, +hild heorugrimme, Hreþles eaferan, +adl oþðe iren ealdor ðinne, +folces hyrde, ond þu þin feorh hafast, +þæt þe Sægeatas selran næbben +to geceosenne cyning ænigne, +hordweard hæleþa, gyf þu healdan wylt +maga rice. Me þin modsefa +licað leng swa wel, leofa Beowulf. +Hafast þu gefered þæt þam folcum sceal, +Geata leodum ond Gardenum, +sib gemæne, ond sacu restan, +inwitniþas, þe hie ær drugon, +wesan, þenden ic wealde widan rices, +maþmas gemæne, manig oþerne +godum gegretan ofer ganotes bæð; +sceal hringnaca ofer heafu bringan +lac ond luftacen. Ic þa leode wat +ge wið feond ge wið freond fæste geworhte, +æghwæs untæle ealde wisan." +ða git him eorla hleo inne gesealde, +mago Healfdenes, maþmas [XII]; +het hine mid þæm lacum leode swæse +secean on gesyntum, snude eft cuman. +Gecyste þa cyning æþelum god, +þeoden Scyldinga, ðegn betstan +ond be healse genam; hruron him tearas, +blondenfeaxum. Him wæs bega wen, +ealdum infrodum, oþres swiðor, +þæt hie seoððan no geseon moston, +modige on meþle. Wæs him se man to þon leof +þæt he þone breostwylm forberan ne mehte, +ac him on hreþre hygebendum fæst +æfter deorum men dyrne langað +beorn wið blode. Him Beowulf þanan, +guðrinc goldwlanc, græsmoldan træd +since hremig; sægenga bad +agendfrean, se þe on ancre rad. +þa wæs on gange gifu Hroðgares +oft geæhted; þæt wæs an cyning, +æghwæs orleahtre, oþþæt hine yldo benam +mægenes wynnum, se þe oft manegum scod. +Cwom þa to flode felamodigra, +hægstealdra heap, hringnet bæron, +locene leoðosyrcan. Landweard onfand +eftsið eorla, swa he ær dyde; +no he mid hearme of hliðes nosan +gæstas grette, ac him togeanes rad, +cwæð þæt wilcuman Wedera leodum +scaþan scirhame to scipe foron. +þa wæs on sande sægeap naca +hladen herewædum, hringedstefna, +mearum ond maðmum; mæst hlifade +ofer Hroðgares hordgestreonum. +He þæm batwearde bunden golde +swurd gesealde, þæt he syðþan wæs +on meodubence maþme þy weorþra, +yrfelafe. Gewat him on naca +drefan deop wæter, Dena land ofgeaf. +þa wæs be mæste merehrægla sum, +segl sale fæst; sundwudu þunede. +No þær wegflotan wind ofer yðum +siðes getwæfde; sægenga for, +fleat famigheals forð ofer yðe, +bundenstefna ofer brimstreamas, +þæt hie Geata clifu ongitan meahton, +cuþe næssas. Ceol up geþrang +lyftgeswenced, on lande stod. +Hraþe wæs æt holme hyðweard geara, +se þe ær lange tid leofra manna +fus æt faroðe feor wlatode; +sælde to sande sidfæþme scip, +oncerbendum fæst, þy læs hym yþa ðrym +wudu wynsuman forwrecan meahte. +Het þa up beran æþelinga gestreon, +frætwe ond fætgold; næs him feor þanon +to gesecanne sinces bryttan, +Higelac Hreþling, þær æt ham wunað +selfa mid gesiðum sæwealle neah. +Bold wæs betlic, bregorof cyning, +heah in healle, Hygd swiðe geong, +wis, welþungen, þeah ðe wintra lyt +under burhlocan gebiden hæbbe, +Hæreþes dohtor; næs hio hnah swa þeah, +ne to gneað gifa Geata leodum, +maþmgestreona. Mod þryðo wæg, +fremu folces cwen, firen ondrysne. +Nænig þæt dorste deor geneþan +swæsra gesiða, nefne sinfrea, +þæt hire an dæges eagum starede, +ac him wælbende weotode tealde +handgewriþene; hraþe seoþðan wæs +æfter mundgripe mece geþinged, +þæt hit sceadenmæl scyran moste, +cwealmbealu cyðan. Ne bið swylc cwenlic þeaw +idese to efnanne, þeah ðe hio ænlicu sy, +þætte freoðuwebbe feores onsæce +æfter ligetorne leofne mannan. +Huru þæt onhohsnode Hemminges mæg; +ealodrincende oðer sædan, +þæt hio leodbealewa læs gefremede, +inwitniða, syððan ærest wearð +gyfen goldhroden geongum cempan, +æðelum diore, syððan hio Offan flet +ofer fealone flod be fæder lare +siðe gesohte; ðær hio syððan well +in gumstole, gode, mære, +lifgesceafta lifigende breac, +hiold heahlufan wið hæleþa brego, +ealles moncynnes mine gefræge +þone selestan bi sæm tweonum, +eormencynnes. Forðam Offa wæs +geofum ond guðum, garcene man, +wide geweorðod, wisdome heold +eðel sinne; þonon Eomer woc +hæleðum to helpe, Hemminges mæg, +nefa Garmundes, niða cræftig. +Gewat him ða se hearda mid his hondscole +sylf æfter sande sæwong tredan, +wide waroðas. Woruldcandel scan, +sigel suðan fus. Hi sið drugon, +elne geeodon, to ðæs ðe eorla hleo, +bonan Ongenþeoes burgum in innan, +geongne guðcyning godne gefrunon +hringas dælan. Higelace wæs +sið Beowulfes snude gecyðed, +þæt ðær on worðig wigendra hleo, +lindgestealla, lifigende cwom, +heaðolaces hal to hofe gongan. +Hraðe wæs gerymed, swa se rica bebead, +feðegestum flet innanweard. +Gesæt þa wið sylfne se ða sæcce genæs, +mæg wið mæge, syððan mandryhten +þurh hleoðorcwyde holdne gegrette, +meaglum wordum. Meoduscencum hwearf +geond þæt healreced Hæreðes dohtor, +lufode ða leode, liðwæge bær +hæleðum to handa. Higelac ongan +sinne geseldan in sele þam hean +fægre fricgcean (hyne fyrwet bræc, +hwylce Sægeata siðas wæron): +"Hu lomp eow on lade, leofa Biowulf, +þa ðu færinga feorr gehogodest +sæcce secean ofer sealt wæter, +hilde to Hiorote? Ac ðu Hroðgare +widcuðne wean wihte gebettest, +mærum ðeodne? Ic ðæs modceare +sorhwylmum seað, siðe ne truwode +leofes mannes; ic ðe lange bæd +þæt ðu þone wælgæst wihte ne grette, +lete Suðdene sylfe geweorðan +guðe wið Grendel. Gode ic þanc secge +þæs ðe ic ðe gesundne geseon moste." +Biowulf maðelode, bearn Ecgðioes: +"þæt is undyrne, dryhten Higelac, +micel gemeting, monegum fira, +hwylc orleghwil uncer Grendles +wearð on ðam wange, þær he worna fela +Sigescyldingum sorge gefremede, +yrmðe to aldre. Ic ðæt eall gewræc, +swa begylpan ne þearf Grendeles maga +ænig ofer eorðan uhthlem þone, +se ðe lengest leofað laðan cynnes, +facne bifongen. Ic ðær furðum cwom +to ðam hringsele Hroðgar gretan; +sona me se mæra mago Healfdenes, +syððan he modsefan minne cuðe, +wið his sylfes sunu setl getæhte. +Weorod wæs on wynne; ne seah ic widan feorh +under heofones hwealf healsittendra +medudream maran. Hwilum mæru cwen, +friðusibb folca, flet eall geondhwearf, +bædde byre geonge; oft hio beahwriðan +secge sealde, ær hie to setle geong. +Hwilum for duguðe dohtor Hroðgares +eorlum on ende ealuwæge bær; +þa ic Freaware fletsittende +nemnan hyrde, þær hio nægled sinc +hæleðum sealde. Sio gehaten is, +geong, goldhroden, gladum suna Frodan; +hafað þæs geworden wine Scyldinga, +rices hyrde, ond þæt ræd talað, +þæt he mid ðy wife wælfæhða dæl, +sæcca gesette. Oft seldan hwær +æfter leodhryre lytle hwile +bongar bugeð, þeah seo bryd duge! +Mæg þæs þonne ofþyncan ðeodne Heaðobeardna +ond þegna gehwam þara leoda, +þonne he mid fæmnan on flett gæð, +dryhtbearn Dena, duguða biwenede; +on him gladiað gomelra lafe, +heard ond hringmæl Heaðabeardna gestreon +þenden hie ðam wæpnum wealdan moston, +oððæt hie forlæddan to ðam lindplegan +swæse gesiðas ond hyra sylfra feorh. +þonne cwið æt beore se ðe beah gesyhð, +eald æscwiga, se ðe eall geman, +garcwealm gumena (him bið grim sefa), +onginneð geomormod geongum cempan +þurh hreðra gehygd higes cunnian, +wigbealu weccean, ond þæt word acwyð: +'Meaht ðu, min wine, mece gecnawan +þone þin fæder to gefeohte bær +under heregriman hindeman siðe, +dyre iren, þær hyne Dene slogon, +weoldon wælstowe, syððan Wiðergyld læg, +æfter hæleþa hryre, hwate Scyldungas? +Nu her þara banena byre nathwylces +frætwum hremig on flet gæð, +morðres gylpeð, ond þone maðþum byreð, +þone þe ðu mid rihte rædan sceoldest.' +Manað swa ond myndgað mæla gehwylce +sarum wordum, oððæt sæl cymeð +þæt se fæmnan þegn fore fæder dædum +æfter billes bite blodfag swefeð, +ealdres scyldig; him se oðer þonan +losað lifigende, con him land geare. +þonne bioð abrocene on ba healfe +aðsweord eorla; syððan Ingelde +weallað wælniðas, ond him wiflufan +æfter cearwælmum colran weorðað. +þy ic Heaðobeardna hyldo ne telge, +dryhtsibbe dæl Denum unfæcne, +freondscipe fæstne. Ic sceal forð sprecan +gen ymbe Grendel, þæt ðu geare cunne, +sinces brytta, to hwan syððan wearð +hondræs hæleða. Syððan heofones gim +glad ofer grundas, gæst yrre cwom, +eatol, æfengrom, user neosan, +ðær we gesunde sæl weardodon. +þær wæs Hondscio hild onsæge, +feorhbealu fægum; he fyrmest læg, +gyrded cempa; him Grendel wearð, +mærum maguþegne to muðbonan, +leofes mannes lic eall forswealg. +No ðy ær ut ða gen idelhende +bona blodigtoð, bealewa gemyndig, +of ðam goldsele gongan wolde, +ac he mægnes rof min costode, +grapode gearofolm. Glof hangode +sid ond syllic, searobendum fæst; +sio wæs orðoncum eall gegyrwed +deofles cræftum ond dracan fellum. +He mec þær on innan unsynnigne, +dior dædfruma, gedon wolde +manigra sumne; hyt ne mihte swa, +syððan ic on yrre uppriht astod. +To lang ys to reccenne hu ic ðam leodsceaðan +yfla gehwylces ondlean forgeald; +þær ic, þeoden min, þine leode +weorðode weorcum. He on weg losade, +lytle hwile lifwynna breac; +hwæþre him sio swiðre swaðe weardade +hand on Hiorte, ond he hean ðonan +modes geomor meregrund gefeoll. +Me þone wælræs wine Scildunga +fættan golde fela leanode, +manegum maðmum, syððan mergen com +ond we to symble geseten hæfdon. +þær wæs gidd ond gleo. Gomela Scilding, +felafricgende, feorran rehte; +hwilum hildedeor hearpan wynne, +gomenwudu grette, hwilum gyd awræc +soð ond sarlic, hwilum syllic spell +rehte æfter rihte rumheort cyning. +Hwilum eft ongan, eldo gebunden, +gomel guðwiga gioguðe cwiðan, +hildestrengo; hreðer inne weoll, +þonne he wintrum frod worn gemunde. +Swa we þær inne ondlangne dæg +niode naman, oððæt niht becwom +oðer to yldum. þa wæs eft hraðe +gearo gyrnwræce Grendeles modor, +siðode sorhfull; sunu deað fornam, +wighete Wedra. Wif unhyre +hyre bearn gewræc, beorn acwealde +ellenlice; þær wæs æschere, +frodan fyrnwitan, feorh uðgenge. +Noðer hy hine ne moston, syððan mergen cwom, +deaðwerigne, Denia leode, +bronde forbærnan, ne on bęl hladan +leofne mannan; hio þæt lic ætbær +feondes fæðmum under firgenstream. +þæt wæs Hroðgare hreowa tornost +þara þe leodfruman lange begeate. +þa se ðeoden mec ðine life +healsode hreohmod, þæt ic on holma geþring +eorlscipe efnde, ealdre geneðde, +mærðo fremede; he me mede gehet. +Ic ða ðæs wælmes, þe is wide cuð, +grimne gryrelicne grundhyrde fond; +þær unc hwile wæs hand gemæne, +holm heolfre weoll, ond ic heafde becearf +in ðam guðsele Grendeles modor +eacnum ecgum, unsofte þonan +feorh oðferede. Næs ic fæge þa gyt, +ac me eorla hleo eft gesealde +maðma menigeo, maga Healfdenes. +Swa se ðeodkyning þeawum lyfde. +Nealles ic ðam leanum forloren hæfde, +mægnes mede, ac he me maðmas geaf, +sunu Healfdenes, on minne sylfes dom; +ða ic ðe, beorncyning, bringan wylle, +estum geywan. Gen is eall æt ðe +lissa gelong; ic lyt hafo +heafodmaga nefne, Hygelac, ðec." +Het ða in beran eaforheafodsegn, +heaðosteapne helm, hare byrnan, +guðsweord geatolic, gyd æfter wræc: +"Me ðis hildesceorp Hroðgar sealde, +snotra fengel, sume worde het +þæt ic his ærest ðe est gesægde; +cwæð þæt hyt hæfde Hiorogar cyning, +leod Scyldunga lange hwile; +no ðy ær suna sinum syllan wolde, +hwatum Heorowearde, þeah he him hold wære, +breostgewædu. Bruc ealles well!" +Hyrde ic þæt þam frætwum feower mearas +lungre, gelice, last weardode, +æppelfealuwe; he him est geteah +meara ond maðma. Swa sceal mæg don, +nealles inwitnet oðrum bregdon +dyrnum cræfte, deað renian +hondgesteallan. Hygelace wæs, +niða heardum, nefa swyðe hold, +ond gehwæðer oðrum hroþra gemyndig. +Hyrde ic þæt he ðone healsbeah Hygde gesealde, +wrætlicne wundurmaððum, ðone þe him Wealhðeo geaf, +ðeodnes dohtor, þrio wicg somod +swancor ond sadolbeorht; hyre syððan wæs +æfter beahðege breost geweorðod. +Swa bealdode bearn Ecgðeowes, +guma guðum cuð, godum dædum, +dreah æfter dome, nealles druncne slog +heorðgeneatas; næs him hreoh sefa, +ac he mancynnes mæste cræfte +ginfæstan gife, þe him god sealde, +heold hildedeor. Hean wæs lange, +swa hyne Geata bearn godne ne tealdon, +ne hyne on medobence micles wyrðne +drihten Wedera gedon wolde; +swyðe wendon þæt he sleac wære, +æðeling unfrom. Edwenden cwom +tireadigum menn torna gehwylces. +Het ða eorla hleo in gefetian, +heaðorof cyning, Hreðles lafe +golde gegyrede; næs mid Geatum ða +sincmaðþum selra on sweordes had; +þæt he on Biowulfes bearm alegde +ond him gesealde seofan þusendo, +bold ond bregostol. Him wæs bam samod +on ðam leodscipe lond gecynde, +eard, eðelriht, oðrum swiðor +side rice þam ðær selra wæs. +Eft þæt geiode ufaran dogrum +hildehlæmmum, syððan Hygelac læg +ond Heardrede hildemeceas +under bordhreoðan to bonan wurdon, +ða hyne gesohtan on sigeþeode +hearde hildefrecan, Heaðoscilfingas, +niða genægdan nefan Hererices, +syððan Beowulfe brade rice +on hand gehwearf; he geheold tela +fiftig wintra (wæs ða frod cyning, +eald eþelweard), oððæt an ongan +deorcum nihtum draca ricsian, +se ðe on heaum hofe hord beweotode, +stanbeorh steapne; stig under læg, +eldum uncuð. þær on innan giong +niða nathwylc, se ðe neh gefeng +hæðnum horde, hond [...], +since fahne. He þæt syððan [...], +þeah ðe he slæpende besyred wurde +þeofes cræfte; þæt sie ðiod onfand, +bufolc beorna, þæt he gebolgen wæs. +Nealles mid gewealdum wyrmhord abræc +sylfes willum, se ðe him sare gesceod, +ac for þreanedlan þeow nathwylces +hæleða bearna heteswengeas fleah, +ærnes þearfa, ond ðær inne fealh, +secg synbysig, sona onfunde +þæt þær ðam gyste gryrebroga stod; +hwæðre earmsceapen +sceapen +þa hyne se fær begeat. +Sincfæt [...]; þær wæs swylcra fela +in ðam eorðhuse ærgestreona, +swa hy on geardagum gumena nathwylc, +eormenlafe æþelan cynnes, +þanchycgende þær gehydde, +deore maðmas. Ealle hie deað fornam +ærran mælum, ond se an ða gen +leoda duguðe, se ðær lengest hwearf, +weard winegeomor, wende þæs ylcan, +þæt he lytel fæc longgestreona +brucan moste. Beorh eallgearo +wunode on wonge wæteryðum neah, +niwe be næsse, nearocræftum fæst. +þær on innan bær eorlgestreona +hringa hyrde hordwyrðne dæl, +fættan goldes, fea worda cwæð: +"Heald þu nu, hruse, nu hæleð ne moston, +eorla æhte! Hwæt, hyt ær on ðe +gode begeaton. Guðdeað fornam, +feorhbealo frecne, fyra gehwylcne +leoda minra, þara ðe þis lif ofgeaf, +gesawon seledream. Ic nah hwa sweord wege +oððe feormie fæted wæge, +dryncfæt deore; duguð ellor sceoc. +Sceal se hearda helm hyrsted golde +fætum befeallen; feormynd swefað, +þa ðe beadogriman bywan sceoldon, +ge swylce seo herepad, sio æt hilde gebad +ofer borda gebræc bite irena, +brosnað æfter beorne. Ne mæg byrnan hring +æfter wigfruman wide feran, +hæleðum be healfe. Næs hearpan wyn, +gomen gleobeames, ne god hafoc +geond sæl swingeð, ne se swifta mearh +burhstede beateð. Bealocwealm hafað +fela feorhcynna forð onsended!" +Swa giomormod giohðo mænde +an æfter eallum, unbliðe hwearf +dæges ond nihtes, oððæt deaðes wylm +hran æt heortan. Hordwynne fond +eald uhtsceaða opene standan, +se ðe byrnende biorgas seceð, +nacod niðdraca, nihtes fleogeð +fyre befangen; hyne foldbuend +swiðe ondrædað. He gesecean sceall +hord on hrusan, þær he hæðen gold +warað wintrum frod, ne byð him wihte ðy sel. +Swa se ðeodsceaða þreo hund wintra +heold on hrusan hordærna sum, +eacencræftig, oððæt hyne an abealch +mon on mode; mandryhtne bær +fæted wæge, frioðowære bæd +hlaford sinne. ða wæs hord rasod, +onboren beaga hord, bene getiðad +feasceaftum men. Frea sceawode +fira fyrngeweorc forman siðe. +þa se wyrm onwoc, wroht wæs geniwad; +stonc ða æfter stane, stearcheort onfand +feondes fotlast; he to forð gestop +dyrnan cræfte dracan heafde neah. +Swa mæg unfæge eaðe gedigan +wean ond wræcsið, se ðe waldendes +hyldo gehealdeþ! Hordweard sohte +georne æfter grunde, wolde guman findan, +þone þe him on sweofote sare geteode, +hat ond hreohmod hlæw oft ymbehwearf +ealne utanweardne, ne ðær ænig mon +on þære westenne; hwæðre wiges gefeh, +beaduwe weorces, hwilum on beorh æthwearf, +sincfæt sohte. He þæt sona onfand +ðæt hæfde gumena sum goldes gefandod, +heahgestreona. Hordweard onbad +earfoðlice oððæt æfen cwom; +wæs ða gebolgen beorges hyrde, +wolde se laða lige forgyldan +drincfæt dyre. þa wæs dæg sceacen +wyrme on willan; no on wealle læg, +bidan wolde, ac mid bæle for, +fyre gefysed. Wæs se fruma egeslic +leodum on lande, swa hyt lungre wearð +on hyra sincgifan sare geendod. +ða se gæst ongan gledum spiwan, +beorht hofu bærnan; bryneleoma stod +eldum on andan. No ðær aht cwices +lað lyftfloga læfan wolde. +Wæs þæs wyrmes wig wide gesyne, +nearofages nið nean ond feorran, +hu se guðsceaða Geata leode +hatode ond hynde; hord eft gesceat, +dryhtsele dyrnne, ær dæges hwile. +Hæfde landwara lige befangen, +bæle ond bronde, beorges getruwode, +wiges ond wealles; him seo wen geleah. +þa wæs Biowulfe broga gecyðed +snude to soðe, þæt his sylfes ham, +bolda selest, brynewylmum mealt, +gifstol Geata. þæt ðam godan wæs +hreow on hreðre, hygesorga mæst; +wende se wisa þæt he wealdende +ofer ealde riht, ecean dryhtne, +bitre gebulge. Breost innan weoll +þeostrum geþoncum, swa him geþywe ne wæs. +Hæfde ligdraca leoda fæsten, +ealond utan, eorðweard ðone +gledum forgrunden; him ðæs guðkyning, +Wedera þioden, wræce leornode. +Heht him þa gewyrcean wigendra hleo +eallirenne, eorla dryhten, +wigbord wrætlic; wisse he gearwe +þæt him holtwudu helpan ne meahte, +lind wið lige. Sceolde lændaga +æþeling ærgod ende gebidan, +worulde lifes, ond se wyrm somod, +þeah ðe hordwelan heolde lange. +Oferhogode ða hringa fengel +þæt he þone widflogan weorode gesohte, +sidan herge; no he him þa sæcce ondred, +ne him þæs wyrmes wig for wiht dyde, +eafoð ond ellen, forðon he ær fela +nearo neðende niða gedigde, +hildehlemma, syððan he Hroðgares, +sigoreadig secg, sele fælsode +ond æt guðe forgrap Grendeles mægum +laðan cynnes. No þæt læsest wæs +hondgemota, þær mon Hygelac sloh, +syððan Geata cyning guðe ræsum, +freawine folca Freslondum on, +Hreðles eafora hiorodryncum swealt, +bille gebeaten. þonan Biowulf com +sylfes cræfte, sundnytte dreah; +hæfde him on earme ana [XXX] +hildegeatwa, þa he to holme beag. +Nealles Hetware hremge þorfton +feðewiges, þe him foran ongean +linde bæron; lyt eft becwom +fram þam hildfrecan hames niosan. +Oferswam ða sioleða bigong sunu Ecgðeowes, +earm anhaga, eft to leodum; +þær him Hygd gebead hord ond rice, +beagas ond bregostol, bearne ne truwode +þæt he wið ælfylcum eþelstolas +healdan cuðe, ða wæs Hygelac dead. +No ðy ær feasceafte findan meahton +æt ðam æðelinge ænige ðinga, +þæt he Heardrede hlaford wære +oððe þone cynedom ciosan wolde; +hwæðre he him on folce freondlarum heold, +estum mid are, oððæt he yldra wearð, +Wedergeatum weold. Hyne wræcmæcgas +ofer sæ sohtan, suna Ohteres; +hæfdon hy forhealden helm Scylfinga, +þone selestan sæcyninga +þara ðe in Swiorice sinc brytnade, +mærne þeoden. Him þæt to mearce wearð; +he þær for feorme feorhwunde hleat +sweordes swengum, sunu Hygelaces, +ond him eft gewat Ongenðioes bearn +hames niosan, syððan Heardred læg, +let ðone bregostol Biowulf healdan, +Geatum wealdan. þæt wæs god cyning! +Se ðæs leodhryres lean gemunde +uferan dogrum, Eadgilse wearð +feasceaftum freond, folce gestepte +ofer sæ side sunu Ohteres, +wigum ond wæpnum; he gewræc syððan +cealdum cearsiðum, cyning ealdre bineat. +Swa he niða gehwane genesen hæfde, +sliðra geslyhta, sunu Ecgðiowes, +ellenweorca, oð ðone anne dæg +þe he wið þam wyrme gewegan sceolde. +Gewat þa [XII]a sum torne gebolgen +dryhten Geata dracan sceawian. +Hæfde þa gefrunen hwanan sio fæhð aras, +bealonið biorna; him to bearme cwom +maðþumfæt mære þurh ðæs meldan hond. +Se wæs on ðam ðreate þreotteoða secg, +se ðæs orleges or onstealde, +hæft hygegiomor, sceolde hean ðonon +wong wisian. He ofer willan giong +to ðæs ðe he eorðsele anne wisse, +hlæw under hrusan holmwylme neh, +yðgewinne; se wæs innan full +wrætta ond wira. Weard unhiore, +gearo guðfreca, goldmaðmas heold, +eald under eorðan. Næs þæt yðe ceap +to gegangenne gumena ænigum! +Gesæt ða on næsse niðheard cyning, +þenden hælo abead heorðgeneatum, +goldwine Geata. Him wæs geomor sefa, +wæfre ond wælfus, wyrd ungemete neah, +se ðone gomelan gretan sceolde, +secean sawle hord, sundur gedælan +lif wið lice, no þon lange wæs +feorh æþelinges flæsce bewunden. +Biowulf maþelade, bearn Ecgðeowes: +"Fela ic on giogoðe guðræsa genæs, +orleghwila; ic þæt eall gemon. +Ic wæs syfanwintre, þa mec sinca baldor, +freawine folca, æt minum fæder genam; +heold mec ond hæfde Hreðel cyning, +geaf me sinc ond symbel, sibbe gemunde. +Næs ic him to life laðra owihte, +beorn in burgum, þonne his bearna hwylc, +Herebeald ond Hæðcyn oððe Hygelac min. +Wæs þam yldestan ungedefelice +mæges dædum morþorbed stred, +syððan hyne Hæðcyn of hornbogan, +his freawine, flane geswencte, +miste mercelses ond his mæg ofscet, +broðor oðerne blodigan gare. +þæt wæs feohleas gefeoht, fyrenum gesyngad, +hreðre hygemeðe; sceolde hwæðre swa þeah +æðeling unwrecen ealdres linnan. +Swa bið geomorlic gomelum ceorle +to gebidanne, þæt his byre ride +giong on galgan, þonne he gyd wrece, +sarigne sang, þonne his sunu hangað +hrefne to hroðre, ond he him helpe ne mæg, +eald ond infrod, ænige gefremman. +Symble bið gemyndgad morna gehwylce +eaforan ellorsið; oðres ne gymeð +to gebidanne burgum in innan +yrfeweardas, þonne se an hafað +þurh deaðes nyd dæda gefondad. +Gesyhð sorhcearig on his suna bure +winsele westne, windge reste +reote berofene. Ridend swefað, +hæleð in hoðman; nis þær hearpan sweg, +gomen in geardum, swylce ðær iu wæron. +Gewiteð þonne on sealman, sorhleoð gæleð +an æfter anum; þuhte him eall to rum, +wongas ond wicstede. Swa Wedra helm +æfter Herebealde heortan sorge +weallende wæg. Wihte ne meahte +on ðam feorhbonan fæghðe gebetan; +no ðy ær he þone heaðorinc hatian ne meahte +laðum dædum, þeah him leof ne wæs. +He ða mid þære sorhge, þe him swa sar belamp, +gumdream ofgeaf, godes leoht geceas, +eaferum læfde, swa deð eadig mon, +lond ond leodbyrig, þa he of life gewat. +þa wæs synn ond sacu Sweona ond Geata +ofer wid wæter, wroht gemæne, +herenið hearda, syððan Hreðel swealt, +oððe him Ongenðeowes eaferan wæran +frome, fyrdhwate, freode ne woldon +ofer heafo healdan, ac ymb Hreosnabeorh +eatolne inwitscear oft gefremedon. +þæt mægwine mine gewræcan, +fæhðe ond fyrene, swa hyt gefræge wæs, +þeah ðe oðer his ealdre gebohte, +heardan ceape; Hæðcynne wearð, +Geata dryhtne, guð onsæge. +þa ic on morgne gefrægn mæg oðerne +billes ecgum on bonan stælan, +þær Ongenþeow Eofores niosað. +Guðhelm toglad, gomela Scylfing +hreas hildeblac; hond gemunde +fæhðo genoge, feorhsweng ne ofteah. +Ic him þa maðmas, þe he me sealde, +geald æt guðe, swa me gifeðe wæs, +leohtan sweorde; he me lond forgeaf, +eard, eðelwyn. Næs him ænig þearf +þæt he to Gifðum oððe to Gardenum +oððe in Swiorice secean þurfe +wyrsan wigfrecan, weorðe gecypan. +Symle ic him on feðan beforan wolde, +ana on orde, ond swa to aldre sceall +sæcce fremman, þenden þis sweord þolað, +þæt mec ær ond sið oft gelæste. +Syððan ic for dugeðum Dæghrefne wearð +to handbonan, Huga cempan; +nalles he ða frætwe Frescyninge, +breostweorðunge, bringan moste, +ac in compe gecrong cumbles hyrde, +æþeling on elne; ne wæs ecg bona, +ac him hildegrap heortan wylmas, +banhus gebræc. Nu sceall billes ecg, +hond ond heard sweord, ymb hord wigan." +Beowulf maðelode, beotwordum spræc +niehstan siðe: "Ic geneðde fela +guða on geogoðe; gyt ic wylle, +frod folces weard, fæhðe secan, +mærðu fremman, gif mec se mansceaða +of eorðsele ut geseceð." +Gegrette ða gumena gehwylcne, +hwate helmberend, hindeman siðe, +swæse gesiðas: "Nolde ic sweord beran, +wæpen to wyrme, gif ic wiste hu +wið ðam aglæcean elles meahte +gylpe wiðgripan, swa ic gio wið Grendle dyde. +Ac ic ðær heaðufyres hates wene, +oreðes ond attres; forðon ic me on hafu +bord ond byrnan. Nelle ic beorges weard +forfleon fotes trem, ac unc furður sceal +weorðan æt wealle, swa unc wyrd geteoð, +metod manna gehwæs. Ic eom on mode from +þæt ic wið þone guðflogan gylp ofersitte. +Gebide ge on beorge byrnum werede, +secgas on searwum, hwæðer sel mæge +æfter wælræse wunde gedygan +uncer twega. Nis þæt eower sið +ne gemet mannes, nefne min anes, +þæt he wið aglæcean eofoðo dæle, +eorlscype efne. Ic mid elne sceall +gold gegangan, oððe guð nimeð, +feorhbealu frecne, frean eowerne!" +Aras ða bi ronde rof oretta, +heard under helme, hiorosercean bær +under stancleofu, strengo getruwode +anes mannes. Ne bið swylc earges sið! +Geseah ða be wealle se ðe worna fela, +gumcystum god, guða gedigde, +hildehlemma, þonne hnitan feðan, +stondan stanbogan, stream ut þonan +brecan of beorge. Wæs þære burnan wælm +heaðofyrum hat; ne meahte horde neah +unbyrnende ænige hwile +deop gedygan for dracan lege. +Let ða of breostum, ða he gebolgen wæs, +Wedergeata leod word ut faran, +stearcheort styrmde; stefn in becom +heaðotorht hlynnan under harne stan. +Hete wæs onhrered, hordweard oncniow +mannes reorde; næs ðær mara fyrst +freode to friclan. From ærest cwom +oruð aglæcean ut of stane, +hat hildeswat. Hruse dynede. +Biorn under beorge bordrand onswaf +wið ðam gryregieste, Geata dryhten; +ða wæs hringbogan heorte gefysed +sæcce to seceanne. Sweord ær gebræd +god guðcyning, gomele lafe, +ecgum unslaw; æghwæðrum wæs +bealohycgendra broga fram oðrum. +Stiðmod gestod wið steapne rond +winia bealdor, ða se wyrm gebeah +snude tosomne; he on searwum bad. +Gewat ða byrnende gebogen scriðan, +to gescipe scyndan. Scyld wel gebearg +life ond lice læssan hwile +mærum þeodne þonne his myne sohte, +ðær he þy fyrste, forman dogore +wealdan moste swa him wyrd ne gescraf +hreð æt hilde. Hond up abræd +Geata dryhten, gryrefahne sloh +incgelafe, þæt sio ecg gewac +brun on bane, bat unswiðor +þonne his ðiodcyning þearfe hæfde, +bysigum gebæded. þa wæs beorges weard +æfter heaðuswenge on hreoum mode, +wearp wælfyre; wide sprungon +hildeleoman. Hreðsigora ne gealp +goldwine Geata; guðbill geswac, +nacod æt niðe, swa hyt no sceolde, +iren ærgod. Ne wæs þæt eðe sið, +þæt se mæra maga Ecgðeowes +grundwong þone ofgyfan wolde; +sceolde ofer willan wic eardian +elles hwergen, swa sceal æghwylc mon +alætan lændagas. Næs ða long to ðon +þæt ða aglæcean hy eft gemetton. +Hyrte hyne hordweard (hreðer æðme weoll) +niwan stefne; nearo ðrowode, +fyre befongen, se ðe ær folce weold. +Nealles him on heape handgesteallan, +æðelinga bearn, ymbe gestodon +hildecystum, ac hy on holt bugon, +ealdre burgan. Hiora in anum weoll +sefa wið sorgum; sibb æfre ne mæg +wiht onwendan þam ðe wel þenceð. +Wiglaf wæs haten Weoxstanes sunu, +leoflic lindwiga, leod Scylfinga, +mæg ælfheres; geseah his mondryhten +under heregriman hat þrowian. +Gemunde ða ða are þe he him ær forgeaf, +wicstede weligne Wægmundinga, +folcrihta gehwylc, swa his fæder ahte. +Ne mihte ða forhabban; hond rond gefeng, +geolwe linde, gomel swyrd geteah, +þæt wæs mid eldum Eanmundes laf, +suna Ohteres. þam æt sæcce wearð, +wræccan wineleasum, Weohstan bana +meces ecgum, ond his magum ætbær +brunfagne helm, hringde byrnan, +eald sweord etonisc; þæt him Onela forgeaf, +his gædelinges guðgewædu, +fyrdsearo fuslic, no ymbe ða fæhðe spræc, +þeah ðe he his broðor bearn abredwade. +He frætwe geheold fela missera, +bill ond byrnan, oððæt his byre mihte +eorlscipe efnan swa his ærfæder; +geaf him ða mid Geatum guðgewæda, +æghwæs unrim, þa he of ealdre gewat, +frod on forðweg. þa wæs forma sið +geongan cempan, þæt he guðe ræs +mid his freodryhtne fremman sceolde. +Ne gemealt him se modsefa, ne his mæges laf +gewac æt wige; þæt se wyrm onfand, +syððan hie togædre gegan hæfdon. +Wiglaf maðelode, wordrihta fela +sægde gesiðum (him wæs sefa geomor): +"Ic ðæt mæl geman, þær we medu þegun, +þonne we geheton ussum hlaforde +in biorsele, ðe us ðas beagas geaf, +þæt we him ða guðgetawa gyldan woldon +gif him þyslicu þearf gelumpe, +helmas ond heard sweord. ðe he usic on herge geceas +to ðyssum siðfate sylfes willum, +onmunde usic mærða, ond me þas maðmas geaf, +þe he usic garwigend gode tealde, +hwate helmberend, þeah ðe hlaford us +þis ellenweorc ana aðohte +to gefremmanne, folces hyrde, +for ðam he manna mæst mærða gefremede, +dæda dollicra. Nu is se dæg cumen +þæt ure mandryhten mægenes behofað, +godra guðrinca; wutun gongan to, +helpan hildfruman, þenden hyt sy, +gledegesa grim. God wat on mec +þæt me is micle leofre þæt minne lichaman +mid minne goldgyfan gled fæðmie. +Ne þynceð me gerysne þæt we rondas beren +eft to earde, nemne we æror mægen +fane gefyllan, feorh ealgian +Wedra ðeodnes. Ic wat geare +þæt næron ealdgewyrht, þæt he ana scyle +Geata duguðe gnorn þrowian, +gesigan æt sæcce; urum sceal sweord ond helm, +byrne ond beaduscrud, bam gemæne." +Wod þa þurh þone wælrec, wigheafolan bær +frean on fultum, fea worda cwæð: +"Leofa Biowulf, læst eall tela, +swa ðu on geoguðfeore geara gecwæde +þæt ðu ne alæte be ðe lifigendum +dom gedreosan. Scealt nu dædum rof, +æðeling anhydig, ealle mægene +feorh ealgian; ic ðe fullæstu." +æfter ðam wordum wyrm yrre cwom, +atol inwitgæst, oðre siðe +fyrwylmum fah fionda niosian, +laðra manna; ligyðum for. +Born bord wið rond, byrne ne meahte +geongum garwigan geoce gefremman, +ac se maga geonga under his mæges scyld +elne geeode, þa his agen wæs +gledum forgrunden. þa gen guðcyning +mærða gemunde, mægenstrengo sloh +hildebille, þæt hyt on heafolan stod +niþe genyded; Nægling forbærst, +geswac æt sæcce sweord Biowulfes, +gomol ond grægmæl. Him þæt gifeðe ne wæs +þæt him irenna ecge mihton +helpan æt hilde; wæs sio hond to strong, +se ðe meca gehwane, mine gefræge, +swenge ofersohte, þonne he to sæcce bær +wæpen wundrum heard; næs him wihte ðe sel. +þa wæs þeodsceaða þriddan siðe, +frecne fyrdraca, fæhða gemyndig, +ræsde on ðone rofan, þa him rum ageald, +hat ond heaðogrim, heals ealne ymbefeng +biteran banum; he geblodegod wearð +sawuldriore, swat yðum weoll. +ða ic æt þearfe gefrægn þeodcyninges +andlongne eorl ellen cyðan, +cræft ond cenðu, swa him gecynde wæs. +Ne hedde he þæs heafolan, ac sio hand gebarn +modiges mannes, þær he his mæges healp, +þæt he þone niðgæst nioðor hwene sloh, +secg on searwum, þæt ðæt sweord gedeaf, +fah ond fæted, þæt ðæt fyr ongon +sweðrian syððan. þa gen sylf cyning +geweold his gewitte, wællseaxe gebræd +biter ond beaduscearp, þæt he on byrnan wæg; +forwrat Wedra helm wyrm on middan. +Feond gefyldan (ferh ellen wræc), +ond hi hyne þa begen abroten hæfdon, +sibæðelingas. Swylc sceolde secg wesan, +þegn æt ðearfe! þæt ðam þeodne wæs +siðast sigehwila sylfes dædum, +worlde geweorces. ða sio wund ongon, +þe him se eorðdraca ær geworhte, +swelan ond swellan; he þæt sona onfand, +þæt him on breostum bealoniðe weoll +attor on innan. ða se æðeling giong +þæt he bi wealle wishycgende +gesæt on sesse; seah on enta geweorc, +hu ða stanbogan stapulum fæste +ece eorðreced innan healde. +Hyne þa mid handa heorodreorigne, +þeoden mærne, þegn ungemete till +winedryhten his wætere gelafede, +hilde sædne, ond his helm onspeon. +Biowulf maþelode (he ofer benne spræc, +wunde wælbleate; wisse he gearwe +þæt he dæghwila gedrogen hæfde, +eorðan wynne; ða wæs eall sceacen +dogorgerimes, deað ungemete neah): +"Nu ic suna minum syllan wolde +guðgewædu, þær me gifeðe swa +ænig yrfeweard æfter wurde +lice gelenge. Ic ðas leode heold +fiftig wintra; næs se folccyning, +ymbesittendra ænig ðara, +þe mec guðwinum gretan dorste, +egesan ðeon. Ic on earde bad +mælgesceafta, heold min tela, +ne sohte searoniðas, ne me swor fela +aða on unriht. Ic ðæs ealles mæg +feorhbennum seoc gefean habban; +for ðam me witan ne ðearf waldend fira +morðorbealo maga, þonne min sceaceð +lif of lice. Nu ðu lungre geong +hord sceawian under harne stan, +Wiglaf leofa, nu se wyrm ligeð, +swefeð sare wund, since bereafod. +Bio nu on ofoste, þæt ic ærwelan, +goldæht ongite, gearo sceawige +swegle searogimmas, þæt ic ðy seft mæge +æfter maððumwelan min alætan +lif ond leodscipe, þone ic longe heold." +ða ic snude gefrægn sunu Wihstanes +æfter wordcwydum wundum dryhtne +hyran heaðosiocum, hringnet beran, +brogdne beadusercean under beorges hrof. +Geseah ða sigehreðig, þa he bi sesse geong, +magoþegn modig maððumsigla fealo, +gold glitinian grunde getenge, +wundur on wealle, ond þæs wyrmes denn, +ealdes uhtflogan, orcas stondan, +fyrnmanna fatu feormendlease, +hyrstum behrorene; þær wæs helm monig +eald ond omig, earmbeaga fela +searwum gesæled. Sinc eaðe mæg, +gold on grunde, gumcynnes gehwone +oferhigian, hyde se ðe wylle. +Swylce he siomian geseah segn eallgylden +heah ofer horde, hondwundra mæst, +gelocen leoðocræftum; of ðam leoma stod, +þæt he þone grundwong ongitan meahte, +wræte giondwlitan. Næs ðæs wyrmes þær +onsyn ænig, ac hyne ecg fornam. +ða ic on hlæwe gefrægn hord reafian, +eald enta geweorc, anne mannan, +him on bearm hladon bunan ond discas +sylfes dome; segn eac genom, +beacna beorhtost. Bill ær gescod +(ecg wæs iren) ealdhlafordes +þam ðara maðma mundbora wæs +longe hwile, ligegesan wæg +hatne for horde, hioroweallende +middelnihtum, oðþæt he morðre swealt. +Ar wæs on ofoste, eftsiðes georn, +frætwum gefyrðred; hyne fyrwet bræc, +hwæðer collenferð cwicne gemette +in ðam wongstede Wedra þeoden +ellensiocne, þær he hine ær forlet. +He ða mid þam maðmum mærne þioden, +dryhten sinne, driorigne fand +ealdres æt ende; he hine eft ongon +wæteres weorpan, oðþæt wordes ord +breosthord þurhbræc. +gomel on giohðe (gold sceawode): +"Ic ðara frætwa frean ealles ðanc, +wuldurcyninge, wordum secge, +ecum dryhtne, þe ic her on starie, +þæs ðe ic moste minum leodum +ær swyltdæge swylc gestrynan. +Nu ic on maðma hord mine bebohte +frode feorhlege, fremmað gena +leoda þearfe; ne mæg ic her leng wesan. +Hatað heaðomære hlæw gewyrcean +beorhtne æfter bæle æt brimes nosan; +se scel to gemyndum minum leodum +heah hlifian on Hronesnæsse, +þæt hit sæliðend syððan hatan +Biowulfes biorh, ða ðe brentingas +ofer floda genipu feorran drifað." +Dyde him of healse hring gyldenne +þioden þristhydig, þegne gesealde, +geongum garwigan, goldfahne helm, +beah ond byrnan, het hyne brucan well: +"þu eart endelaf usses cynnes, +Wægmundinga. Ealle wyrd forsweop +mine magas to metodsceafte, +eorlas on elne; ic him æfter sceal." +þæt wæs þam gomelan gingæste word +breostgehygdum, ær he bæl cure, +hate heaðowylmas; him of hreðre gewat +sawol secean soðfæstra dom. +ða wæs gegongen guman unfrodum +earfoðlice, þæt he on eorðan geseah +þone leofestan lifes æt ende +bleate gebæran. Bona swylce læg, +egeslic eorðdraca ealdre bereafod, +bealwe gebæded. Beahhordum leng +wyrm wohbogen wealdan ne moste, +ac hine irenna ecga fornamon, +hearde, heaðoscearde homera lafe, +þæt se widfloga wundum stille +hreas on hrusan hordærne neah. +Nalles æfter lyfte lacende hwearf +middelnihtum, maðmæhta wlonc +ansyn ywde, ac he eorðan gefeoll +for ðæs hildfruman hondgeweorce. +Huru þæt on lande lyt manna ðah, +mægenagendra, mine gefræge, +þeah ðe he dæda gehwæs dyrstig wære, +þæt he wið attorsceaðan oreðe geræsde, +oððe hringsele hondum styrede, +gif he wæccende weard onfunde +buon on beorge. Biowulfe wearð +dryhtmaðma dæl deaðe forgolden; +hæfde æghwæðer ende gefered +lænan lifes. Næs ða lang to ðon +þæt ða hildlatan holt ofgefan, +tydre treowlogan tyne ætsomne. +ða ne dorston ær dareðum lacan +on hyra mandryhtnes miclan þearfe, +ac hy scamiende scyldas bæran, +guðgewædu, þær se gomela læg, +wlitan on Wilaf. He gewergad sæt, +feðecempa, frean eaxlum neah, +wehte hyne wætre; him wiht ne speow. +Ne meahte he on eorðan, ðeah he uðe wel, +on ðam frumgare feorh gehealdan, +ne ðæs wealdendes wiht oncirran; +wolde dom godes dædum rædan +gumena gehwylcum, swa he nu gen deð. +þa wæs æt ðam geongan grim ondswaru +eðbegete þam ðe ær his elne forleas. +Wiglaf maðelode, Weohstanes sunu, +sec, sarigferð (seah on unleofe): +"þæt, la, mæg secgan se ðe wyle soð specan +þæt se mondryhten se eow ða maðmas geaf, +eoredgeatwe, þe ge þær on standað, +þonne he on ealubence oft gesealde +healsittendum helm ond byrnan, +þeoden his þegnum, swylce he þrydlicost +ower feor oððe neah findan meahte, +þæt he genunga guðgewædu +wraðe forwurpe, ða hyne wig beget. +Nealles folccyning fyrdgesteallum +gylpan þorfte; hwæðre him god uðe, +sigora waldend, þæt he hyne sylfne gewræc +ana mid ecge, þa him wæs elnes þearf. +Ic him lifwraðe lytle meahte +ætgifan æt guðe, ond ongan swa þeah +ofer min gemet mæges helpan; +symle wæs þy sæmra, þonne ic sweorde drep +ferhðgeniðlan, fyr unswiðor +weoll of gewitte. Wergendra to lyt +þrong ymbe þeoden, þa hyne sio þrag becwom. +Nu sceal sincþego ond swyrdgifu, +eall eðelwyn eowrum cynne, +lufen alicgean; londrihtes mot +þære mægburge monna æghwylc +idel hweorfan, syððan æðelingas +feorran gefricgean fleam eowerne, +domleasan dæd. Deað bið sella +eorla gehwylcum þonne edwitlif!" +Heht ða þæt heaðoweorc to hagan biodan +up ofer ecgclif, þær þæt eorlweorod +morgenlongne dæg modgiomor sæt, +bordhæbbende, bega on wenum, +endedogores ond eftcymes +leofes monnes. Lyt swigode +niwra spella se ðe næs gerad, +ac he soðlice sægde ofer ealle: +"Nu is wilgeofa Wedra leoda, +dryhten Geata, deaðbedde fæst, +wunað wælreste wyrmes dædum. +Him on efn ligeð ealdorgewinna +sexbennum seoc; sweorde ne meahte +on ðam aglæcean ænige þinga +wunde gewyrcean. Wiglaf siteð +ofer Biowulfe, byre Wihstanes, +eorl ofer oðrum unlifigendum, +healdeð higemæðum heafodwearde +leofes ond laðes. Nu ys leodum wen +orleghwile, syððan underne +Froncum ond Frysum fyll cyninges +wide weorðeð. Wæs sio wroht scepen +heard wið Hugas, syððan Higelac cwom +faran flotherge on Fresna land, +þær hyne Hetware hilde genægdon, +elne geeodon mid ofermægene, +þæt se byrnwiga bugan sceolde, +feoll on feðan, nalles frætwe geaf +ealdor dugoðe. Us wæs a syððan +Merewioingas milts ungyfeðe. +Ne ic to Sweoðeode sibbe oððe treowe +wihte ne wene, ac wæs wide cuð +þætte Ongenðio ealdre besnyðede +Hæðcen Hreþling wið Hrefnawudu, +þa for onmedlan ærest gesohton +Geata leode Guðscilfingas. +Sona him se froda fæder Ohtheres, +eald ond egesfull, ondslyht ageaf, +abreot brimwisan, bryd ahredde, +gomela iomeowlan golde berofene, +Onelan modor ond Ohtheres, +ond ða folgode feorhgeniðlan, +oððæt hi oðeodon earfoðlice +in Hrefnesholt hlafordlease. +Besæt ða sinherge sweorda lafe, +wundum werge, wean oft gehet +earmre teohhe ondlonge niht, +cwæð, he on mergenne meces ecgum +getan wolde, sum on galgtreowum +fuglum to gamene. Frofor eft gelamp +sarigmodum somod ærdæge, +syððan hie Hygelaces horn ond byman, +gealdor ongeaton, þa se goda com +leoda dugoðe on last faran. +Wæs sio swatswaðu Sweona ond Geata, +wælræs weora wide gesyne, +hu ða folc mid him fæhðe towehton. +Gewat him ða se goda mid his gædelingum, +frod, felageomor, fæsten secean, +eorl Ongenþio, ufor oncirde; +hæfde Higelaces hilde gefrunen, +wlonces wigcræft, wiðres ne truwode, +þæt he sæmannum onsacan mihte, +heaðoliðendum hord forstandan, +bearn ond bryde; beah eft þonan +eald under eorðweall. þa wæs æht boden +Sweona leodum, segn Higelaces +freoðowong þone forð ofereodon, +syððan Hreðlingas to hagan þrungon. +þær wearð Ongenðiow ecgum sweorda, +blondenfexa, on bid wrecen, +þæt se þeodcyning ðafian sceolde +Eafores anne dom. Hyne yrringa +Wulf Wonreding wæpne geræhte, +þæt him for swenge swat ædrum sprong +forð under fexe. Næs he forht swa ðeh, +gomela Scilfing, ac forgeald hraðe +wyrsan wrixle wælhlem þone, +syððan ðeodcyning þyder oncirde. +Ne meahte se snella sunu Wonredes +ealdum ceorle ondslyht giofan, +ac he him on heafde helm ær gescer, +þæt he blode fah bugan sceolde, +feoll on foldan; næs he fæge þa git, +ac he hyne gewyrpte, þeah ðe him wund hrine. +Let se hearda Higelaces þegn +bradne mece, þa his broðor læg, +eald sweord eotonisc, entiscne helm +brecan ofer bordweal; ða gebeah cyning, +folces hyrde, wæs in feorh dropen. +ða wæron monige þe his mæg wriðon, +ricone arærdon, ða him gerymed wearð +þæt hie wælstowe wealdan moston. +þenden reafode rinc oðerne, +nam on Ongenðio irenbyrnan, +heard swyrd hilted ond his helm somod, +hares hyrste Higelace bær. +He ðam frætwum feng ond him fægre gehet +leana mid leodum, ond gelæste swa; +geald þone guðræs Geata dryhten, +Hreðles eafora, þa he to ham becom, +Iofore ond Wulfe mid ofermaðmum, +sealde hiora gehwæðrum hund þusenda +landes ond locenra beaga (ne ðorfte him ða lean oðwitan +mon on middangearde), syððan hie ða mærða geslogon, +ond ða Iofore forgeaf angan dohtor, +hamweorðunge, hyldo to wedde. +þæt ys sio fæhðo ond se feondscipe, +wælnið wera, ðæs ðe ic wen hafo, +þe us seceað to Sweona leoda, +syððan hie gefricgeað frean userne +ealdorleasne, þone ðe ær geheold +wið hettendum hord ond rice +æfter hæleða hryre, hwate Scildingas, +folcred fremede oððe furður gen +eorlscipe efnde. Nu is ofost betost +þæt we þeodcyning þær sceawian +ond þone gebringan, þe us beagas geaf, +on adfære. Ne scel anes hwæt +meltan mid þam modigan, ac þær is maðma hord, +gold unrime grimme geceapod, +ond nu æt siðestan sylfes feore +beagas gebohte. þa sceall brond fretan, +æled þeccean, nalles eorl wegan +maððum to gemyndum, ne mægð scyne +habban on healse hringweorðunge, +ac sceal geomormod, golde bereafod, +oft nalles æne elland tredan, +nu se herewisa hleahtor alegde, +gamen ond gleodream. Forðon sceall gar wesan +monig, morgenceald, mundum bewunden, +hæfen on handa, nalles hearpan sweg +wigend weccean, ac se wonna hrefn +fus ofer fægum fela reordian, +earne secgan hu him æt æte speow, +þenden he wið wulf wæl reafode." +Swa se secg hwata secggende wæs +laðra spella; he ne leag fela +wyrda ne worda. Weorod eall aras; +eodon unbliðe under Earnanæs, +wollenteare wundur sceawian. +Fundon ða on sande sawulleasne +hlimbed healdan þone þe him hringas geaf +ærran mælum; þa wæs endedæg +godum gegongen, þæt se guðcyning, +Wedra þeoden, wundordeaðe swealt. +ær hi þær gesegan syllicran wiht, +wyrm on wonge wiðerræhtes þær +laðne licgean; wæs se legdraca +grimlic, gryrefah, gledum beswæled. +Se wæs fiftiges fotgemearces +lang on legere, lyftwynne heold +nihtes hwilum, nyðer eft gewat +dennes niosian; wæs ða deaðe fæst, +hæfde eorðscrafa ende genyttod. +Him big stodan bunan ond orcas, +discas lagon ond dyre swyrd, +omige, þurhetone, swa hie wið eorðan fæðm +þusend wintra þær eardodon. +þonne wæs þæt yrfe, eacencræftig, +iumonna gold galdre bewunden, +þæt ðam hringsele hrinan ne moste +gumena ænig, nefne god sylfa, +sigora soðcyning, sealde þam ðe he wolde +(he is manna gehyld) hord openian, +efne swa hwylcum manna swa him gemet ðuhte. +þa wæs gesyne þæt se sið ne ðah +þam ðe unrihte inne gehydde +wræte under wealle. Weard ær ofsloh +feara sumne; þa sio fæhð gewearð +gewrecen wraðlice. Wundur hwar þonne +eorl ellenrof ende gefere +lifgesceafta, þonne leng ne mæg +mon mid his magum meduseld buan. +Swa wæs Biowulfe, þa he biorges weard +sohte, searoniðas; seolfa ne cuðe +þurh hwæt his worulde gedal weorðan sceolde. +Swa hit oð domes dæg diope benemdon +þeodnas mære, þa ðæt þær dydon, +þæt se secg wære synnum scildig, +hergum geheaðerod, hellbendum fæst, +wommum gewitnad, se ðone wong strude, +næs he goldhwæte gearwor hæfde +agendes est ær gesceawod. +Wiglaf maðelode, Wihstanes sunu: +"Oft sceall eorl monig anes willan +wræc adreogan, swa us geworden is. +Ne meahton we gelæran leofne þeoden, +rices hyrde, ræd ænigne, +þæt he ne grette goldweard þone, +lete hyne licgean þær he longe wæs, +wicum wunian oð woruldende; +heold on heahgesceap. Hord ys gesceawod, +grimme gegongen; wæs þæt gifeðe to swið +þe ðone þeodcyning þyder ontyhte. +Ic wæs þær inne ond þæt eall geondseh, +recedes geatwa, þa me gerymed wæs, +nealles swæslice sið alyfed +inn under eorðweall. Ic on ofoste gefeng +micle mid mundum mægenbyrðenne +hordgestreona, hider ut ætbær +cyninge minum. Cwico wæs þa gena, +wis ond gewittig; worn eall gespræc +gomol on gehðo ond eowic gretan het, +bæd þæt ge geworhton æfter wines dædum +in bælstede beorh þone hean, +micelne ond mærne, swa he manna wæs +wigend weorðfullost wide geond eorðan, +þenden he burhwelan brucan moste. +Uton nu efstan oðre siðe, +seon ond secean searogimma geþræc, +wundur under wealle; ic eow wisige, +þæt ge genoge neon sceawiað +beagas ond brad gold. Sie sio bær gearo, +ædre geæfned, þonne we ut cymen, +ond þonne geferian frean userne, +leofne mannan, þær he longe sceal +on ðæs waldendes wære geþolian." +Het ða gebeodan byre Wihstanes, +hæle hildedior, hæleða monegum, +boldagendra, þæt hie bælwudu +feorran feredon, folcagende, +godum togenes: "Nu sceal gled fretan, +weaxan wonna leg wigena strengel, +þone ðe oft gebad isernscure, +þonne stræla storm strengum gebæded +scoc ofer scildweall, sceft nytte heold, +feðergearwum fus flane fulleode." +Huru se snotra sunu Wihstanes +acigde of corðre cyninges þegnas +syfone tosomne, þa selestan, +eode eahta sum under inwithrof +hilderinca; sum on handa bær +æledleoman, se ðe on orde geong. +Næs ða on hlytme hwa þæt hord strude, +syððan orwearde ænigne dæl +secgas gesegon on sele wunian, +læne licgan; lyt ænig mearn +þæt hi ofostlice ut geferedon +dyre maðmas. Dracan ec scufun, +wyrm ofer weallclif, leton weg niman, +flod fæðmian frætwa hyrde. +þa wæs wunden gold on wæn hladen, +æghwæs unrim, æþeling boren, +har hilderinc to Hronesnæsse. +Him ða gegiredan Geata leode +ad on eorðan unwaclicne, +helmum behongen, hildebordum, +beorhtum byrnum, swa he bena wæs; +alegdon ða tomiddes mærne þeoden +hæleð hiofende, hlaford leofne. +Ongunnon þa on beorge bælfyra mæst +wigend weccan; wudurec astah, +sweart ofer swioðole, swogende leg +wope bewunden (windblond gelæg), +oðþæt he ða banhus gebrocen hæfde, +hat on hreðre. Higum unrote +modceare mændon, mondryhtnes cwealm; +swylce giomorgyd Geatisc meowle +bundenheorde +song sorgcearig swiðe geneahhe +þæt hio hyre heofungdagas hearde ondrede, +wælfylla worn, werudes egesan, +hynðo ond hæftnyd. Heofon rece swealg. +Geworhton ða Wedra leode +hleo on hoe, se wæs heah ond brad, +wægliðendum wide gesyne, +ond betimbredon on tyn dagum +beadurofes becn, bronda lafe +wealle beworhton, swa hyt weorðlicost +foresnotre men findan mihton. +Hi on beorg dydon beg ond siglu, +eall swylce hyrsta, swylce on horde ær +niðhedige men genumen hæfdon, +forleton eorla gestreon eorðan healdan, +gold on greote, þær hit nu gen lifað +eldum swa unnyt swa hit æror wæs. +þa ymbe hlæw riodan hildediore, +æþelinga bearn, ealra twelfe, +woldon ceare cwiðan ond kyning mænan, +wordgyd wrecan ond ymb wer sprecan; +eahtodan eorlscipe ond his ellenweorc +duguðum demdon, swa hit gedefe bið +þæt mon his winedryhten wordum herge, +ferhðum freoge, þonne he forð scile +of lichaman læded weorðan. +Swa begnornodon Geata leode +hlafordes hryre, heorðgeneatas, +cwædon þæt he wære wyruldcyninga +manna mildust ond monðwærust, +leodum liðost ond lofgeornost. \ No newline at end of file diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stdout-hello.rs b/tests/wasi.fyi/wasi-libstd-test/io_stdout-hello.rs new file mode 100644 index 00000000000..a572acc1288 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stdout-hello.rs @@ -0,0 +1,6 @@ +use std::io; +use std::io::Write; + +fn main() { + assert!(io::stdout().write_all(include_bytes!("io_stdout-hello.stdout")).is_ok()); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/io_stdout-hello.stdout b/tests/wasi.fyi/wasi-libstd-test/io_stdout-hello.stdout new file mode 100644 index 00000000000..c8fdade72be --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/io_stdout-hello.stdout @@ -0,0 +1 @@ +Hello, stdout! diff --git a/tests/wasi.fyi/wasi-libstd-test/main.rs b/tests/wasi.fyi/wasi-libstd-test/main.rs new file mode 100644 index 00000000000..f79c691f085 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/main.rs @@ -0,0 +1,2 @@ +fn main() { +} diff --git a/tests/wasi.fyi/wasi-libstd-test/process_exit-0.rs b/tests/wasi.fyi/wasi-libstd-test/process_exit-0.rs new file mode 100644 index 00000000000..24ec32ca8fd --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/process_exit-0.rs @@ -0,0 +1,5 @@ +use std::process; + +fn main() { + process::exit(0); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/process_exit-0.status b/tests/wasi.fyi/wasi-libstd-test/process_exit-0.status new file mode 100644 index 00000000000..573541ac970 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/process_exit-0.status @@ -0,0 +1 @@ +0 diff --git a/tests/wasi.fyi/wasi-libstd-test/process_exit-1.rs b/tests/wasi.fyi/wasi-libstd-test/process_exit-1.rs new file mode 100644 index 00000000000..21913454120 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/process_exit-1.rs @@ -0,0 +1,5 @@ +use std::process; + +fn main() { + process::exit(1); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/process_exit-1.status b/tests/wasi.fyi/wasi-libstd-test/process_exit-1.status new file mode 100644 index 00000000000..d00491fd7e5 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/process_exit-1.status @@ -0,0 +1 @@ +1 diff --git a/tests/wasi.fyi/wasi-libstd-test/process_exit-120.rs b/tests/wasi.fyi/wasi-libstd-test/process_exit-120.rs new file mode 100644 index 00000000000..8ff2e51bea5 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/process_exit-120.rs @@ -0,0 +1,5 @@ +use std::process; + +fn main() { + process::exit(120); +} diff --git a/tests/wasi.fyi/wasi-libstd-test/process_exit-120.status b/tests/wasi.fyi/wasi-libstd-test/process_exit-120.status new file mode 100644 index 00000000000..52bd8e43afb --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/process_exit-120.status @@ -0,0 +1 @@ +120 diff --git a/tests/wasi.fyi/wasi-libstd-test/test.sh b/tests/wasi.fyi/wasi-libstd-test/test.sh new file mode 100644 index 00000000000..e90b1ff5a50 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/test.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -ueo pipefail + +usage() { + echo "Usage: $0 " + exit 1 +} + +if [ $# -ne 1 ]; then + usage +else + runtime=$1 +fi + +bash build.sh + +status=0 + +for input in *.wasm; do + echo "Testing $input..." + tools/wasm-test $runtime $input || status=1 +done + +exit $status + diff --git a/tests/wasi.fyi/wasi-libstd-test/tools/README.md b/tests/wasi.fyi/wasi-libstd-test/tools/README.md new file mode 100644 index 00000000000..ed462ea3bdc --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/tools/README.md @@ -0,0 +1 @@ +# WebAssembly Test Tools diff --git a/tests/wasi.fyi/wasi-libstd-test/tools/run-wasmer b/tests/wasi.fyi/wasi-libstd-test/tools/run-wasmer new file mode 100755 index 00000000000..e25173b5a21 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/tools/run-wasmer @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +if [[ $1 == "-V" ]]; then + exec /Users/syrusakbary/Development/wasmer/target/release/wasmer -V +fi + +exec /Users/syrusakbary/Development/wasmer/target/release/wasmer run "$@" diff --git a/tests/wasi.fyi/wasi-libstd-test/tools/wasm-test b/tests/wasi.fyi/wasi-libstd-test/tools/wasm-test new file mode 100755 index 00000000000..b41417a14a4 --- /dev/null +++ b/tests/wasi.fyi/wasi-libstd-test/tools/wasm-test @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +set -e + +runtime=$1 +input=$2 + +input_dir=$(dirname $input) +cd $input_dir + +input_base=$(basename $input .wasm) + +if [ -e "$input_base.stdin" ]; then + stdin="$input_base.stdin" +else + stdin="/dev/null" +fi + +out_dir="$(mktemp -d)" +stdout_actual="$out_dir/stdout" +stderr_actual="$out_dir/stderr" +status_actual="$out_dir/status" + +if [ -e "$input_base.arg" ]; then + arg=$(cat "$input_base.arg") +else + arg="" +fi + +if [ -e "$input_base.dir" ]; then + dir="--dir $input_base.dir" +else + dir="" +fi + +if [ -e "$input_base.env" ]; then + env=$(sed -e 's/^/ --env /' < "$input_base.env") +else + env="" +fi + +status=0 + +echo "╰─▶ $runtime $input_base.wasm $dir $env -- $arg < $stdin" | tr -d '\n\t\r' +echo "" +"$runtime" "$input_base.wasm" $dir $env -- $arg \ + < "$stdin" \ + > "$stdout_actual" \ + 2> "$stderr_actual" \ + || status=$? + +echo $status > "$status_actual" + +stdout_expected="$input_base.stdout" +if [ -e "$stdout_expected" ]; then + diff -u "$stdout_expected" "$stdout_actual" +fi + +stderr_expected="$input_base.stderr" +if [ -e "$stderr_expected" ]; then + diff -u "$stderr_expected" "$stderr_actual" +fi + +status_expected="$input_base.status" +if [ -e "$input_base.status" ]; then + diff -u "$status_expected" "$status_actual" +elif [ ! "$status" -eq "0" ]; then + cat $stderr_actual + exit 1 +fi diff --git a/tests/wasmer-web/Cargo.toml b/tests/wasmer-web/Cargo.toml index 995e2c6179a..4fbf50cf670 100644 --- a/tests/wasmer-web/Cargo.toml +++ b/tests/wasmer-web/Cargo.toml @@ -17,5 +17,5 @@ futures = "0.3.28" macro_rules_attribute = "0.2.0" predicates = "3.0.3" serde_json = "1.0.99" -tempfile = "3.6.0" +tempfile.workspace = true tokio = { version = "1.29.0", features = ["process", "macros", "rt", "fs", "rt-multi-thread"] }