Browse Source

drstd初始构建 (#4)

* 连接Allocator

* 连接Allocator

* pal

* pal

* 初步构建drstd
GnoCiYeH 1 year ago
parent
commit
507ea70e05
100 changed files with 16958 additions and 617 deletions
  1. 0 0
      .cargo/config.toml
  2. 15 0
      .vscode/c_cpp_properties.json
  3. 7 7
      .vscode/settings.json
  4. 38 4
      Cargo.toml
  5. 235 0
      Makefile
  6. 67 10
      build.rs
  7. 3 0
      core_io/.gitignore
  8. 32 0
      core_io/Cargo.toml
  9. 201 0
      core_io/LICENSE-APACHE
  10. 25 0
      core_io/LICENSE-MIT
  11. 49 0
      core_io/README.md
  12. 71 0
      core_io/build-src.sh
  13. 81 0
      core_io/build.rs
  14. 10 0
      core_io/doc.sh
  15. 61 0
      core_io/edit-patches.sh
  16. 89 0
      core_io/functions.sh
  17. 593 0
      core_io/mapping.rs
  18. 6 0
      core_io/publish.sh
  19. 1303 0
      core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/buffered.rs
  20. 678 0
      core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/cursor.rs
  21. 575 0
      core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/error.rs
  22. 341 0
      core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/impls.rs
  23. 2218 0
      core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/mod.rs
  24. 25 0
      core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/prelude.rs
  25. 255 0
      core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/util.rs
  26. 50 0
      core_io/src/lib.rs
  27. 0 70
      src/allocator/dragonos_malloc.rs
  28. 0 4
      src/allocator/mod.rs
  29. 0 75
      src/allocator/test.rs
  30. 0 430
      src/c/dragonos_malloc.c
  31. 1255 0
      src/c_str.rs
  32. 289 0
      src/c_vec.rs
  33. 81 0
      src/crt0/mod.rs
  34. 145 0
      src/fs.rs
  35. 9 0
      src/header/ctype/cbindgen.toml
  36. 105 0
      src/header/ctype/mod.rs
  37. 10 0
      src/header/dirent/cbindgen.toml
  38. 189 2
      src/header/dirent/mod.rs
  39. 9 0
      src/header/dl_tls/cbindgen.toml
  40. 47 0
      src/header/dl_tls/mod.rs
  41. 9 0
      src/header/errno/cbindgen.toml
  42. 300 0
      src/header/errno/mod.rs
  43. 15 0
      src/header/fcntl/cbindgen.toml
  44. 17 0
      src/header/fcntl/dragonos.rs
  45. 17 0
      src/header/fcntl/linux.rs
  46. 58 0
      src/header/fcntl/mod.rs
  47. 23 0
      src/header/fcntl/redox.rs
  48. 9 0
      src/header/getopt/cbindgen.toml
  49. 219 0
      src/header/getopt/mod.rs
  50. 9 0
      src/header/libgen/cbindgen.toml
  51. 47 0
      src/header/libgen/mod.rs
  52. 10 0
      src/header/limits/cbindgen.toml
  53. 3 0
      src/header/limits/mod.rs
  54. 22 4
      src/header/mod.rs
  55. 15 0
      src/header/signal/cbindgen.toml
  56. 76 0
      src/header/signal/dragonos.rs
  57. 75 0
      src/header/signal/linux.rs
  58. 285 0
      src/header/signal/mod.rs
  59. 83 0
      src/header/signal/redox.rs
  60. 13 0
      src/header/stdio/cbindgen.toml
  61. 37 0
      src/header/stdio/constants.rs
  62. 52 0
      src/header/stdio/default.rs
  63. 41 0
      src/header/stdio/ext.rs
  64. 55 0
      src/header/stdio/getdelim.rs
  65. 82 0
      src/header/stdio/helpers.rs
  66. 100 0
      src/header/stdio/lookaheadreader.rs
  67. 1208 0
      src/header/stdio/mod.rs
  68. 986 0
      src/header/stdio/printf.rs
  69. 463 0
      src/header/stdio/scanf.rs
  70. 13 0
      src/header/stdlib/cbindgen.toml
  71. 1256 0
      src/header/stdlib/mod.rs
  72. 90 0
      src/header/stdlib/rand48.rs
  73. 97 0
      src/header/stdlib/random.rs
  74. 242 0
      src/header/stdlib/sort.rs
  75. 9 0
      src/header/string/cbindgen.toml
  76. 485 0
      src/header/string/mod.rs
  77. 8 0
      src/header/sys_auxv/cbindgen.toml
  78. 10 0
      src/header/sys_auxv/mod.rs
  79. 16 0
      src/header/sys_ioctl/cbindgen.toml
  80. 197 0
      src/header/sys_ioctl/dragonos.rs
  81. 198 0
      src/header/sys_ioctl/linux.rs
  82. 36 0
      src/header/sys_ioctl/mod.rs
  83. 149 0
      src/header/sys_ioctl/redox.rs
  84. 15 0
      src/header/sys_mman/cbindgen.toml
  85. 9 0
      src/header/sys_mman/dragonos.rs
  86. 9 0
      src/header/sys_mman/linux.rs
  87. 132 0
      src/header/sys_mman/mod.rs
  88. 9 0
      src/header/sys_mman/redox.rs
  89. 18 0
      src/header/sys_resource/cbindgen.toml
  90. 82 1
      src/header/sys_resource/mod.rs
  91. 13 0
      src/header/sys_stat/cbindgen.toml
  92. 116 3
      src/header/sys_stat/mod.rs
  93. 9 0
      src/header/sys_statvfs/cbindgen.toml
  94. 30 2
      src/header/sys_statvfs/mod.rs
  95. 10 0
      src/header/sys_time/cbindgen.toml
  96. 60 2
      src/header/sys_time/mod.rs
  97. 8 0
      src/header/sys_utsname/cbindgen.toml
  98. 9 3
      src/header/sys_utsname/mod.rs
  99. 14 0
      src/header/termios/cbindgen.toml
  100. 113 0
      src/header/termios/dragonos.rs

+ 0 - 0
.cargo/config.toml


+ 15 - 0
.vscode/c_cpp_properties.json

@@ -0,0 +1,15 @@
+{
+    "configurations": [
+        {
+            "name": "Linux",
+            "includePath": [
+                "${workspaceFolder}/**"
+            ],
+            "defines": [],
+            "compilerPath": "/usr/bin/clang",
+            "cStandard": "c17",
+            "intelliSenseMode": "linux-clang-x64"
+        }
+    ],
+    "version": 4
+}

+ 7 - 7
.vscode/settings.json

@@ -1,14 +1,14 @@
 {
     "rust-analyzer.linkedProjects": [
+        "./Cargo.toml",
+        "./Cargo.toml",
+        "./Cargo.toml",
+        "./Cargo.toml",
+        "./Cargo.toml",
+        "./Cargo.toml",
         "./Cargo.toml",
         "./Cargo.toml",
         "./Cargo.toml",
         "./Cargo.toml"
-    ],
-
-    "rust-analyzer.cargo.target": "x86_64-unknown-dragonos",
-    "files.associations": {
-        "errno.h": "c",
-        "stdint.h": "c"
-    }
+    ]
 }

+ 38 - 4
Cargo.toml

@@ -1,16 +1,50 @@
 [package]
-name = "dragonos-rs-std"
+name = "drstd"
 version = "0.1.0"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
+#[lib]
+#name = "drstd"
+#crate-type = ["staticlib"]
+
+[workspace]
+members = ["src/ld_so"]
+exclude = ["core_io"]
+
+[build-dependencies]
+cbindgen = "0.24.3"
+cc = "1.0.25"
+
 [dependencies]
+cbitset = "0.1.0"
+core_io = { path = "core_io", features = ["collections"] }
+lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] }
+memoffset = "0.5.1"
+rand = { version = "0.5.5", default-features = false }
+memchr = { version = "2.2.0", default-features = false }
+plain = "0.2"
+unicode-width = "0.1"
+
+[dependencies.goblin]
+version = "0.0.21"
+default-features = false
+features = ["elf32", "elf64", "endian_fd"]
+
+#[target.'cfg(target_os = "linux")'.dependencies]
+#sc = "0.2.3"
 
 [target.'cfg(target_os = "dragonos")'.dependencies]
 # Development
 dragonos-dsc = { git = "https://github.com/DragonOS-Community/dsc.git", rev = "d6e4fd8" }
 
-# 构建时依赖项
-[build-dependencies]
-cc = "1.0"
+[features]
+default = []
+trace = []
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"

+ 235 - 0
Makefile

@@ -0,0 +1,235 @@
+# TARGET?=$(shell rustc -Z unstable-options --print target-spec-json | grep llvm-target | cut -d '"' -f4)
+TARGET=x86_64-unknown-dragonos
+
+CARGO?=cargo
+CARGO_TEST?=$(CARGO)
+CARGO_COMMON_FLAGS=-Z build-std=core,alloc,compiler_builtins
+CARGOFLAGS?=$(CARGO_COMMON_FLAGS)
+RUSTCFLAGS?=
+export OBJCOPY?=objcopy
+
+BUILD="target/$(TARGET)"
+CARGOFLAGS+="--target=$(TARGET)"
+
+ifeq ($(TARGET),aarch64-unknown-linux-gnu)
+	export CC=aarch64-linux-gnu-gcc
+	export LD=aarch64-linux-gnu-ld
+	export AR=aarch64-linux-gnu-ar
+	export OBJCOPY=aarch64-linux-gnu-objcopy
+endif
+
+ifeq ($(TARGET),aarch64-unknown-redox)
+	export CC=aarch64-unknown-redox-gcc
+	export LD=aarch64-unknown-redox-ld
+	export AR=aarch64-unknown-redox-ar
+	export OBJCOPY=aarch64-unknown-redox-objcopy
+endif
+
+ifeq ($(TARGET),x86_64-unknown-linux-gnu)
+	export CC=x86_64-linux-gnu-gcc
+	export LD=x86_64-linux-gnu-ld
+	export AR=x86_64-linux-gnu-ar
+	export OBJCOPY=x86_64-linux-gnu-objcopy
+endif
+
+ifeq ($(TARGET),i686-unknown-redox)
+	export CC=i686-unknown-redox-gcc
+	export LD=i686-unknown-redox-ld
+	export AR=i686-unknown-redox-ar
+	export OBJCOPY=i686-unknown-redox-objcopy
+endif
+
+ifeq ($(TARGET),x86_64-unknown-redox)
+	export CC=x86_64-unknown-redox-gcc
+	export LD=x86_64-unknown-redox-ld
+	export AR=x86_64-unknown-redox-ar
+	export OBJCOPY=x86_64-unknown-redox-objcopy
+endif
+
+ifeq ($(TARGET),x86_64-unknown-dragonos)
+# 如果存在x86_64-dragonos-gcc,就用它,否则用gcc
+
+ifeq ($(shell which x86_64-dragonos-gcc),)
+	export CC=gcc
+# export LD=ld
+	export LD=ld
+	export AR=ar
+# export AR=x86_64-dragonos-ar
+	export OBJCOPY=objcopy
+# export OBJCOPY=x86_64-dragonos-objcopy
+else
+	export CC=x86_64-dragonos-gcc
+	export LD=x86_64-dragonos-ld
+	export AR=x86_64-dragonos-ar
+	export OBJCOPY=x86_64-dragonos-objcopy
+endif
+endif
+
+SRC=\
+	Cargo.* \
+	$(shell find src -type f)
+
+BUILTINS_VERSION=0.1.70
+
+.PHONY: all clean fmt install install-headers libs submodules test
+
+all: | libs
+
+clean:
+	$(CARGO) clean
+	$(MAKE) -C tests clean
+	rm -rf sysroot
+
+check:
+	$(CARGO) check
+
+fmt:
+	./fmt.sh
+
+install-headers: libs
+	mkdir -pv "$(DESTDIR)/include"
+	cp -rv "include"/* "$(DESTDIR)/include"
+	cp -rv "target/include"/* "$(DESTDIR)/include"
+	cp -v "openlibm/include"/*.h "$(DESTDIR)/include"
+	cp -v "openlibm/src"/*.h "$(DESTDIR)/include"
+	cp -v "pthreads-emb/"*.h "$(DESTDIR)/include"
+
+# $(BUILD)/release/libc.so
+libs: 
+	@cargo -Z build-std=core,alloc,compiler_builtins build --target x86_64-unknown-dragonos
+#$(BUILD)/release/ld_so
+
+install-libs: libs
+	mkdir -pv "$(DESTDIR)/lib"
+	cp -v "$(BUILD)/release/libc.a" "$(DESTDIR)/lib"
+# cp -v "$(BUILD)/release/libc.so" "$(DESTDIR)/lib"
+# ln -frsv "$(DESTDIR)/lib/libc.so" "$(DESTDIR)/lib/libc.so.6"
+	cp -v "$(BUILD)/release/crt0.o" "$(DESTDIR)/lib"
+	ln -frsv "$(DESTDIR)/lib/crt0.o" "$(DESTDIR)/lib/crt1.o"
+	cp -v "$(BUILD)/release/crti.o" "$(DESTDIR)/lib"
+	cp -v "$(BUILD)/release/crtn.o" "$(DESTDIR)/lib"
+# cp -v "$(BUILD)/release/ld_so" "$(DESTDIR)/lib/ld64.so.1"
+	cp -v "$(BUILD)/openlibm/libopenlibm.a" "$(DESTDIR)/lib/libm.a"
+	cp -v "$(BUILD)/pthreads-emb/libpthread.a" "$(DESTDIR)/lib/libpthread.a"
+	# Empty libraries for dl and rt
+	$(AR) -rcs "$(DESTDIR)/lib/libdl.a"
+	$(AR) -rcs "$(DESTDIR)/lib/librt.a"
+
+install: install-headers install-libs
+
+submodules:
+	git submodule sync
+	git submodule update --init --recursive
+
+sysroot: all
+	rm -rf $@
+	rm -rf [email protected]
+	mkdir -p [email protected]
+	$(MAKE) install [email protected]
+	mv [email protected] $@
+	touch $@
+
+test: sysroot
+	# TODO: Fix SIGILL when running cargo test
+	# $(CARGO_TEST) test
+	$(MAKE) -C tests verify
+
+# Debug targets
+
+$(BUILD)/debug/libc.a: $(BUILD)/debug/libdrsstd.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
+	echo "create $@" > "[email protected]"
+	for lib in $^; do\
+		echo "addlib $$lib" >> "[email protected]"; \
+	done
+	echo "save" >> "[email protected]"
+	echo "end" >> "[email protected]"
+	$(AR) -M < "[email protected]"
+
+$(BUILD)/debug/libc.so: $(BUILD)/debug/libdrsstd.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
+	$(CC) -nostdlib -shared -Wl,--allow-multiple-definition -Wl,--whole-archive $^ -Wl,--no-whole-archive -Wl,-soname,libc.so.6 -o $@
+
+$(BUILD)/debug/libdrsstd.a: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc $(CARGOFLAGS) -- --emit link=$@ $(RUSTCFLAGS)
+	./renamesyms.sh $@ $(BUILD)/debug/deps/
+	touch $@
+
+$(BUILD)/debug/crt0.o: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc --manifest-path src/crt0/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
+	touch $@
+
+$(BUILD)/debug/crti.o: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc --manifest-path src/crti/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
+	touch $@
+
+$(BUILD)/debug/crtn.o: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
+	touch $@
+
+$(BUILD)/debug/ld_so.o: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc --manifest-path src/ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
+	touch $@
+
+$(BUILD)/debug/ld_so: $(BUILD)/debug/ld_so.o $(BUILD)/debug/crti.o $(BUILD)/debug/libc.a $(BUILD)/debug/crtn.o
+	$(LD) --no-relax -T src/ld_so/ld_script/$(TARGET).ld --allow-multiple-definition --gc-sections --gc-keep-exported $^ -o $@
+
+# Release targets
+
+$(BUILD)/release/libc.a: $(BUILD)/release/libdrsstd.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
+	echo "create $@" > "[email protected]"
+	for lib in $^; do\
+		echo "addlib $$lib" >> "[email protected]"; \
+	done
+	echo "save" >> "[email protected]"
+	echo "end" >> "[email protected]"
+	$(AR) -M < "[email protected]"
+
+$(BUILD)/release/libc.so: $(BUILD)/release/libdrsstd.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
+	$(CC) -nostdlib -shared -Wl,--allow-multiple-definition -Wl,--whole-archive $^ -Wl,--no-whole-archive -Wl,-soname,libc.so.6 -o $@
+
+$(BUILD)/release/libdrsstd.a: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc --release $(CARGOFLAGS) -- --emit link=$@ $(RUSTCFLAGS)
+	# TODO: Better to only allow a certain whitelisted set of symbols? Perhaps
+	# use some cbindgen hook, specify them manually, or grep for #[no_mangle].
+	./renamesyms.sh $@ $(BUILD)/release/deps/
+	touch $@
+
+$(BUILD)/release/crt0.o: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc --release --manifest-path src/crt0/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
+	touch $@
+
+$(BUILD)/release/crti.o: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc --release --manifest-path src/crti/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
+	touch $@
+
+$(BUILD)/release/crtn.o: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc --release --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
+	touch $@
+
+$(BUILD)/release/ld_so.o: $(SRC)
+	CARGO_INCREMENTAL=0 $(CARGO) rustc --release --manifest-path src/ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
+	touch $@
+
+$(BUILD)/release/ld_so: $(BUILD)/release/ld_so.o $(BUILD)/release/crti.o $(BUILD)/release/libc.a $(BUILD)/release/crtn.o
+	$(LD) --no-relax -T src/ld_so/ld_script/$(TARGET).ld --allow-multiple-definition --gc-sections --gc-keep-exported $^ -o $@
+
+# Other targets
+
+$(BUILD)/openlibm: openlibm
+	rm -rf $@ [email protected]
+	mkdir -p $(BUILD)
+	cp -r $< [email protected]
+	mv [email protected] $@
+	touch $@
+
+$(BUILD)/openlibm/libopenlibm.a: $(BUILD)/openlibm $(BUILD)/release/libdrsstd.a
+	$(MAKE) AR=$(AR) CC=$(CC) LD=$(LD) CPPFLAGS="-fno-stack-protector -I $(shell pwd)/include -I $(shell pwd)/target/include" -C $< libopenlibm.a
+
+$(BUILD)/pthreads-emb: pthreads-emb
+	rm -rf $@ [email protected]
+	mkdir -p $(BUILD)
+	cp -r $< [email protected]
+	mv [email protected] $@
+	touch $@
+
+$(BUILD)/pthreads-emb/libpthread.a: $(BUILD)/pthreads-emb $(BUILD)/release/libdrsstd.a
+	$(MAKE) AR=$(AR) CC=$(CC) LD=$(LD) CFLAGS="-fno-stack-protector -I $(shell pwd)/include -I $(shell pwd)/target/include" -C $< libpthread.a

+ 67 - 10
build.rs

@@ -1,15 +1,72 @@
+extern crate cbindgen;
 extern crate cc;
 
+use std::{env, fs, fs::DirEntry, path::Path};
+
+// include src/header directories that don't start with '_'
+fn include_dir(d: &DirEntry) -> bool {
+    d.metadata().map(|m| m.is_dir()).unwrap_or(false)
+        && d.path()
+            .iter()
+            .nth(2)
+            .map_or(false, |c| c.to_str().map_or(false, |x| !x.starts_with("_")))
+}
+
+fn generate_bindings(cbindgen_config_path: &Path) {
+    let relative_path = cbindgen_config_path
+        .strip_prefix("src/header")
+        .ok()
+        .and_then(|p| p.parent())
+        .and_then(|p| p.to_str())
+        .unwrap()
+        .replace("_", "/");
+    let header_path = Path::new("target/include")
+        .join(&relative_path)
+        .with_extension("h");
+    let mod_path = cbindgen_config_path.with_file_name("mod.rs");
+    let config = cbindgen::Config::from_file(cbindgen_config_path).unwrap();
+    cbindgen::Builder::new()
+        .with_config(config)
+        .with_src(mod_path)
+        .generate()
+        .expect("Unable to generate bindings")
+        .write_to_file(header_path);
+}
+
 fn main() {
-    #[cfg(target_os = "linux")]
-    cc::Build::new()
-        .flag("-nostdlib")
-        .file("src/platform/c/dragonos_malloc.c")
-        .compile("dragonos_malloc");
-    #[cfg(not(target_os = "linux"))]
-    cc::Build::new()
-        .flag("-nostdinc")
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
+
+    // Generate C includes
+    // - based on contents of src/header/**
+    // - headers written to target/include
+    fs::read_dir(&Path::new("src/header"))
+        .unwrap()
+        .into_iter()
+        .filter_map(Result::ok)
+        .filter(|d| include_dir(d))
+        .map(|d| d.path().as_path().join("cbindgen.toml"))
+        .filter(|p| p.exists())
+        .for_each(|p| {
+            println!("cargo:rerun-if-changed={:?}", p.parent().unwrap());
+            println!("cargo:rerun-if-changed={:?}", p);
+            println!("cargo:rerun-if-changed={:?}", p.with_file_name("mod.rs"));
+            generate_bindings(&p);
+        });
+
+    let mut c = cc::Build::new();
+    c.flag("-nostdinc")
         .flag("-nostdlib")
-        .file("src/platform/c/dragonos_malloc.c")
-        .compile("dragonos_malloc");
+        .flag("-fno-stack-protector")
+        .flag("-Wno-expansion-to-defined")
+        .file("src/platform/c/dragonos_malloc.c");
+
+    #[cfg(target_os = "dragonos")]
+    {
+        // for dragonos only
+        c.define("HAVE_MMAP", "0");
+    }
+
+    c.compile("drstd_c");
+
+    println!("cargo:rustc-link-lib=static=drstd_c");
 }

+ 3 - 0
core_io/.gitignore

@@ -0,0 +1,3 @@
+target
+Cargo.lock
+#src/????????????????????????????????????????

+ 32 - 0
core_io/Cargo.toml

@@ -0,0 +1,32 @@
+[package]
+name = "core_io"
+version = "0.1.20181107"
+authors = ["The Rust Project Developers", "Jethro Beekman"]
+license = "MIT/Apache-2.0"
+description = """
+This is a copy of libstd::io with all the parts that don't work in core removed.
+Most importantly, it provides the Read and Write traits.
+
+This crate is (mostly) automatically generated from the rust git source. The
+version of the source that corresponds to your compiler version will be
+selected automatically by the build script.
+"""
+repository = "https://github.com/jethrogb/rust-core_io"
+documentation = "https://doc.rust-lang.org/nightly/std/io/index.html"
+keywords = ["core", "no_std", "io", "read", "write"]
+include = [
+	"build.rs",
+	"Cargo.toml",
+	"LICENSE-*",
+	"mapping.rs",
+	"src/**/*.rs",
+]
+
+build = "build.rs"
+
+[build-dependencies]
+rustc_version = "0.1.7"
+
+[features]
+alloc = []
+collections = ["alloc"]

+ 201 - 0
core_io/LICENSE-APACHE

@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 25 - 0
core_io/LICENSE-MIT

@@ -0,0 +1,25 @@
+Copyright (c) 2014 The Rust Project Developers
+
+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.

+ 49 - 0
core_io/README.md

@@ -0,0 +1,49 @@
+# core_io
+
+`std::io` with all the parts that don't work in core removed.
+
+## Adding new nightly versions
+
+First, make sure the commit you want to add is fetch in the git tree at
+`/your/rust/dir/.git`. Then, import the right source files:
+
+```
+$ echo FULL_COMMIT_ID ...|GIT_DIR=/your/rust/dir/.git ./build-src.sh
+```
+
+Instead of echoing in the commit IDs, you might pipe in `rustc-commit-db
+list-valid`.
+
+The build-src script will prompt you to create patches for new commits. You
+will be dropped in a shell prompt with a temporary new, clean, git repository
+just for this patch. Make any changes necessary to make it build. **Don't**
+commit any changes! When exiting the shell and the script will use the working
+tree diff as the patch. The temporary git repository will be deleted. Before
+dropping into the shell, the script will show you nearby commits, you can try
+to apply `$PATCH_DIR/that_commit.patch` and see if it works for you.
+
+## Publishing
+
+```
+$ echo FULL_COMMIT_ID ...|GIT_DIR=/your/rust/dir/.git ./build-src.sh publish
+```
+
+Again, instead of echoing in the commit IDs, you might pipe in `rustc-commit-db
+list-valid`.
+
+## Editing patches
+
+To edit all patches, again make a checkout of the rust source. Then, run:
+
+```
+$ GIT_DIR=/your/rust/dir/.git ./edit-patches.sh
+```
+
+The script will prompt you to make changes. You will be dropped in a shell
+prompt with a temporary new, clean, git repository just for this patch edit.
+The original patch will be the HEAD commit in the repository. Make any changes
+you want. **Don't** commit any changes! When exiting the shell and the script
+will use the diff between the working tree and the root commit as the patch.
+The temporary git repository will be deleted. When editing further commits, the
+previous patch changes will already be applied to the working tree (if
+succesful).

+ 71 - 0
core_io/build-src.sh

@@ -0,0 +1,71 @@
+#!/bin/bash
+# Recommended command-line:
+#
+# commit-db.rb list-valid nightly|GIT_DIR=/your/rust/dir/.git ./build-src.sh
+
+prompt_changes() {
+	local MAIN_GIT_DIR="$GIT_DIR"
+	local GIT_DIR=./.git CORE_IO_COMMIT=$IO_COMMIT
+	git init > /dev/null
+	git add .
+	git commit -m "rust src import" > /dev/null
+	export CORE_IO_COMMIT
+	
+	bold_arrow; echo 'No patch found for' $IO_COMMIT
+	bold_arrow; echo 'Nearby commit(s) with patches:'
+	echo
+	GIT_DIR="$MAIN_GIT_DIR" git_commits_ordered '%H %cd' $(get_patch_commits) $IO_COMMIT | \
+	grep --color=always -1 $IO_COMMIT | sed /$IO_COMMIT/'s/$/ <=== your commit/'
+	echo
+	bold_arrow; echo -e "Try applying one of those using: \e[1;36mtry_patch COMMIT\e[0m"
+	bold_arrow; echo -e "Remember to test your changes with: \e[1;36mcargo build\e[0m"
+	bold_arrow; echo -e "Make your changes now (\e[1;36mctrl-D\e[0m when finished)"
+	bash_diff_loop "No changes were made"
+	bold_arrow; echo "Saving changes as $IO_COMMIT.patch"
+	git clean -f -x
+	git diff > ../../patches/$IO_COMMIT.patch
+	rm -rf .git
+}
+
+if [ ! -t 1 ] || [ ! -t 2 ]; then
+	echo "==> /dev/stdout or /dev/stderr is not attached to a terminal!"
+	echo "==> This script must be run interactively."
+	exit 1
+fi
+
+cd "$(dirname "$0")"
+
+. ./functions.sh
+
+PATCH_DIR="$PWD/patches"
+COMPILER_COMMITS=$(cat)
+IO_COMMITS=$(get_io_commits|sort -u)
+PATCH_COMMITS=$(get_patch_commits|sort -u)
+NEW_COMMITS=$(comm -2 -3 <(echo_lines $IO_COMMITS) <(echo_lines $PATCH_COMMITS))
+OLD_COMMITS=$(comm -1 -2 <(echo_lines $IO_COMMITS) <(echo_lines $PATCH_COMMITS))
+
+set -e
+set -o pipefail
+
+find src -mindepth 1 -type d -prune -exec rm -rf {} \;
+
+for IO_COMMIT in $OLD_COMMITS $(git_commits_ordered %H $NEW_COMMITS|tac); do
+	if ! [ -d src/$IO_COMMIT ]; then
+		prepare_version
+		
+		if [ -f patches/$IO_COMMIT.patch ]; then
+			bold_arrow; echo "Patching $IO_COMMIT"
+			patch -s -p1 -d src/$IO_COMMIT < patches/$IO_COMMIT.patch
+		else
+			cd src/$IO_COMMIT
+			prompt_changes
+			cd ../..
+		fi
+	fi
+done
+
+OLD_GIT_PERM=$(stat --printf=%a .git)
+trap "chmod $OLD_GIT_PERM .git; exit 1" SIGINT
+chmod 000 .git
+cargo ${1:-package}
+chmod $OLD_GIT_PERM .git

+ 81 - 0
core_io/build.rs

@@ -0,0 +1,81 @@
+extern crate rustc_version;
+
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+use std::ops::{Neg,Sub};
+
+/*
+ * Let me explain this hack. For the sync shell script it's easiest if every 
+ * line in mapping.rs looks exactly the same. This means that specifying an 
+ * array literal is not possible. include!() can only expand to expressions, so 
+ * just specifying the contents of an array is also not possible.
+ *
+ * This leaves us with trying to find an expression in which every line looks 
+ * the same. This can be done using the `-` operator. This can be a unary 
+ * operator (first thing on the first line), or a binary operator (later 
+ * lines). That is exactly what's going on here, and Neg and Sub simply build a 
+ * vector of the operangs.
+ */
+struct Mapping(&'static str,&'static str);
+
+impl Neg for Mapping {
+	type Output = Vec<Mapping>;
+    fn neg(self) -> Vec<Mapping> {
+		vec![self.into()]
+	}
+}
+
+impl Sub<Mapping> for Vec<Mapping> {
+    type Output=Vec<Mapping>;
+    fn sub(mut self, rhs: Mapping) -> Vec<Mapping> {
+		self.push(rhs.into());
+		self
+	}
+}
+
+fn main() {
+	let ver=rustc_version::version_meta();
+
+	let io_commit="b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d";
+	/*
+	let io_commit=match env::var("CORE_IO_COMMIT") {
+		Ok(c) => c,
+		Err(env::VarError::NotUnicode(_)) => panic!("Invalid commit specified in CORE_IO_COMMIT"),
+		Err(env::VarError::NotPresent) => {
+			let mappings=include!("mapping.rs");
+			
+			let compiler=ver.commit_hash.expect("Couldn't determine compiler version");
+			mappings.iter().find(|&&Mapping(elem,_)|elem==compiler).expect("Unknown compiler version, upgrade core_io?").1.to_owned()
+		}
+	};
+	*/
+
+	if ver.commit_date.as_ref().map_or(true,|d| &**d>="2018-01-01") {
+		println!("cargo:rustc-cfg=core_memchr");
+	}
+
+	if ver.commit_date.as_ref().map_or(true,|d| &**d>="2017-06-15") {
+		println!("cargo:rustc-cfg=no_collections");
+	}
+
+	if ver.commit_date.as_ref().map_or(false,|d| &**d<"2016-12-15") {
+		println!("cargo:rustc-cfg=rustc_unicode");
+	} else if ver.commit_date.as_ref().map_or(false,|d| &**d<"2017-03-03") {
+		println!("cargo:rustc-cfg=std_unicode");
+	}
+
+	let mut dest_path=PathBuf::from(env::var_os("OUT_DIR").unwrap());
+	dest_path.push("io.rs");
+	let mut f=File::create(&dest_path).unwrap();
+	
+	let mut target_path=PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
+	target_path.push("src");
+	target_path.push(io_commit);
+	target_path.push("mod.rs");
+
+	f.write_all(br#"#[path=""#).unwrap();
+	f.write_all(target_path.into_os_string().into_string().unwrap().replace("\\", "\\\\").as_bytes()).unwrap();
+	f.write_all(br#""] mod io;"#).unwrap();
+}

+ 10 - 0
core_io/doc.sh

@@ -0,0 +1,10 @@
+#!/bin/bash
+cd "$(dirname "$0")"
+HIDE_DOCBLOCKS='.docblock>*, .collapse-toggle, #toggle-all-docs { display: none; } #core_io-show-docblock+p { display: initial }'
+FIX_ERRORSTRING='.method a.type[title="core_io::ErrorString"]:before { content: "Error"; }'
+rm -rf target/doc
+cargo rustdoc --features collections -- --html-in-header <(echo '<style type="text/css">'"$HIDE_DOCBLOCKS"'</style>')
+mv target/doc target/doc_collections
+cargo rustdoc --features alloc -- --html-in-header <(echo '<style type="text/css">'"$HIDE_DOCBLOCKS $FIX_ERROR_STRING"'</style>')
+mv target/doc target/doc_alloc
+cargo rustdoc -- --html-in-header <(echo '<style type="text/css">'"$HIDE_DOCBLOCKS $FIX_ERROR_STRING"'</style>')

+ 61 - 0
core_io/edit-patches.sh

@@ -0,0 +1,61 @@
+#!/bin/bash
+# Recommended command-line:
+#
+# GIT_DIR=/your/rust/dir/.git ./edit-patches.sh
+
+prompt_changes() {
+	bold_arrow; echo "Editing $IO_COMMIT"
+	bold_arrow; echo -e "Remember to test your changes with: \e[1;36mcargo build\e[0m"
+
+	local MAIN_GIT_DIR="$GIT_DIR"
+	local GIT_DIR=./.git CORE_IO_COMMIT=$IO_COMMIT
+	export CORE_IO_COMMIT
+
+	git init > /dev/null
+	git add .
+	git commit -m "rust src import" > /dev/null
+	IMPORT_COMMIT=$(git log -n1 --pretty=format:%H)
+	patch -s -p1 < $PATCH_DIR/$IO_COMMIT.patch
+	git commit -a -m "existing patch for $IO_COMMIT" > /dev/null
+
+	bold_arrow; echo -e "Applying patch from \e[1;36m$TMP_PATCH\e[0m"
+	patch -p1 < $TMP_PATCH || true
+	bold_arrow; echo -e "Make your changes now (\e[1;36mctrl-D\e[0m when finished)"
+	bash_diff_loop "No changes were made"
+	bold_arrow; echo "Replacing $IO_COMMIT.patch with updated version"
+	git diff > $TMP_PATCH
+	git clean -f -x
+	git diff > $PATCH_DIR/$IO_COMMIT.patch
+	rm -rf .git
+}
+
+if [ ! -t 1 ] || [ ! -t 2 ]; then
+	echo "==> /dev/stdout or /dev/stderr is not attached to a terminal!"
+	echo "==> This script must be run interactively."
+	exit 1
+fi
+
+cd "$(dirname "$0")"
+
+. ./functions.sh
+
+PATCH_DIR="$PWD/patches"
+PATCH_COMMITS=$(get_patch_commits|sort -u)
+
+TMP_PATCH=$(mktemp)
+
+set -e
+set -o pipefail
+
+find src -mindepth 1 -type d -prune -exec rm -rf {} \;
+
+for IO_COMMIT in $(git_commits_ordered %H $PATCH_COMMITS|tac); do
+	prepare_version
+	cd src/$IO_COMMIT
+	prompt_changes
+	cd ../..
+done
+
+rm -rf $TMP_PATCH
+
+bold_arrow; echo "Done"

+ 89 - 0
core_io/functions.sh

@@ -0,0 +1,89 @@
+#!/bin/bash
+
+git_file_exists() {
+	[ "$(git ls-tree --name-only $IO_COMMIT -- $1)" = "$1" ]
+}
+
+git_extract() {
+	slashes=${1//[^\/]/}
+	git archive $IO_COMMIT $1|tar xf - -C src/$IO_COMMIT --strip-components=${#slashes}
+}
+
+git_commits_ordered() {
+	format="$1"
+	shift
+	if [ $# -ge 1 ]; then
+		git log --topo-order --no-walk=sorted --date=iso-local --pretty=format:"$format" "$@"
+	fi
+	echo
+}
+
+echo_lines() {
+	for i in "$@"; do
+		echo $i
+	done
+}
+
+get_io_commits() {
+	for COMPILER_COMMIT in $COMPILER_COMMITS; do
+		IO_COMMIT=$(git log -n1 --pretty=format:%H $COMPILER_COMMIT -- src/libstd/io)
+		if ! grep -q $COMPILER_COMMIT mapping.rs; then
+			echo "-Mapping(\"$COMPILER_COMMIT\",\"$IO_COMMIT\")" >> mapping.rs
+		fi
+		echo $IO_COMMIT
+	done
+}
+
+get_patch_commits() {
+	find $PATCH_DIR -type f -printf %f\\n|cut -d. -f1
+}
+
+prepare_version() {
+	mkdir src/$IO_COMMIT
+	git_extract src/libstd/io/
+	if git_file_exists src/libcore/slice/memchr.rs; then
+		true
+	elif git_file_exists src/libstd/sys_common/memchr.rs; then
+		git_extract src/libstd/sys_common/memchr.rs
+	elif git_file_exists src/libstd/sys/common/memchr.rs; then
+		git_extract src/libstd/sys/common/memchr.rs
+	else
+		git_extract src/libstd/memchr.rs
+	fi
+	rm -f src/$IO_COMMIT/stdio.rs src/$IO_COMMIT/lazy.rs
+}
+
+bold_arrow() {
+	echo -ne '\e[1;36m==> \e[0m'
+}
+
+custom_bashrc() {
+	echo '
+if [ -f ~/.bashrc ]; then . ~/.bashrc; fi
+
+try_patch() {
+	patch -p1 < ../../patches/$1.patch
+}
+'
+}
+
+bash_diff_loop() {
+	bash --rcfile <(custom_bashrc) <> /dev/stderr
+	while git diff --exit-code > /dev/null; do
+		bold_arrow; echo "$1"
+		while true; do
+			bold_arrow; echo -n "(T)ry again or (A)bort? "
+			read answer <> /dev/stderr
+			case "$answer" in
+				[tT])
+					break
+					;;
+				[aA])
+					bold_arrow; echo "Aborting..."
+					exit 1
+					;;
+			esac
+		done
+		bash <> /dev/stderr
+	done
+}

+ 593 - 0
core_io/mapping.rs

@@ -0,0 +1,593 @@
+-Mapping("01411937ff6b2a2dfad03d060d636941b0034591","dd56a6ad0845b76509c4f8967e8ca476471ab7e0")
+-Mapping("0554abac637800415bb1b30d8656898552a55ea0","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("0667ae93fb72eb25594258e55de9b4ae8f9f02a8","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("0dcc413e42f15f4fc51a0ca88a99cc89454ec43d","ce943eb369c9bdd0aef4917675e515f39f3b4a1e")
+-Mapping("12238b984abfacb2cccea176f862c94aa1231fb5","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("12d16599d84c25899f02a6e53110d1e70cdcbd8a","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("17790570373a7f560950d53ea4d67807232db255","8128817119e479b0610685e3fc7a6ff21cde5abc")
+-Mapping("179539f6eb61f75244a0dde641b6e4e09c0921ec","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("1ab87b65a220a933dc9d171ef0fd865ddd88fe89","dd56a6ad0845b76509c4f8967e8ca476471ab7e0")
+-Mapping("1c975eafa934e291e4f94b7252faae767de17313","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("2174bd97c1458d89a87eb2b614135d7ad68d6f18","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("21922e1f48b263b39498cfeec79c1ca3f5886efe","ce943eb369c9bdd0aef4917675e515f39f3b4a1e")
+-Mapping("22ac88f1a47a82195a49fbff3cf24a2c395d7a81","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("23ccaddaa7d1cb71e49ef1b1f423b3245fa3a879","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("241a9d0ddf99fd40d273c615e9b1e8ce6052d94a","161c541afdd18423940e97c7a02b517b1f6d61be")
+-Mapping("267cde2598db3b858730cc1f700f740964343828","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("2b6020723115e77ebe94f228c0c9b977b9199c6e","552eda70d33cead1398adfecce1a75e7a61e3daf")
+-Mapping("2b79e05a05f7259891adc4d7b0487d44121eb0c1","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("30a3849f228833f9dc280120126d16aef3a292ba","161c541afdd18423940e97c7a02b517b1f6d61be")
+-Mapping("34505e22289d3b2416ab0922131e8526d0d5cc0b","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("476fe6eefe17db91ff7a60aab34aa67a0a750a18","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("4ec5ce5e44823c29d4f641f764e53d57e8b28a6a","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("51d2d3da8081df21c51ee7ef9ae174531bb6557e","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("526f2bf5c534308193246e13ab2da8b3c0cf3cbb","8128817119e479b0610685e3fc7a6ff21cde5abc")
+-Mapping("5522e678bcefe14cc2ab3d0ab329b7059ce52b36","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("576229fea054105f1f3a49ca5f31f5f4983f5266","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("57ef015132ec09345b88d2ec20a9d9809b5d3dfc","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("5ab11d72cab23f0cea63cbf7a88817ff2a45bab0","161c541afdd18423940e97c7a02b517b1f6d61be")
+-Mapping("5c2a5d4499376ade0dd6bb30e8c5909abb42e574","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("5ebe41835fcc3dbfdbe282a9b4c3780968c0a97a","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("600dc3552ffcdff014cc770e98a67b674496d10a","161c541afdd18423940e97c7a02b517b1f6d61be")
+-Mapping("601eb13dc4dd075f82f03c85bbf8a1fbadfe2d6e","cae91d7c8c21aa860bda29c62207a6726837952b")
+-Mapping("62e2b2fb7acf5f8331781cd7128c754ed1b66c4f","9fe3c065b0e94b1e2ce7f14ab512475e79426ce4")
+-Mapping("645dd013ac6b334ab5bf7a7240c2243f4bb590c9","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("696b703b5a58816bb0e549ac332a98fa7e635949","dd56a6ad0845b76509c4f8967e8ca476471ab7e0")
+-Mapping("6974800c6b3733beb3aea31a0994d0c47c7a76c9","8e414e0e3f27d1917d11ee80de827698beb53891")
+-Mapping("6b4511755cfe63a46f2db8c72145e07f94911c08","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("6d215fe04ce3f638d717d7fcea95c40d0a655ff9","ce943eb369c9bdd0aef4917675e515f39f3b4a1e")
+-Mapping("6dcc2c1dee3b58afd44665d1df4a248bdd04cce5","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("6e00b55568c23e6270ae193a72256cc1c7c5f23a","cae91d7c8c21aa860bda29c62207a6726837952b")
+-Mapping("6e0f2f2f050443f2aec4e9c7d25618a6a6639b83","ce943eb369c9bdd0aef4917675e515f39f3b4a1e")
+-Mapping("74b886ab14d48c1f043dde0102aeff365c2f991f","ce943eb369c9bdd0aef4917675e515f39f3b4a1e")
+-Mapping("763f9234b052c7911dc4cf952a81a85c51c57784","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("764ef92ae7a26cbb9c2121de3812a0a17739f65f","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("7746a334da364e5e4c25360cd52e97691cbddc08","cae91d7c8c21aa860bda29c62207a6726837952b")
+-Mapping("7979dd6089ee5cba39cfbe6e880a3edeb7fff788","161c541afdd18423940e97c7a02b517b1f6d61be")
+-Mapping("7bddce693cec4ae4eb6970ed91289815b316cff3","cae91d7c8c21aa860bda29c62207a6726837952b")
+-Mapping("7d2f75a953b5645d3a336b2978b48b60d310bf54","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("7de2e6dc828473b60aefe4d2140a602cbeb6d6f9","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("801d2682df6cac505916644ebe678c9105f4c418","dd56a6ad0845b76509c4f8967e8ca476471ab7e0")
+-Mapping("8492b6aa4545e3e86f3b144c9a3834c31c612e38","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("8da2bcac5db1e091b90cceb19d0496f0f7501c88","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("915b003e32ca169c5c9b907a5457bc03582d5f67","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("924da295c3c1e697e96e359435c4052f3c6d8b56","8128817119e479b0610685e3fc7a6ff21cde5abc")
+-Mapping("97e3a2401e4b2f659d69ed0c0822cae04e3495b7","cae91d7c8c21aa860bda29c62207a6726837952b")
+-Mapping("98f0a9128f0fc6545de14a5de8f0e91675045e56","0f02309e4b0ea05ee905205278fb6d131341c41f")
+-Mapping("9c6904ca1e4ab95f6c48973dea718326735ad564","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("a0c325980367d5ee981145e31c70585acee40cd2","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("a1e29daf1a9ca4e26719887b0c934de5d1695031","87aee45988e81cb1a7bc9881aa7172d4f9caefd4")
+-Mapping("a43eb4e774f6d51b7012bba3d25212819ab0e3dc","552eda70d33cead1398adfecce1a75e7a61e3daf")
+-Mapping("a967611d8ffececb5ed0ecf6a205b464d7a5a31e","cae91d7c8c21aa860bda29c62207a6726837952b")
+-Mapping("ab0b87458f8c5d4762feae5e9d5c93ce6f644f6b","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("ad7fe6521b8a59d84102113ad660edb21de2cba6","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("ae33aa74f4e03b11a9a82e10dbf7369c3ae6bd04","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("af000a7bbffcaf5e75ff97b245fa5a413062acc1","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("b12b4e4e3266644d519647afc2943cefa2026e07","ce943eb369c9bdd0aef4917675e515f39f3b4a1e")
+-Mapping("b324fa7204dbdc17544d4402ffd0b1964df326f7","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("b5ba5923f8a15f7f06c660442ad895aff15599c0","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("b622c3e0856767d8e53cf141e2e0a7b6d72a198b","8128817119e479b0610685e3fc7a6ff21cde5abc")
+-Mapping("b678600ac94ee9cf3e679bb6128cd77b169231cb","161c541afdd18423940e97c7a02b517b1f6d61be")
+-Mapping("b9a93fad92a3411a0e452e339af06703e31c1464","ce943eb369c9bdd0aef4917675e515f39f3b4a1e")
+-Mapping("bb4a79b087158f396b984bdf552d2c90890b12a3","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("bd938166d6dabc689777555d5046dce893555eb7","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("bf5da36f1dfae45941ec39ef67a41fdbd22c1a50","161c541afdd18423940e97c7a02b517b1f6d61be")
+-Mapping("c2aaad4e2288647c5235754a5e1439a5124978fe","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("c66d2380a810c9a2b3dbb4f93a830b101ee49cc2","ce943eb369c9bdd0aef4917675e515f39f3b4a1e")
+-Mapping("c8b8eb1fda90998832ba1cdf96a34dc676f7124b","161c541afdd18423940e97c7a02b517b1f6d61be")
+-Mapping("c9629d61c6947030666379a6f46445f07849bbd9","c1fb50f5d377a41dd5833e4621e9a14879647503")
+-Mapping("cd6a400175cc230008a5094a8bbb44a3794f0465","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("cda7c1cf2463443aee4a2f51a5141bc7ce4a4f97","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("d5a91e69582b63f19192ad860df0f7a9a8530f56","87aee45988e81cb1a7bc9881aa7172d4f9caefd4")
+-Mapping("d7a71687ef1a9fa5665944608d5bad58d98a9684","87aee45988e81cb1a7bc9881aa7172d4f9caefd4")
+-Mapping("d91f8ab0f58fa123857d96b9e151fc5185f5ff08","9f935c8dd891ec6eb0809b8438656d1b39c2e2f5")
+-Mapping("dd6e8d45e183861d44ed91a99f0a50403b2776a3","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("e0fd34bba05cb43119abd6a45d3c33fcdf48c6b1","62b19c627ebde2bbfa6021de146c502124da7975")
+-Mapping("e1195c24bb567019d7cdc65bf5a4c642e38475d1","161c541afdd18423940e97c7a02b517b1f6d61be")
+-Mapping("ec872dc8a3f008299ca1508105ee064d1f0f0367","80d733385aa2ff150a5d6f83ecfe55afc7e19e68")
+-Mapping("ed7c56796ef17f13227a50dc1a72a018b1d5e33f","78ab18199d69bcc801668bfbeea8190b2c73a939")
+-Mapping("2ad5ed07f8f3e7d5c84be2d2df747fbd90f70d68","dd56a6ad0845b76509c4f8967e8ca476471ab7e0")
+-Mapping("5e18b4bad8450622aef8e077d3470f5626403588","98e3120ad218b8d9c50e25a525dcff689c515776")
+-Mapping("f93aaf84cb50dfaaba44b08c05bd51320263f592","d40c593f42fafbac1ff3d827f6df96338b5b7d8b")
+-Mapping("080e0e072f9c654893839cf1f7ea71dc153b08a9","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("0a3180baab7c361ee85958c88d971190649c3b70","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("0be88eb794949d27331ec45c300a40369b541001","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("0ef24eed2fe3bfdd050e246327332fadb5985a6a","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("1225e122fda8cfbe3a5da6007e912f204b97f8c4","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("1265cbf4e05628c98f51afebe0b662c451173faa","d6aa4e828c3dc3b7c417197990741b024f8c4ca3")
+-Mapping("144af3e97aa30feba3d36a98ac04c0f1b2bc0bea","d311079a6f70577d02f35bb80d27eef7e2b18a4a")
+-Mapping("1576de0ce6b75fd177eca289a2826d0190e407a5","e6cc4c5d13f8819c72568f9675e84c1d17368c67")
+-Mapping("197be89f367d1240d5f9cd9c4efd77812775354e","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("1987131063f08afc54d57cdba56c2acddcff191d","9a2c8783d91624261317316f996d8d2d09b7b6a4")
+-Mapping("19ac57926abb749a93e2eb84502048d9c57f2d7b","8d06332a27b020f5252238946fa9dccc3843d52a")
+-Mapping("1bf5fa3269ba32ae21e349ac675bdedcc7e99a66","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("1deb02ea69a7ca3fd8011a45bb75ff22c3f7579a","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("1fca1ab0e7be574022b2d229f0a6ad9bd580d1bf","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("27e766d7bc84be992c8ddef710affc92ef4a0adf","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("289f3a4ca79916d6445b452fc19a18a1e42a879a","26f9949bf678abc1fae595e3f6eb59a5bf8a7564")
+-Mapping("28ce3e8a55b21a285f7075612d140a44b42eb889","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("2c01bb885108c436adae2006632ff6dfc0a5f2cd","9a2c8783d91624261317316f996d8d2d09b7b6a4")
+-Mapping("3210fd5c20ffc6da420eb00e60bdc8704577fd3b","1f9036872d7ea8bee91f8588e3c4a613c58c76cb")
+-Mapping("32571c05c82c3b0fcb5d38afe03542226ca25d2d","d6aa4e828c3dc3b7c417197990741b024f8c4ca3")
+-Mapping("34f35ed29c8acdbe1e3c172786fc41d6f4fb6090","d40c593f42fafbac1ff3d827f6df96338b5b7d8b")
+-Mapping("378195665cc365720c784752877d5b1242c38ed8","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("388ccda455140e51456980efc07d175c19dcf005","f1e191c0b959111aef19f3aa06b7f1743419470c")
+-Mapping("3c5a0fa45b5e2786b6e64e27f48cd129e7aefdbd","e6cc4c5d13f8819c72568f9675e84c1d17368c67")
+-Mapping("47b3a983406f91489f781ae8cbd45590423fa701","d40c593f42fafbac1ff3d827f6df96338b5b7d8b")
+-Mapping("490189634b656dcca9e41e6b52093569c03bd4df","e6cc4c5d13f8819c72568f9675e84c1d17368c67")
+-Mapping("497d67d708e5e54344efc10f9c16ea83b215da9e","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("499484f56d336f4628a6fa016626beb3ef21ba81","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("4db1874f4c26a2c88acb5e46b413e9c4adce3477","d40c593f42fafbac1ff3d827f6df96338b5b7d8b")
+-Mapping("4f9812a59ab7247f0f52b01ca89b0793a2d289c3","d6aa4e828c3dc3b7c417197990741b024f8c4ca3")
+-Mapping("545a3a94fcbdd68c4eeb60848c8eae2118c639c7","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("54c0dcfd634cf31e6c18df5776cab2f3e7870157","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("5531c314a2855aec368e811da6fcd9e98365af51","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("55bf6a4f870cda7afddea7c6ca2b3ee9aac23ca2","d6aa4e828c3dc3b7c417197990741b024f8c4ca3")
+-Mapping("576f7665942414cb95239f8cbec4b654f231f4aa","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("6e8f92f11cdc713ddec4c60c66097d05c194bab2","8d06332a27b020f5252238946fa9dccc3843d52a")
+-Mapping("6ffdda1ba183c981d57e63b59c88184be449eee4","d6aa4e828c3dc3b7c417197990741b024f8c4ca3")
+-Mapping("70598e04f922a0f451f63cec4134bd28b31c6411","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("7333c4ac25648e831fb2033ee77fbbdc62ae492a","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("77d2cd28fd715d2b9751de82b14d28ce6e376728","9a2c8783d91624261317316f996d8d2d09b7b6a4")
+-Mapping("7ad125c4eb3d620c12a868dbe77180f1a133021b","d40c593f42fafbac1ff3d827f6df96338b5b7d8b")
+-Mapping("86affcdf6c622278a89b73bb7f1b8ac00e970888","26f9949bf678abc1fae595e3f6eb59a5bf8a7564")
+-Mapping("8787a12334439d47e931be26fef53381ce337c3a","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("91f057de35066d0a34102bd0673b56684509b93d","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("923bac45964940c56ab1075fb7980896de1eb620","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("9316ae515e2f8f3f497fb4f1559910c1eef2433d","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("936bfea94b800551c972e5689ae7da86d3d601de","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("9c31d76e97c6116ba2480aa23a48f3e7bd25a7cb","d311079a6f70577d02f35bb80d27eef7e2b18a4a")
+-Mapping("a005b6785935d7e92e87774c8f585839ddd12e46","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("a059cb2f3344c0a9efae17dde3d0e16a55ce93db","e107c8b84969fbe52cae7c9fd61858fddc6e016b")
+-Mapping("a23064af5ec7f52b287e2c60823fed92a4763502","9a2c8783d91624261317316f996d8d2d09b7b6a4")
+-Mapping("a3bc191b5f41df5143cc65084b13999896411817","8d06332a27b020f5252238946fa9dccc3843d52a")
+-Mapping("a7b2232d20320dc3b4044a2aec1d51a129e7e17d","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("a7bfb1aba9d089a0464c03b3841e889c6ee7c4f1","8d06332a27b020f5252238946fa9dccc3843d52a")
+-Mapping("acd3f796d26e9295db1eba1ef16e0d4cc3b96dd5","9a2c8783d91624261317316f996d8d2d09b7b6a4")
+-Mapping("ad19c32a58a1c5502e2f63350f72a2479c219498","8d06332a27b020f5252238946fa9dccc3843d52a")
+-Mapping("aef6971ca96be5f04291420cc773b8bfacb8b36d","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("b30eff7ba72a78e31acd61a2b6931919a0ad62e8","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("b5ad2779ea155f6a1b2b61415bc804dcbb23400c","d40c593f42fafbac1ff3d827f6df96338b5b7d8b")
+-Mapping("b6c1ef3745f707a0f76f17dc2b313b831ee1bfb0","d40c593f42fafbac1ff3d827f6df96338b5b7d8b")
+-Mapping("bbfcb471db0799a7d92d62e66cf44bbd68051675","d40c593f42fafbac1ff3d827f6df96338b5b7d8b")
+-Mapping("c772948b687488a087356cb91432425662e034b9","d6aa4e828c3dc3b7c417197990741b024f8c4ca3")
+-Mapping("cbe4de78e2daf84499988c79317c0862b8106115","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("cc62db802f9cb19606d3bfa4c4df0d0bc438543b","f1e191c0b959111aef19f3aa06b7f1743419470c")
+-Mapping("d0623cf7bda44849ab5df78a06b22f9108cf821a","e107c8b84969fbe52cae7c9fd61858fddc6e016b")
+-Mapping("d4037fc47682ba3aa02656b3bfca962c28965936","d6aa4e828c3dc3b7c417197990741b024f8c4ca3")
+-Mapping("e07dd59eaeb7be95afd2fb3dc131108ae750c91c","e6cc4c5d13f8819c72568f9675e84c1d17368c67")
+-Mapping("e9bc1bac8c7664fb1b487879b3fbd56221f6a721","e6cc4c5d13f8819c72568f9675e84c1d17368c67")
+-Mapping("eac41469d778d18ae7bf38fa917ed0fe122f944b","9a2c8783d91624261317316f996d8d2d09b7b6a4")
+-Mapping("ef9786ce0eac75bbe293d04dadc959bd481236a6","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("f164cf5d6443fd265f93662055d744074648189f","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("f1f40f850e2546c2c187514e3d61d17544ba433f","117cbb879e6ef498ea04e08bd80688bf2fc4a183")
+-Mapping("f883b0bbab6c433eb7b7042b605b4339022c563a","fda473f00fa07b9a8246b104396f9922e54bff16")
+-Mapping("feeca945738ffc6d252ae0fbb2f35723e4eb95a6","92400cf8dcf411ce7e70ab2960639977d46d5b01")
+-Mapping("098d22845933814a92497cbfaa8eb4a9a36b117f","8f10d6652ac212a7e30cb64017914ea1d5687767")
+-Mapping("6dc035ed911672c6a1f7afc9eed15fb08e574e5b","67aaddddd6195f7283a94b472b2f14cbed9d95fc")
+-Mapping("e0111758eb4f215db4ec26f809ef3edf5dfb66f5","67aaddddd6195f7283a94b472b2f14cbed9d95fc")
+-Mapping("16eeeac783d2ede28e09f2a433c612dea309fe33","67aaddddd6195f7283a94b472b2f14cbed9d95fc")
+-Mapping("f094206851e72e70528790cc9c70a745184ff7b0","32820c149b4b92aafc5f8d2e48a4265c5d865a1d")
+-Mapping("3caf63cc00f5cec580954bdb117f4fa756cc757d","32820c149b4b92aafc5f8d2e48a4265c5d865a1d")
+-Mapping("aef18be1bc4e03617177c5e9df1164ce3df49ba2","32820c149b4b92aafc5f8d2e48a4265c5d865a1d")
+-Mapping("c59cb71d976ceabf00c7da0224a795fab530601e","32820c149b4b92aafc5f8d2e48a4265c5d865a1d")
+-Mapping("3f4408347d2109803edbf53c89c8bce575de4b67","32820c149b4b92aafc5f8d2e48a4265c5d865a1d")
+-Mapping("cae6ab1c458ade22b4c228fcd4195917c96e2465","d2bc30b03fa4bf5425d080710f681f36f58f1706")
+-Mapping("71c06a56a120a0d5e3b224105ee3e6754f83e5fa","9a5cef4de51c1c90fb2d05b0c7e6feb9cf0224d6")
+-Mapping("40feadb966f825de7aa54a3138416c906b60f54a","88badb98c74f764f6e4baea3f6c9d3fd16013023")
+-Mapping("7846dbe0c8de17f59cdfc3d2b914d58faad7eade","8fba638b08eb85cda1bd2a4e855f7f76727dfc52")
+-Mapping("c07a6ae77cd4ceb3cf591d34c5608ca91d1f75d4","d5c3becf00452fd1d35e695494d7ae41dedb11d8")
+-Mapping("df8debf6d9afc431adbbd8311dcaf2b70eb9762e","19724d34d2b223f940363cc07aa83a8a530f8093")
+-Mapping("03bdaade2a0c39118a5be927c667776a5de0d681","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("24a70eb598a76edb0941f628a87946b40f2a1c83","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("7789881747f2ae40a520ae169eb90eb5d93795cc","d5c3becf00452fd1d35e695494d7ae41dedb11d8")
+-Mapping("a583f6f47cbfc4f0a21f70f7e4ed3e0fbe514c10","19724d34d2b223f940363cc07aa83a8a530f8093")
+-Mapping("ba7cf7cc5daefb9f28371b8be87dc262fb55937c","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("24055d0f2aa8dce5caed7544e6006aa48dceaea5","19724d34d2b223f940363cc07aa83a8a530f8093")
+-Mapping("f0b42075981d9914c39e848377a3e12f0adf37d7","d5c3becf00452fd1d35e695494d7ae41dedb11d8")
+-Mapping("d5814b03e652043be607f96e24709e06c2b55429","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("daf8c1dfce3b448fc581cc319f64632ec22bd0e1","3be2c3b3092e934bdc2db67d5bdcabd611deca9c")
+-Mapping("908dba0c9477b7dd022a236cb1514ddfca9369f2","3be2c3b3092e934bdc2db67d5bdcabd611deca9c")
+-Mapping("691eba1358fc3c9c7a8033314a4112d43680c128","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("5c94997b6b1cca3e65ecfc5ba40c033d6838019b","88badb98c74f764f6e4baea3f6c9d3fd16013023")
+-Mapping("8c4f2c64c6759a82f143e23964a46a65c67509c9","e7b0f2badf7c3393f1b36339b121054d05353442")
+-Mapping("c80c31a502c838f9ec06f1003d7c61cf9de9d551","3be2c3b3092e934bdc2db67d5bdcabd611deca9c")
+-Mapping("c8af93f0901c336e873ce18274026d0fd9bc7c1f","d5c3becf00452fd1d35e695494d7ae41dedb11d8")
+-Mapping("29dece1c8bbebf7ae8034ef0826b119281730937","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("3bf2be9ceea90b650105cd1f78ad5a098a0d158d","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("7b3eeea22c9b81f6e7277b79517a0dab25b9f383","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("28d6623bccf8f7e9a40a47895df75dd9ef2619da","3be2c3b3092e934bdc2db67d5bdcabd611deca9c")
+-Mapping("02310fd313cf3eed11fe5ac11921b73cc3b648d4","ce943eb369c9bdd0aef4917675e515f39f3b4a1e")
+-Mapping("8f02c429ad3e2ad687a222d1daae2e04bb9bb876","7e7775ce7bfc916ce723bd1fdaf4ae54662c6627")
+-Mapping("666e7148d167de551a7c3692caf9966f49773f4c","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("0ed951993fb5721a303ca5fa743543dd9f3f6b10","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("306035c21741928bef75b8915d2195cce400b70a","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("eedaa94e330094a84f4df9aa52949515327f8e80","19724d34d2b223f940363cc07aa83a8a530f8093")
+-Mapping("9761b17d558d0c980d4d2d5a0baba54f2bc6b63a","d5c3becf00452fd1d35e695494d7ae41dedb11d8")
+-Mapping("6f1ae663ef21602841173c0b9549347904e3c9a8","3c26ff450c914ab18e69b59777084eb101c65019")
+-Mapping("c49d10207a7e105525fb3bd71c18fde6fc2f5aed","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("ff591b6dc0e0a107c778d0bb4cf103881527e1a5","d5c3becf00452fd1d35e695494d7ae41dedb11d8")
+-Mapping("5d994d8b7e482e87467d4a521911477bd8284ce3","3c26ff450c914ab18e69b59777084eb101c65019")
+-Mapping("2217bd771c55aceff8eac61763af9bff11efd30c","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("50c186419bb38e8ea2f1e6f9c31b754e3a1a3e65","6edab01499c2af1b04e5914a64f0e66ae50253c3")
+-Mapping("91ae22a012fae7fa7589b1bba77bf4579708ee33","6edab01499c2af1b04e5914a64f0e66ae50253c3")
+-Mapping("0e77277950aafd38ce3e52b7b1cd9bcc6664de3c","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("6eb9960d3603aadab62b8f0877e87c63f67001d6","e7b0f2badf7c3393f1b36339b121054d05353442")
+-Mapping("62eb6056d332be09206dc664f2e949ae64341e64","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("c0b7112ba246d96f253ba845d91f36c0b7398e42","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("4be034e62270ca15c9fff173faef11939092f4e3","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("6f10e2f63de720468e2b4bfcb275e4b90b1f9870","031f9b15df3df5da19b64a1f824463053898d021")
+-Mapping("5309a3e31d88def1f3ea966162ed4f81f161d500","6edab01499c2af1b04e5914a64f0e66ae50253c3")
+-Mapping("134c4a0f08a3d1f55ea8968fbe728fa935c71698","e7b0f2badf7c3393f1b36339b121054d05353442")
+-Mapping("2564711e803f62e04bebf10408cc1c11297c0caf","6edab01499c2af1b04e5914a64f0e66ae50253c3")
+-Mapping("a52da95ced667fe8ff490f73c0b041a4f926c041","d5c3becf00452fd1d35e695494d7ae41dedb11d8")
+-Mapping("956e2bcbaa00c05e051718b1375375915064f1c3","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("fc2373c5a24646745dcbc14dc58889a9d8843f4e","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("4ce7accaa7e64af918e5e8b3fee65096132350f6","d5c3becf00452fd1d35e695494d7ae41dedb11d8")
+-Mapping("be760566cf938d11d34c2f6bd90d8fd0f67c2344","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("fd182c4010b5aee72d070b15e90c98cb0fdc3776","031f9b15df3df5da19b64a1f824463053898d021")
+-Mapping("bf6d7b665b85506dac663945229f00a406904fa5","d5c3becf00452fd1d35e695494d7ae41dedb11d8")
+-Mapping("536a900c471dffad6e33766a2866889000fbfa75","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("49c67bd632e961a57863805e5d0a400f97da9b93","e7b0f2badf7c3393f1b36339b121054d05353442")
+-Mapping("4853584000c2e71710318b1ff3393b6be25c076a","e7b0f2badf7c3393f1b36339b121054d05353442")
+-Mapping("0bd2ce62b27e2b9a7dfe92fc23d9098854008089","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("d9bdc636da951314064d8c3442bc5842a13e5b79","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("1a2ed98d344b6cbddc57db8841b42f935877e08d","3c26ff450c914ab18e69b59777084eb101c65019")
+-Mapping("a559452b05c20041a27f518d262573c56b876b64","e7b0f2badf7c3393f1b36339b121054d05353442")
+-Mapping("5665bdf3e3953a3fe67e047794913a0c88a83bde","0ca9967af75f7a279dcf4921f119b2602b41dd71")
+-Mapping("83c2d95238e3545e7ae9af4873c48b1e3651c164","19724d34d2b223f940363cc07aa83a8a530f8093")
+-Mapping("53f4bc311b5ff11a16185dd40dc116cf6b8cc162","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("b1e31766da75b188062c59f38cd6e8544b902afd","031f9b15df3df5da19b64a1f824463053898d021")
+-Mapping("ea7a6486a26af085862cd7a5596bb69e83d85e12","19724d34d2b223f940363cc07aa83a8a530f8093")
+-Mapping("ebeee0e27e32e212979d9f38d285b1dc2816cd0a","3be2c3b3092e934bdc2db67d5bdcabd611deca9c")
+-Mapping("08230775a026c955873ba557e624b7f665661f37","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("e703b33e3e03d1078c8825e1f64ecfb45884f5cb","e7b0f2badf7c3393f1b36339b121054d05353442")
+-Mapping("e4eb964dd950eb9afe861efc4ea5fc58c33b8296","031f9b15df3df5da19b64a1f824463053898d021")
+-Mapping("4ecc85beb339aa8089d936e450b0d800bdf580ae","3c26ff450c914ab18e69b59777084eb101c65019")
+-Mapping("064a0ee131b3129fcad68570975ccc85d0fb54d0","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("1572bf104dbf65d58bd6b889fa46229c9b92d6f9","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("468227129d08b52c4cf90313b29fdad1b80e596b","3c26ff450c914ab18e69b59777084eb101c65019")
+-Mapping("cab4bff3de1a61472f3c2e7752ef54b87344d1c9","e7b0f2badf7c3393f1b36339b121054d05353442")
+-Mapping("43006fcea0066a935b657fff9ccef56983cbf56c","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("2782e8f8fcefdce77c5e0dd0846c15c4c5103d84","3c26ff450c914ab18e69b59777084eb101c65019")
+-Mapping("1c448574bc668b0de70ed75223bf8798d17bf058","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("7821a9b995b34d6b2ab460e045797e6d2662e5bb","19724d34d2b223f940363cc07aa83a8a530f8093")
+-Mapping("0aeb9c12979e6da753701a798d04105b6b1a8c28","031f9b15df3df5da19b64a1f824463053898d021")
+-Mapping("ba872f270781ada15426cfac7db20b30b81777dc","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("47c8d9fdcf2e6502cf4ca7d7f059fdc1a2810afa","3c26ff450c914ab18e69b59777084eb101c65019")
+-Mapping("668864d9edd4f28d48005b57e5b177228cb974c5","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("60a0edc6c223a19d5288c90b0e7fbc85d6701ddc","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("5e122f59ba23494d460466cca53c71646d99c767","6edab01499c2af1b04e5914a64f0e66ae50253c3")
+-Mapping("e1cec5d4bf626f151a779323e16d62fe60117086","88badb98c74f764f6e4baea3f6c9d3fd16013023")
+-Mapping("a17e5e2949db53c9c1e3a697e41c254e31c0bdf3","9128f6100c9bfe2c2c22d85ccec92f01166f5d25")
+-Mapping("fc6f092c21a7a7249a9f8860f3cd10160aa36c02","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("ac635aa95ba851898e125b047ad7b8d6a8fecf8e","dcd80b80ae3fe2f327515e57fdc423a3927e44e6")
+-Mapping("3da40237e542e7859adab48049ec15cf18154817","e7b0f2badf7c3393f1b36339b121054d05353442")
+-Mapping("413a975e31584d1e22d158a70c6d3073b991a618","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("7e38a89a7b970181be083691504825a23e6b0a0f","3c26ff450c914ab18e69b59777084eb101c65019")
+-Mapping("0648517faf1e2cf37c8b6770cbd0180a816ed9a0","19724d34d2b223f940363cc07aa83a8a530f8093")
+-Mapping("7c69b0d5ae8c404c4847fa214126ebd7c0246277","e593c3b89343a98bdcc76ce9f5869ff18882dfff")
+-Mapping("ccce2c6eb914a66571f60fa0afe8a46faa9fb3bd","8fba638b08eb85cda1bd2a4e855f7f76727dfc52")
+-Mapping("824c9ebbd5f0611e326648d90ee3e50caf04bb7f","031f9b15df3df5da19b64a1f824463053898d021")
+-Mapping("0f34b532af590d25e9178f87c620931dd671cc2e","a2d176e8f4774b84db22540a45eed7b29482f154")
+-Mapping("3b5754e5ce73d24c6684b3ed0c68a557dfdd2f52","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("c58c928e658d2e45f816fd05796a964aa83759da","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("28a74299778cdad4ea999e4ee8f8c1ef793338bd","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("bbdaad0dc8dc64e036ccee817f90a91876b32a9d","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("d5cf1cb64cd1948a8c289e29838716f03d49d5aa","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("7627e3d31dd641ae9042675e9032857f58d0c5d1","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("9f2abadca2d065bf81772cb84981d0a22d8e98b3","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("452bf0852e1d47f7478d8b81328c15b183c6d971","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("ddc5d7bd4b9ea3e8a8ccf82cb443e950be311d61","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("1785bca5137fad1f26e4d3c347cbb68408a28fa9","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("252d3da8a6c715ccafcf77d83b826f6fb899cfe5","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("2bd4b5c6db1468235f730bce403bf657123ecc57","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("63c77214c1d38789652b465694b254205d1886e0","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("2b4c911581099e247a68b3a8adc782d778f5190b","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("036983201d4e9aeb5c5e56e47c305971972b2569","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("94e884b6307a59f1e6e64aa7ebc1996b651a7629","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("128aa262e8fe445f5c4d5c1f15dd28a2007c0234","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("afa1240e57330d85a372db4e28cd8bc8fa528ccb","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("06fb4d25642a3f223db1441972dd5962085cfba1","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("777ee20796e80a31d4b7c985dd68eda2941460d6","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("6a5fc9eecec235312755e737fb5b984abe537f2e","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("2d4ed8e0cbe2c5f3763273a5d8f6b15119473ba7","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("59f1a2f948a5e17d6675957813376ad8cc1d95ec","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("f4209651ec4d4455dab4fc3f3a3456a897d9da7f","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("f1140a33176a5fb2e91e26ea3ae42a834dd9bfdf","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("d3abc80b3e601473e763b129acb636757ed96fc7","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("978d2cfee1ee9da704c960c8047e978a7003b582","5f62b2716fb3f11bcbe00bd32ca2ca2b9de94a11")
+-Mapping("e40beb3af162e676e40704854dd6547ee8d4cf60","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("e17a1227ac779a181b2839998e26a7e4e434c2a0","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("826d8f3850b37a23481dfcf4a899b5dfc82d22e3","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("386b0b9d39274701f30d31ee6ce31c363c6036ea","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("75b05681239cb309a23fcb4f8864f177e5aa62da","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("0ed1ec9f9eb8174273867343d01177b5ac13ff4c","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("5dfcd85fd4bae49445383baadf472fbdb414a0e6","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("01951a61a49dca35747dc9ba03e5536f337de239","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("14f30da6132c25543da1f06c32a8c5699d3e5747","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("81734e0e06d24cf580dd5352c64d10110e4d3b7b","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("5b13bff5203c1bdc6ac6dc87f69b5359a9503078","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("5f39668642e445fedcf477493f206905dc51c2c8","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("557967766be6139bd747ab2c3dc56ff0c9b8852a","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("28fd1e519a3807c632d58d01e73b4948000639ba","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("d47cf08d57d881f34f9724edfb0b3b93209af202","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("5de00925bd3eb59711dee4982eb96f82d5a5e71a","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("f89d8d184490ecb3cf91f7b6bb7296d649f931ba","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("e0cc22b4bae8007c59fbe58f2c104ecd743d746a","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("4ed2edaafe82fb8d44e81e00ca3e4f7659855ba2","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("107bd67ef7fb3e8027d7234d687cdd27c3efaa0d","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("6684d176c78647c467870c75e276f5d37ffd3e3c","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("0418fa9d382a47d782cc1e195c14573be9c32095","4ab3bcb9ca137ad6e6ee4ae4a70a234d92b6d4ab")
+-Mapping("d015610db7b7d30f3c92d3272ce166397a81349e","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("76242aebb9d47558124c991a6faf0eb706d35703","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("f062832b208e94f2f0f26ed7fb5c48c172069fbe","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("148e9171481da43738d7d7a79c5e6f7bc2c2ccde","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("3d5b8c6266fd58cefa0d7af8c6115fe22532d069","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("4bf5c99afc75f411a4e064150781eefc749c10df","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("e2eaef8497bd212694840515a568d592b17d0e07","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("cfb5debbcb610eae16e8c5602416930f20fefa39","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("03abb1bd70ac56e4aba0684bab819892a0157843","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("554c685b0b3b25b7aa752717edf50b8d6bcab7a0","4bda94d0d820bf7baf2e97ec3552fe290b826391")
+-Mapping("5516bcc4588ea6192298b4e3682eb1d09581912a","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("258ae6dd9b1a8ac97986852fc9f00f7687004ccb","3cb78259862d37da082f628af3ccb54edf264fd0")
+-Mapping("ad36c2f5528d617db66c244d8bcbfc4b36da0ca0","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("14481f72102ba2abb5f314d5537fee90352981c5","b4be4758361bf1b03410a523e8672b1c1fa7d385")
+-Mapping("29f5c699b11a6a148f097f82eaa05202f8799bbc","f0a968eada509f71971e3ece02f8ec91b6f79e8a")
+-Mapping("a0dcecff90c45ad5d4eb60859e22bb3f1b03842a","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("8d22af87d812d9a132f0a030753a5cdf53c87ee8","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("bacb5c58dfdde7c35e99b2b0d8171238cc33cf6c","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("720c596ec62e8fec855c2953f21b0118ae408bdd","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("23032d0afa2b0e0c60a9b2ae62709f846d90007c","4c8cddb11b34021434d8d757e174096b10475840")
+-Mapping("15aa15b03f41278aa5b9e56975889929ee734c63","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("f85579d4a2c342654f9b158fafd565eb159fdb59","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("7eb64b86ce44cc1828dd176a8b981e37ea08fc38","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("ae920dcc98c9b18b38aac03367f7f1cd6dce7d2d","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("5965b790142eff7a8546e947914e7a8e00c61575","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("ee2286149a5f0b148334841d4f067dc819dcca3b","58557fafae060c500394d5df13cd0cf68170903e")
+-Mapping("b7960878ba77124505aabe7dc99d0a898354c326","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("417c73891ffd3a769e27c83b1d34916c3924ec94","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("37c7d0ebb3ec5b62bd37df9ee8826194e3c6300a","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("b2c0707872082c890f332178f59fd02eea5b98f3","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("8b22e70b2de5152db3b0c53cfa16eb96b0b9e40e","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("4e3901d35f6a8652f67111e7272263c9e62ab3e1","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("6a360194404c07e09b548626efa4b7c7777510e9","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("02a24dbdd8c3a5daa6578af72116020de75b5f93","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("1d2a6df38442a297b4ae25899700e29d1f150bb0","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("4502e2aa9c28d8caa610fc1815fd9c5b5a16e91c","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("ddd123ed9a35ec76103d42cecf322ee8d2896bf9","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("6fa53b00e7450060a3af9b1ef63169db37e589c2","02c1862fb55c6ae4198038b1b317bcdd06e395d1")
+-Mapping("445077963c55297ef1e196a3525723090fe80b22","f5f74a22c94a7053d33c88d135f9fdc44fa2ea5b")
+-Mapping("3c96d40d326b64f6a50f4a902051fe71c4acdc92","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("981ce7d8dd2c24063df648895196d9d557666fb1","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("ca94c75c527006be0824c764773380bbeea6030b","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("d762b1d6c67db12e117186d94d70e46cddb22965","e2554b36fc805c5dcb8bef65fee12e0753d5ad03")
+-Mapping("73bca2b9fa9399751e432734f7f12bd6a37fc167","4c8cddb11b34021434d8d757e174096b10475840")
+-Mapping("edbd7d232ee1272285be332b8a38eb47b4c8f5c6","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("77efd6800c57ba83923dddbbabf03c7afa6a34a4","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("250b492052e94d76bd318a4b932159395da55981","8835289434ba88351610f1ca7a19f7fefe5a53fa")
+-Mapping("dd53dd5f9e21dce1fbc06b7f9f451d1009bdcfd8","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("6f87d20a7cce70b8cc59a1adf3037d14bc83f237","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("05b5797664d6aeaa0c7d0606610f336fe0b57e97","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("21882aad7299e8e859785845ac12374990f24dae","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("4279e2b4c14dc90191595c97ad3a019d618e7158","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("c9bb93576d4484edd1b3c40eb2aea0dfa0788851","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("3610a70ce488953c5b0379fece70f2baad30a825","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("fc9ccfdbe02f4cf3e3ea60ee4412f00d29ef7f53","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("622e7e6487b6fb7fdbb901720cd4214f9179ed67","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("b633341c49498488b6e3fce501e23e9f9f8fadec","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("33374fa9d09e2a790979b31e61100dfed4b44139","838a38365daa047fca7e57f63f9c54614c45595f")
+-Mapping("dd08c30703d052205a68ae34331eea464178cd99","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("f62f774035735a06c880c48c0b9017fcc0577e33","27ede55414e01f13c6869a8763da207e544cc6ad")
+-Mapping("2d4df9584bebbdc72db77f550a6786819a3a791f","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("9fe7aa353fac5084d0a44d6a15970310e9be67f4","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("4fdb4bedfd2395e1e1ebb923b10165b850e6064c","c9f99924192e5c3a8d120eb36bcf96419b3fc7e0")
+-Mapping("56733bc9f8302409a2b6110f422512923c878154","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("150b625a07f135d0a5e1693adf2b14315709779e","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("5041b3bb3d953a14f32b15d1e41341c629acae12","838a38365daa047fca7e57f63f9c54614c45595f")
+-Mapping("932c736479f43dc8893a924946e4335d8e308c2e","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("90eb44a5897c39e3dff9c7e48e3973671dcd9496","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("3681220877771954fa923e50f227e632aabe8bbc","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("15a1e2844dfea7850be5c6c901b67ceff370b0eb","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("52a3309695e82ed399c1a22b4e4fdde5d3aa0f3b","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("827cb0d61e22eb6d5c9c5e8e8d05b07108a9968b","4c8cddb11b34021434d8d757e174096b10475840")
+-Mapping("0ff9872b2280009f094af0df3dcdc542cc46a5fd","f0a968eada509f71971e3ece02f8ec91b6f79e8a")
+-Mapping("d6b06c63a0c735fc15c9c704422375c17b7c7e12","1ccb50eaa670f86b69e7a64484a8c97e13169183")
+-Mapping("aac223f4f5d5ca979c694b614d4db37a7200528d","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("5dfc84cfa72b405c194228b53c4de3f6474204ec","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("e6072a7b3835f1875e81c9fd27799f9b20a0770c","27ede55414e01f13c6869a8763da207e544cc6ad")
+-Mapping("4d2d3fc5dadf894a8ad709a5860a549f2c0b1032","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("8c303ed8799edb0ea76d681a6ee97f7ef9f8f2a1","c9f99924192e5c3a8d120eb36bcf96419b3fc7e0")
+-Mapping("e340996ff5faa77b72d9b859aff34211033c1b68","e2554b36fc805c5dcb8bef65fee12e0753d5ad03")
+-Mapping("f9b0897c5d42a4dfa425db799073c6feb21b0178","4c8cddb11b34021434d8d757e174096b10475840")
+-Mapping("79cfce3d35cc8c2716c65650389d79551c2ea6ea","1ccb50eaa670f86b69e7a64484a8c97e13169183")
+-Mapping("bd0e45a323f85a1940d997ac237023c00670da67","58557fafae060c500394d5df13cd0cf68170903e")
+-Mapping("cbbe17aa7f13f9568a652c2180de03fa6881b86a","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("d9f124965551e8fb9403def6a715e13dfd5e9c95","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("277476c4fb9e967ca28a7b529dbcf6b348cb787d","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("734c83642cff23f0d9b4b8f006b05437697bcd91","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("3b82e4c74d43fc1273244532c3a90bf9912061cf","e2554b36fc805c5dcb8bef65fee12e0753d5ad03")
+-Mapping("d0f8e2913a93573c78cddfd297944cff4eb4c41a","838a38365daa047fca7e57f63f9c54614c45595f")
+-Mapping("c8ddf28527119a06a9f5da9bd34c97ae97afe531","02c1862fb55c6ae4198038b1b317bcdd06e395d1")
+-Mapping("599be0d18f4c6ddf36366d2a5a2ca6dc65886896","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("0701b37d97d08da7074ece7a7dcb4449498f4bfa","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("59d484575a714291481563d13ad058b9a3d31fa8","e2554b36fc805c5dcb8bef65fee12e0753d5ad03")
+-Mapping("73ac5d6a80f26c692f1e084b72d69637d7de2c8c","27ede55414e01f13c6869a8763da207e544cc6ad")
+-Mapping("0c6091fbd0eee290c651f73be899f221eeab3c05","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("322d7f7b97f1672bade31e1c43d5753e0e45a1a8","f0a968eada509f71971e3ece02f8ec91b6f79e8a")
+-Mapping("cfcac37204c8dbdde192c1c9387cdbe663fe5ed5","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("a47c9f870f13603a06ffe63ab4834fc716912843","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("b98fd524eca6dca5c4788f0d20becb10e099b876","f3ef077b910c9dada20eb106e8469ec071c27dad")
+-Mapping("b5392f54503fdaf04df4b9578510b2baa944f4af","d301da55f8cd7b8b10771d3171ae60ba334bf067")
+-Mapping("b8398d947d160ad4f26cc22da66e5fbc7030817b","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("5165ee9e209e0e70d89946ccbb7e90b9c0c3a7ac","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("3f92e8d89861f0f5408ad9381a7467ec6e7d76bc","80e2e67f4c6fbbef5e4789df7fc96804e6a84196")
+-Mapping("469a6f9bd9aef394c5cff6b3bc41b8c520f9515b","871bd237ee233bce3c3ba964c0b3948d685d7902")
+-Mapping("16362c737fe740f630ada06349fa9004e2a51bb7","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("229d0d3266002d343cdd2f4a3bf7f2fe9da15f38","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("d692a91fa69a057d82cf6cb71aa3d50260f9de4a","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("8e7a609e635b728eba65d471c985ab462dc4cfc7","f3ef077b910c9dada20eb106e8469ec071c27dad")
+-Mapping("da569fa9ddf8369a9809184d43c600dc06bd4b4d","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("a7e0d3a81f224649c8fcfc8ac3cb93f1e1107bea","972d67cec1fc0aeafebcc60ffcdf4dea0eadff8c")
+-Mapping("c284f8807eb3a1d728242bb6a767b0306d6f6bd5","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("0077d128d33543290140763ce7d84d05eb57c40a","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("63739ab7b210c1a8c890c2ea5238a3284877daa3","9b090a026108fab89cfe5f39bfd3492597e76ad4")
+-Mapping("9cb18a92ad87852c4c5d6726b8fbe8c38deda4ba","cb56b2d1522e83c5bb0613abcf78b686e994df9e")
+-Mapping("c9334404f06a188854af33835a0efe1e834e4ac4","cb56b2d1522e83c5bb0613abcf78b686e994df9e")
+-Mapping("f25c2283b3f8a7518b2f83a252b50d29d9bfbfda","972d67cec1fc0aeafebcc60ffcdf4dea0eadff8c")
+-Mapping("eba374fb21b63751ac10a09dbf269fd5067d4eb8","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("6828cf90146c7fefc4ba4f16dffe75f763f2d910","d301da55f8cd7b8b10771d3171ae60ba334bf067")
+-Mapping("2c0558f635861533e2fcb4298ea93250cdfc2c58","871bd237ee233bce3c3ba964c0b3948d685d7902")
+-Mapping("126321e2e505ea07887134ffe63afc759a8b7e9f","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("16992930835ce3376a4aaed42307726e1fc78e45","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("5f44c653cff61d0f55f53e07a188f755c7acddd1","9b090a026108fab89cfe5f39bfd3492597e76ad4")
+-Mapping("7ac979d8cbe97241fd39f4037e1d4069caaff4d2","1b6c9605e41b7c7dc23e0e6f633f05912d0463dd")
+-Mapping("2bb8fca18215298487a8684a132da828fdb5a751","871bd237ee233bce3c3ba964c0b3948d685d7902")
+-Mapping("2fbba5bdbadeef403a64e9e1568cdad225cbcec1","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("215e0b10eac17e43f0132971f4e2dd018fc33d43","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("45594d5dec4237f49e794a2a854a69f50b63d31e","9b090a026108fab89cfe5f39bfd3492597e76ad4")
+-Mapping("b1f8e6fb06d7362eeb2065347a7db94e76b1cb2f","f0a968eada509f71971e3ece02f8ec91b6f79e8a")
+-Mapping("0f9c784751434c70ddd6719ccda6817c819126f9","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("90ef3372e8ad74517eafa61e9494688c258b15ce","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("dc39c31699a83313edf2ac096d0bf3cef871b705","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("3eeb5a665e313c5b281820099e04d4c6c8188b46","f0a968eada509f71971e3ece02f8ec91b6f79e8a")
+-Mapping("560a5da9f1cc7f67d2fc372925aef18c96c82629","4c8cddb11b34021434d8d757e174096b10475840")
+-Mapping("088216fb997c9cb12ce049bbe7975d1f657551ca","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("ee220daca345302c3277befee2732b6b2a5a711c","d301da55f8cd7b8b10771d3171ae60ba334bf067")
+-Mapping("1ed7d41d8849d930f0622eaf54049f66fff0ca2a","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("003a929f99f7d4b36f62c4bdd5e5b0c7406e1189","49ee9f3f08ba4583bc722a663e43551067ace271")
+-Mapping("10d7cb44c98f25c04dcefb6b6555237de8b8bd7e","f5f74a22c94a7053d33c88d135f9fdc44fa2ea5b")
+-Mapping("9b85e1cfa5aa2aaa4b5df4359a023ad793983ffc","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("d93036a043dbd19f394ad320313bdbe81644f121","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("79a521bb9a8ace1a6663578a4c409906adde620d","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("fd4bef54abafe6d93ec3c87498de696da6ef5819","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("8493813cd8143940264f17d7bcb026c968d43b03","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("3f916bd3029262e2270dfbafb9ab045927499abd","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("ab40a7cb0e01159a04d4cfffc432c6d77f1f23c8","972d67cec1fc0aeafebcc60ffcdf4dea0eadff8c")
+-Mapping("97b01abf3d222523d0db4f79c13ed45e7fef27e3","bba7fd9dd54937719a6e88c954db7ab2ea5a3541")
+-Mapping("f590a44ce61888c78b9044817d8b798db5cd2ffd","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("fe7227f6c8704f0186091085a14fd1027920e4bb","f5f74a22c94a7053d33c88d135f9fdc44fa2ea5b")
+-Mapping("f1b5225e8b67adab52dda2b5ed5c8b805b716a6d","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("45fba43b3d5b4d1944268cf973099bfacb11bf4c","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("f861b6ee46465097eec266c160ac53e230df7cf0","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("bedbad61195d2eae69b43eca49c6d3e2aee8f208","f0a968eada509f71971e3ece02f8ec91b6f79e8a")
+-Mapping("ff0f5de3b3220e1276bfc9a70ce1787ca7a45388","838a38365daa047fca7e57f63f9c54614c45595f")
+-Mapping("269cf5026cdac6ff47f886a948e99101316d7091","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("ab5bec25530aac43dfd64384b405c909b6e405e3","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("5af17242ccb151e136122b2231df2fe4031d340e","c9f99924192e5c3a8d120eb36bcf96419b3fc7e0")
+-Mapping("7778906bee9e8e93792353824548044a758b72f4","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("7eeac1b81446c6327f1827ef334eca2db7fe28f7","49ee9f3f08ba4583bc722a663e43551067ace271")
+-Mapping("3bcda48a30b21e46b81a7989deb30a3ba85fb918","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("063deba92e44809125a433ca6e6c1ad0993313bf","f0a968eada509f71971e3ece02f8ec91b6f79e8a")
+-Mapping("2aeb5930f32514b9f2a4b90cd8ce6362af5f3c9f","871bd237ee233bce3c3ba964c0b3948d685d7902")
+-Mapping("9389e23a8a754097e233c7bf3ea1bb404ccf1075","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("0a2e9ade83ff253bb489c63a95b1f499c5e0916f","4c8cddb11b34021434d8d757e174096b10475840")
+-Mapping("6d9d82d3dff580d2ec31e4db5cdef73c9625a864","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("e026b59cf4f4cb9dd86510438085efafbc630e5a","cb56b2d1522e83c5bb0613abcf78b686e994df9e")
+-Mapping("3bfc18a9619a5151ff4f11618db9cd882996ba6f","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("bb42071f63830a984c4983f6fbdf982916857f72","4c8cddb11b34021434d8d757e174096b10475840")
+-Mapping("2dad872a2dae12b882cd73536a66c9289a2b65ae","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("29ed49fb0aeab444adcfe16ef3d04e5e910fb08d","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("4c053db233d69519b548e5b8ed7192d0783e582a","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("04145943a25c3b8c7e7d7fe8c2efb04f259c25fb","f5f74a22c94a7053d33c88d135f9fdc44fa2ea5b")
+-Mapping("539f2083de809b5c8304fe7426655cfeb0e66d5e","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("930d3b17dd91b6564cf535ac717c688db757be5d","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("c6884b12d9298f1e0af919cb9458a0d80acb3b0a","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("afe145d227c5739ec5305f6b5352230a58ebb029","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("0a3761e63e5961ddd6ae5b9923e7a3c0725541f8","f3ef077b910c9dada20eb106e8469ec071c27dad")
+-Mapping("2652ce6771b114189cdc1f9bd026a10af0a714e0","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("45caff88d1dabd71aec9431c07c0b4a77b20f203","1ccb50eaa670f86b69e7a64484a8c97e13169183")
+-Mapping("616b66dca25a67321b1654e5a65acc6337d63cf4","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("dead08cb331343b84564628b139b657f93548320","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("51b0b3734cbd0ca58c8be3512d53fce2d95f40dd","27ede55414e01f13c6869a8763da207e544cc6ad")
+-Mapping("687d3d15ba726dbb1ac6b85223ebe0e98c6820cc","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("97520ccb101609af63f29919bb0a39115269c89e","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("744dd6c1d5db522d5d3b7f2bb82abde5dc41cbeb","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("ed16b0a1de57bac50477ad83e35d648688cc0ded","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("9fd7da904b46ff7aa78c2e2cc1986c4975aeccc6","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("cfe1668ca3ddb3dc57b1af319e258a16664486fa","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("29c8276cee4a0eab7e0634ff25c6b47bd9f87c6c","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("086eaa78ea70075abe4e6b7fb9dc76259867b4be","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("27a046e9338fb0455c33b13e8fe28da78212dedc","af140ecdbc64251d7f536411c84e0d398a3d6631")
+-Mapping("4750c1ec047f18bc0e33823182e09711a3826fb5","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("f6d7514545cbe83e771a400d04049b96dfb210cd","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("230a379a452e5a2bcdfd0a956b259e0a1d83b512","c9f99924192e5c3a8d120eb36bcf96419b3fc7e0")
+-Mapping("598eddf4f785df12e79fba5a996f153dc6fdb7e0","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("a35a3abcda67a729edbb7d649dbc663c6feabd4c","1ccb50eaa670f86b69e7a64484a8c97e13169183")
+-Mapping("cddc4a62d8e72c2bd303994752a7f8545ffb9c79","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("4a7c072fa61b42f96d8b75c37fc1edfd71172695","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("8ccab7eed5f4fc93500fbf242e575073ca70d7cb","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("325ba23d5525ecdd555f19c7f527bce913dfd756","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("6c476ce462333fccd89ce3ed8c290998db874653","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("df511d5548ebb7f971abcd3a5283cb1d37b64596","972d67cec1fc0aeafebcc60ffcdf4dea0eadff8c")
+-Mapping("dcbbfb6e807fdff9c9ba80073bb755f9d9d95e31","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("78d8416caf65cfb50de61bb9423e9efa026bd45a","f5f74a22c94a7053d33c88d135f9fdc44fa2ea5b")
+-Mapping("8f1339af2e5d1b33ec9ee3c8a3c531bcd61770fc","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("05cbece0948f4fc0da3e21a7309e5ed34afdafe2","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("b39c4bc12358078f77ddd01288b24252f757f37d","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("d7e73e4b1abe120520d1894b89c0e25469f41e69","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("e97ba83287a6f0f85cc9cc7a51ab309487e17038","9b090a026108fab89cfe5f39bfd3492597e76ad4")
+-Mapping("3bee2b44cfd5610ad0346f0179602d91a8dedfd0","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("0679711398bef656699e1ff6b004ecccbdb67284","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("e21df8020d0d1a37d2856117b1be2f1a91d8bc42","1ccb50eaa670f86b69e7a64484a8c97e13169183")
+-Mapping("59ccba995de202fb9d9a8d795d2770fb2d199db0","c9f99924192e5c3a8d120eb36bcf96419b3fc7e0")
+-Mapping("692b94ae25e0ae7d74cf15a5800e10a16239dab1","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("def3269a71be2e737cad27418a3dad9f5bd6cd32","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("bf0a9e0b4d3a4dd09717960840798e2933ec7568","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("bd98fe0c05601d8a318a709adc4263f3348ea8d4","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("28a1e4ffefa2620ad9f4179ea339833448874fd3","f0a968eada509f71971e3ece02f8ec91b6f79e8a")
+-Mapping("3bd4af88bea2e6ecdd3455ed89b3ef1fc3500aa4","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("aabfed5e0c84211005c1cb2ecec2206a574a5146","838a38365daa047fca7e57f63f9c54614c45595f")
+-Mapping("2789b067da2ac921b86199bde21dd231ace1da39","cb56b2d1522e83c5bb0613abcf78b686e994df9e")
+-Mapping("185cc5f26d2c8a794189b028b43f6a3b8fc586db","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("77e189cd79ce98cf8d39082157445db54696f316","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("3ec5a99aaa0084d97a9e845b34fdf03d1462c475","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("246a6d19c9844744737876fc55701395ae535579","9b090a026108fab89cfe5f39bfd3492597e76ad4")
+-Mapping("13d94d5fa8129a34f5c77a1bcd76983f5aed2434","9c854db82b767ddd228dbff1e51bb3eed87464b4")
+-Mapping("5a2465e2b44ecdd3b5d835c0abe29e9a4c9dcfe4","02c1862fb55c6ae4198038b1b317bcdd06e395d1")
+-Mapping("61452e506f0c88861cccaeea4ced3419bdb3cbe0","93969734f6a8f38e95c7038c926ab2504e87dad6")
+-Mapping("02004ef78383cb174a41df7735a552823fa10b90","58557fafae060c500394d5df13cd0cf68170903e")
+-Mapping("b65f0bedd2f22d9661ecb7092f07746dc2ccfb0d","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("69c65d29615c391c958ebf75dd65258ec23e175c","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("e2668882406b68739c6ed33d420358d5d710e67b","49ee9f3f08ba4583bc722a663e43551067ace271")
+-Mapping("14039a42ac6365afc842214989613f9a688c9a66","ff457f012aef26f82c42c73783d7d3810d04d624")
+-Mapping("7d6e5b9da0865fbc9fa54edb324fefe80f358da7","6966f335ac7037900831007022f8d655bc186904")
+-Mapping("f142499539d038ef60f4e22cafe11ecdd8a29a1d","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("83c659ef655b1f740777f83eb415fd7ebe5a3fe5","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("58a8e0c27152e9306f8e0cd4fa3a162f5ae8e8c4","45d5a420ada9c11f61347fd4c63c7f0234adaea7")
+-Mapping("2be4cc040211a85b17f21e813ff62351ae4de642","e2554b36fc805c5dcb8bef65fee12e0753d5ad03")
+-Mapping("1956d5535ad77ddf46e4b29ba089a8b4a73cfaea","4c8cddb11b34021434d8d757e174096b10475840")
+-Mapping("f8af59d95225d122e38bb5dceb1027844d4ce170","3024c1434a667425d30e4b0785857381323712aa")
+-Mapping("f774bced502cf190426f778001a342715acb1d47","972d67cec1fc0aeafebcc60ffcdf4dea0eadff8c")
+-Mapping("2f1ef9ef1181298d46e79d5dde6bafeb6483926f","1d6d09fa6d3392343a89e1a4d116bf4170334300")
+-Mapping("26015da01497b4014fc4f2ecedee5a7090c354e6","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("01c65cb15ac57bfdc91613a4f6032ecc76c402a3","ff457f012aef26f82c42c73783d7d3810d04d624")
+-Mapping("6160040d8547222e761ad876cbe3a48c9c90a5bf","838a38365daa047fca7e57f63f9c54614c45595f")
+-Mapping("05f8ddc46a3fc09762a19f6c168550ce1ae66593","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("cfba0d446e8ab90f0c81aa0942819d05621c8b8e","02c1862fb55c6ae4198038b1b317bcdd06e395d1")
+-Mapping("17f56c549c35bb2cb316e5abff116e65277c7bb1","ff457f012aef26f82c42c73783d7d3810d04d624")
+-Mapping("37849a002ed91ac2b80aeb2172364b4e19250e05","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("696412de7e4e119f8536686c643621115b90c775","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("1abeb436d5b9618d96fe5ac093146aa3d782ef26","b60e6f82855d387c0ad98179c33e6c019e8a7d26")
+-Mapping("ba1d065ffa3606b61201ef69fec3ad0bfc5b2f7b","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("5313e8728f028cb7914f3c9f02804158a5732b52","62d6ba4638c0a4623f9aa703aa790da1380806d7")
+-Mapping("c11f689d2475dd9ab956e881238d5d7b6b485efb","49ee9f3f08ba4583bc722a663e43551067ace271")
+-Mapping("ae98ebfcb9ad5a5384fd229a6ee91315b02ca969","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("3d292b793ade0c1c9098fb32586033d79f6e9969","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("ad3543db3408b8d4ca53133a2999833befde8494","02c1862fb55c6ae4198038b1b317bcdd06e395d1")
+-Mapping("9475ae477a4d42c564eab9621ffb6aa7c160a3dc","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("859c3236e5ab974f24a82bbebffc72f58cf43800","ecbb896b9eb2acadefde57be493e4298c1aa04a3")
+-Mapping("c417ee9ae8c30ac307c58591da46cf62e91caac1","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("259e4a67843d5fbe6761a5e442836d7109d72cbe","cb56b2d1522e83c5bb0613abcf78b686e994df9e")
+-Mapping("4e9527cf6f2d3749554d07a96fe14967f5470ef6","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("0e6f4cf51cd3b799fb057956f8e733d16605d09b","075e16b2615ed16db9225bb28048cb334324e071")
+-Mapping("f0fe716dbcbf2363ab8f929325d32a17e51039d0","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("d84693b93dae3958e3504f817face0184c5c3fdd","d280b40b18532dfeb80b1a98109fa6218630b939")
+-Mapping("582af6e1ad75c12320e7237ff4361a1ed3514124","cc20ab1f2509de4ef0a9953e514d62fa23b6c572")
+-Mapping("fa26421f56e385b1055e65b29a55b36bb2eae23e","838a38365daa047fca7e57f63f9c54614c45595f")
+-Mapping("6c04c41034c46730fba97bfe9cfa2dd0687c2a5f","e9d70417cae7fcb08323351d9388b65b39560156")
+-Mapping("b75d1f0ce252f4b53f8a97aee0fcf4a785186fef","72e8009185b537083015f43a8e0fd34509ab1938")
+-Mapping("d6d711dd8f7ad5885294b8e1f0009a23dc1f8b1f","d52acbe37f69a2ebc9d161c479ed628da1cbea4e")
+-Mapping("8503b3ff822c1ed01c89773d30e4e10b886d77a5","02c1862fb55c6ae4198038b1b317bcdd06e395d1")
+-Mapping("5230979794db209de492b3f7cc688020b72bc7c6","b81da278623d9dcda1776008612bd42e1922e9c3")
+-Mapping("15d770400eed9018f18bddf83dd65cb7789280a5","b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d")

+ 6 - 0
core_io/publish.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+OLD_GIT_PERM=$(stat --printf=%a .git)
+trap "chmod $OLD_GIT_PERM .git; exit 1" SIGINT
+chmod 000 .git
+cargo publish
+chmod $OLD_GIT_PERM .git

+ 1303 - 0
core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/buffered.rs

@@ -0,0 +1,1303 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Buffering wrappers for I/O traits
+
+use core::prelude::v1::*;
+use io::prelude::*;
+
+use core::cmp;
+use core::fmt;
+use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
+use io::memchr;
+
+/// The `BufReader` struct adds buffering to any reader.
+///
+/// It can be excessively inefficient to work directly with a [`Read`] instance.
+/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
+/// results in a system call. A `BufReader` performs large, infrequent reads on
+/// the underlying [`Read`] and maintains an in-memory buffer of the results.
+///
+/// `BufReader` can improve the speed of programs that make *small* and
+/// *repeated* read calls to the same file or network socket.  It does not
+/// help when reading very large amounts at once, or reading just one or a few
+/// times.  It also provides no advantage when reading from a source that is
+/// already in memory, like a `Vec<u8>`.
+///
+/// [`Read`]: ../../std/io/trait.Read.html
+/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufReader;
+/// use std::fs::File;
+///
+/// fn main() -> std::io::Result<()> {
+///     let f = File::open("log.txt")?;
+///     let mut reader = BufReader::new(f);
+///
+///     let mut line = String::new();
+///     let len = reader.read_line(&mut line)?;
+///     println!("First line is {} bytes long", len);
+///     Ok(())
+/// }
+/// ```
+pub struct BufReader<R> {
+    inner: R,
+    buf: Box<[u8]>,
+    pos: usize,
+    cap: usize,
+}
+
+impl<R: Read> BufReader<R> {
+    /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB,
+    /// but may change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let reader = BufReader::new(f);
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn new(inner: R) -> BufReader<R> {
+        BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
+    }
+
+    /// Creates a new `BufReader` with the specified buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// Creating a buffer with ten bytes of capacity:
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let reader = BufReader::with_capacity(10, f);
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
+        unsafe {
+            let mut buffer = Vec::with_capacity(cap);
+            buffer.set_len(cap);
+            inner.initializer().initialize(&mut buffer);
+            BufReader {
+                inner,
+                buf: buffer.into_boxed_slice(),
+                pos: 0,
+                cap: 0,
+            }
+        }
+    }
+
+    /// Gets a reference to the underlying reader.
+    ///
+    /// It is inadvisable to directly read from the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f1 = File::open("log.txt")?;
+    ///     let reader = BufReader::new(f1);
+    ///
+    ///     let f2 = reader.get_ref();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn get_ref(&self) -> &R { &self.inner }
+
+    /// Gets a mutable reference to the underlying reader.
+    ///
+    /// It is inadvisable to directly read from the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f1 = File::open("log.txt")?;
+    ///     let mut reader = BufReader::new(f1);
+    ///
+    ///     let f2 = reader.get_mut();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
+
+    /// Returns a reference to the internally buffered data.
+    ///
+    /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # #![feature(bufreader_buffer)]
+    /// use std::io::{BufReader, BufRead};
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let mut reader = BufReader::new(f);
+    ///     assert!(reader.buffer().is_empty());
+    ///
+    ///     if reader.fill_buf()?.len() > 0 {
+    ///         assert!(!reader.buffer().is_empty());
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn buffer(&self) -> &[u8] {
+        &self.buf[self.pos..self.cap]
+    }
+
+    /// Unwraps this `BufReader`, returning the underlying reader.
+    ///
+    /// Note that any leftover data in the internal buffer is lost.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f1 = File::open("log.txt")?;
+    ///     let reader = BufReader::new(f1);
+    ///
+    ///     let f2 = reader.into_inner();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn into_inner(self) -> R { self.inner }
+}
+
+impl<R: Seek> BufReader<R> {
+    /// Seeks relative to the current position. If the new position lies within the buffer,
+    /// the buffer will not be flushed, allowing for more efficient seeks.
+    /// This method does not return the location of the underlying reader, so the caller
+    /// must track this information themselves if it is required.
+    pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
+        let pos = self.pos as u64;
+        if offset < 0 {
+            if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
+                self.pos = new_pos as usize;
+                return Ok(())
+            }
+        } else {
+            if let Some(new_pos) = pos.checked_add(offset as u64) {
+                if new_pos <= self.cap as u64 {
+                    self.pos = new_pos as usize;
+                    return Ok(())
+                }
+            }
+        }
+        self.seek(SeekFrom::Current(offset)).map(|_|())
+    }
+}
+
+impl<R: Read> Read for BufReader<R> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        // If we don't have any buffered data and we're doing a massive read
+        // (larger than our internal buffer), bypass our internal buffer
+        // entirely.
+        if self.pos == self.cap && buf.len() >= self.buf.len() {
+            return self.inner.read(buf);
+        }
+        let nread = {
+            let mut rem = self.fill_buf()?;
+            rem.read(buf)?
+        };
+        self.consume(nread);
+        Ok(nread)
+    }
+
+    // we can't skip unconditionally because of the large buffer case in read.
+    unsafe fn initializer(&self) -> Initializer {
+        self.inner.initializer()
+    }
+}
+
+impl<R: Read> BufRead for BufReader<R> {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> {
+        // If we've reached the end of our internal buffer then we need to fetch
+        // some more data from the underlying reader.
+        // Branch using `>=` instead of the more correct `==`
+        // to tell the compiler that the pos..cap slice is always valid.
+        if self.pos >= self.cap {
+            debug_assert!(self.pos == self.cap);
+            self.cap = self.inner.read(&mut self.buf)?;
+            self.pos = 0;
+        }
+        Ok(&self.buf[self.pos..self.cap])
+    }
+
+    fn consume(&mut self, amt: usize) {
+        self.pos = cmp::min(self.pos + amt, self.cap);
+    }
+}
+
+impl<R> fmt::Debug for BufReader<R> where R: fmt::Debug {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt.debug_struct("BufReader")
+            .field("reader", &self.inner)
+            .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
+            .finish()
+    }
+}
+
+impl<R: Seek> Seek for BufReader<R> {
+    /// Seek to an offset, in bytes, in the underlying reader.
+    ///
+    /// The position used for seeking with `SeekFrom::Current(_)` is the
+    /// position the underlying reader would be at if the `BufReader` had no
+    /// internal buffer.
+    ///
+    /// Seeking always discards the internal buffer, even if the seek position
+    /// would otherwise fall within it. This guarantees that calling
+    /// `.into_inner()` immediately after a seek yields the underlying reader
+    /// at the same position.
+    ///
+    /// To seek without discarding the internal buffer, use [`Seek::seek_relative`].
+    ///
+    /// See [`std::io::Seek`] for more details.
+    ///
+    /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)`
+    /// where `n` minus the internal buffer length overflows an `i64`, two
+    /// seeks will be performed instead of one. If the second seek returns
+    /// `Err`, the underlying reader will be left at the same position it would
+    /// have if you called `seek` with `SeekFrom::Current(0)`.
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        let result: u64;
+        if let SeekFrom::Current(n) = pos {
+            let remainder = (self.cap - self.pos) as i64;
+            // it should be safe to assume that remainder fits within an i64 as the alternative
+            // means we managed to allocate 8 exbibytes and that's absurd.
+            // But it's not out of the realm of possibility for some weird underlying reader to
+            // support seeking by i64::min_value() so we need to handle underflow when subtracting
+            // remainder.
+            if let Some(offset) = n.checked_sub(remainder) {
+                result = self.inner.seek(SeekFrom::Current(offset))?;
+            } else {
+                // seek backwards by our remainder, and then by the offset
+                self.inner.seek(SeekFrom::Current(-remainder))?;
+                self.pos = self.cap; // empty the buffer
+                result = self.inner.seek(SeekFrom::Current(n))?;
+            }
+        } else {
+            // Seeking with Start/End doesn't care about our buffer length.
+            result = self.inner.seek(pos)?;
+        }
+        self.pos = self.cap; // empty the buffer
+        Ok(result)
+    }
+}
+
+/// Wraps a writer and buffers its output.
+///
+/// It can be excessively inefficient to work directly with something that
+/// implements [`Write`]. For example, every call to
+/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A
+/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
+/// writer in large, infrequent batches.
+///
+/// `BufWriter` can improve the speed of programs that make *small* and
+/// *repeated* write calls to the same file or network socket.  It does not
+/// help when writing very large amounts at once, or writing just one or a few
+/// times.  It also provides no advantage when writing to a destination that is
+/// in memory, like a `Vec<u8>`.
+///
+/// When the `BufWriter` is dropped, the contents of its buffer will be written
+/// out. However, any errors that happen in the process of flushing the buffer
+/// when the writer is dropped will be ignored. Code that wishes to handle such
+/// errors must manually call [`flush`] before the writer is dropped.
+///
+/// # Examples
+///
+/// Let's write the numbers one through ten to a [`TcpStream`]:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::net::TcpStream;
+///
+/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+///
+/// for i in 0..10 {
+///     stream.write(&[i+1]).unwrap();
+/// }
+/// ```
+///
+/// Because we're not buffering, we write each one in turn, incurring the
+/// overhead of a system call per byte written. We can fix this with a
+/// `BufWriter`:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// for i in 0..10 {
+///     stream.write(&[i+1]).unwrap();
+/// }
+/// ```
+///
+/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped
+/// together by the buffer, and will all be written out in one system call when
+/// the `stream` is dropped.
+///
+/// [`Write`]: ../../std/io/trait.Write.html
+/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+/// [`flush`]: #method.flush
+pub struct BufWriter<W: Write> {
+    inner: Option<W>,
+    pub /* relibc */ buf: Vec<u8>,
+    // #30888: If the inner writer panics in a call to write, we don't want to
+    // write the buffered data a second time in BufWriter's destructor. This
+    // flag tells the Drop impl if it should skip the flush.
+    panicked: bool,
+}
+
+/// An error returned by `into_inner` which combines an error that
+/// happened while writing out the buffer, and the buffered writer object
+/// which may be used to recover from the condition.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// // do stuff with the stream
+///
+/// // we want to get our `TcpStream` back, so let's try:
+///
+/// let stream = match stream.into_inner() {
+///     Ok(s) => s,
+///     Err(e) => {
+///         // Here, e is an IntoInnerError
+///         panic!("An error occurred");
+///     }
+/// };
+/// ```
+#[derive(Debug)]
+pub struct IntoInnerError<W>(W, Error);
+
+impl<W: Write> BufWriter<W> {
+    /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB,
+    /// but may change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    /// ```
+    pub fn new(inner: W) -> BufWriter<W> {
+        BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
+    }
+
+    /// Creates a new `BufWriter` with the specified buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// Creating a buffer with a buffer of a hundred bytes.
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+    /// let mut buffer = BufWriter::with_capacity(100, stream);
+    /// ```
+    pub fn with_capacity(cap: usize, inner: W) -> BufWriter<W> {
+        BufWriter {
+            inner: Some(inner),
+            buf: Vec::with_capacity(cap),
+            panicked: false,
+        }
+    }
+
+    fn flush_buf(&mut self) -> io::Result<()> {
+        let mut written = 0;
+        let len = self.buf.len();
+        let mut ret = Ok(());
+        while written < len {
+            self.panicked = true;
+            let r = self.inner.as_mut().unwrap().write(&self.buf[written..]);
+            self.panicked = false;
+
+            match r {
+                Ok(0) => {
+                    ret = Err(Error::new(ErrorKind::WriteZero,
+                                         "failed to write the buffered data"));
+                    break;
+                }
+                Ok(n) => written += n,
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => { ret = Err(e); break }
+
+            }
+        }
+        if written > 0 {
+            self.buf.drain(..written);
+        }
+        ret
+    }
+
+    pub fn purge_buf(&mut self) {
+        self.buf = vec![];
+    }
+
+    /// Gets a reference to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // we can use reference just like buffer
+    /// let reference = buffer.get_ref();
+    /// ```
+    pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() }
+
+    /// Gets a mutable reference to the underlying writer.
+    ///
+    /// It is inadvisable to directly write to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // we can use reference just like buffer
+    /// let reference = buffer.get_mut();
+    /// ```
+    pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() }
+
+    /// Unwraps this `BufWriter`, returning the underlying writer.
+    ///
+    /// The buffer is written out before returning the writer.
+    ///
+    /// # Errors
+    ///
+    /// An `Err` will be returned if an error occurs while flushing the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // unwrap the TcpStream and flush the buffer
+    /// let stream = buffer.into_inner().unwrap();
+    /// ```
+    pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
+        match self.flush_buf() {
+            Err(e) => Err(IntoInnerError(self, e)),
+            Ok(()) => Ok(self.inner.take().unwrap())
+        }
+    }
+}
+
+impl<W: Write> Write for BufWriter<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        if self.buf.len() + buf.len() > self.buf.capacity() {
+            self.flush_buf()?;
+        }
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.inner.as_mut().unwrap().write(buf);
+            self.panicked = false;
+            r
+        } else {
+            Write::write(&mut self.buf, buf)
+        }
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        self.flush_buf().and_then(|()| self.get_mut().flush())
+    }
+}
+
+impl<W: Write> fmt::Debug for BufWriter<W> where W: fmt::Debug {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt.debug_struct("BufWriter")
+            .field("writer", &self.inner.as_ref().unwrap())
+            .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
+            .finish()
+    }
+}
+
+impl<W: Write + Seek> Seek for BufWriter<W> {
+    /// Seek to the offset, in bytes, in the underlying writer.
+    ///
+    /// Seeking always writes out the internal buffer before seeking.
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        self.flush_buf().and_then(|_| self.get_mut().seek(pos))
+    }
+}
+
+impl<W: Write> Drop for BufWriter<W> {
+    fn drop(&mut self) {
+        if self.inner.is_some() && !self.panicked {
+            // dtors should not panic, so we ignore a failed flush
+            let _r = self.flush_buf();
+        }
+    }
+}
+
+impl<W> IntoInnerError<W> {
+    /// Returns the error which caused the call to `into_inner()` to fail.
+    ///
+    /// This error was returned when attempting to write the internal buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // do stuff with the stream
+    ///
+    /// // we want to get our `TcpStream` back, so let's try:
+    ///
+    /// let stream = match stream.into_inner() {
+    ///     Ok(s) => s,
+    ///     Err(e) => {
+    ///         // Here, e is an IntoInnerError, let's log the inner error.
+    ///         //
+    ///         // We'll just 'log' to stdout for this example.
+    ///         println!("{}", e.error());
+    ///
+    ///         panic!("An unexpected error occurred.");
+    ///     }
+    /// };
+    /// ```
+    pub fn error(&self) -> &Error { &self.1 }
+
+    /// Returns the buffered writer instance which generated the error.
+    ///
+    /// The returned object can be used for error recovery, such as
+    /// re-inspecting the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // do stuff with the stream
+    ///
+    /// // we want to get our `TcpStream` back, so let's try:
+    ///
+    /// let stream = match stream.into_inner() {
+    ///     Ok(s) => s,
+    ///     Err(e) => {
+    ///         // Here, e is an IntoInnerError, let's re-examine the buffer:
+    ///         let buffer = e.into_inner();
+    ///
+    ///         // do stuff to try to recover
+    ///
+    ///         // afterwards, let's just return the stream
+    ///         buffer.into_inner().unwrap()
+    ///     }
+    /// };
+    /// ```
+    pub fn into_inner(self) -> W { self.0 }
+}
+
+impl<W> From<IntoInnerError<W>> for Error {
+    fn from(iie: IntoInnerError<W>) -> Error { iie.1 }
+}
+
+impl<W> fmt::Display for IntoInnerError<W> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.error().fmt(f)
+    }
+}
+
+/// Wraps a writer and buffers output to it, flushing whenever a newline
+/// (`0x0a`, `'\n'`) is detected.
+///
+/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output.
+/// But it only does this batched write when it goes out of scope, or when the
+/// internal buffer is full. Sometimes, you'd prefer to write each line as it's
+/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
+/// does exactly that.
+///
+/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
+/// `LineWriter` goes out of scope or when its internal buffer is full.
+///
+/// [bufwriter]: struct.BufWriter.html
+///
+/// If there's still a partial line in the buffer when the `LineWriter` is
+/// dropped, it will flush those contents.
+///
+/// # Examples
+///
+/// We can use `LineWriter` to write one line at a time, significantly
+/// reducing the number of actual writes to the file.
+///
+/// ```no_run
+/// use std::fs::{self, File};
+/// use std::io::prelude::*;
+/// use std::io::LineWriter;
+///
+/// fn main() -> std::io::Result<()> {
+///     let road_not_taken = b"I shall be telling this with a sigh
+/// Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.";
+///
+///     let file = File::create("poem.txt")?;
+///     let mut file = LineWriter::new(file);
+///
+///     file.write_all(b"I shall be telling this with a sigh")?;
+///
+///     // No bytes are written until a newline is encountered (or
+///     // the internal buffer is filled).
+///     assert_eq!(fs::read_to_string("poem.txt")?, "");
+///     file.write_all(b"\n")?;
+///     assert_eq!(
+///         fs::read_to_string("poem.txt")?,
+///         "I shall be telling this with a sigh\n",
+///     );
+///
+///     // Write the rest of the poem.
+///     file.write_all(b"Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.")?;
+///
+///     // The last line of the poem doesn't end in a newline, so
+///     // we have to flush or drop the `LineWriter` to finish
+///     // writing.
+///     file.flush()?;
+///
+///     // Confirm the whole poem was written.
+///     assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]);
+///     Ok(())
+/// }
+/// ```
+pub struct LineWriter<W: Write> {
+    pub /* relibc */ inner: BufWriter<W>,
+    need_flush: bool,
+}
+
+impl<W: Write> LineWriter<W> {
+    /// Creates a new `LineWriter`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::new(file);
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn new(inner: W) -> LineWriter<W> {
+        // Lines typically aren't that long, don't use a giant buffer
+        LineWriter::with_capacity(1024, inner)
+    }
+
+    /// Creates a new `LineWriter` with a specified capacity for the internal
+    /// buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::with_capacity(100, file);
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> {
+        LineWriter {
+            inner: BufWriter::with_capacity(cap, inner),
+            need_flush: false,
+        }
+    }
+
+    /// Gets a reference to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::new(file);
+    ///
+    ///     let reference = file.get_ref();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn get_ref(&self) -> &W { self.inner.get_ref() }
+
+    /// Gets a mutable reference to the underlying writer.
+    ///
+    /// Caution must be taken when calling methods on the mutable reference
+    /// returned as extra writes could corrupt the output stream.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let mut file = LineWriter::new(file);
+    ///
+    ///     // we can use reference just like file
+    ///     let reference = file.get_mut();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() }
+
+    /// Unwraps this `LineWriter`, returning the underlying writer.
+    ///
+    /// The internal buffer is written out before returning the writer.
+    ///
+    /// # Errors
+    ///
+    /// An `Err` will be returned if an error occurs while flushing the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///
+    ///     let writer: LineWriter<File> = LineWriter::new(file);
+    ///
+    ///     let file: File = writer.into_inner()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
+        self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
+            IntoInnerError(LineWriter {
+                inner: buf,
+                need_flush: false,
+            }, e)
+        })
+    }
+
+    pub fn purge(&mut self) {
+        self.inner.purge_buf();
+        self.need_flush = false;
+    }
+}
+
+impl<W: Write> Write for LineWriter<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        if self.need_flush {
+            self.flush()?;
+        }
+
+        // Find the last newline character in the buffer provided. If found then
+        // we're going to write all the data up to that point and then flush,
+        // otherwise we just write the whole block to the underlying writer.
+        let i = match memchr::memrchr(b'\n', buf) {
+            Some(i) => i,
+            None => return self.inner.write(buf),
+        };
+
+
+        // Ok, we're going to write a partial amount of the data given first
+        // followed by flushing the newline. After we've successfully written
+        // some data then we *must* report that we wrote that data, so future
+        // errors are ignored. We set our internal `need_flush` flag, though, in
+        // case flushing fails and we need to try it first next time.
+        let n = self.inner.write(&buf[..i + 1])?;
+        self.need_flush = true;
+        if self.flush().is_err() || n != i + 1 {
+            return Ok(n)
+        }
+
+        // At this point we successfully wrote `i + 1` bytes and flushed it out,
+        // meaning that the entire line is now flushed out on the screen. While
+        // we can attempt to finish writing the rest of the data provided.
+        // Remember though that we ignore errors here as we've successfully
+        // written data, so we need to report that.
+        match self.inner.write(&buf[i + 1..]) {
+            Ok(i) => Ok(n + i),
+            Err(_) => Ok(n),
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.inner.flush()?;
+        self.need_flush = false;
+        Ok(())
+    }
+}
+
+impl<W: Write> fmt::Debug for LineWriter<W> where W: fmt::Debug {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt.debug_struct("LineWriter")
+            .field("writer", &self.inner.inner)
+            .field("buffer",
+                   &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity()))
+            .finish()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use io::prelude::*;
+    use io::{self, BufReader, BufWriter, LineWriter, SeekFrom};
+    use sync::atomic::{AtomicUsize, Ordering};
+    use thread;
+    use test;
+
+    /// A dummy reader intended at testing short-reads propagation.
+    pub struct ShortReader {
+        lengths: Vec<usize>,
+    }
+
+    impl Read for ShortReader {
+        fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
+            if self.lengths.is_empty() {
+                Ok(0)
+            } else {
+                Ok(self.lengths.remove(0))
+            }
+        }
+    }
+
+    #[test]
+    fn test_buffered_reader() {
+        let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+        let mut reader = BufReader::with_capacity(2, inner);
+
+        let mut buf = [0, 0, 0];
+        let nread = reader.read(&mut buf);
+        assert_eq!(nread.unwrap(), 3);
+        let b: &[_] = &[5, 6, 7];
+        assert_eq!(buf, b);
+
+        let mut buf = [0, 0];
+        let nread = reader.read(&mut buf);
+        assert_eq!(nread.unwrap(), 2);
+        let b: &[_] = &[0, 1];
+        assert_eq!(buf, b);
+
+        let mut buf = [0];
+        let nread = reader.read(&mut buf);
+        assert_eq!(nread.unwrap(), 1);
+        let b: &[_] = &[2];
+        assert_eq!(buf, b);
+
+        let mut buf = [0, 0, 0];
+        let nread = reader.read(&mut buf);
+        assert_eq!(nread.unwrap(), 1);
+        let b: &[_] = &[3, 0, 0];
+        assert_eq!(buf, b);
+
+        let nread = reader.read(&mut buf);
+        assert_eq!(nread.unwrap(), 1);
+        let b: &[_] = &[4, 0, 0];
+        assert_eq!(buf, b);
+
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    }
+
+    #[test]
+    fn test_buffered_reader_seek() {
+        let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+        let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
+
+        assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3));
+        assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+        assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3));
+        assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+        assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4));
+        assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..]));
+        reader.consume(1);
+        assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3));
+    }
+
+    #[test]
+    fn test_buffered_reader_seek_relative() {
+        let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+        let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
+
+        assert!(reader.seek_relative(3).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+        assert!(reader.seek_relative(0).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+        assert!(reader.seek_relative(1).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[1][..]));
+        assert!(reader.seek_relative(-1).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+        assert!(reader.seek_relative(2).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..]));
+    }
+
+    #[test]
+    fn test_buffered_reader_seek_underflow() {
+        // gimmick reader that yields its position modulo 256 for each byte
+        struct PositionReader {
+            pos: u64
+        }
+        impl Read for PositionReader {
+            fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+                let len = buf.len();
+                for x in buf {
+                    *x = self.pos as u8;
+                    self.pos = self.pos.wrapping_add(1);
+                }
+                Ok(len)
+            }
+        }
+        impl Seek for PositionReader {
+            fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+                match pos {
+                    SeekFrom::Start(n) => {
+                        self.pos = n;
+                    }
+                    SeekFrom::Current(n) => {
+                        self.pos = self.pos.wrapping_add(n as u64);
+                    }
+                    SeekFrom::End(n) => {
+                        self.pos = u64::max_value().wrapping_add(n as u64);
+                    }
+                }
+                Ok(self.pos)
+            }
+        }
+
+        let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 });
+        assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..]));
+        assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value()-5));
+        assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
+        // the following seek will require two underlying seeks
+        let expected = 9223372036854775802;
+        assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected));
+        assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
+        // seeking to 0 should empty the buffer.
+        assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected));
+        assert_eq!(reader.get_ref().pos, expected);
+    }
+
+    #[test]
+    fn test_buffered_writer() {
+        let inner = Vec::new();
+        let mut writer = BufWriter::with_capacity(2, inner);
+
+        writer.write(&[0, 1]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1]);
+
+        writer.write(&[2]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1]);
+
+        writer.write(&[3]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1]);
+
+        writer.flush().unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
+
+        writer.write(&[4]).unwrap();
+        writer.write(&[5]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
+
+        writer.write(&[6]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
+
+        writer.write(&[7, 8]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+        writer.write(&[9, 10, 11]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+
+        writer.flush().unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+    }
+
+    #[test]
+    fn test_buffered_writer_inner_flushes() {
+        let mut w = BufWriter::with_capacity(3, Vec::new());
+        w.write(&[0, 1]).unwrap();
+        assert_eq!(*w.get_ref(), []);
+        let w = w.into_inner().unwrap();
+        assert_eq!(w, [0, 1]);
+    }
+
+    #[test]
+    fn test_buffered_writer_seek() {
+        let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new()));
+        w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap();
+        w.write_all(&[6, 7]).unwrap();
+        assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8));
+        assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]);
+        assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2));
+        w.write_all(&[8, 9]).unwrap();
+        assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]);
+    }
+
+    #[test]
+    fn test_read_until() {
+        let inner: &[u8] = &[0, 1, 2, 1, 0];
+        let mut reader = BufReader::with_capacity(2, inner);
+        let mut v = Vec::new();
+        reader.read_until(0, &mut v).unwrap();
+        assert_eq!(v, [0]);
+        v.truncate(0);
+        reader.read_until(2, &mut v).unwrap();
+        assert_eq!(v, [1, 2]);
+        v.truncate(0);
+        reader.read_until(1, &mut v).unwrap();
+        assert_eq!(v, [1]);
+        v.truncate(0);
+        reader.read_until(8, &mut v).unwrap();
+        assert_eq!(v, [0]);
+        v.truncate(0);
+        reader.read_until(9, &mut v).unwrap();
+        assert_eq!(v, []);
+    }
+
+    #[test]
+    fn test_line_buffer_fail_flush() {
+        // Issue #32085
+        struct FailFlushWriter<'a>(&'a mut Vec<u8>);
+
+        impl<'a> Write for FailFlushWriter<'a> {
+            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+                self.0.extend_from_slice(buf);
+                Ok(buf.len())
+            }
+            fn flush(&mut self) -> io::Result<()> {
+                Err(io::Error::new(io::ErrorKind::Other, "flush failed"))
+            }
+        }
+
+        let mut buf = Vec::new();
+        {
+            let mut writer = LineWriter::new(FailFlushWriter(&mut buf));
+            let to_write = b"abc\ndef";
+            if let Ok(written) = writer.write(to_write) {
+                assert!(written < to_write.len(), "didn't flush on new line");
+                // PASS
+                return;
+            }
+        }
+        assert!(buf.is_empty(), "write returned an error but wrote data");
+    }
+
+    #[test]
+    fn test_line_buffer() {
+        let mut writer = LineWriter::new(Vec::new());
+        writer.write(&[0]).unwrap();
+        assert_eq!(*writer.get_ref(), []);
+        writer.write(&[1]).unwrap();
+        assert_eq!(*writer.get_ref(), []);
+        writer.flush().unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1]);
+        writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']);
+        writer.flush().unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]);
+        writer.write(&[3, b'\n']).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']);
+    }
+
+    #[test]
+    fn test_read_line() {
+        let in_buf: &[u8] = b"a\nb\nc";
+        let mut reader = BufReader::with_capacity(2, in_buf);
+        let mut s = String::new();
+        reader.read_line(&mut s).unwrap();
+        assert_eq!(s, "a\n");
+        s.truncate(0);
+        reader.read_line(&mut s).unwrap();
+        assert_eq!(s, "b\n");
+        s.truncate(0);
+        reader.read_line(&mut s).unwrap();
+        assert_eq!(s, "c");
+        s.truncate(0);
+        reader.read_line(&mut s).unwrap();
+        assert_eq!(s, "");
+    }
+
+    #[test]
+    fn test_lines() {
+        let in_buf: &[u8] = b"a\nb\nc";
+        let reader = BufReader::with_capacity(2, in_buf);
+        let mut it = reader.lines();
+        assert_eq!(it.next().unwrap().unwrap(), "a".to_string());
+        assert_eq!(it.next().unwrap().unwrap(), "b".to_string());
+        assert_eq!(it.next().unwrap().unwrap(), "c".to_string());
+        assert!(it.next().is_none());
+    }
+
+    #[test]
+    fn test_short_reads() {
+        let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]};
+        let mut reader = BufReader::new(inner);
+        let mut buf = [0, 0];
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+        assert_eq!(reader.read(&mut buf).unwrap(), 1);
+        assert_eq!(reader.read(&mut buf).unwrap(), 2);
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+        assert_eq!(reader.read(&mut buf).unwrap(), 1);
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    }
+
+    #[test]
+    #[should_panic]
+    fn dont_panic_in_drop_on_panicked_flush() {
+        struct FailFlushWriter;
+
+        impl Write for FailFlushWriter {
+            fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
+            fn flush(&mut self) -> io::Result<()> {
+                Err(io::Error::last_os_error())
+            }
+        }
+
+        let writer = FailFlushWriter;
+        let _writer = BufWriter::new(writer);
+
+        // If writer panics *again* due to the flush error then the process will
+        // abort.
+        panic!();
+    }
+
+    #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
+    fn panic_in_write_doesnt_flush_in_drop() {
+        static WRITES: AtomicUsize = AtomicUsize::new(0);
+
+        struct PanicWriter;
+
+        impl Write for PanicWriter {
+            fn write(&mut self, _: &[u8]) -> io::Result<usize> {
+                WRITES.fetch_add(1, Ordering::SeqCst);
+                panic!();
+            }
+            fn flush(&mut self) -> io::Result<()> { Ok(()) }
+        }
+
+        thread::spawn(|| {
+            let mut writer = BufWriter::new(PanicWriter);
+            let _ = writer.write(b"hello world");
+            let _ = writer.flush();
+        }).join().unwrap_err();
+
+        assert_eq!(WRITES.load(Ordering::SeqCst), 1);
+    }
+
+    #[bench]
+    fn bench_buffered_reader(b: &mut test::Bencher) {
+        b.iter(|| {
+            BufReader::new(io::empty())
+        });
+    }
+
+    #[bench]
+    fn bench_buffered_writer(b: &mut test::Bencher) {
+        b.iter(|| {
+            BufWriter::new(io::sink())
+        });
+    }
+
+    struct AcceptOneThenFail {
+        written: bool,
+        flushed: bool,
+    }
+
+    impl Write for AcceptOneThenFail {
+        fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+            if !self.written {
+                assert_eq!(data, b"a\nb\n");
+                self.written = true;
+                Ok(data.len())
+            } else {
+                Err(io::Error::new(io::ErrorKind::NotFound, "test"))
+            }
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            assert!(self.written);
+            assert!(!self.flushed);
+            self.flushed = true;
+            Err(io::Error::new(io::ErrorKind::Other, "test"))
+        }
+    }
+
+    #[test]
+    fn erroneous_flush_retried() {
+        let a = AcceptOneThenFail {
+            written: false,
+            flushed: false,
+        };
+
+        let mut l = LineWriter::new(a);
+        assert_eq!(l.write(b"a\nb\na").unwrap(), 4);
+        assert!(l.get_ref().written);
+        assert!(l.get_ref().flushed);
+        l.get_mut().flushed = false;
+
+        assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other)
+    }
+}

+ 678 - 0
core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/cursor.rs

@@ -0,0 +1,678 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io::prelude::*;
+
+#[cfg(feature="alloc")]
+use core::convert::TryInto;
+use core::cmp;
+use io::{self, Initializer, SeekFrom, Error, ErrorKind};
+
+/// A `Cursor` wraps an in-memory buffer and provides it with a
+/// [`Seek`] implementation.
+///
+/// `Cursor`s are used with in-memory buffers, anything implementing
+/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
+/// allowing these buffers to be used anywhere you might use a reader or writer
+/// that does actual I/O.
+///
+/// The standard library implements some I/O traits on various types which
+/// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
+/// `Cursor<`[`&[u8]`][bytes]`>`.
+///
+/// # Examples
+///
+/// We may want to write bytes to a [`File`] in our production
+/// code, but use an in-memory buffer in our tests. We can do this with
+/// `Cursor`:
+///
+/// [`Seek`]: trait.Seek.html
+/// [`Read`]: ../../std/io/trait.Read.html
+/// [`Write`]: ../../std/io/trait.Write.html
+/// [`Vec`]: ../../std/vec/struct.Vec.html
+/// [bytes]: ../../std/primitive.slice.html
+/// [`File`]: ../fs/struct.File.html
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::{self, SeekFrom};
+/// use std::fs::File;
+///
+/// // a library function we've written
+/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
+///     writer.seek(SeekFrom::End(-10))?;
+///
+///     for i in 0..10 {
+///         writer.write(&[i])?;
+///     }
+///
+///     // all went well
+///     Ok(())
+/// }
+///
+/// # fn foo() -> io::Result<()> {
+/// // Here's some code that uses this library function.
+/// //
+/// // We might want to use a BufReader here for efficiency, but let's
+/// // keep this example focused.
+/// let mut file = File::create("foo.txt")?;
+///
+/// write_ten_bytes_at_end(&mut file)?;
+/// # Ok(())
+/// # }
+///
+/// // now let's write a test
+/// #[test]
+/// fn test_writes_bytes() {
+///     // setting up a real File is much slower than an in-memory buffer,
+///     // let's use a cursor instead
+///     use std::io::Cursor;
+///     let mut buff = Cursor::new(vec![0; 15]);
+///
+///     write_ten_bytes_at_end(&mut buff).unwrap();
+///
+///     assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+/// }
+/// ```
+#[derive(Clone, Debug)]
+pub struct Cursor<T> {
+    inner: T,
+    pos: u64,
+}
+
+impl<T> Cursor<T> {
+    /// Creates a new cursor wrapping the provided underlying in-memory buffer.
+    ///
+    /// Cursor initial position is `0` even if underlying buffer (e.g. `Vec`)
+    /// is not empty. So writing to cursor starts with overwriting `Vec`
+    /// content, not with appending to it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    /// ```
+    pub fn new(inner: T) -> Cursor<T> {
+        Cursor { pos: 0, inner: inner }
+    }
+
+    /// Consumes this cursor, returning the underlying value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    ///
+    /// let vec = buff.into_inner();
+    /// ```
+    pub fn into_inner(self) -> T { self.inner }
+
+    /// Gets a reference to the underlying value in this cursor.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    ///
+    /// let reference = buff.get_ref();
+    /// ```
+    pub fn get_ref(&self) -> &T { &self.inner }
+
+    /// Gets a mutable reference to the underlying value in this cursor.
+    ///
+    /// Care should be taken to avoid modifying the internal I/O state of the
+    /// underlying value as it may corrupt this cursor's position.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let mut buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    ///
+    /// let reference = buff.get_mut();
+    /// ```
+    pub fn get_mut(&mut self) -> &mut T { &mut self.inner }
+
+    /// Returns the current position of this cursor.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    /// use std::io::prelude::*;
+    /// use std::io::SeekFrom;
+    ///
+    /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+    ///
+    /// assert_eq!(buff.position(), 0);
+    ///
+    /// buff.seek(SeekFrom::Current(2)).unwrap();
+    /// assert_eq!(buff.position(), 2);
+    ///
+    /// buff.seek(SeekFrom::Current(-1)).unwrap();
+    /// assert_eq!(buff.position(), 1);
+    /// ```
+    pub fn position(&self) -> u64 { self.pos }
+
+    /// Sets the position of this cursor.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+    ///
+    /// assert_eq!(buff.position(), 0);
+    ///
+    /// buff.set_position(2);
+    /// assert_eq!(buff.position(), 2);
+    ///
+    /// buff.set_position(4);
+    /// assert_eq!(buff.position(), 4);
+    /// ```
+    pub fn set_position(&mut self, pos: u64) { self.pos = pos; }
+}
+
+impl<T> io::Seek for Cursor<T> where T: AsRef<[u8]> {
+    fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
+        let (base_pos, offset) = match style {
+            SeekFrom::Start(n) => { self.pos = n; return Ok(n); }
+            SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
+            SeekFrom::Current(n) => (self.pos, n),
+        };
+        let new_pos = if offset >= 0 {
+            base_pos.checked_add(offset as u64)
+        } else {
+            base_pos.checked_sub((offset.wrapping_neg()) as u64)
+        };
+        match new_pos {
+            Some(n) => {self.pos = n; Ok(self.pos)}
+            None => Err(Error::new(ErrorKind::InvalidInput,
+                           "invalid seek to a negative or overflowing position"))
+        }
+    }
+}
+
+impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let n = Read::read(&mut self.get_buf()?, buf)?;
+        self.pos += n as u64;
+        Ok(n)
+    }
+
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        let n = buf.len();
+        Read::read_exact(&mut self.get_buf()?, buf)?;
+        self.pos += n as u64;
+        Ok(())
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+impl<T> Cursor<T> where T: AsRef<[u8]> {
+    fn get_buf(&mut self) -> io::Result<&[u8]> {
+        let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
+        Ok(&self.inner.as_ref()[(amt as usize)..])
+    }
+}
+
+#[cfg(feature="alloc")]
+impl<T> BufRead for Cursor<T> where T: AsRef<[u8]> {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> { self.get_buf() }
+    fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
+}
+
+// Non-resizing write implementation
+fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<usize> {
+    let pos = cmp::min(*pos_mut, slice.len() as u64);
+    let amt = (&mut slice[(pos as usize)..]).write(buf)?;
+    *pos_mut += amt as u64;
+    Ok(amt)
+}
+
+// Resizing write implementation
+#[cfg(feature="alloc")]
+fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
+    let pos: usize = (*pos_mut).try_into().map_err(|_| {
+        Error::new(ErrorKind::InvalidInput,
+                    "cursor position exceeds maximum possible vector length")
+    })?;
+    // Make sure the internal buffer is as least as big as where we
+    // currently are
+    let len = vec.len();
+    if len < pos {
+        // use `resize` so that the zero filling is as efficient as possible
+        vec.resize(pos, 0);
+    }
+    // Figure out what bytes will be used to overwrite what's currently
+    // there (left), and what will be appended on the end (right)
+    {
+        let space = vec.len() - pos;
+        let (left, right) = buf.split_at(cmp::min(space, buf.len()));
+        vec[pos..pos + left.len()].copy_from_slice(left);
+        vec.extend_from_slice(right);
+    }
+
+    // Bump us forward
+    *pos_mut = (pos + buf.len()) as u64;
+    Ok(buf.len())
+}
+
+impl<'a> Write for Cursor<&'a mut [u8]> {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        slice_write(&mut self.pos, self.inner, buf)
+    }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[cfg(feature="alloc")]
+impl<'a> Write for Cursor<&'a mut Vec<u8>> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        vec_write(&mut self.pos, self.inner, buf)
+    }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[cfg(feature="alloc")]
+impl Write for Cursor<Vec<u8>> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        vec_write(&mut self.pos, &mut self.inner, buf)
+    }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[cfg(feature="alloc")]
+impl Write for Cursor<::alloc::boxed::Box<[u8]>> {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        slice_write(&mut self.pos, &mut self.inner, buf)
+    }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[cfg(test)]
+mod tests {
+    use io::prelude::*;
+    use io::{Cursor, SeekFrom};
+
+    #[test]
+    fn test_vec_writer() {
+        let mut writer = Vec::new();
+        assert_eq!(writer.write(&[0]).unwrap(), 1);
+        assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+        assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+        assert_eq!(writer, b);
+    }
+
+    #[test]
+    fn test_mem_writer() {
+        let mut writer = Cursor::new(Vec::new());
+        assert_eq!(writer.write(&[0]).unwrap(), 1);
+        assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+        assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+        assert_eq!(&writer.get_ref()[..], b);
+    }
+
+    #[test]
+    fn test_mem_mut_writer() {
+        let mut vec = Vec::new();
+        let mut writer = Cursor::new(&mut vec);
+        assert_eq!(writer.write(&[0]).unwrap(), 1);
+        assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+        assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+        assert_eq!(&writer.get_ref()[..], b);
+    }
+
+    #[test]
+    fn test_box_slice_writer() {
+        let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+        assert_eq!(writer.position(), 0);
+        assert_eq!(writer.write(&[0]).unwrap(), 1);
+        assert_eq!(writer.position(), 1);
+        assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+        assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+        assert_eq!(writer.position(), 8);
+        assert_eq!(writer.write(&[]).unwrap(), 0);
+        assert_eq!(writer.position(), 8);
+
+        assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
+        assert_eq!(writer.write(&[10]).unwrap(), 0);
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+        assert_eq!(&**writer.get_ref(), b);
+    }
+
+    #[test]
+    fn test_buf_writer() {
+        let mut buf = [0 as u8; 9];
+        {
+            let mut writer = Cursor::new(&mut buf[..]);
+            assert_eq!(writer.position(), 0);
+            assert_eq!(writer.write(&[0]).unwrap(), 1);
+            assert_eq!(writer.position(), 1);
+            assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+            assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+            assert_eq!(writer.position(), 8);
+            assert_eq!(writer.write(&[]).unwrap(), 0);
+            assert_eq!(writer.position(), 8);
+
+            assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
+            assert_eq!(writer.write(&[10]).unwrap(), 0);
+        }
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+        assert_eq!(buf, b);
+    }
+
+    #[test]
+    fn test_buf_writer_seek() {
+        let mut buf = [0 as u8; 8];
+        {
+            let mut writer = Cursor::new(&mut buf[..]);
+            assert_eq!(writer.position(), 0);
+            assert_eq!(writer.write(&[1]).unwrap(), 1);
+            assert_eq!(writer.position(), 1);
+
+            assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
+            assert_eq!(writer.position(), 2);
+            assert_eq!(writer.write(&[2]).unwrap(), 1);
+            assert_eq!(writer.position(), 3);
+
+            assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
+            assert_eq!(writer.position(), 1);
+            assert_eq!(writer.write(&[3]).unwrap(), 1);
+            assert_eq!(writer.position(), 2);
+
+            assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
+            assert_eq!(writer.position(), 7);
+            assert_eq!(writer.write(&[4]).unwrap(), 1);
+            assert_eq!(writer.position(), 8);
+
+        }
+        let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
+        assert_eq!(buf, b);
+    }
+
+    #[test]
+    fn test_buf_writer_error() {
+        let mut buf = [0 as u8; 2];
+        let mut writer = Cursor::new(&mut buf[..]);
+        assert_eq!(writer.write(&[0]).unwrap(), 1);
+        assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
+        assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
+    }
+
+    #[test]
+    fn test_mem_reader() {
+        let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
+        let mut buf = [];
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+        assert_eq!(reader.position(), 0);
+        let mut buf = [0];
+        assert_eq!(reader.read(&mut buf).unwrap(), 1);
+        assert_eq!(reader.position(), 1);
+        let b: &[_] = &[0];
+        assert_eq!(buf, b);
+        let mut buf = [0; 4];
+        assert_eq!(reader.read(&mut buf).unwrap(), 4);
+        assert_eq!(reader.position(), 5);
+        let b: &[_] = &[1, 2, 3, 4];
+        assert_eq!(buf, b);
+        assert_eq!(reader.read(&mut buf).unwrap(), 3);
+        let b: &[_] = &[5, 6, 7];
+        assert_eq!(&buf[..3], b);
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    }
+
+    #[test]
+    fn test_boxed_slice_reader() {
+        let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
+        let mut buf = [];
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+        assert_eq!(reader.position(), 0);
+        let mut buf = [0];
+        assert_eq!(reader.read(&mut buf).unwrap(), 1);
+        assert_eq!(reader.position(), 1);
+        let b: &[_] = &[0];
+        assert_eq!(buf, b);
+        let mut buf = [0; 4];
+        assert_eq!(reader.read(&mut buf).unwrap(), 4);
+        assert_eq!(reader.position(), 5);
+        let b: &[_] = &[1, 2, 3, 4];
+        assert_eq!(buf, b);
+        assert_eq!(reader.read(&mut buf).unwrap(), 3);
+        let b: &[_] = &[5, 6, 7];
+        assert_eq!(&buf[..3], b);
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    }
+
+    #[test]
+    fn read_to_end() {
+        let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
+        let mut v = Vec::new();
+        reader.read_to_end(&mut v).unwrap();
+        assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
+    }
+
+    #[test]
+    fn test_slice_reader() {
+        let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+        let reader = &mut &in_buf[..];
+        let mut buf = [];
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+        let mut buf = [0];
+        assert_eq!(reader.read(&mut buf).unwrap(), 1);
+        assert_eq!(reader.len(), 7);
+        let b: &[_] = &[0];
+        assert_eq!(&buf[..], b);
+        let mut buf = [0; 4];
+        assert_eq!(reader.read(&mut buf).unwrap(), 4);
+        assert_eq!(reader.len(), 3);
+        let b: &[_] = &[1, 2, 3, 4];
+        assert_eq!(&buf[..], b);
+        assert_eq!(reader.read(&mut buf).unwrap(), 3);
+        let b: &[_] = &[5, 6, 7];
+        assert_eq!(&buf[..3], b);
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    }
+
+    #[test]
+    fn test_read_exact() {
+        let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+        let reader = &mut &in_buf[..];
+        let mut buf = [];
+        assert!(reader.read_exact(&mut buf).is_ok());
+        let mut buf = [8];
+        assert!(reader.read_exact(&mut buf).is_ok());
+        assert_eq!(buf[0], 0);
+        assert_eq!(reader.len(), 7);
+        let mut buf = [0, 0, 0, 0, 0, 0, 0];
+        assert!(reader.read_exact(&mut buf).is_ok());
+        assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]);
+        assert_eq!(reader.len(), 0);
+        let mut buf = [0];
+        assert!(reader.read_exact(&mut buf).is_err());
+    }
+
+    #[test]
+    fn test_buf_reader() {
+        let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+        let mut reader = Cursor::new(&in_buf[..]);
+        let mut buf = [];
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+        assert_eq!(reader.position(), 0);
+        let mut buf = [0];
+        assert_eq!(reader.read(&mut buf).unwrap(), 1);
+        assert_eq!(reader.position(), 1);
+        let b: &[_] = &[0];
+        assert_eq!(buf, b);
+        let mut buf = [0; 4];
+        assert_eq!(reader.read(&mut buf).unwrap(), 4);
+        assert_eq!(reader.position(), 5);
+        let b: &[_] = &[1, 2, 3, 4];
+        assert_eq!(buf, b);
+        assert_eq!(reader.read(&mut buf).unwrap(), 3);
+        let b: &[_] = &[5, 6, 7];
+        assert_eq!(&buf[..3], b);
+        assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    }
+
+    #[test]
+    fn seek_past_end() {
+        let buf = [0xff];
+        let mut r = Cursor::new(&buf[..]);
+        assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+        assert_eq!(r.read(&mut [0]).unwrap(), 0);
+
+        let mut r = Cursor::new(vec![10]);
+        assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+        assert_eq!(r.read(&mut [0]).unwrap(), 0);
+
+        let mut buf = [0];
+        let mut r = Cursor::new(&mut buf[..]);
+        assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+        assert_eq!(r.write(&[3]).unwrap(), 0);
+
+        let mut r = Cursor::new(vec![10].into_boxed_slice());
+        assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+        assert_eq!(r.write(&[3]).unwrap(), 0);
+    }
+
+    #[test]
+    fn seek_past_i64() {
+        let buf = [0xff];
+        let mut r = Cursor::new(&buf[..]);
+        assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+        assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+        assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+        assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+        assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+        assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+        let mut r = Cursor::new(vec![10]);
+        assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+        assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+        assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+        assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+        assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+        assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+        let mut buf = [0];
+        let mut r = Cursor::new(&mut buf[..]);
+        assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+        assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+        assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+        assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+        assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+        assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+        let mut r = Cursor::new(vec![10].into_boxed_slice());
+        assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+        assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+        assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+        assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+        assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+        assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+    }
+
+    #[test]
+    fn seek_before_0() {
+        let buf = [0xff];
+        let mut r = Cursor::new(&buf[..]);
+        assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+        let mut r = Cursor::new(vec![10]);
+        assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+        let mut buf = [0];
+        let mut r = Cursor::new(&mut buf[..]);
+        assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+        let mut r = Cursor::new(vec![10].into_boxed_slice());
+        assert!(r.seek(SeekFrom::End(-2)).is_err());
+    }
+
+    #[test]
+    fn test_seekable_mem_writer() {
+        let mut writer = Cursor::new(Vec::<u8>::new());
+        assert_eq!(writer.position(), 0);
+        assert_eq!(writer.write(&[0]).unwrap(), 1);
+        assert_eq!(writer.position(), 1);
+        assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+        assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+        assert_eq!(writer.position(), 8);
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+        assert_eq!(&writer.get_ref()[..], b);
+
+        assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
+        assert_eq!(writer.position(), 0);
+        assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
+        let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
+        assert_eq!(&writer.get_ref()[..], b);
+
+        assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
+        assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
+        let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
+        assert_eq!(&writer.get_ref()[..], b);
+
+        assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
+        assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
+        let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
+        assert_eq!(&writer.get_ref()[..], b);
+
+        assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
+        assert_eq!(writer.write(&[1]).unwrap(), 1);
+        let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
+        assert_eq!(&writer.get_ref()[..], b);
+    }
+
+    #[test]
+    fn vec_seek_past_end() {
+        let mut r = Cursor::new(Vec::new());
+        assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+        assert_eq!(r.write(&[3]).unwrap(), 1);
+    }
+
+    #[test]
+    fn vec_seek_before_0() {
+        let mut r = Cursor::new(Vec::new());
+        assert!(r.seek(SeekFrom::End(-2)).is_err());
+    }
+
+    #[test]
+    #[cfg(target_pointer_width = "32")]
+    fn vec_seek_and_write_past_usize_max() {
+        let mut c = Cursor::new(Vec::new());
+        c.set_position(<usize>::max_value() as u64 + 1);
+        assert!(c.write_all(&[1, 2, 3]).is_err());
+    }
+}

+ 575 - 0
core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/error.rs

@@ -0,0 +1,575 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature="alloc")] use alloc::boxed::Box;
+#[cfg(not(feature="alloc"))] use ::FakeBox as Box;
+use core::fmt;
+use core::marker::{Send, Sync};
+use core::option::Option::{self, Some, None};
+use core::result;
+#[cfg(feature="alloc")] use alloc::string::String;
+#[cfg(not(feature="alloc"))] use ::ErrorString as String;
+use core::convert::From;
+
+/// A specialized [`Result`](../result/enum.Result.html) type for I/O
+/// operations.
+///
+/// This type is broadly used across [`std::io`] for any operation which may
+/// produce an error.
+///
+/// This typedef is generally used to avoid writing out [`io::Error`] directly and
+/// is otherwise a direct mapping to [`Result`].
+///
+/// While usual Rust style is to import types directly, aliases of [`Result`]
+/// often are not, to make it easier to distinguish between them. [`Result`] is
+/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
+/// will generally use `io::Result` instead of shadowing the prelude's import
+/// of [`std::result::Result`][`Result`].
+///
+/// [`std::io`]: ../io/index.html
+/// [`io::Error`]: ../io/struct.Error.html
+/// [`Result`]: ../result/enum.Result.html
+///
+/// # Examples
+///
+/// A convenience function that bubbles an `io::Result` to its caller:
+///
+/// ```
+/// use std::io;
+///
+/// fn get_string() -> io::Result<String> {
+///     let mut buffer = String::new();
+///
+///     io::stdin().read_line(&mut buffer)?;
+///
+///     Ok(buffer)
+/// }
+/// ```
+pub type Result<T> = result::Result<T, Error>;
+
+/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
+/// associated traits.
+///
+/// Errors mostly originate from the underlying OS, but custom instances of
+/// `Error` can be created with crafted error messages and a particular value of
+/// [`ErrorKind`].
+///
+/// [`Read`]: ../io/trait.Read.html
+/// [`Write`]: ../io/trait.Write.html
+/// [`Seek`]: ../io/trait.Seek.html
+/// [`ErrorKind`]: enum.ErrorKind.html
+pub struct Error {
+    repr: Repr,
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.repr, f)
+    }
+}
+
+enum Repr {
+    Os(i32),
+    Simple(ErrorKind),
+    #[cfg(feature = "alloc")]
+    Custom(Box<Custom>),
+    #[cfg(not(feature = "alloc"))]
+    Custom(Custom),
+}
+
+#[derive(Debug)]
+struct Custom {
+    kind: ErrorKind,
+    error: String,
+}
+
+/// A list specifying general categories of I/O error.
+///
+/// This list is intended to grow over time and it is not recommended to
+/// exhaustively match against it.
+///
+/// It is used with the [`io::Error`] type.
+///
+/// [`io::Error`]: struct.Error.html
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[allow(deprecated)]
+pub enum ErrorKind {
+    /// An entity was not found, often a file.
+    NotFound,
+    /// The operation lacked the necessary privileges to complete.
+    PermissionDenied,
+    /// The connection was refused by the remote server.
+    ConnectionRefused,
+    /// The connection was reset by the remote server.
+    ConnectionReset,
+    /// The connection was aborted (terminated) by the remote server.
+    ConnectionAborted,
+    /// The network operation failed because it was not connected yet.
+    NotConnected,
+    /// A socket address could not be bound because the address is already in
+    /// use elsewhere.
+    AddrInUse,
+    /// A nonexistent interface was requested or the requested address was not
+    /// local.
+    AddrNotAvailable,
+    /// The operation failed because a pipe was closed.
+    BrokenPipe,
+    /// An entity already exists, often a file.
+    AlreadyExists,
+    /// The operation needs to block to complete, but the blocking operation was
+    /// requested to not occur.
+    WouldBlock,
+    /// A parameter was incorrect.
+    InvalidInput,
+    /// Data not valid for the operation were encountered.
+    ///
+    /// Unlike [`InvalidInput`], this typically means that the operation
+    /// parameters were valid, however the error was caused by malformed
+    /// input data.
+    ///
+    /// For example, a function that reads a file into a string will error with
+    /// `InvalidData` if the file's contents are not valid UTF-8.
+    ///
+    /// [`InvalidInput`]: #variant.InvalidInput
+    InvalidData,
+    /// The I/O operation's timeout expired, causing it to be canceled.
+    TimedOut,
+    /// An error returned when an operation could not be completed because a
+    /// call to [`write`] returned [`Ok(0)`].
+    ///
+    /// This typically means that an operation could only succeed if it wrote a
+    /// particular number of bytes but only a smaller number of bytes could be
+    /// written.
+    ///
+    /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+    /// [`Ok(0)`]: ../../std/io/type.Result.html
+    WriteZero,
+    /// This operation was interrupted.
+    ///
+    /// Interrupted operations can typically be retried.
+    Interrupted,
+    /// Any I/O error not part of this list.
+    Other,
+
+    /// An error returned when an operation could not be completed because an
+    /// "end of file" was reached prematurely.
+    ///
+    /// This typically means that an operation could only succeed if it read a
+    /// particular number of bytes but only a smaller number of bytes could be
+    /// read.
+    UnexpectedEof,
+
+    /// A marker variant that tells the compiler that users of this enum cannot
+    /// match it exhaustively.
+    #[doc(hidden)]
+    __Nonexhaustive,
+}
+
+impl ErrorKind {
+    fn as_str(&self) -> &'static str {
+        match *self {
+            ErrorKind::NotFound => "entity not found",
+            ErrorKind::PermissionDenied => "permission denied",
+            ErrorKind::ConnectionRefused => "connection refused",
+            ErrorKind::ConnectionReset => "connection reset",
+            ErrorKind::ConnectionAborted => "connection aborted",
+            ErrorKind::NotConnected => "not connected",
+            ErrorKind::AddrInUse => "address in use",
+            ErrorKind::AddrNotAvailable => "address not available",
+            ErrorKind::BrokenPipe => "broken pipe",
+            ErrorKind::AlreadyExists => "entity already exists",
+            ErrorKind::WouldBlock => "operation would block",
+            ErrorKind::InvalidInput => "invalid input parameter",
+            ErrorKind::InvalidData => "invalid data",
+            ErrorKind::TimedOut => "timed out",
+            ErrorKind::WriteZero => "write zero",
+            ErrorKind::Interrupted => "operation interrupted",
+            ErrorKind::Other => "other os error",
+            ErrorKind::UnexpectedEof => "unexpected end of file",
+            _ => "unknown error",
+        }
+    }
+}
+
+/// Intended for use for errors not exposed to the user, where allocating onto
+/// the heap (for normal construction via Error::new) is too costly.
+impl From<ErrorKind> for Error {
+    /// Converts an [`ErrorKind`] into an [`Error`].
+    ///
+    /// This conversion allocates a new error with a simple representation of error kind.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{Error, ErrorKind};
+    ///
+    /// let not_found = ErrorKind::NotFound;
+    /// let error = Error::from(not_found);
+    /// assert_eq!("entity not found", format!("{}", error));
+    /// ```
+    #[inline]
+    fn from(kind: ErrorKind) -> Error {
+        Error {
+            repr: Repr::Simple(kind)
+        }
+    }
+}
+
+impl Error {
+    /// Creates a new I/O error from a known kind of error as well as an
+    /// arbitrary error payload.
+    ///
+    /// This function is used to generically create I/O errors which do not
+    /// originate from the OS itself. The `error` argument is an arbitrary
+    /// payload which will be contained in this `Error`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{Error, ErrorKind};
+    ///
+    /// // errors can be created from strings
+    /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
+    ///
+    /// // errors can also be created from other errors
+    /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
+    /// ```
+    pub fn new<E>(kind: ErrorKind, error: E) -> Error
+        where E: Into<String>
+    {
+        Self::_new(kind, error.into())
+    }
+
+    fn _new(kind: ErrorKind, error: String) -> Error {
+        Error {
+            repr: Repr::Custom(Box::new(Custom {
+                kind,
+                error,
+            }))
+        }
+    }
+
+    /// Creates a new instance of an `Error` from a particular OS error code.
+    ///
+    /// # Examples
+    ///
+    /// On Linux:
+    ///
+    /// ```
+    /// # if cfg!(target_os = "linux") {
+    /// use std::io;
+    ///
+    /// let error = io::Error::from_raw_os_error(22);
+    /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
+    /// # }
+    /// ```
+    ///
+    /// On Windows:
+    ///
+    /// ```
+    /// # if cfg!(windows) {
+    /// use std::io;
+    ///
+    /// let error = io::Error::from_raw_os_error(10022);
+    /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
+    /// # }
+    /// ```
+    pub fn from_raw_os_error(code: i32) -> Error {
+        Error { repr: Repr::Os(code) }
+    }
+
+    /// Returns the OS error that this error represents (if any).
+    ///
+    /// If this `Error` was constructed via `last_os_error` or
+    /// `from_raw_os_error`, then this function will return `Some`, otherwise
+    /// it will return `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{Error, ErrorKind};
+    ///
+    /// fn print_os_error(err: &Error) {
+    ///     if let Some(raw_os_err) = err.raw_os_error() {
+    ///         println!("raw OS error: {:?}", raw_os_err);
+    ///     } else {
+    ///         println!("Not an OS error");
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///     // Will print "raw OS error: ...".
+    ///     print_os_error(&Error::last_os_error());
+    ///     // Will print "Not an OS error".
+    ///     print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
+    /// }
+    /// ```
+    pub fn raw_os_error(&self) -> Option<i32> {
+        match self.repr {
+            Repr::Os(i) => Some(i),
+            Repr::Custom(..) => None,
+            Repr::Simple(..) => None,
+        }
+    }
+
+    /// Returns a reference to the inner error wrapped by this error (if any).
+    ///
+    /// If this `Error` was constructed via `new` then this function will
+    /// return `Some`, otherwise it will return `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{Error, ErrorKind};
+    ///
+    /// fn print_error(err: &Error) {
+    ///     if let Some(inner_err) = err.get_ref() {
+    ///         println!("Inner error: {:?}", inner_err);
+    ///     } else {
+    ///         println!("No inner error");
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///     // Will print "No inner error".
+    ///     print_error(&Error::last_os_error());
+    ///     // Will print "Inner error: ...".
+    ///     print_error(&Error::new(ErrorKind::Other, "oh no!"));
+    /// }
+    /// ```
+    pub fn get_ref(&self) -> Option<&String> {
+        match self.repr {
+            Repr::Os(..) => None,
+            Repr::Simple(..) => None,
+            Repr::Custom(ref c) => Some(&c.error),
+        }
+    }
+
+    /// Returns a mutable reference to the inner error wrapped by this error
+    /// (if any).
+    ///
+    /// If this `Error` was constructed via `new` then this function will
+    /// return `Some`, otherwise it will return `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{Error, ErrorKind};
+    /// use std::{error, fmt};
+    /// use std::fmt::Display;
+    ///
+    /// #[derive(Debug)]
+    /// struct MyError {
+    ///     v: String,
+    /// }
+    ///
+    /// impl MyError {
+    ///     fn new() -> MyError {
+    ///         MyError {
+    ///             v: "oh no!".to_string()
+    ///         }
+    ///     }
+    ///
+    ///     fn change_message(&mut self, new_message: &str) {
+    ///         self.v = new_message.to_string();
+    ///     }
+    /// }
+    ///
+    /// impl error::Error for MyError {
+    ///     fn description(&self) -> &str { &self.v }
+    /// }
+    ///
+    /// impl Display for MyError {
+    ///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    ///         write!(f, "MyError: {}", &self.v)
+    ///     }
+    /// }
+    ///
+    /// fn change_error(mut err: Error) -> Error {
+    ///     if let Some(inner_err) = err.get_mut() {
+    ///         inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!");
+    ///     }
+    ///     err
+    /// }
+    ///
+    /// fn print_error(err: &Error) {
+    ///     if let Some(inner_err) = err.get_ref() {
+    ///         println!("Inner error: {}", inner_err);
+    ///     } else {
+    ///         println!("No inner error");
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///     // Will print "No inner error".
+    ///     print_error(&change_error(Error::last_os_error()));
+    ///     // Will print "Inner error: ...".
+    ///     print_error(&change_error(Error::new(ErrorKind::Other, MyError::new())));
+    /// }
+    /// ```
+    pub fn get_mut(&mut self) -> Option<&mut String> {
+        match self.repr {
+            Repr::Os(..) => None,
+            Repr::Simple(..) => None,
+            Repr::Custom(ref mut c) => Some(&mut c.error),
+        }
+    }
+
+    /// Consumes the `Error`, returning its inner error (if any).
+    ///
+    /// If this `Error` was constructed via `new` then this function will
+    /// return `Some`, otherwise it will return `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{Error, ErrorKind};
+    ///
+    /// fn print_error(err: Error) {
+    ///     if let Some(inner_err) = err.into_inner() {
+    ///         println!("Inner error: {}", inner_err);
+    ///     } else {
+    ///         println!("No inner error");
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///     // Will print "No inner error".
+    ///     print_error(Error::last_os_error());
+    ///     // Will print "Inner error: ...".
+    ///     print_error(Error::new(ErrorKind::Other, "oh no!"));
+    /// }
+    /// ```
+    pub fn into_inner(self) -> Option<String> {
+        match self.repr {
+            Repr::Os(..) => None,
+            Repr::Simple(..) => None,
+            Repr::Custom(c) => Some(c.error)
+        }
+    }
+
+    /// Returns the corresponding `ErrorKind` for this error.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{Error, ErrorKind};
+    ///
+    /// fn print_error(err: Error) {
+    ///     println!("{:?}", err.kind());
+    /// }
+    ///
+    /// fn main() {
+    ///     // Will print "No inner error".
+    ///     print_error(Error::last_os_error());
+    ///     // Will print "Inner error: ...".
+    ///     print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
+    /// }
+    /// ```
+    pub fn kind(&self) -> ErrorKind {
+        match self.repr {
+            Repr::Os(_code) => ErrorKind::Other,
+            Repr::Custom(ref c) => c.kind,
+            Repr::Simple(kind) => kind,
+        }
+    }
+}
+
+impl fmt::Debug for Repr {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            Repr::Os(code) =>
+                fmt.debug_struct("Os")
+                    .field("code", &code).finish(),
+            Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
+            Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
+        }
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        match self.repr {
+            Repr::Os(code) => {
+                write!(fmt, "os error {}", code)
+            }
+            Repr::Custom(ref c) => c.error.fmt(fmt),
+            Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
+        }
+    }
+}
+
+fn _assert_error_is_sync_send() {
+    fn _is_sync_send<T: Sync+Send>() {}
+    _is_sync_send::<Error>();
+}
+
+#[cfg(test)]
+mod test {
+    use super::{Error, ErrorKind, Repr, Custom};
+    use error;
+    use fmt;
+    use sys::os::error_string;
+    use sys::decode_error_kind;
+
+    #[test]
+    fn test_debug_error() {
+        let code = 6;
+        let msg = error_string(code);
+        let kind = decode_error_kind(code);
+        let err = Error {
+            repr: Repr::Custom(Box::new(Custom {
+                kind: ErrorKind::InvalidInput,
+                error: Box::new(Error {
+                    repr: super::Repr::Os(code)
+                }),
+            }))
+        };
+        let expected = format!(
+            "Custom {{ \
+                kind: InvalidInput, \
+                error: Os {{ \
+                    code: {:?}, \
+                    kind: {:?}, \
+                    message: {:?} \
+                }} \
+            }}",
+            code, kind, msg
+        );
+        assert_eq!(format!("{:?}", err), expected);
+    }
+
+    #[test]
+    fn test_downcasting() {
+        #[derive(Debug)]
+        struct TestError;
+
+        impl fmt::Display for TestError {
+            fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
+                Ok(())
+            }
+        }
+
+        impl error::Error for TestError {
+            fn description(&self) -> &str {
+                "asdf"
+            }
+        }
+
+        // we have to call all of these UFCS style right now since method
+        // resolution won't implicitly drop the Send+Sync bounds
+        let mut err = Error::new(ErrorKind::Other, TestError);
+        assert!(err.get_ref().unwrap().is::<TestError>());
+        assert_eq!("asdf", err.get_ref().unwrap().description());
+        assert!(err.get_mut().unwrap().is::<TestError>());
+        let extracted = err.into_inner().unwrap();
+        extracted.downcast::<TestError>().unwrap();
+    }
+}

+ 341 - 0
core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/impls.rs

@@ -0,0 +1,341 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature="alloc")] use alloc::boxed::Box;
+use core::cmp;
+use io::{self, SeekFrom, Read, Initializer, Write, Seek, Error, ErrorKind};
+#[cfg(feature="alloc")] use io::BufRead;
+use core::fmt;
+use core::mem;
+#[cfg(feature="alloc")] use alloc::string::String;
+#[cfg(feature="alloc")] use alloc::vec::Vec;
+
+// =============================================================================
+// Forwarding implementations
+
+impl<'a, R: Read + ?Sized> Read for &'a mut R {
+    #[inline]
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        (**self).initializer()
+    }
+
+    #[cfg(feature="alloc")]
+    #[inline]
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        (**self).read_to_end(buf)
+    }
+
+    #[cfg(feature="alloc")]
+    #[inline]
+    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+        (**self).read_to_string(buf)
+    }
+
+    #[inline]
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        (**self).read_exact(buf)
+    }
+}
+impl<'a, W: Write + ?Sized> Write for &'a mut W {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> { (**self).flush() }
+
+    #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        (**self).write_all(buf)
+    }
+
+    #[inline]
+    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
+        (**self).write_fmt(fmt)
+    }
+}
+impl<'a, S: Seek + ?Sized> Seek for &'a mut S {
+    #[inline]
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
+}
+#[cfg(feature="alloc")]
+impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B {
+    #[inline]
+    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
+
+    #[inline]
+    fn consume(&mut self, amt: usize) { (**self).consume(amt) }
+
+    #[inline]
+    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
+        (**self).read_until(byte, buf)
+    }
+
+    #[inline]
+    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
+        (**self).read_line(buf)
+    }
+}
+
+#[cfg(feature="alloc")]
+impl<R: Read + ?Sized> Read for Box<R> {
+    #[inline]
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        (**self).initializer()
+    }
+
+    #[cfg(feature="alloc")]
+    #[inline]
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        (**self).read_to_end(buf)
+    }
+
+    #[cfg(feature="alloc")]
+    #[inline]
+    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+        (**self).read_to_string(buf)
+    }
+
+    #[inline]
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        (**self).read_exact(buf)
+    }
+}
+#[cfg(feature="alloc")]
+impl<W: Write + ?Sized> Write for Box<W> {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> { (**self).flush() }
+
+    #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        (**self).write_all(buf)
+    }
+
+    #[inline]
+    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
+        (**self).write_fmt(fmt)
+    }
+}
+#[cfg(feature="alloc")]
+impl<S: Seek + ?Sized> Seek for Box<S> {
+    #[inline]
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
+}
+#[cfg(feature="alloc")]
+impl<B: BufRead + ?Sized> BufRead for Box<B> {
+    #[inline]
+    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
+
+    #[inline]
+    fn consume(&mut self, amt: usize) { (**self).consume(amt) }
+
+    #[inline]
+    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
+        (**self).read_until(byte, buf)
+    }
+
+    #[inline]
+    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
+        (**self).read_line(buf)
+    }
+}
+
+// =============================================================================
+// In-memory buffer implementations
+
+/// Read is implemented for `&[u8]` by copying from the slice.
+///
+/// Note that reading updates the slice to point to the yet unread part.
+/// The slice will be empty when EOF is reached.
+impl<'a> Read for &'a [u8] {
+    #[inline]
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let amt = cmp::min(buf.len(), self.len());
+        let (a, b) = self.split_at(amt);
+
+        // First check if the amount of bytes we want to read is small:
+        // `copy_from_slice` will generally expand to a call to `memcpy`, and
+        // for a single byte the overhead is significant.
+        if amt == 1 {
+            buf[0] = a[0];
+        } else {
+            buf[..amt].copy_from_slice(a);
+        }
+
+        *self = b;
+        Ok(amt)
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+
+    #[inline]
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        if buf.len() > self.len() {
+            return Err(Error::new(ErrorKind::UnexpectedEof,
+                                  "failed to fill whole buffer"));
+        }
+        let (a, b) = self.split_at(buf.len());
+
+        // First check if the amount of bytes we want to read is small:
+        // `copy_from_slice` will generally expand to a call to `memcpy`, and
+        // for a single byte the overhead is significant.
+        if buf.len() == 1 {
+            buf[0] = a[0];
+        } else {
+            buf.copy_from_slice(a);
+        }
+
+        *self = b;
+        Ok(())
+    }
+
+    #[cfg(feature="alloc")]
+    #[inline]
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        buf.extend_from_slice(*self);
+        let len = self.len();
+        *self = &self[len..];
+        Ok(len)
+    }
+}
+
+#[cfg(feature="alloc")]
+impl<'a> BufRead for &'a [u8] {
+    #[inline]
+    fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }
+
+    #[inline]
+    fn consume(&mut self, amt: usize) { *self = &self[amt..]; }
+}
+
+/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting
+/// its data.
+///
+/// Note that writing updates the slice to point to the yet unwritten part.
+/// The slice will be empty when it has been completely overwritten.
+impl<'a> Write for &'a mut [u8] {
+    #[inline]
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        let amt = cmp::min(data.len(), self.len());
+        let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
+        a.copy_from_slice(&data[..amt]);
+        *self = b;
+        Ok(amt)
+    }
+
+    #[inline]
+    fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
+        if self.write(data)? == data.len() {
+            Ok(())
+        } else {
+            Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
+        }
+    }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+/// Write is implemented for `Vec<u8>` by appending to the vector.
+/// The vector will grow as needed.
+#[cfg(feature="alloc")]
+impl Write for Vec<u8> {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.extend_from_slice(buf);
+        Ok(buf.len())
+    }
+
+    #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.extend_from_slice(buf);
+        Ok(())
+    }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[cfg(test)]
+mod tests {
+    use io::prelude::*;
+    use test;
+
+    #[bench]
+    fn bench_read_slice(b: &mut test::Bencher) {
+        let buf = [5; 1024];
+        let mut dst = [0; 128];
+
+        b.iter(|| {
+            let mut rd = &buf[..];
+            for _ in 0..8 {
+                let _ = rd.read(&mut dst);
+                test::black_box(&dst);
+            }
+        })
+    }
+
+    #[bench]
+    fn bench_write_slice(b: &mut test::Bencher) {
+        let mut buf = [0; 1024];
+        let src = [5; 128];
+
+        b.iter(|| {
+            let mut wr = &mut buf[..];
+            for _ in 0..8 {
+                let _ = wr.write_all(&src);
+                test::black_box(&wr);
+            }
+        })
+    }
+
+    #[bench]
+    fn bench_read_vec(b: &mut test::Bencher) {
+        let buf = vec![5; 1024];
+        let mut dst = [0; 128];
+
+        b.iter(|| {
+            let mut rd = &buf[..];
+            for _ in 0..8 {
+                let _ = rd.read(&mut dst);
+                test::black_box(&dst);
+            }
+        })
+    }
+
+    #[bench]
+    fn bench_write_vec(b: &mut test::Bencher) {
+        let mut buf = Vec::with_capacity(1024);
+        let src = [5; 128];
+
+        b.iter(|| {
+            let mut wr = &mut buf[..];
+            for _ in 0..8 {
+                let _ = wr.write_all(&src);
+                test::black_box(&wr);
+            }
+        })
+    }
+}

+ 2218 - 0
core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/mod.rs

@@ -0,0 +1,2218 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Traits, helpers, and type definitions for core I/O functionality.
+//!
+//! The `std::io` module contains a number of common things you'll need
+//! when doing input and output. The most core part of this module is
+//! the [`Read`] and [`Write`] traits, which provide the
+//! most general interface for reading and writing input and output.
+//!
+//! # Read and Write
+//!
+//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
+//! of other types, and you can implement them for your types too. As such,
+//! you'll see a few different types of I/O throughout the documentation in
+//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
+//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
+//! [`File`]s:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//!     let mut f = File::open("foo.txt")?;
+//!     let mut buffer = [0; 10];
+//!
+//!     // read up to 10 bytes
+//!     f.read(&mut buffer)?;
+//!
+//!     println!("The bytes: {:?}", buffer);
+//!     Ok(())
+//! }
+//! ```
+//!
+//! [`Read`] and [`Write`] are so important, implementors of the two traits have a
+//! nickname: readers and writers. So you'll sometimes see 'a reader' instead
+//! of 'a type that implements the [`Read`] trait'. Much easier!
+//!
+//! ## Seek and BufRead
+//!
+//! Beyond that, there are two important traits that are provided: [`Seek`]
+//! and [`BufRead`]. Both of these build on top of a reader to control
+//! how the reading happens. [`Seek`] lets you control where the next byte is
+//! coming from:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::io::SeekFrom;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//!     let mut f = File::open("foo.txt")?;
+//!     let mut buffer = [0; 10];
+//!
+//!     // skip to the last 10 bytes of the file
+//!     f.seek(SeekFrom::End(-10))?;
+//!
+//!     // read up to 10 bytes
+//!     f.read(&mut buffer)?;
+//!
+//!     println!("The bytes: {:?}", buffer);
+//!     Ok(())
+//! }
+//! ```
+//!
+//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but
+//! to show it off, we'll need to talk about buffers in general. Keep reading!
+//!
+//! ## BufReader and BufWriter
+//!
+//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
+//! making near-constant calls to the operating system. To help with this,
+//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap
+//! readers and writers. The wrapper uses a buffer, reducing the number of
+//! calls and providing nicer methods for accessing exactly what you want.
+//!
+//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra
+//! methods to any reader:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::io::BufReader;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//!     let f = File::open("foo.txt")?;
+//!     let mut reader = BufReader::new(f);
+//!     let mut buffer = String::new();
+//!
+//!     // read a line into buffer
+//!     reader.read_line(&mut buffer)?;
+//!
+//!     println!("{}", buffer);
+//!     Ok(())
+//! }
+//! ```
+//!
+//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
+//! to [`write`][`Write::write`]:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::io::BufWriter;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//!     let f = File::create("foo.txt")?;
+//!     {
+//!         let mut writer = BufWriter::new(f);
+//!
+//!         // write a byte to the buffer
+//!         writer.write(&[42])?;
+//!
+//!     } // the buffer is flushed once writer goes out of scope
+//!
+//!     Ok(())
+//! }
+//! ```
+//!
+//! ## Standard input and output
+//!
+//! A very common source of input is standard input:
+//!
+//! ```no_run
+//! use std::io;
+//!
+//! fn main() -> io::Result<()> {
+//!     let mut input = String::new();
+//!
+//!     io::stdin().read_line(&mut input)?;
+//!
+//!     println!("You typed: {}", input.trim());
+//!     Ok(())
+//! }
+//! ```
+//!
+//! Note that you cannot use the [`?` operator] in functions that do not return
+//! a [`Result<T, E>`][`Result`]. Instead, you can call [`.unwrap()`]
+//! or `match` on the return value to catch any possible errors:
+//!
+//! ```no_run
+//! use std::io;
+//!
+//! let mut input = String::new();
+//!
+//! io::stdin().read_line(&mut input).unwrap();
+//! ```
+//!
+//! And a very common source of output is standard output:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//!
+//! fn main() -> io::Result<()> {
+//!     io::stdout().write(&[42])?;
+//!     Ok(())
+//! }
+//! ```
+//!
+//! Of course, using [`io::stdout`] directly is less common than something like
+//! [`println!`].
+//!
+//! ## Iterator types
+//!
+//! A large number of the structures provided by `std::io` are for various
+//! ways of iterating over I/O. For example, [`Lines`] is used to split over
+//! lines:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::io::BufReader;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//!     let f = File::open("foo.txt")?;
+//!     let reader = BufReader::new(f);
+//!
+//!     for line in reader.lines() {
+//!         println!("{}", line?);
+//!     }
+//!     Ok(())
+//! }
+//! ```
+//!
+//! ## Functions
+//!
+//! There are a number of [functions][functions-list] that offer access to various
+//! features. For example, we can use three of these functions to copy everything
+//! from standard input to standard output:
+//!
+//! ```no_run
+//! use std::io;
+//!
+//! fn main() -> io::Result<()> {
+//!     io::copy(&mut io::stdin(), &mut io::stdout())?;
+//!     Ok(())
+//! }
+//! ```
+//!
+//! [functions-list]: #functions-1
+//!
+//! ## io::Result
+//!
+//! Last, but certainly not least, is [`io::Result`]. This type is used
+//! as the return type of many `std::io` functions that can cause an error, and
+//! can be returned from your own functions as well. Many of the examples in this
+//! module use the [`?` operator]:
+//!
+//! ```
+//! use std::io;
+//!
+//! fn read_input() -> io::Result<()> {
+//!     let mut input = String::new();
+//!
+//!     io::stdin().read_line(&mut input)?;
+//!
+//!     println!("You typed: {}", input.trim());
+//!
+//!     Ok(())
+//! }
+//! ```
+//!
+//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very
+//! common type for functions which don't have a 'real' return value, but do want to
+//! return errors if they happen. In this case, the only purpose of this function is
+//! to read the line and print it, so we use `()`.
+//!
+//! ## Platform-specific behavior
+//!
+//! Many I/O functions throughout the standard library are documented to indicate
+//! what various library or syscalls they are delegated to. This is done to help
+//! applications both understand what's happening under the hood as well as investigate
+//! any possibly unclear semantics. Note, however, that this is informative, not a binding
+//! contract. The implementation of many of these functions are subject to change over
+//! time and may call fewer or more syscalls/library functions.
+//!
+//! [`Read`]: trait.Read.html
+//! [`Write`]: trait.Write.html
+//! [`Seek`]: trait.Seek.html
+//! [`BufRead`]: trait.BufRead.html
+//! [`File`]: ../fs/struct.File.html
+//! [`TcpStream`]: ../net/struct.TcpStream.html
+//! [`Vec<T>`]: ../vec/struct.Vec.html
+//! [`BufReader`]: struct.BufReader.html
+//! [`BufWriter`]: struct.BufWriter.html
+//! [`Write::write`]: trait.Write.html#tymethod.write
+//! [`io::stdout`]: fn.stdout.html
+//! [`println!`]: ../macro.println.html
+//! [`Lines`]: struct.Lines.html
+//! [`io::Result`]: type.Result.html
+//! [`?` operator]: ../../book/first-edition/syntax-index.html
+//! [`Read::read`]: trait.Read.html#tymethod.read
+//! [`Result`]: ../result/enum.Result.html
+//! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap
+
+#[cfg(feature="alloc")]
+use alloc::string::String;
+#[cfg(feature="alloc")]
+use alloc::vec::Vec;
+use core::cmp;
+use core::fmt;
+use core::str;
+#[cfg(feature="alloc")]
+use core::slice::memchr;
+use core::ptr;
+
+#[cfg(feature="alloc")]
+pub use self::buffered::{BufReader, BufWriter, LineWriter};
+#[cfg(feature="alloc")]
+pub use self::buffered::IntoInnerError;
+pub use self::cursor::Cursor;
+pub use self::error::{Result, Error, ErrorKind};
+pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
+
+pub mod prelude;
+#[cfg(feature="alloc")]
+mod buffered;
+mod cursor;
+mod error;
+mod impls;
+mod util;
+
+const DEFAULT_BUF_SIZE: usize = 8 * 1024;
+
+#[cfg(feature="alloc")]
+struct Guard<'a> { buf: &'a mut Vec<u8>, len: usize }
+
+#[cfg(feature="alloc")]
+impl<'a> Drop for Guard<'a> {
+    fn drop(&mut self) {
+        unsafe { self.buf.set_len(self.len); }
+    }
+}
+
+// A few methods below (read_to_string, read_line) will append data into a
+// `String` buffer, but we need to be pretty careful when doing this. The
+// implementation will just call `.as_mut_vec()` and then delegate to a
+// byte-oriented reading method, but we must ensure that when returning we never
+// leave `buf` in a state such that it contains invalid UTF-8 in its bounds.
+//
+// To this end, we use an RAII guard (to protect against panics) which updates
+// the length of the string when it is dropped. This guard initially truncates
+// the string to the prior length and only after we've validated that the
+// new contents are valid UTF-8 do we allow it to set a longer length.
+//
+// The unsafety in this function is twofold:
+//
+// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8
+//    checks.
+// 2. We're passing a raw buffer to the function `f`, and it is expected that
+//    the function only *appends* bytes to the buffer. We'll get undefined
+//    behavior if existing bytes are overwritten to have non-UTF-8 data.
+#[cfg(feature="alloc")]
+fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
+    where F: FnOnce(&mut Vec<u8>) -> Result<usize>
+{
+    unsafe {
+        let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() };
+        let ret = f(g.buf);
+        if str::from_utf8(&g.buf[g.len..]).is_err() {
+            ret.and_then(|_| {
+                Err(Error::new(ErrorKind::InvalidData,
+                               "stream did not contain valid UTF-8"))
+            })
+        } else {
+            g.len = g.buf.len();
+            ret
+        }
+    }
+}
+
+// This uses an adaptive system to extend the vector when it fills. We want to
+// avoid paying to allocate and zero a huge chunk of memory if the reader only
+// has 4 bytes while still making large reads if the reader does have a ton
+// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
+// time is 4,500 times (!) slower than a default reservation size of 32 if the
+// reader has a very small amount of data to return.
+//
+// Because we're extending the buffer with uninitialized data for trusted
+// readers, we need to make sure to truncate that if any of this panics.
+#[cfg(feature="alloc")]
+fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
+    read_to_end_with_reservation(r, buf, 32)
+}
+
+#[cfg(feature="alloc")]
+fn read_to_end_with_reservation<R: Read + ?Sized>(r: &mut R,
+                                                  buf: &mut Vec<u8>,
+                                                  reservation_size: usize) -> Result<usize>
+{
+    let start_len = buf.len();
+    let mut g = Guard { len: buf.len(), buf: buf };
+    let ret;
+    loop {
+        if g.len == g.buf.len() {
+            unsafe {
+                g.buf.reserve(reservation_size);
+                let capacity = g.buf.capacity();
+                g.buf.set_len(capacity);
+                r.initializer().initialize(&mut g.buf[g.len..]);
+            }
+        }
+
+        match r.read(&mut g.buf[g.len..]) {
+            Ok(0) => {
+                ret = Ok(g.len - start_len);
+                break;
+            }
+            Ok(n) => g.len += n,
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+            Err(e) => {
+                ret = Err(e);
+                break;
+            }
+        }
+    }
+
+    ret
+}
+
+/// The `Read` trait allows for reading bytes from a source.
+///
+/// Implementors of the `Read` trait are called 'readers'.
+///
+/// Readers are defined by one required method, [`read()`]. Each call to [`read()`]
+/// will attempt to pull bytes from this source into a provided buffer. A
+/// number of other methods are implemented in terms of [`read()`], giving
+/// implementors a number of ways to read bytes while only needing to implement
+/// a single method.
+///
+/// Readers are intended to be composable with one another. Many implementors
+/// throughout [`std::io`] take and provide types which implement the `Read`
+/// trait.
+///
+/// Please note that each call to [`read()`] may involve a system call, and
+/// therefore, using something that implements [`BufRead`], such as
+/// [`BufReader`], will be more efficient.
+///
+/// # Examples
+///
+/// [`File`]s implement `Read`:
+///
+/// ```no_run
+/// use std::io;
+/// use std::io::prelude::*;
+/// use std::fs::File;
+///
+/// fn main() -> io::Result<()> {
+///     let mut f = File::open("foo.txt")?;
+///     let mut buffer = [0; 10];
+///
+///     // read up to 10 bytes
+///     f.read(&mut buffer)?;
+///
+///     let mut buffer = vec![0; 10];
+///     // read the whole file
+///     f.read_to_end(&mut buffer)?;
+///
+///     // read into a String, so that you don't need to do the conversion.
+///     let mut buffer = String::new();
+///     f.read_to_string(&mut buffer)?;
+///
+///     // and more! See the other methods for more details.
+///     Ok(())
+/// }
+/// ```
+///
+/// Read from [`&str`] because [`&[u8]`][slice] implements `Read`:
+///
+/// ```no_run
+/// # use std::io;
+/// use std::io::prelude::*;
+///
+/// fn main() -> io::Result<()> {
+///     let mut b = "This string will be read".as_bytes();
+///     let mut buffer = [0; 10];
+///
+///     // read up to 10 bytes
+///     b.read(&mut buffer)?;
+///
+///     // etc... it works exactly as a File does!
+///     Ok(())
+/// }
+/// ```
+///
+/// [`read()`]: trait.Read.html#tymethod.read
+/// [`std::io`]: ../../std/io/index.html
+/// [`File`]: ../fs/struct.File.html
+/// [`BufRead`]: trait.BufRead.html
+/// [`BufReader`]: struct.BufReader.html
+/// [`&str`]: ../../std/primitive.str.html
+/// [slice]: ../../std/primitive.slice.html
+#[doc(notable_trait)]
+pub trait Read {
+    /// Pull some bytes from this source into the specified buffer, returning
+    /// how many bytes were read.
+    ///
+    /// This function does not provide any guarantees about whether it blocks
+    /// waiting for data, but if an object needs to block for a read but cannot
+    /// it will typically signal this via an [`Err`] return value.
+    ///
+    /// If the return value of this method is [`Ok(n)`], then it must be
+    /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates
+    /// that the buffer `buf` has been filled in with `n` bytes of data from this
+    /// source. If `n` is `0`, then it can indicate one of two scenarios:
+    ///
+    /// 1. This reader has reached its "end of file" and will likely no longer
+    ///    be able to produce bytes. Note that this does not mean that the
+    ///    reader will *always* no longer be able to produce bytes.
+    /// 2. The buffer specified was 0 bytes in length.
+    ///
+    /// No guarantees are provided about the contents of `buf` when this
+    /// function is called, implementations cannot rely on any property of the
+    /// contents of `buf` being true. It is recommended that implementations
+    /// only write data to `buf` instead of reading its contents.
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters any form of I/O or other error, an error
+    /// variant will be returned. If an error is returned then it must be
+    /// guaranteed that no bytes were read.
+    ///
+    /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read
+    /// operation should be retried if there is nothing else to do.
+    ///
+    /// # Examples
+    ///
+    /// [`File`]s implement `Read`:
+    ///
+    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+    /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok
+    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`File`]: ../fs/struct.File.html
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f = File::open("foo.txt")?;
+    ///     let mut buffer = [0; 10];
+    ///
+    ///     // read up to 10 bytes
+    ///     f.read(&mut buffer[..])?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
+
+    /// Determines if this `Read`er can work with buffers of uninitialized
+    /// memory.
+    ///
+    /// The default implementation returns an initializer which will zero
+    /// buffers.
+    ///
+    /// If a `Read`er guarantees that it can work properly with uninitialized
+    /// memory, it should call [`Initializer::nop()`]. See the documentation for
+    /// [`Initializer`] for details.
+    ///
+    /// The behavior of this method must be independent of the state of the
+    /// `Read`er - the method only takes `&self` so that it can be used through
+    /// trait objects.
+    ///
+    /// # Safety
+    ///
+    /// This method is unsafe because a `Read`er could otherwise return a
+    /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
+    /// block.
+    ///
+    /// [`Initializer::nop()`]: ../../std/io/struct.Initializer.html#method.nop
+    /// [`Initializer`]: ../../std/io/struct.Initializer.html
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::zeroing()
+    }
+
+    /// Read all bytes until EOF in this source, placing them into `buf`.
+    ///
+    /// All bytes read from this source will be appended to the specified buffer
+    /// `buf`. This function will continuously call [`read()`] to append more data to
+    /// `buf` until [`read()`] returns either [`Ok(0)`] or an error of
+    /// non-[`ErrorKind::Interrupted`] kind.
+    ///
+    /// If successful, this function will return the total number of bytes read.
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind
+    /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// will continue.
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns. Any bytes which have already been read will be appended to
+    /// `buf`.
+    ///
+    /// # Examples
+    ///
+    /// [`File`]s implement `Read`:
+    ///
+    /// [`read()`]: trait.Read.html#tymethod.read
+    /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`File`]: ../fs/struct.File.html
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f = File::open("foo.txt")?;
+    ///     let mut buffer = Vec::new();
+    ///
+    ///     // read the whole file
+    ///     f.read_to_end(&mut buffer)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// (See also the [`std::fs::read`] convenience function for reading from a
+    /// file.)
+    ///
+    /// [`std::fs::read`]: ../fs/fn.read.html
+    #[cfg(feature="alloc")]
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
+        read_to_end(self, buf)
+    }
+
+    /// Read all bytes until EOF in this source, appending them to `buf`.
+    ///
+    /// If successful, this function returns the number of bytes which were read
+    /// and appended to `buf`.
+    ///
+    /// # Errors
+    ///
+    /// If the data in this stream is *not* valid UTF-8 then an error is
+    /// returned and `buf` is unchanged.
+    ///
+    /// See [`read_to_end`][readtoend] for other error semantics.
+    ///
+    /// [readtoend]: #method.read_to_end
+    ///
+    /// # Examples
+    ///
+    /// [`File`][file]s implement `Read`:
+    ///
+    /// [file]: ../fs/struct.File.html
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f = File::open("foo.txt")?;
+    ///     let mut buffer = String::new();
+    ///
+    ///     f.read_to_string(&mut buffer)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// (See also the [`std::fs::read_to_string`] convenience function for
+    /// reading from a file.)
+    ///
+    /// [`std::fs::read_to_string`]: ../fs/fn.read_to_string.html
+    #[cfg(feature="alloc")]
+    fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
+        // Note that we do *not* call `.read_to_end()` here. We are passing
+        // `&mut Vec<u8>` (the raw contents of `buf`) into the `read_to_end`
+        // method to fill it up. An arbitrary implementation could overwrite the
+        // entire contents of the vector, not just append to it (which is what
+        // we are expecting).
+        //
+        // To prevent extraneously checking the UTF-8-ness of the entire buffer
+        // we pass it to our hardcoded `read_to_end` implementation which we
+        // know is guaranteed to only read data into the end of the buffer.
+        append_to_string(buf, |b| read_to_end(self, b))
+    }
+
+    /// Read the exact number of bytes required to fill `buf`.
+    ///
+    /// This function reads as many bytes as necessary to completely fill the
+    /// specified buffer `buf`.
+    ///
+    /// No guarantees are provided about the contents of `buf` when this
+    /// function is called, implementations cannot rely on any property of the
+    /// contents of `buf` being true. It is recommended that implementations
+    /// only write data to `buf` instead of reading its contents.
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind
+    /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// will continue.
+    ///
+    /// If this function encounters an "end of file" before completely filling
+    /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+    /// The contents of `buf` are unspecified in this case.
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns. The contents of `buf` are unspecified in this case.
+    ///
+    /// If this function returns an error, it is unspecified how many bytes it
+    /// has read, but it will never read more than would be necessary to
+    /// completely fill the buffer.
+    ///
+    /// # Examples
+    ///
+    /// [`File`]s implement `Read`:
+    ///
+    /// [`File`]: ../fs/struct.File.html
+    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`ErrorKind::UnexpectedEof`]: ../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f = File::open("foo.txt")?;
+    ///     let mut buffer = [0; 10];
+    ///
+    ///     // read exactly 10 bytes
+    ///     f.read_exact(&mut buffer)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
+        while !buf.is_empty() {
+            match self.read(buf) {
+                Ok(0) => break,
+                Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
+                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        if !buf.is_empty() {
+            Err(Error::new(ErrorKind::UnexpectedEof,
+                           "failed to fill whole buffer"))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Creates a "by reference" adaptor for this instance of `Read`.
+    ///
+    /// The returned adaptor also implements `Read` and will simply borrow this
+    /// current reader.
+    ///
+    /// # Examples
+    ///
+    /// [`File`][file]s implement `Read`:
+    ///
+    /// [file]: ../fs/struct.File.html
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::Read;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f = File::open("foo.txt")?;
+    ///     let mut buffer = Vec::new();
+    ///     let mut other_buffer = Vec::new();
+    ///
+    ///     {
+    ///         let reference = f.by_ref();
+    ///
+    ///         // read at most 5 bytes
+    ///         reference.take(5).read_to_end(&mut buffer)?;
+    ///
+    ///     } // drop our &mut reference so we can use f again
+    ///
+    ///     // original file still usable, read the rest
+    ///     f.read_to_end(&mut other_buffer)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn by_ref(&mut self) -> &mut Self where Self: Sized { self }
+
+    /// Transforms this `Read` instance to an [`Iterator`] over its bytes.
+    ///
+    /// The returned type implements [`Iterator`] where the `Item` is
+    /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`.
+    /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`]
+    /// otherwise. EOF is mapped to returning [`None`] from this iterator.
+    ///
+    /// # Examples
+    ///
+    /// [`File`][file]s implement `Read`:
+    ///
+    /// [file]: ../fs/struct.File.html
+    /// [`Iterator`]: ../../std/iter/trait.Iterator.html
+    /// [`Result`]: ../../std/result/enum.Result.html
+    /// [`io::Error`]: ../../std/io/struct.Error.html
+    /// [`u8`]: ../../std/primitive.u8.html
+    /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f = File::open("foo.txt")?;
+    ///
+    ///     for byte in f.bytes() {
+    ///         println!("{}", byte.unwrap());
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    fn bytes(self) -> Bytes<Self> where Self: Sized {
+        Bytes { inner: self }
+    }
+
+    /// Creates an adaptor which will chain this stream with another.
+    ///
+    /// The returned `Read` instance will first read all bytes from this object
+    /// until EOF is encountered. Afterwards the output is equivalent to the
+    /// output of `next`.
+    ///
+    /// # Examples
+    ///
+    /// [`File`][file]s implement `Read`:
+    ///
+    /// [file]: ../fs/struct.File.html
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f1 = File::open("foo.txt")?;
+    ///     let mut f2 = File::open("bar.txt")?;
+    ///
+    ///     let mut handle = f1.chain(f2);
+    ///     let mut buffer = String::new();
+    ///
+    ///     // read the value into a String. We could use any Read method here,
+    ///     // this is just one example.
+    ///     handle.read_to_string(&mut buffer)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn chain<R: Read>(self, next: R) -> Chain<Self, R> where Self: Sized {
+        Chain { first: self, second: next, done_first: false }
+    }
+
+    /// Creates an adaptor which will read at most `limit` bytes from it.
+    ///
+    /// This function returns a new instance of `Read` which will read at most
+    /// `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any
+    /// read errors will not count towards the number of bytes read and future
+    /// calls to [`read()`] may succeed.
+    ///
+    /// # Examples
+    ///
+    /// [`File`]s implement `Read`:
+    ///
+    /// [`File`]: ../fs/struct.File.html
+    /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+    /// [`read()`]: trait.Read.html#tymethod.read
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f = File::open("foo.txt")?;
+    ///     let mut buffer = [0; 5];
+    ///
+    ///     // read at most five bytes
+    ///     let mut handle = f.take(5);
+    ///
+    ///     handle.read(&mut buffer)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn take(self, limit: u64) -> Take<Self> where Self: Sized {
+        Take { inner: self, limit: limit }
+    }
+}
+
+/// A type used to conditionally initialize buffers passed to `Read` methods.
+#[derive(Debug)]
+pub struct Initializer(bool);
+
+impl Initializer {
+    /// Returns a new `Initializer` which will zero out buffers.
+    #[inline]
+    pub fn zeroing() -> Initializer {
+        Initializer(true)
+    }
+
+    /// Returns a new `Initializer` which will not zero out buffers.
+    ///
+    /// # Safety
+    ///
+    /// This may only be called by `Read`ers which guarantee that they will not
+    /// read from buffers passed to `Read` methods, and that the return value of
+    /// the method accurately reflects the number of bytes that have been
+    /// written to the head of the buffer.
+    #[inline]
+    pub unsafe fn nop() -> Initializer {
+        Initializer(false)
+    }
+
+    /// Indicates if a buffer should be initialized.
+    #[inline]
+    pub fn should_initialize(&self) -> bool {
+        self.0
+    }
+
+    /// Initializes a buffer if necessary.
+    #[inline]
+    pub fn initialize(&self, buf: &mut [u8]) {
+        if self.should_initialize() {
+            unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
+        }
+    }
+}
+
+/// A trait for objects which are byte-oriented sinks.
+///
+/// Implementors of the `Write` trait are sometimes called 'writers'.
+///
+/// Writers are defined by two required methods, [`write`] and [`flush`]:
+///
+/// * The [`write`] method will attempt to write some data into the object,
+///   returning how many bytes were successfully written.
+///
+/// * The [`flush`] method is useful for adaptors and explicit buffers
+///   themselves for ensuring that all buffered data has been pushed out to the
+///   'true sink'.
+///
+/// Writers are intended to be composable with one another. Many implementors
+/// throughout [`std::io`] take and provide types which implement the `Write`
+/// trait.
+///
+/// [`write`]: #tymethod.write
+/// [`flush`]: #tymethod.flush
+/// [`std::io`]: index.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::fs::File;
+///
+/// fn main() -> std::io::Result<()> {
+///     let mut buffer = File::create("foo.txt")?;
+///
+///     buffer.write(b"some bytes")?;
+///     Ok(())
+/// }
+/// ```
+#[doc(notable_trait)]
+pub trait Write {
+    /// Write a buffer into this object, returning how many bytes were written.
+    ///
+    /// This function will attempt to write the entire contents of `buf`, but
+    /// the entire write may not succeed, or the write may also generate an
+    /// error. A call to `write` represents *at most one* attempt to write to
+    /// any wrapped object.
+    ///
+    /// Calls to `write` are not guaranteed to block waiting for data to be
+    /// written, and a write which would otherwise block can be indicated through
+    /// an [`Err`] variant.
+    ///
+    /// If the return value is [`Ok(n)`] then it must be guaranteed that
+    /// `0 <= n <= buf.len()`. A return value of `0` typically means that the
+    /// underlying object is no longer able to accept bytes and will likely not
+    /// be able to in the future as well, or that the buffer provided is empty.
+    ///
+    /// # Errors
+    ///
+    /// Each call to `write` may generate an I/O error indicating that the
+    /// operation could not be completed. If an error is returned then no bytes
+    /// in the buffer were written to this writer.
+    ///
+    /// It is **not** considered an error if the entire buffer could not be
+    /// written to this writer.
+    ///
+    /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the
+    /// write operation should be retried if there is nothing else to do.
+    ///
+    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+    /// [`Ok(n)`]:  ../../std/result/enum.Result.html#variant.Ok
+    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut buffer = File::create("foo.txt")?;
+    ///
+    ///     // Writes some prefix of the byte string, not necessarily all of it.
+    ///     buffer.write(b"some bytes")?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn write(&mut self, buf: &[u8]) -> Result<usize>;
+
+    /// Flush this output stream, ensuring that all intermediately buffered
+    /// contents reach their destination.
+    ///
+    /// # Errors
+    ///
+    /// It is considered an error if not all bytes could be written due to
+    /// I/O errors or EOF being reached.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::prelude::*;
+    /// use std::io::BufWriter;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut buffer = BufWriter::new(File::create("foo.txt")?);
+    ///
+    ///     buffer.write(b"some bytes")?;
+    ///     buffer.flush()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn flush(&mut self) -> Result<()>;
+
+    /// Attempts to write an entire buffer into this write.
+    ///
+    /// This method will continuously call [`write`] until there is no more data
+    /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+    /// returned. This method will not return until the entire buffer has been
+    /// successfully written or such an error occurs. The first error that is
+    /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+    /// returned.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the first error of
+    /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns.
+    ///
+    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`write`]: #tymethod.write
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut buffer = File::create("foo.txt")?;
+    ///
+    ///     buffer.write_all(b"some bytes")?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
+        while !buf.is_empty() {
+            match self.write(buf) {
+                Ok(0) => return Err(Error::new(ErrorKind::WriteZero,
+                                               "failed to write whole buffer")),
+                Ok(n) => buf = &buf[n..],
+                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
+
+    /// Writes a formatted string into this writer, returning any error
+    /// encountered.
+    ///
+    /// This method is primarily used to interface with the
+    /// [`format_args!`][formatargs] macro, but it is rare that this should
+    /// explicitly be called. The [`write!`][write] macro should be favored to
+    /// invoke this method instead.
+    ///
+    /// [formatargs]: ../macro.format_args.html
+    /// [write]: ../macro.write.html
+    ///
+    /// This function internally uses the [`write_all`][writeall] method on
+    /// this trait and hence will continuously write data so long as no errors
+    /// are received. This also means that partial writes are not indicated in
+    /// this signature.
+    ///
+    /// [writeall]: #method.write_all
+    ///
+    /// # Errors
+    ///
+    /// This function will return any I/O error reported while formatting.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut buffer = File::create("foo.txt")?;
+    ///
+    ///     // this call
+    ///     write!(buffer, "{:.*}", 2, 1.234567)?;
+    ///     // turns into this:
+    ///     buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> {
+        // Create a shim which translates a Write to a fmt::Write and saves
+        // off I/O errors. instead of discarding them
+        struct Adaptor<'a, T: ?Sized + 'a> {
+            inner: &'a mut T,
+            error: Result<()>,
+        }
+
+        impl<'a, T: Write + ?Sized> fmt::Write for Adaptor<'a, T> {
+            fn write_str(&mut self, s: &str) -> fmt::Result {
+                match self.inner.write_all(s.as_bytes()) {
+                    Ok(()) => Ok(()),
+                    Err(e) => {
+                        self.error = Err(e);
+                        Err(fmt::Error)
+                    }
+                }
+            }
+        }
+
+        let mut output = Adaptor { inner: self, error: Ok(()) };
+        match fmt::write(&mut output, fmt) {
+            Ok(()) => Ok(()),
+            Err(..) => {
+                // check if the error came from the underlying `Write` or not
+                if output.error.is_err() {
+                    output.error
+                } else {
+                    Err(Error::new(ErrorKind::Other, "formatter error"))
+                }
+            }
+        }
+    }
+
+    /// Creates a "by reference" adaptor for this instance of `Write`.
+    ///
+    /// The returned adaptor also implements `Write` and will simply borrow this
+    /// current writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::Write;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut buffer = File::create("foo.txt")?;
+    ///
+    ///     let reference = buffer.by_ref();
+    ///
+    ///     // we can use reference just like our original buffer
+    ///     reference.write_all(b"some bytes")?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn by_ref(&mut self) -> &mut Self where Self: Sized { self }
+}
+
+/// The `Seek` trait provides a cursor which can be moved within a stream of
+/// bytes.
+///
+/// The stream typically has a fixed size, allowing seeking relative to either
+/// end or the current offset.
+///
+/// # Examples
+///
+/// [`File`][file]s implement `Seek`:
+///
+/// [file]: ../fs/struct.File.html
+///
+/// ```no_run
+/// use std::io;
+/// use std::io::prelude::*;
+/// use std::fs::File;
+/// use std::io::SeekFrom;
+///
+/// fn main() -> io::Result<()> {
+///     let mut f = File::open("foo.txt")?;
+///
+///     // move the cursor 42 bytes from the start of the file
+///     f.seek(SeekFrom::Start(42))?;
+///     Ok(())
+/// }
+/// ```
+pub trait Seek {
+    /// Seek to an offset, in bytes, in a stream.
+    ///
+    /// A seek beyond the end of a stream is allowed, but behavior is defined
+    /// by the implementation.
+    ///
+    /// If the seek operation completed successfully,
+    /// this method returns the new position from the start of the stream.
+    /// That position can be used later with [`SeekFrom::Start`].
+    ///
+    /// # Errors
+    ///
+    /// Seeking to a negative offset is considered an error.
+    ///
+    /// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start
+    fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
+}
+
+/// Enumeration of possible methods to seek within an I/O object.
+///
+/// It is used by the [`Seek`] trait.
+///
+/// [`Seek`]: trait.Seek.html
+#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+pub enum SeekFrom {
+    /// Set the offset to the provided number of bytes.
+    Start(u64),
+
+    /// Set the offset to the size of this object plus the specified number of
+    /// bytes.
+    ///
+    /// It is possible to seek beyond the end of an object, but it's an error to
+    /// seek before byte 0.
+    End(i64),
+
+    /// Set the offset to the current position plus the specified number of
+    /// bytes.
+    ///
+    /// It is possible to seek beyond the end of an object, but it's an error to
+    /// seek before byte 0.
+    Current(i64),
+}
+
+#[cfg(feature="alloc")]
+fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
+                                   -> Result<usize> {
+    let mut read = 0;
+    loop {
+        let (done, used) = {
+            let available = match r.fill_buf() {
+                Ok(n) => n,
+                Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+                Err(e) => return Err(e)
+            };
+            match memchr::memchr(delim, available) {
+                Some(i) => {
+                    buf.extend_from_slice(&available[..i + 1]);
+                    (true, i + 1)
+                }
+                None => {
+                    buf.extend_from_slice(available);
+                    (false, available.len())
+                }
+            }
+        };
+        r.consume(used);
+        read += used;
+        if done || used == 0 {
+            return Ok(read);
+        }
+    }
+}
+
+/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it
+/// to perform extra ways of reading.
+///
+/// For example, reading line-by-line is inefficient without using a buffer, so
+/// if you want to read by line, you'll need `BufRead`, which includes a
+/// [`read_line`] method as well as a [`lines`] iterator.
+///
+/// # Examples
+///
+/// A locked standard input implements `BufRead`:
+///
+/// ```no_run
+/// use std::io;
+/// use std::io::prelude::*;
+///
+/// let stdin = io::stdin();
+/// for line in stdin.lock().lines() {
+///     println!("{}", line.unwrap());
+/// }
+/// ```
+///
+/// If you have something that implements [`Read`], you can use the [`BufReader`
+/// type][`BufReader`] to turn it into a `BufRead`.
+///
+/// For example, [`File`] implements [`Read`], but not `BufRead`.
+/// [`BufReader`] to the rescue!
+///
+/// [`BufReader`]: struct.BufReader.html
+/// [`File`]: ../fs/struct.File.html
+/// [`read_line`]: #method.read_line
+/// [`lines`]: #method.lines
+/// [`Read`]: trait.Read.html
+///
+/// ```no_run
+/// use std::io::{self, BufReader};
+/// use std::io::prelude::*;
+/// use std::fs::File;
+///
+/// fn main() -> io::Result<()> {
+///     let f = File::open("foo.txt")?;
+///     let f = BufReader::new(f);
+///
+///     for line in f.lines() {
+///         println!("{}", line.unwrap());
+///     }
+///
+///     Ok(())
+/// }
+/// ```
+///
+#[cfg(feature="alloc")]
+pub trait BufRead: Read {
+    /// Returns the contents of the internal buffer, filling it with more data
+    /// from the inner reader if it is empty.
+    ///
+    /// This function is a lower-level call. It needs to be paired with the
+    /// [`consume`] method to function properly. When calling this
+    /// method, none of the contents will be "read" in the sense that later
+    /// calling `read` may return the same contents. As such, [`consume`] must
+    /// be called with the number of bytes that are consumed from this buffer to
+    /// ensure that the bytes are never returned twice.
+    ///
+    /// [`consume`]: #tymethod.consume
+    ///
+    /// An empty buffer returned indicates that the stream has reached EOF.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an I/O error if the underlying reader was
+    /// read, but returned an error.
+    ///
+    /// # Examples
+    ///
+    /// A locked standard input implements `BufRead`:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    ///
+    /// let stdin = io::stdin();
+    /// let mut stdin = stdin.lock();
+    ///
+    /// // we can't have two `&mut` references to `stdin`, so use a block
+    /// // to end the borrow early.
+    /// let length = {
+    ///     let buffer = stdin.fill_buf().unwrap();
+    ///
+    ///     // work with buffer
+    ///     println!("{:?}", buffer);
+    ///
+    ///     buffer.len()
+    /// };
+    ///
+    /// // ensure the bytes we worked with aren't returned again later
+    /// stdin.consume(length);
+    /// ```
+    fn fill_buf(&mut self) -> Result<&[u8]>;
+
+    /// Tells this buffer that `amt` bytes have been consumed from the buffer,
+    /// so they should no longer be returned in calls to `read`.
+    ///
+    /// This function is a lower-level call. It needs to be paired with the
+    /// [`fill_buf`] method to function properly. This function does
+    /// not perform any I/O, it simply informs this object that some amount of
+    /// its buffer, returned from [`fill_buf`], has been consumed and should
+    /// no longer be returned. As such, this function may do odd things if
+    /// [`fill_buf`] isn't called before calling it.
+    ///
+    /// The `amt` must be `<=` the number of bytes in the buffer returned by
+    /// [`fill_buf`].
+    ///
+    /// # Examples
+    ///
+    /// Since `consume()` is meant to be used with [`fill_buf`],
+    /// that method's example includes an example of `consume()`.
+    ///
+    /// [`fill_buf`]: #tymethod.fill_buf
+    fn consume(&mut self, amt: usize);
+
+    /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached.
+    ///
+    /// This function will read bytes from the underlying stream until the
+    /// delimiter or EOF is found. Once found, all bytes up to, and including,
+    /// the delimiter (if found) will be appended to `buf`.
+    ///
+    /// If successful, this function will return the total number of bytes read.
+    ///
+    /// # Errors
+    ///
+    /// This function will ignore all instances of [`ErrorKind::Interrupted`] and
+    /// will otherwise return any errors returned by [`fill_buf`].
+    ///
+    /// If an I/O error is encountered then all bytes read so far will be
+    /// present in `buf` and its length will have been adjusted appropriately.
+    ///
+    /// [`fill_buf`]: #tymethod.fill_buf
+    /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted
+    ///
+    /// # Examples
+    ///
+    /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+    /// this example, we use [`Cursor`] to read all the bytes in a byte slice
+    /// in hyphen delimited segments:
+    ///
+    /// [`Cursor`]: struct.Cursor.html
+    ///
+    /// ```
+    /// use std::io::{self, BufRead};
+    ///
+    /// let mut cursor = io::Cursor::new(b"lorem-ipsum");
+    /// let mut buf = vec![];
+    ///
+    /// // cursor is at 'l'
+    /// let num_bytes = cursor.read_until(b'-', &mut buf)
+    ///     .expect("reading from cursor won't fail");
+    /// assert_eq!(num_bytes, 6);
+    /// assert_eq!(buf, b"lorem-");
+    /// buf.clear();
+    ///
+    /// // cursor is at 'i'
+    /// let num_bytes = cursor.read_until(b'-', &mut buf)
+    ///     .expect("reading from cursor won't fail");
+    /// assert_eq!(num_bytes, 5);
+    /// assert_eq!(buf, b"ipsum");
+    /// buf.clear();
+    ///
+    /// // cursor is at EOF
+    /// let num_bytes = cursor.read_until(b'-', &mut buf)
+    ///     .expect("reading from cursor won't fail");
+    /// assert_eq!(num_bytes, 0);
+    /// assert_eq!(buf, b"");
+    /// ```
+    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
+        read_until(self, byte, buf)
+    }
+
+    /// Read all bytes until a newline (the 0xA byte) is reached, and append
+    /// them to the provided buffer.
+    ///
+    /// This function will read bytes from the underlying stream until the
+    /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes
+    /// up to, and including, the delimiter (if found) will be appended to
+    /// `buf`.
+    ///
+    /// If successful, this function will return the total number of bytes read.
+    ///
+    /// An empty buffer returned indicates that the stream has reached EOF.
+    ///
+    /// # Errors
+    ///
+    /// This function has the same error semantics as [`read_until`] and will
+    /// also return an error if the read bytes are not valid UTF-8. If an I/O
+    /// error is encountered then `buf` may contain some bytes already read in
+    /// the event that all data read so far was valid UTF-8.
+    ///
+    /// [`read_until`]: #method.read_until
+    ///
+    /// # Examples
+    ///
+    /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+    /// this example, we use [`Cursor`] to read all the lines in a byte slice:
+    ///
+    /// [`Cursor`]: struct.Cursor.html
+    ///
+    /// ```
+    /// use std::io::{self, BufRead};
+    ///
+    /// let mut cursor = io::Cursor::new(b"foo\nbar");
+    /// let mut buf = String::new();
+    ///
+    /// // cursor is at 'f'
+    /// let num_bytes = cursor.read_line(&mut buf)
+    ///     .expect("reading from cursor won't fail");
+    /// assert_eq!(num_bytes, 4);
+    /// assert_eq!(buf, "foo\n");
+    /// buf.clear();
+    ///
+    /// // cursor is at 'b'
+    /// let num_bytes = cursor.read_line(&mut buf)
+    ///     .expect("reading from cursor won't fail");
+    /// assert_eq!(num_bytes, 3);
+    /// assert_eq!(buf, "bar");
+    /// buf.clear();
+    ///
+    /// // cursor is at EOF
+    /// let num_bytes = cursor.read_line(&mut buf)
+    ///     .expect("reading from cursor won't fail");
+    /// assert_eq!(num_bytes, 0);
+    /// assert_eq!(buf, "");
+    /// ```
+    fn read_line(&mut self, buf: &mut String) -> Result<usize> {
+        // Note that we are not calling the `.read_until` method here, but
+        // rather our hardcoded implementation. For more details as to why, see
+        // the comments in `read_to_end`.
+        append_to_string(buf, |b| read_until(self, b'\n', b))
+    }
+
+    /// Returns an iterator over the contents of this reader split on the byte
+    /// `byte`.
+    ///
+    /// The iterator returned from this function will return instances of
+    /// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
+    /// the delimiter byte at the end.
+    ///
+    /// This function will yield errors whenever [`read_until`] would have
+    /// also yielded an error.
+    ///
+    /// [`io::Result`]: type.Result.html
+    /// [`Vec<u8>`]: ../vec/struct.Vec.html
+    /// [`read_until`]: #method.read_until
+    ///
+    /// # Examples
+    ///
+    /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+    /// this example, we use [`Cursor`] to iterate over all hyphen delimited
+    /// segments in a byte slice
+    ///
+    /// [`Cursor`]: struct.Cursor.html
+    ///
+    /// ```
+    /// use std::io::{self, BufRead};
+    ///
+    /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor");
+    ///
+    /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap());
+    /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec()));
+    /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec()));
+    /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec()));
+    /// assert_eq!(split_iter.next(), None);
+    /// ```
+    fn split(self, byte: u8) -> Split<Self> where Self: Sized {
+        Split { buf: self, delim: byte }
+    }
+
+    /// Returns an iterator over the lines of this reader.
+    ///
+    /// The iterator returned from this function will yield instances of
+    /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline
+    /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
+    ///
+    /// [`io::Result`]: type.Result.html
+    /// [`String`]: ../string/struct.String.html
+    ///
+    /// # Examples
+    ///
+    /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+    /// this example, we use [`Cursor`] to iterate over all the lines in a byte
+    /// slice.
+    ///
+    /// [`Cursor`]: struct.Cursor.html
+    ///
+    /// ```
+    /// use std::io::{self, BufRead};
+    ///
+    /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor");
+    ///
+    /// let mut lines_iter = cursor.lines().map(|l| l.unwrap());
+    /// assert_eq!(lines_iter.next(), Some(String::from("lorem")));
+    /// assert_eq!(lines_iter.next(), Some(String::from("ipsum")));
+    /// assert_eq!(lines_iter.next(), Some(String::from("dolor")));
+    /// assert_eq!(lines_iter.next(), None);
+    /// ```
+    ///
+    /// # Errors
+    ///
+    /// Each line of the iterator has the same error semantics as [`BufRead::read_line`].
+    ///
+    /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line
+    fn lines(self) -> Lines<Self> where Self: Sized {
+        Lines { buf: self }
+    }
+}
+
+/// Adaptor to chain together two readers.
+///
+/// This struct is generally created by calling [`chain`] on a reader.
+/// Please see the documentation of [`chain`] for more details.
+///
+/// [`chain`]: trait.Read.html#method.chain
+pub struct Chain<T, U> {
+    first: T,
+    second: U,
+    done_first: bool,
+}
+
+impl<T, U> Chain<T, U> {
+    /// Consumes the `Chain`, returning the wrapped readers.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut foo_file = File::open("foo.txt")?;
+    ///     let mut bar_file = File::open("bar.txt")?;
+    ///
+    ///     let chain = foo_file.chain(bar_file);
+    ///     let (foo_file, bar_file) = chain.into_inner();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn into_inner(self) -> (T, U) {
+        (self.first, self.second)
+    }
+
+    /// Gets references to the underlying readers in this `Chain`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut foo_file = File::open("foo.txt")?;
+    ///     let mut bar_file = File::open("bar.txt")?;
+    ///
+    ///     let chain = foo_file.chain(bar_file);
+    ///     let (foo_file, bar_file) = chain.get_ref();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn get_ref(&self) -> (&T, &U) {
+        (&self.first, &self.second)
+    }
+
+    /// Gets mutable references to the underlying readers in this `Chain`.
+    ///
+    /// Care should be taken to avoid modifying the internal I/O state of the
+    /// underlying readers as doing so may corrupt the internal state of this
+    /// `Chain`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut foo_file = File::open("foo.txt")?;
+    ///     let mut bar_file = File::open("bar.txt")?;
+    ///
+    ///     let mut chain = foo_file.chain(bar_file);
+    ///     let (foo_file, bar_file) = chain.get_mut();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn get_mut(&mut self) -> (&mut T, &mut U) {
+        (&mut self.first, &mut self.second)
+    }
+}
+
+impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Chain")
+            .field("t", &self.first)
+            .field("u", &self.second)
+            .finish()
+    }
+}
+
+impl<T: Read, U: Read> Read for Chain<T, U> {
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        if !self.done_first {
+            match self.first.read(buf)? {
+                0 if buf.len() != 0 => { self.done_first = true; }
+                n => return Ok(n),
+            }
+        }
+        self.second.read(buf)
+    }
+
+    unsafe fn initializer(&self) -> Initializer {
+        let initializer = self.first.initializer();
+        if initializer.should_initialize() {
+            initializer
+        } else {
+            self.second.initializer()
+        }
+    }
+}
+
+#[cfg(feature="alloc")]
+impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
+    fn fill_buf(&mut self) -> Result<&[u8]> {
+        if !self.done_first {
+            match self.first.fill_buf()? {
+                buf if buf.len() == 0 => { self.done_first = true; }
+                buf => return Ok(buf),
+            }
+        }
+        self.second.fill_buf()
+    }
+
+    fn consume(&mut self, amt: usize) {
+        if !self.done_first {
+            self.first.consume(amt)
+        } else {
+            self.second.consume(amt)
+        }
+    }
+}
+
+/// Reader adaptor which limits the bytes read from an underlying reader.
+///
+/// This struct is generally created by calling [`take`] on a reader.
+/// Please see the documentation of [`take`] for more details.
+///
+/// [`take`]: trait.Read.html#method.take
+#[derive(Debug)]
+pub struct Take<T> {
+    inner: T,
+    limit: u64,
+}
+
+impl<T> Take<T> {
+    /// Returns the number of bytes that can be read before this instance will
+    /// return EOF.
+    ///
+    /// # Note
+    ///
+    /// This instance may reach `EOF` after reading fewer bytes than indicated by
+    /// this method if the underlying [`Read`] instance reaches EOF.
+    ///
+    /// [`Read`]: ../../std/io/trait.Read.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let f = File::open("foo.txt")?;
+    ///
+    ///     // read at most five bytes
+    ///     let handle = f.take(5);
+    ///
+    ///     println!("limit: {}", handle.limit());
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn limit(&self) -> u64 { self.limit }
+
+    /// Sets the number of bytes that can be read before this instance will
+    /// return EOF. This is the same as constructing a new `Take` instance, so
+    /// the amount of bytes read and the previous limit value don't matter when
+    /// calling this method.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let f = File::open("foo.txt")?;
+    ///
+    ///     // read at most five bytes
+    ///     let mut handle = f.take(5);
+    ///     handle.set_limit(10);
+    ///
+    ///     assert_eq!(handle.limit(), 10);
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn set_limit(&mut self, limit: u64) {
+        self.limit = limit;
+    }
+
+    /// Consumes the `Take`, returning the wrapped reader.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("foo.txt")?;
+    ///
+    ///     let mut buffer = [0; 5];
+    ///     let mut handle = file.take(5);
+    ///     handle.read(&mut buffer)?;
+    ///
+    ///     let file = handle.into_inner();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn into_inner(self) -> T {
+        self.inner
+    }
+
+    /// Gets a reference to the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("foo.txt")?;
+    ///
+    ///     let mut buffer = [0; 5];
+    ///     let mut handle = file.take(5);
+    ///     handle.read(&mut buffer)?;
+    ///
+    ///     let file = handle.get_ref();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn get_ref(&self) -> &T {
+        &self.inner
+    }
+
+    /// Gets a mutable reference to the underlying reader.
+    ///
+    /// Care should be taken to avoid modifying the internal I/O state of the
+    /// underlying reader as doing so may corrupt the internal limit of this
+    /// `Take`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::io::prelude::*;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("foo.txt")?;
+    ///
+    ///     let mut buffer = [0; 5];
+    ///     let mut handle = file.take(5);
+    ///     handle.read(&mut buffer)?;
+    ///
+    ///     let file = handle.get_mut();
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn get_mut(&mut self) -> &mut T {
+        &mut self.inner
+    }
+}
+
+impl<T: Read> Read for Take<T> {
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        // Don't call into inner reader at all at EOF because it may still block
+        if self.limit == 0 {
+            return Ok(0);
+        }
+
+        let max = cmp::min(buf.len() as u64, self.limit) as usize;
+        let n = self.inner.read(&mut buf[..max])?;
+        self.limit -= n as u64;
+        Ok(n)
+    }
+
+    unsafe fn initializer(&self) -> Initializer {
+        self.inner.initializer()
+    }
+
+    #[cfg(feature="alloc")]
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
+        let reservation_size = cmp::min(self.limit, 32) as usize;
+
+        read_to_end_with_reservation(self, buf, reservation_size)
+    }
+}
+
+#[cfg(feature="alloc")]
+impl<T: BufRead> BufRead for Take<T> {
+    fn fill_buf(&mut self) -> Result<&[u8]> {
+        // Don't call into inner reader at all at EOF because it may still block
+        if self.limit == 0 {
+            return Ok(&[]);
+        }
+
+        let buf = self.inner.fill_buf()?;
+        let cap = cmp::min(buf.len() as u64, self.limit) as usize;
+        Ok(&buf[..cap])
+    }
+
+    fn consume(&mut self, amt: usize) {
+        // Don't let callers reset the limit by passing an overlarge value
+        let amt = cmp::min(amt as u64, self.limit) as usize;
+        self.limit -= amt as u64;
+        self.inner.consume(amt);
+    }
+}
+
+fn read_one_byte(reader: &mut dyn Read) -> Option<Result<u8>> {
+    let mut buf = [0];
+    loop {
+        return match reader.read(&mut buf) {
+            Ok(0) => None,
+            Ok(..) => Some(Ok(buf[0])),
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+            Err(e) => Some(Err(e)),
+        };
+    }
+}
+
+/// An iterator over `u8` values of a reader.
+///
+/// This struct is generally created by calling [`bytes`] on a reader.
+/// Please see the documentation of [`bytes`] for more details.
+///
+/// [`bytes`]: trait.Read.html#method.bytes
+#[derive(Debug)]
+pub struct Bytes<R> {
+    inner: R,
+}
+
+impl<R: Read> Iterator for Bytes<R> {
+    type Item = Result<u8>;
+
+    fn next(&mut self) -> Option<Result<u8>> {
+        read_one_byte(&mut self.inner)
+    }
+}
+
+/// An iterator over the contents of an instance of `BufRead` split on a
+/// particular byte.
+///
+/// This struct is generally created by calling [`split`][split] on a
+/// `BufRead`. Please see the documentation of `split()` for more details.
+///
+/// [split]: trait.BufRead.html#method.split
+#[cfg(feature="alloc")]
+#[derive(Debug)]
+pub struct Split<B> {
+    buf: B,
+    delim: u8,
+}
+
+#[cfg(feature="alloc")]
+impl<B: BufRead> Iterator for Split<B> {
+    type Item = Result<Vec<u8>>;
+
+    fn next(&mut self) -> Option<Result<Vec<u8>>> {
+        let mut buf = Vec::new();
+        match self.buf.read_until(self.delim, &mut buf) {
+            Ok(0) => None,
+            Ok(_n) => {
+                if buf[buf.len() - 1] == self.delim {
+                    buf.pop();
+                }
+                Some(Ok(buf))
+            }
+            Err(e) => Some(Err(e))
+        }
+    }
+}
+
+/// An iterator over the lines of an instance of `BufRead`.
+///
+/// This struct is generally created by calling [`lines`][lines] on a
+/// `BufRead`. Please see the documentation of `lines()` for more details.
+///
+/// [lines]: trait.BufRead.html#method.lines
+#[cfg(feature="alloc")]
+#[derive(Debug)]
+pub struct Lines<B> {
+    buf: B,
+}
+
+#[cfg(feature="alloc")]
+impl<B: BufRead> Iterator for Lines<B> {
+    type Item = Result<String>;
+
+    fn next(&mut self) -> Option<Result<String>> {
+        let mut buf = String::new();
+        match self.buf.read_line(&mut buf) {
+            Ok(0) => None,
+            Ok(_n) => {
+                if buf.ends_with("\n") {
+                    buf.pop();
+                    if buf.ends_with("\r") {
+                        buf.pop();
+                    }
+                }
+                Some(Ok(buf))
+            }
+            Err(e) => Some(Err(e))
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use io::prelude::*;
+    use io;
+    use super::Cursor;
+    use test;
+    use super::repeat;
+
+    #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
+    fn read_until() {
+        let mut buf = Cursor::new(&b"12"[..]);
+        let mut v = Vec::new();
+        assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2);
+        assert_eq!(v, b"12");
+
+        let mut buf = Cursor::new(&b"1233"[..]);
+        let mut v = Vec::new();
+        assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3);
+        assert_eq!(v, b"123");
+        v.truncate(0);
+        assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1);
+        assert_eq!(v, b"3");
+        v.truncate(0);
+        assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0);
+        assert_eq!(v, []);
+    }
+
+    #[test]
+    fn split() {
+        let buf = Cursor::new(&b"12"[..]);
+        let mut s = buf.split(b'3');
+        assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+        assert!(s.next().is_none());
+
+        let buf = Cursor::new(&b"1233"[..]);
+        let mut s = buf.split(b'3');
+        assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+        assert_eq!(s.next().unwrap().unwrap(), vec![]);
+        assert!(s.next().is_none());
+    }
+
+    #[test]
+    fn read_line() {
+        let mut buf = Cursor::new(&b"12"[..]);
+        let mut v = String::new();
+        assert_eq!(buf.read_line(&mut v).unwrap(), 2);
+        assert_eq!(v, "12");
+
+        let mut buf = Cursor::new(&b"12\n\n"[..]);
+        let mut v = String::new();
+        assert_eq!(buf.read_line(&mut v).unwrap(), 3);
+        assert_eq!(v, "12\n");
+        v.truncate(0);
+        assert_eq!(buf.read_line(&mut v).unwrap(), 1);
+        assert_eq!(v, "\n");
+        v.truncate(0);
+        assert_eq!(buf.read_line(&mut v).unwrap(), 0);
+        assert_eq!(v, "");
+    }
+
+    #[test]
+    fn lines() {
+        let buf = Cursor::new(&b"12\r"[..]);
+        let mut s = buf.lines();
+        assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string());
+        assert!(s.next().is_none());
+
+        let buf = Cursor::new(&b"12\r\n\n"[..]);
+        let mut s = buf.lines();
+        assert_eq!(s.next().unwrap().unwrap(), "12".to_string());
+        assert_eq!(s.next().unwrap().unwrap(), "".to_string());
+        assert!(s.next().is_none());
+    }
+
+    #[test]
+    fn read_to_end() {
+        let mut c = Cursor::new(&b""[..]);
+        let mut v = Vec::new();
+        assert_eq!(c.read_to_end(&mut v).unwrap(), 0);
+        assert_eq!(v, []);
+
+        let mut c = Cursor::new(&b"1"[..]);
+        let mut v = Vec::new();
+        assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
+        assert_eq!(v, b"1");
+
+        let cap = 1024 * 1024;
+        let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
+        let mut v = Vec::new();
+        let (a, b) = data.split_at(data.len() / 2);
+        assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len());
+        assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len());
+        assert_eq!(v, data);
+    }
+
+    #[test]
+    fn read_to_string() {
+        let mut c = Cursor::new(&b""[..]);
+        let mut v = String::new();
+        assert_eq!(c.read_to_string(&mut v).unwrap(), 0);
+        assert_eq!(v, "");
+
+        let mut c = Cursor::new(&b"1"[..]);
+        let mut v = String::new();
+        assert_eq!(c.read_to_string(&mut v).unwrap(), 1);
+        assert_eq!(v, "1");
+
+        let mut c = Cursor::new(&b"\xff"[..]);
+        let mut v = String::new();
+        assert!(c.read_to_string(&mut v).is_err());
+    }
+
+    #[test]
+    fn read_exact() {
+        let mut buf = [0; 4];
+
+        let mut c = Cursor::new(&b""[..]);
+        assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
+                   io::ErrorKind::UnexpectedEof);
+
+        let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..]));
+        c.read_exact(&mut buf).unwrap();
+        assert_eq!(&buf, b"1234");
+        c.read_exact(&mut buf).unwrap();
+        assert_eq!(&buf, b"5678");
+        assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
+                   io::ErrorKind::UnexpectedEof);
+    }
+
+    #[test]
+    fn read_exact_slice() {
+        let mut buf = [0; 4];
+
+        let mut c = &b""[..];
+        assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
+                   io::ErrorKind::UnexpectedEof);
+
+        let mut c = &b"123"[..];
+        assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
+                   io::ErrorKind::UnexpectedEof);
+        // make sure the optimized (early returning) method is being used
+        assert_eq!(&buf, &[0; 4]);
+
+        let mut c = &b"1234"[..];
+        c.read_exact(&mut buf).unwrap();
+        assert_eq!(&buf, b"1234");
+
+        let mut c = &b"56789"[..];
+        c.read_exact(&mut buf).unwrap();
+        assert_eq!(&buf, b"5678");
+        assert_eq!(c, b"9");
+    }
+
+    #[test]
+    fn take_eof() {
+        struct R;
+
+        impl Read for R {
+            fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
+                Err(io::Error::new(io::ErrorKind::Other, ""))
+            }
+        }
+        impl BufRead for R {
+            fn fill_buf(&mut self) -> io::Result<&[u8]> {
+                Err(io::Error::new(io::ErrorKind::Other, ""))
+            }
+            fn consume(&mut self, _amt: usize) { }
+        }
+
+        let mut buf = [0; 1];
+        assert_eq!(0, R.take(0).read(&mut buf).unwrap());
+        assert_eq!(b"", R.take(0).fill_buf().unwrap());
+    }
+
+    fn cmp_bufread<Br1: BufRead, Br2: BufRead>(mut br1: Br1, mut br2: Br2, exp: &[u8]) {
+        let mut cat = Vec::new();
+        loop {
+            let consume = {
+                let buf1 = br1.fill_buf().unwrap();
+                let buf2 = br2.fill_buf().unwrap();
+                let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() };
+                assert_eq!(buf1[..minlen], buf2[..minlen]);
+                cat.extend_from_slice(&buf1[..minlen]);
+                minlen
+            };
+            if consume == 0 {
+                break;
+            }
+            br1.consume(consume);
+            br2.consume(consume);
+        }
+        assert_eq!(br1.fill_buf().unwrap().len(), 0);
+        assert_eq!(br2.fill_buf().unwrap().len(), 0);
+        assert_eq!(&cat[..], &exp[..])
+    }
+
+    #[test]
+    fn chain_bufread() {
+        let testdata = b"ABCDEFGHIJKL";
+        let chain1 = (&testdata[..3]).chain(&testdata[3..6])
+                                     .chain(&testdata[6..9])
+                                     .chain(&testdata[9..]);
+        let chain2 = (&testdata[..4]).chain(&testdata[4..8])
+                                     .chain(&testdata[8..]);
+        cmp_bufread(chain1, chain2, &testdata[..]);
+    }
+
+    #[test]
+    fn chain_zero_length_read_is_not_eof() {
+        let a = b"A";
+        let b = b"B";
+        let mut s = String::new();
+        let mut chain = (&a[..]).chain(&b[..]);
+        chain.read(&mut []).unwrap();
+        chain.read_to_string(&mut s).unwrap();
+        assert_eq!("AB", s);
+    }
+
+    #[bench]
+    #[cfg_attr(target_os = "emscripten", ignore)]
+    fn bench_read_to_end(b: &mut test::Bencher) {
+        b.iter(|| {
+            let mut lr = repeat(1).take(10000000);
+            let mut vec = Vec::with_capacity(1024);
+            super::read_to_end(&mut lr, &mut vec)
+        });
+    }
+}

+ 25 - 0
core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/prelude.rs

@@ -0,0 +1,25 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The I/O Prelude
+//!
+//! The purpose of this module is to alleviate imports of many common I/O traits
+//! by adding a glob import to the top of I/O heavy modules:
+//!
+//! ```
+//! # #![allow(unused_imports)]
+//! use std::io::prelude::*;
+//! ```
+
+pub use super::{Read, Write, Seek};
+#[cfg(feature="alloc")] pub use super::BufRead;
+
+#[cfg(feature="alloc")] pub use alloc::boxed::Box;
+#[cfg(feature="alloc")] pub use alloc::vec::Vec;

+ 255 - 0
core_io/src/b9adc3327ec7d2820ab2db8bb3cc2a0196a8375d/util.rs

@@ -0,0 +1,255 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(missing_copy_implementations)]
+
+use core::fmt;
+use io::{self, Read, Initializer, Write, ErrorKind};
+use core::mem;
+#[cfg(feature="alloc")] use io::BufRead;
+
+/// Copies the entire contents of a reader into a writer.
+///
+/// This function will continuously read data from `reader` and then
+/// write it into `writer` in a streaming fashion until `reader`
+/// returns EOF.
+///
+/// On success, the total number of bytes that were copied from
+/// `reader` to `writer` is returned.
+///
+/// If you’re wanting to copy the contents of one file to another and you’re
+/// working with filesystem paths, see the [`fs::copy`] function.
+///
+/// [`fs::copy`]: ../fs/fn.copy.html
+///
+/// # Errors
+///
+/// This function will return an error immediately if any call to `read` or
+/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
+/// handled by this function and the underlying operation is retried.
+///
+/// # Examples
+///
+/// ```
+/// use std::io;
+///
+/// fn main() -> io::Result<()> {
+///     let mut reader: &[u8] = b"hello";
+///     let mut writer: Vec<u8> = vec![];
+///
+///     io::copy(&mut reader, &mut writer)?;
+///
+///     assert_eq!(&b"hello"[..], &writer[..]);
+///     Ok(())
+/// }
+/// ```
+pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
+    where R: Read, W: Write
+{
+    let mut buf = unsafe {
+        let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
+        reader.initializer().initialize(&mut buf);
+        buf
+    };
+
+    let mut written = 0;
+    loop {
+        let len = match reader.read(&mut buf) {
+            Ok(0) => return Ok(written),
+            Ok(len) => len,
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+            Err(e) => return Err(e),
+        };
+        writer.write_all(&buf[..len])?;
+        written += len as u64;
+    }
+}
+
+/// A reader which is always at EOF.
+///
+/// This struct is generally created by calling [`empty`]. Please see
+/// the documentation of [`empty()`][`empty`] for more details.
+///
+/// [`empty`]: fn.empty.html
+pub struct Empty { _priv: () }
+
+/// Constructs a new handle to an empty reader.
+///
+/// All reads from the returned reader will return [`Ok`]`(0)`.
+///
+/// [`Ok`]: ../result/enum.Result.html#variant.Ok
+///
+/// # Examples
+///
+/// A slightly sad example of not reading anything into a buffer:
+///
+/// ```
+/// use std::io::{self, Read};
+///
+/// let mut buffer = String::new();
+/// io::empty().read_to_string(&mut buffer).unwrap();
+/// assert!(buffer.is_empty());
+/// ```
+pub fn empty() -> Empty { Empty { _priv: () } }
+
+impl Read for Empty {
+    #[inline]
+    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+#[cfg(feature="alloc")]
+impl BufRead for Empty {
+    #[inline]
+    fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
+    #[inline]
+    fn consume(&mut self, _n: usize) {}
+}
+
+impl fmt::Debug for Empty {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Empty { .. }")
+    }
+}
+
+/// A reader which yields one byte over and over and over and over and over and...
+///
+/// This struct is generally created by calling [`repeat`][repeat]. Please
+/// see the documentation of `repeat()` for more details.
+///
+/// [repeat]: fn.repeat.html
+pub struct Repeat { byte: u8 }
+
+/// Creates an instance of a reader that infinitely repeats one byte.
+///
+/// All reads from this reader will succeed by filling the specified buffer with
+/// the given byte.
+///
+/// # Examples
+///
+/// ```
+/// use std::io::{self, Read};
+///
+/// let mut buffer = [0; 3];
+/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
+/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
+/// ```
+pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }
+
+impl Read for Repeat {
+    #[inline]
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        for slot in &mut *buf {
+            *slot = self.byte;
+        }
+        Ok(buf.len())
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+impl fmt::Debug for Repeat {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Repeat { .. }")
+    }
+}
+
+/// A writer which will move data into the void.
+///
+/// This struct is generally created by calling [`sink`][sink]. Please
+/// see the documentation of `sink()` for more details.
+///
+/// [sink]: fn.sink.html
+pub struct Sink { _priv: () }
+
+/// Creates an instance of a writer which will successfully consume all data.
+///
+/// All calls to `write` on the returned instance will return `Ok(buf.len())`
+/// and the contents of the buffer will not be inspected.
+///
+/// # Examples
+///
+/// ```rust
+/// use std::io::{self, Write};
+///
+/// let buffer = vec![1, 2, 3, 5, 8];
+/// let num_bytes = io::sink().write(&buffer).unwrap();
+/// assert_eq!(num_bytes, 5);
+/// ```
+pub fn sink() -> Sink { Sink { _priv: () } }
+
+impl Write for Sink {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+impl fmt::Debug for Sink {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Sink { .. }")
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use io::prelude::*;
+    use io::{copy, sink, empty, repeat};
+
+    #[test]
+    fn copy_copies() {
+        let mut r = repeat(0).take(4);
+        let mut w = sink();
+        assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
+
+        let mut r = repeat(0).take(1 << 17);
+        assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
+    }
+
+    #[test]
+    fn sink_sinks() {
+        let mut s = sink();
+        assert_eq!(s.write(&[]).unwrap(), 0);
+        assert_eq!(s.write(&[0]).unwrap(), 1);
+        assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
+        assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
+    }
+
+    #[test]
+    fn empty_reads() {
+        let mut e = empty();
+        assert_eq!(e.read(&mut []).unwrap(), 0);
+        assert_eq!(e.read(&mut [0]).unwrap(), 0);
+        assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
+        assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
+    }
+
+    #[test]
+    fn repeat_repeats() {
+        let mut r = repeat(4);
+        let mut b = [0; 1024];
+        assert_eq!(r.read(&mut b).unwrap(), 1024);
+        assert!(b.iter().all(|b| *b == 4));
+    }
+
+    #[test]
+    fn take_some_bytes() {
+        assert_eq!(repeat(4).take(100).bytes().count(), 100);
+        assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
+        assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
+    }
+}

+ 50 - 0
core_io/src/lib.rs

@@ -0,0 +1,50 @@
+//! <p id="core_io-show-docblock"></p>
+//! This is just a listing of the functionality available in this crate. See
+//! the [std documentation](https://doc.rust-lang.org/nightly/std/io/index.html)
+//! for a full description of the functionality.
+#![allow(stable_features,unused_features)]
+#![feature(question_mark,copy_from_slice,
+	doc_notable_trait,try_from,str_internals,align_offset,slice_internals)]
+#![cfg_attr(feature="alloc",feature(alloc))]
+#![no_std]
+
+#[cfg_attr(feature="collections",macro_use)]
+#[cfg(all(feature="collections",not(no_collections)))] extern crate collections;
+#[cfg_attr(feature="collections",allow(unused_imports))]
+#[cfg_attr(feature="collections",macro_use)]
+#[cfg(all(feature="collections",no_collections))] extern crate alloc as collections;
+#[cfg(feature="alloc")] extern crate alloc;
+#[cfg(rustc_unicode)]
+extern crate rustc_unicode;
+#[cfg(std_unicode)]
+extern crate std_unicode;
+
+#[cfg(not(feature="collections"))]
+pub type ErrorString = &'static str;
+
+// Provide Box::new wrapper
+#[cfg(not(feature="alloc"))]
+struct FakeBox<T>(core::marker::PhantomData<T>);
+#[cfg(not(feature="alloc"))]
+impl<T> FakeBox<T> {
+	fn new(val: T) -> T {
+		val
+	}
+}
+
+// Needed for older compilers, to ignore vec!/format! macros in tests
+#[cfg(not(feature="collections"))]
+#[allow(unused)]
+macro_rules! vec (
+	( $ elem : expr ; $ n : expr ) => { () };
+	( $ ( $ x : expr ) , * ) => { () };
+	( $ ( $ x : expr , ) * ) => { () };
+);
+#[cfg(not(feature="collections"))]
+#[allow(unused)]
+macro_rules! format {
+	( $ ( $ arg : tt ) * ) => { () };
+}
+
+include!(concat!(env!("OUT_DIR"), "/io.rs"));
+pub use io::*;

+ 0 - 70
src/allocator/dragonos_malloc.rs

@@ -1,70 +0,0 @@
-use core::{alloc::GlobalAlloc, ffi::c_void, ptr::null_mut};
-
-extern "C" {
-    fn _dragonos_free(ptr: *mut c_void) -> *mut c_void;
-    fn _dragonos_malloc(size: usize) -> *mut c_void;
-    fn _dragonos_chunk_length(ptr: *mut c_void) -> usize;
-}
-
-pub struct Allocator;
-
-pub const NEWALLOCATOR: Allocator = Allocator;
-
-unsafe impl GlobalAlloc for Allocator {
-    unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
-        let size = align_up(layout.size(), layout.align());
-
-        return alloc(size);
-    }
-
-    unsafe fn dealloc(&self, ptr: *mut u8, _layout: core::alloc::Layout) {
-        free(ptr);
-    }
-    unsafe fn realloc(
-        &self,
-        ptr: *mut u8,
-        layout: core::alloc::Layout,
-        new_size: usize,
-    ) -> *mut u8 {
-        let size = align_up(new_size, layout.align());
-        return realloc(ptr, size);
-    }
-}
-
-pub unsafe fn alloc(size: usize) -> *mut u8 {
-    return _dragonos_malloc(size) as *mut u8;
-}
-
-pub unsafe fn free(ptr: *mut u8) {
-    _dragonos_free(ptr as *mut c_void);
-}
-
-fn align_up(addr: usize, align: usize) -> usize {
-    return (addr + align - 1) & !(align - 1);
-}
-
-pub unsafe fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
-    if ptr.is_null() {
-        return alloc(size);
-    }
-    if size == 0 {
-        free(ptr);
-        return null_mut();
-    }
-
-    let old_len = _dragonos_chunk_length(ptr as *mut c_void) - 16;
-
-    // 暴力实现
-
-    let new_ptr = alloc(size);
-    if new_ptr.is_null() {
-        return null_mut();
-    }
-
-    let copy_len = if old_len < size { old_len } else { size };
-    core::ptr::copy_nonoverlapping(ptr, new_ptr, copy_len);
-
-    free(ptr);
-
-    return new_ptr;
-}

+ 0 - 4
src/allocator/mod.rs

@@ -1,4 +0,0 @@
-pub mod dragonos_malloc;
-mod test;
-pub use dragonos_malloc::Allocator;
-pub use dragonos_malloc::NEWALLOCATOR;

+ 0 - 75
src/allocator/test.rs

@@ -1,75 +0,0 @@
-#[cfg(test)]
-mod tests {
-    use crate::allocator::Allocator;
-    use core::alloc::{GlobalAlloc, Layout};
-
-    #[test]
-    fn test_allocation_and_deallocation() {
-        let allocator = Allocator;
-
-        let size = 1024; // 分配 1024 字节的内存
-
-        unsafe {
-            // 使用 Allocator 分配内存
-            let layout = Layout::from_size_align(size, 1).unwrap();
-            let ptr = allocator.alloc(layout);
-
-            assert!(!ptr.is_null()); // 确保分配成功
-
-            // 使用 Allocator 释放内存
-            allocator.dealloc(ptr, layout);
-        }
-    }
-
-    #[test]
-    fn test_alignment() {
-        let allocator = Allocator;
-
-        let size = 1024;
-        let align = 16;
-
-        unsafe {
-            let layout = Layout::from_size_align(size, align).unwrap();
-            let ptr = allocator.alloc(layout);
-
-            assert!(!ptr.is_null());
-            assert_eq!(ptr as usize % align, 0);
-
-            allocator.dealloc(ptr, layout);
-        }
-    }
-
-    #[test]
-    fn test_multiple_allocations() {
-        let allocator = Allocator;
-
-        let sizes = [100, 200, 300, 400, 500];
-
-        unsafe {
-            for &size in &sizes {
-                let layout = Layout::from_size_align(size, 1).unwrap();
-                let ptr = allocator.alloc(layout);
-
-                assert!(!ptr.is_null());
-
-                allocator.dealloc(ptr, layout);
-            }
-        }
-    }
-
-    #[test]
-    fn test_large_allocation() {
-        let allocator = Allocator;
-
-        let size = 1024 * 1024; // 1MB
-
-        unsafe {
-            let layout = Layout::from_size_align(size, 1).unwrap();
-            let ptr = allocator.alloc(layout);
-
-            assert!(!ptr.is_null());
-
-            allocator.dealloc(ptr, layout);
-        }
-    }
-}

+ 0 - 430
src/c/dragonos_malloc.c

@@ -1,430 +0,0 @@
-// Copyright (C) DragonOS Community  longjin
-
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-// Or you can visit https://www.gnu.org/licenses/gpl-2.0.html
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#define PAGE_4K_SHIFT 12
-#define PAGE_2M_SHIFT 21
-#define PAGE_1G_SHIFT 30
-#define PAGE_GDT_SHIFT 39
-
-/***************************/
-
-// 不同大小的页的容量
-#define PAGE_4K_SIZE (1UL << PAGE_4K_SHIFT)
-#define PAGE_2M_SIZE (1UL << PAGE_2M_SHIFT)
-#define PAGE_1G_SIZE (1UL << PAGE_1G_SHIFT)
-
-// 屏蔽低于x的数值
-#define PAGE_4K_MASK (~(PAGE_4K_SIZE - 1))
-#define PAGE_2M_MASK (~(PAGE_2M_SIZE - 1))
-
-#define ALIGN_UP16(x) (((x) + 15) & ~15)
-#define PAGE_ALIGN_UP(x) (((x) + PAGE_4K_SIZE - 1) & PAGE_4K_MASK)
-
-// 将addr按照x的上边界对齐
-// #define PAGE_4K_ALIGN(addr) (((unsigned long)(addr) + PAGE_4K_SIZE - 1) & PAGE_4K_MASK)
-// #define PAGE_2M_ALIGN(addr) (((unsigned long)(addr) + PAGE_2M_SIZE - 1) & PAGE_2M_MASK)
-
-/**
- * @brief 显式链表的结点
- *
- */
-typedef struct malloc_mem_chunk_t
-{
-    uint64_t length; // 整个块所占用的内存区域的大小
-    uint64_t padding;
-    struct malloc_mem_chunk_t *prev; // 上一个结点的指针
-    struct malloc_mem_chunk_t *next; // 下一个结点的指针
-} malloc_mem_chunk_t;
-
-static uint64_t brk_base_addr = 0;    // 堆区域的内存基地址
-static uint64_t brk_max_addr = 0;     // 堆区域的内存最大地址
-static uint64_t brk_managed_addr = 0; // 堆区域已经被管理的地址
-
-// 空闲链表
-//  按start_addr升序排序
-static malloc_mem_chunk_t *malloc_free_list = NULL;
-static malloc_mem_chunk_t *malloc_free_list_end = NULL; // 空闲链表的末尾结点
-
-static uint64_t count_last_free_size = 0; // 统计距离上一次回收内存,已经free了多少内存
-
-/**
- * @brief 将块插入空闲链表
- *
- * @param ck 待插入的块
- */
-static void malloc_insert_free_list(malloc_mem_chunk_t *ck);
-
-/**
- * @brief 当堆顶空闲空间大于2个页的空间的时候,释放1个页
- *
- */
-static void release_brk();
-
-/**
- * @brief 在链表中检索符合要求的空闲块(best fit)
- *
- * @param size 块的大小
- * @return malloc_mem_chunk_t*
- */
-static malloc_mem_chunk_t *malloc_query_free_chunk_bf(uint64_t size)
-{
-    // 在满足best fit的前提下,尽可能的使分配的内存在低地址
-    //  使得总的堆内存可以更快被释放
-
-    if (malloc_free_list == NULL)
-    {
-        return NULL;
-    }
-    malloc_mem_chunk_t *ptr = malloc_free_list;
-    malloc_mem_chunk_t *best = NULL;
-    // printf("query size=%d", size);
-    while (ptr != NULL)
-    {
-        // printf("ptr->length=%#010lx\n", ptr->length);
-        if (ptr->length == size)
-        {
-            best = ptr;
-            break;
-        }
-
-        if (ptr->length > size)
-        {
-            if (best == NULL)
-                best = ptr;
-            else if (best->length > ptr->length)
-                best = ptr;
-        }
-        ptr = ptr->next;
-    }
-
-    return best;
-}
-
-/**
- * @brief 在链表中检索符合要求的空闲块(first fit)
- *
- * @param size
- * @return malloc_mem_chunk_t*
- */
-static malloc_mem_chunk_t *malloc_query_free_chunk_ff(uint64_t size)
-{
-    if (malloc_free_list == NULL)
-        return NULL;
-    malloc_mem_chunk_t *ptr = malloc_free_list;
-
-    while (ptr)
-    {
-        if (ptr->length >= size)
-        {
-            return ptr;
-        }
-        ptr = ptr->next;
-    }
-
-    return NULL;
-}
-
-/**
- * @brief 扩容malloc管理的内存区域
- *
- * @param size 扩大的内存大小
- */
-static int malloc_enlarge(int64_t size)
-{
-    if (brk_base_addr == 0) // 第一次调用,需要初始化
-    {
-        brk_base_addr = sbrk(0);
-        // printf("brk_base_addr=%#018lx\n", brk_base_addr);
-        brk_managed_addr = brk_base_addr;
-        brk_max_addr = sbrk(0);
-    }
-
-    int64_t free_space = brk_max_addr - brk_managed_addr;
-    // printf("size=%ld\tfree_space=%ld\n", size, free_space);
-    if (free_space < size) // 现有堆空间不足
-    {
-        if (sbrk(PAGE_ALIGN_UP(size - free_space)) != (void *)(-1))
-            brk_max_addr = sbrk((0));
-        else
-        {
-            // put_string("malloc_enlarge(): no_mem\n", COLOR_YELLOW, COLOR_BLACK);
-            return -ENOMEM;
-        }
-
-        // printf("brk max addr = %#018lx\n", brk_max_addr);
-    }
-
-    // 扩展管理的堆空间
-    // 在新分配的内存的底部放置header
-    // printf("managed addr = %#018lx\n", brk_managed_addr);
-    malloc_mem_chunk_t *new_ck = (malloc_mem_chunk_t *)brk_managed_addr;
-    new_ck->length = brk_max_addr - brk_managed_addr;
-    // printf("new_ck->start_addr=%#018lx\tbrk_max_addr=%#018lx\tbrk_managed_addr=%#018lx\n", (uint64_t)new_ck,
-    // brk_max_addr, brk_managed_addr);
-    new_ck->prev = NULL;
-    new_ck->next = NULL;
-    brk_managed_addr = brk_max_addr;
-
-    malloc_insert_free_list(new_ck);
-
-    return 0;
-}
-
-/**
- * @brief 合并空闲块
- *
- */
-static void malloc_merge_free_chunk()
-{
-    if (malloc_free_list == NULL)
-        return;
-    malloc_mem_chunk_t *ptr = malloc_free_list->next;
-    while (ptr != NULL)
-    {
-        // 内存块连续
-        if (((uint64_t)(ptr->prev) + ptr->prev->length == (uint64_t)ptr))
-        {
-            // printf("merged %#018lx  and %#018lx\n", (uint64_t)ptr, (uint64_t)(ptr->prev));
-            // 将ptr与前面的空闲块合并
-            ptr->prev->length += ptr->length;
-            ptr->prev->next = ptr->next;
-            if (ptr->next == NULL)
-                malloc_free_list_end = ptr->prev;
-            else
-                ptr->next->prev = ptr->prev;
-            // 由于内存组成结构的原因,不需要free掉header
-            ptr = ptr->prev;
-        }
-        ptr = ptr->next;
-    }
-}
-
-/**
- * @brief 将块插入空闲链表
- *
- * @param ck 待插入的块
- */
-static void malloc_insert_free_list(malloc_mem_chunk_t *ck)
-{
-    if (malloc_free_list == NULL) // 空闲链表为空
-    {
-        malloc_free_list = ck;
-        malloc_free_list_end = ck;
-        ck->prev = ck->next = NULL;
-        return;
-    }
-    else
-    {
-
-        malloc_mem_chunk_t *ptr = malloc_free_list;
-        while (ptr != NULL)
-        {
-            if ((uint64_t)ptr < (uint64_t)ck)
-            {
-                if (ptr->next == NULL) // 当前是最后一个项
-                {
-                    ptr->next = ck;
-                    ck->next = NULL;
-                    ck->prev = ptr;
-                    malloc_free_list_end = ck;
-                    break;
-                }
-                else if ((uint64_t)(ptr->next) > (uint64_t)ck)
-                {
-                    ck->prev = ptr;
-                    ck->next = ptr->next;
-                    ptr->next = ck;
-                    ck->next->prev = ck;
-                    break;
-                }
-            }
-            else // 在ptr之前插入
-            {
-
-                if (ptr->prev == NULL) // 是第一个项
-                {
-                    malloc_free_list = ck;
-                    ck->prev = NULL;
-                    ck->next = ptr;
-                    ptr->prev = ck;
-                    break;
-                }
-                else
-                {
-                    ck->prev = ptr->prev;
-                    ck->next = ptr;
-                    ck->prev->next = ck;
-                    ptr->prev = ck;
-                    break;
-                }
-            }
-            ptr = ptr->next;
-        }
-    }
-}
-
-/**
- * @brief 获取一块堆内存
- *
- * @param size 内存大小
- * @return void* 内存空间的指针
- *
- * 分配内存的时候,结点的prev next指针所占用的空间被当做空闲空间分配出去
- */
-void *_dragonos_malloc(ssize_t size)
-{
-    // 计算需要分配的块的大小
-    if (size < sizeof(malloc_mem_chunk_t) - 16)
-        size = sizeof(malloc_mem_chunk_t);
-    else
-    {
-        size += 16;
-    }
-    // 16字节对齐
-    size = ALIGN_UP16(size);
-
-    // 采用best fit
-    malloc_mem_chunk_t *ck = malloc_query_free_chunk_bf(size);
-
-    if (ck == NULL) // 没有空闲块
-    {
-
-        // printf("no free blocks\n");
-        // 尝试合并空闲块
-        malloc_merge_free_chunk();
-        ck = malloc_query_free_chunk_bf(size);
-
-        // 找到了合适的块
-        if (ck)
-            goto found;
-
-        // printf("before enlarge\n");
-        // 找不到合适的块,扩容堆区域
-        if (malloc_enlarge(size) == -ENOMEM)
-            return (void *)-ENOMEM; // 内存不足
-
-        malloc_merge_free_chunk(); // 扩容后运行合并,否则会导致碎片
-
-        // 扩容后再次尝试获取
-
-        ck = malloc_query_free_chunk_bf(size);
-    }
-found:;
-
-    // printf("ck = %#018lx\n", (uint64_t)ck);
-    if (ck == NULL)
-        return (void *)-ENOMEM;
-    // printf("ck->prev=%#018lx ck->next=%#018lx\n", ck->prev, ck->next);
-    // 分配空闲块
-    // 从空闲链表取出
-    if (ck->prev == NULL) // 当前是链表的第一个块
-    {
-        malloc_free_list = ck->next;
-    }
-    else
-        ck->prev->next = ck->next;
-
-    if (ck->next != NULL) // 当前不是最后一个块
-        ck->next->prev = ck->prev;
-    else
-        malloc_free_list_end = ck->prev;
-
-    // 当前块剩余的空间还能容纳多一个结点的空间,则分裂当前块
-    if ((int64_t)(ck->length) - size > sizeof(malloc_mem_chunk_t))
-    {
-        // printf("seperate\n");
-        malloc_mem_chunk_t *new_ck = (malloc_mem_chunk_t *)(((uint64_t)ck) + size);
-        new_ck->length = ck->length - size;
-        new_ck->prev = new_ck->next = NULL;
-        // printf("new_ck=%#018lx, new_ck->length=%#010lx\n", (uint64_t)new_ck, new_ck->length);
-        ck->length = size;
-        malloc_insert_free_list(new_ck);
-    }
-    // printf("malloc done: %#018lx, length=%#018lx\n", ((uint64_t)ck + sizeof(uint64_t)), ck->length);
-    // 此时链表结点的指针的空间被分配出去
-    return (void *)((uint64_t)ck + 2 * sizeof(uint64_t));
-}
-
-/**
- * @brief 当堆顶空闲空间大于2个页的空间的时候,释放1个页
- *
- */
-static void release_brk()
-{
-    // 先检测最顶上的块
-    // 由于块按照开始地址排列,因此找最后一个块
-    if (malloc_free_list_end == NULL)
-    {
-        printf("release(): free list end is null. \n");
-        return;
-    }
-    if ((uint64_t)malloc_free_list_end + malloc_free_list_end->length == brk_max_addr &&
-        (uint64_t)malloc_free_list_end <= brk_max_addr - (PAGE_2M_SIZE << 1))
-    {
-        int64_t delta = ((brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK) - PAGE_2M_SIZE;
-        // printf("(brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK=%#018lx\n ", (brk_max_addr -
-        // (uint64_t)malloc_free_list_end) & PAGE_2M_MASK); printf("PAGE_2M_SIZE=%#018lx\n", PAGE_2M_SIZE);
-        // printf("tdfghgbdfggkmfn=%#018lx\n ", (brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK -
-        // PAGE_2M_SIZE); printf("delta=%#018lx\n ", delta);
-        if (delta <= 0) // 不用释放内存
-            return;
-        sbrk(-delta);
-        brk_max_addr = sbrk(0);
-        brk_managed_addr = brk_max_addr;
-
-        malloc_free_list_end->length = brk_max_addr - (uint64_t)malloc_free_list_end;
-    }
-}
-/**
- * @brief 释放一块堆内存
- *
- * @param ptr 堆内存的指针
- */
-void _dragonos_free(void *ptr)
-{
-    // 找到结点(此时prev和next都处于未初始化的状态)
-    malloc_mem_chunk_t *ck = (malloc_mem_chunk_t *)((uint64_t)ptr - 2 * sizeof(uint64_t));
-    // printf("free(): addr = %#018lx\t len=%#018lx\n", (uint64_t)ck, ck->length);
-    count_last_free_size += ck->length;
-
-    malloc_insert_free_list(ck);
-
-    if (count_last_free_size > PAGE_2M_SIZE)
-    {
-        count_last_free_size = 0;
-        malloc_merge_free_chunk();
-        release_brk();
-    }
-}
-
-/**
- * @brief 根据分配出去的指针获取堆内存块的长度
- * 
- * @param ptr 分配出去的指针
- * 
- * @return 堆内存块的长度
-*/
-uint64_t _dragonos_chunk_length(void *ptr)
-{
-    malloc_mem_chunk_t *ck = (malloc_mem_chunk_t *)((uint64_t)ptr - 2 * sizeof(uint64_t));
-    return ck->length;
-}

+ 1255 - 0
src/c_str.rs

@@ -0,0 +1,1255 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use alloc::{
+    borrow::{Borrow, Cow, ToOwned},
+    boxed::Box,
+    rc::Rc,
+    string::String,
+    sync::Arc,
+    vec::Vec,
+};
+use core::{
+    ascii,
+    cmp::Ordering,
+    fmt::{self, Write},
+    mem, ops, ptr, slice,
+    str::{self, Utf8Error},
+};
+
+use crate::{header::string::strlen, platform::types::*};
+
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+    use crate::header::string;
+
+    let p = unsafe {
+        string::memchr(
+            haystack.as_ptr() as *const c_void,
+            needle as c_int,
+            haystack.len(),
+        )
+    };
+    if p.is_null() {
+        None
+    } else {
+        Some(p as usize - (haystack.as_ptr() as usize))
+    }
+}
+
+/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
+/// middle.
+///
+/// This type serves the purpose of being able to safely generate a
+/// C-compatible string from a Rust byte slice or vector. An instance of this
+/// type is a static guarantee that the underlying bytes contain no interior 0
+/// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
+///
+/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
+///
+/// # Creating a `CString`
+///
+/// A `CString` is created from either a byte slice or a byte vector,
+/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for
+/// example, you can build a `CString` straight out of a [`String`] or
+/// a [`&str`], since both implement that trait).
+///
+/// The [`new`] method will actually check that the provided `&[u8]`
+/// does not have 0 bytes in the middle, and return an error if it
+/// finds one.
+///
+/// # Extracting a raw pointer to the whole C string
+///
+/// `CString` implements a [`as_ptr`] method through the [`Deref`]
+/// trait. This method will give you a `*const c_char` which you can
+/// feed directly to extern functions that expect a nul-terminated
+/// string, like C's `strdup()`.
+///
+/// # Extracting a slice of the whole C string
+///
+/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a
+/// `CString` with the [`as_bytes`] method. Slices produced in this
+/// way do *not* contain the trailing nul terminator. This is useful
+/// when you will be calling an extern function that takes a `*const
+/// u8` argument which is not necessarily nul-terminated, plus another
+/// argument with the length of the string — like C's `strndup()`.
+/// You can of course get the slice's length with its
+/// [`len`][slice.len] method.
+///
+/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you
+/// can use [`as_bytes_with_nul`] instead.
+///
+/// Once you have the kind of slice you need (with or without a nul
+/// terminator), you can call the slice's own
+/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to
+/// extern functions. See the documentation for that function for a
+/// discussion on ensuring the lifetime of the raw pointer.
+///
+/// [`Into`]: ../convert/trait.Into.html
+/// [`Vec`]: ../vec/struct.Vec.html
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
+/// [`u8`]: ../primitive.u8.html
+/// [`new`]: #method.new
+/// [`as_bytes`]: #method.as_bytes
+/// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
+/// [`as_ptr`]: #method.as_ptr
+/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr
+/// [slice.len]: ../primitive.slice.html#method.len
+/// [`Deref`]: ../ops/trait.Deref.html
+/// [`CStr`]: struct.CStr.html
+///
+/// # Examples
+///
+/// ```ignore (extern-declaration)
+/// # fn main() {
+/// use std::ffi::CString;
+/// use std::os::raw::c_char;
+///
+/// extern {
+///     fn my_printer(s: *const c_char);
+/// }
+///
+/// // We are certain that our string doesn't have 0 bytes in the middle,
+/// // so we can .unwrap()
+/// let c_to_print = CString::new("Hello, world!").unwrap();
+/// unsafe {
+///     my_printer(c_to_print.as_ptr());
+/// }
+/// # }
+/// ```
+///
+/// # Safety
+///
+/// `CString` is intended for working with traditional C-style strings
+/// (a sequence of non-nul bytes terminated by a single nul byte); the
+/// primary use case for these kinds of strings is interoperating with C-like
+/// code. Often you will need to transfer ownership to/from that external
+/// code. It is strongly recommended that you thoroughly read through the
+/// documentation of `CString` before use, as improper ownership management
+/// of `CString` instances can lead to invalid memory accesses, memory leaks,
+/// and other memory errors.
+
+#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
+pub struct CString {
+    // Invariant 1: the slice ends with a zero byte and has a length of at least one.
+    // Invariant 2: the slice contains only one zero byte.
+    // Improper usage of unsafe function can break Invariant 2, but not Invariant 1.
+    inner: Box<[u8]>,
+}
+
+/// Representation of a borrowed C string.
+///
+/// This type represents a borrowed reference to a nul-terminated
+/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]`
+/// slice, or unsafely from a raw `*const c_char`. It can then be
+/// converted to a Rust [`&str`] by performing UTF-8 validation, or
+/// into an owned [`CString`].
+///
+/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
+/// in each pair are borrowed references; the latter are owned
+/// strings.
+///
+/// Note that this structure is **not** `repr(C)` and is not recommended to be
+/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
+/// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe
+/// interface to other consumers.
+///
+/// # Examples
+///
+/// Inspecting a foreign C string:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::CStr;
+/// use std::os::raw::c_char;
+///
+/// extern { fn my_string() -> *const c_char; }
+///
+/// unsafe {
+///     let slice = CStr::from_ptr(my_string());
+///     println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
+/// }
+/// ```
+///
+/// Passing a Rust-originating C string:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::{CString, CStr};
+/// use std::os::raw::c_char;
+///
+/// fn work(data: &CStr) {
+///     extern { fn work_with(data: *const c_char); }
+///
+///     unsafe { work_with(data.as_ptr()) }
+/// }
+///
+/// let s = CString::new("data data data data").unwrap();
+/// work(&s);
+/// ```
+///
+/// Converting a foreign C string into a Rust [`String`]:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::CStr;
+/// use std::os::raw::c_char;
+///
+/// extern { fn my_string() -> *const c_char; }
+///
+/// fn my_string_safe() -> String {
+///     unsafe {
+///         CStr::from_ptr(my_string()).to_string_lossy().into_owned()
+///     }
+/// }
+///
+/// println!("string: {}", my_string_safe());
+/// ```
+///
+/// [`u8`]: ../primitive.u8.html
+/// [`&str`]: ../primitive.str.html
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
+/// [`from_ptr`]: #method.from_ptr
+#[derive(Hash)]
+pub struct CStr {
+    // FIXME: this should not be represented with a DST slice but rather with
+    //        just a raw `c_char` along with some form of marker to make
+    //        this an unsized type. Essentially `sizeof(&CStr)` should be the
+    //        same as `sizeof(&c_char)` but `CStr` should be an unsized type.
+    inner: [c_char],
+}
+
+/// An error indicating that an interior nul byte was found.
+///
+/// While Rust strings may contain nul bytes in the middle, C strings
+/// can't, as that byte would effectively truncate the string.
+///
+/// This error is created by the [`new`][`CString::new`] method on
+/// [`CString`]. See its documentation for more.
+///
+/// [`CString`]: struct.CString.html
+/// [`CString::new`]: struct.CString.html#method.new
+///
+/// # Examples
+///
+/// ```
+/// use std::ffi::{CString, NulError};
+///
+/// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err();
+/// ```
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct NulError(usize, Vec<u8>);
+
+/// An error indicating that a nul byte was not in the expected position.
+///
+/// The slice used to create a [`CStr`] must have one and only one nul
+/// byte at the end of the slice.
+///
+/// This error is created by the
+/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on
+/// [`CStr`]. See its documentation for more.
+///
+/// [`CStr`]: struct.CStr.html
+/// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
+///
+/// # Examples
+///
+/// ```
+/// use std::ffi::{CStr, FromBytesWithNulError};
+///
+/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
+/// ```
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FromBytesWithNulError {
+    kind: FromBytesWithNulErrorKind,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum FromBytesWithNulErrorKind {
+    InteriorNul(usize),
+    NotNulTerminated,
+}
+
+impl FromBytesWithNulError {
+    fn interior_nul(pos: usize) -> FromBytesWithNulError {
+        FromBytesWithNulError {
+            kind: FromBytesWithNulErrorKind::InteriorNul(pos),
+        }
+    }
+    fn not_nul_terminated() -> FromBytesWithNulError {
+        FromBytesWithNulError {
+            kind: FromBytesWithNulErrorKind::NotNulTerminated,
+        }
+    }
+
+    fn description(&self) -> &str {
+        match self.kind {
+            FromBytesWithNulErrorKind::InteriorNul(..) => {
+                "data provided contains an interior nul byte"
+            }
+            FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated",
+        }
+    }
+}
+
+/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
+///
+/// `CString` is just a wrapper over a buffer of bytes with a nul
+/// terminator; [`into_string`][`CString::into_string`] performs UTF-8
+/// validation on those bytes and may return this error.
+///
+/// This `struct` is created by the
+/// [`into_string`][`CString::into_string`] method on [`CString`]. See
+/// its documentation for more.
+///
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
+/// [`CString::into_string`]: struct.CString.html#method.into_string
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct IntoStringError {
+    inner: CString,
+    error: Utf8Error,
+}
+
+impl CString {
+    /// Creates a new C-compatible string from a container of bytes.
+    ///
+    /// This function will consume the provided data and use the
+    /// underlying bytes to construct a new string, ensuring that
+    /// there is a trailing 0 byte. This trailing 0 byte will be
+    /// appended by this function; the provided data should *not*
+    /// contain any 0 bytes in it.
+    ///
+    /// # Examples
+    ///
+    /// ```ignore (extern-declaration)
+    /// use std::ffi::CString;
+    /// use std::os::raw::c_char;
+    ///
+    /// extern { fn puts(s: *const c_char); }
+    ///
+    /// let to_print = CString::new("Hello!").unwrap();
+    /// unsafe {
+    ///     puts(to_print.as_ptr());
+    /// }
+    /// ```
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the supplied bytes contain an
+    /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as
+    /// the position of the nul byte.
+    ///
+    /// [`NulError`]: struct.NulError.html
+    pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
+        Self::_new(t.into())
+    }
+
+    fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
+        match memchr(0, &bytes) {
+            Some(i) => Err(NulError(i, bytes)),
+            None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
+        }
+    }
+
+    /// Creates a C-compatible string by consuming a byte vector,
+    /// without checking for interior 0 bytes.
+    ///
+    /// This method is equivalent to [`new`] except that no runtime assertion
+    /// is made that `v` contains no 0 bytes, and it requires an actual
+    /// byte vector, not anything that can be converted to one with Into.
+    ///
+    /// [`new`]: #method.new
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let raw = b"foo".to_vec();
+    /// unsafe {
+    ///     let c_string = CString::from_vec_unchecked(raw);
+    /// }
+    /// ```
+    pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
+        v.reserve_exact(1);
+        v.push(0);
+        CString {
+            inner: v.into_boxed_slice(),
+        }
+    }
+
+    /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`].
+    ///
+    /// Additionally, the length of the string will be recalculated from the pointer.
+    ///
+    /// # Safety
+    ///
+    /// This should only ever be called with a pointer that was earlier
+    /// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g. trying to take
+    /// ownership of a string that was allocated by foreign code) is likely to lead
+    /// to undefined behavior or allocator corruption.
+    ///
+    /// > **Note:** If you need to borrow a string that was allocated by
+    /// > foreign code, use [`CStr`]. If you need to take ownership of
+    /// > a string that was allocated by foreign code, you will need to
+    /// > make your own provisions for freeing it appropriately, likely
+    /// > with the foreign code's API to do that.
+    ///
+    /// [`into_raw`]: #method.into_raw
+    /// [`CStr`]: struct.CStr.html
+    ///
+    /// # Examples
+    ///
+    /// Create a `CString`, pass ownership to an `extern` function (via raw pointer), then retake
+    /// ownership with `from_raw`:
+    ///
+    /// ```ignore (extern-declaration)
+    /// use std::ffi::CString;
+    /// use std::os::raw::c_char;
+    ///
+    /// extern {
+    ///     fn some_extern_function(s: *mut c_char);
+    /// }
+    ///
+    /// let c_string = CString::new("Hello!").unwrap();
+    /// let raw = c_string.into_raw();
+    /// unsafe {
+    ///     some_extern_function(raw);
+    ///     let c_string = CString::from_raw(raw);
+    /// }
+    /// ```
+    pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
+        let len = strlen(ptr) + 1; // Including the NUL byte
+        let slice = slice::from_raw_parts_mut(ptr, len as usize);
+        CString {
+            inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]),
+        }
+    }
+
+    /// Consumes the `CString` and transfers ownership of the string to a C caller.
+    ///
+    /// The pointer which this function returns must be returned to Rust and reconstituted using
+    /// [`from_raw`] to be properly deallocated. Specifically, one
+    /// should *not* use the standard C `free()` function to deallocate
+    /// this string.
+    ///
+    /// Failure to call [`from_raw`] will lead to a memory leak.
+    ///
+    /// [`from_raw`]: #method.from_raw
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let c_string = CString::new("foo").unwrap();
+    ///
+    /// let ptr = c_string.into_raw();
+    ///
+    /// unsafe {
+    ///     assert_eq!(b'f', *ptr as u8);
+    ///     assert_eq!(b'o', *ptr.offset(1) as u8);
+    ///     assert_eq!(b'o', *ptr.offset(2) as u8);
+    ///     assert_eq!(b'\0', *ptr.offset(3) as u8);
+    ///
+    ///     // retake pointer to free memory
+    ///     let _ = CString::from_raw(ptr);
+    /// }
+    /// ```
+    #[inline]
+    pub fn into_raw(self) -> *mut c_char {
+        Box::into_raw(self.into_inner()) as *mut c_char
+    }
+
+    /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data.
+    ///
+    /// On failure, ownership of the original `CString` is returned.
+    ///
+    /// [`String`]: ../string/struct.String.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let valid_utf8 = vec![b'f', b'o', b'o'];
+    /// let cstring = CString::new(valid_utf8).unwrap();
+    /// assert_eq!(cstring.into_string().unwrap(), "foo");
+    ///
+    /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o'];
+    /// let cstring = CString::new(invalid_utf8).unwrap();
+    /// let err = cstring.into_string().err().unwrap();
+    /// assert_eq!(err.utf8_error().valid_up_to(), 1);
+    /// ```
+
+    pub fn into_string(self) -> Result<String, IntoStringError> {
+        String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError {
+            error: e.utf8_error(),
+            inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) },
+        })
+    }
+
+    /// Consumes the `CString` and returns the underlying byte buffer.
+    ///
+    /// The returned buffer does **not** contain the trailing nul
+    /// terminator, and it is guaranteed to not have any interior nul
+    /// bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let c_string = CString::new("foo").unwrap();
+    /// let bytes = c_string.into_bytes();
+    /// assert_eq!(bytes, vec![b'f', b'o', b'o']);
+    /// ```
+    pub fn into_bytes(self) -> Vec<u8> {
+        let mut vec = self.into_inner().into_vec();
+        let _nul = vec.pop();
+        debug_assert_eq!(_nul, Some(0u8));
+        vec
+    }
+
+    /// Equivalent to the [`into_bytes`] function except that the returned vector
+    /// includes the trailing nul terminator.
+    ///
+    /// [`into_bytes`]: #method.into_bytes
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let c_string = CString::new("foo").unwrap();
+    /// let bytes = c_string.into_bytes_with_nul();
+    /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']);
+    /// ```
+    pub fn into_bytes_with_nul(self) -> Vec<u8> {
+        self.into_inner().into_vec()
+    }
+
+    /// Returns the contents of this `CString` as a slice of bytes.
+    ///
+    /// The returned slice does **not** contain the trailing nul
+    /// terminator, and it is guaranteed to not have any interior nul
+    /// bytes. If you need the nul terminator, use
+    /// [`as_bytes_with_nul`] instead.
+    ///
+    /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let c_string = CString::new("foo").unwrap();
+    /// let bytes = c_string.as_bytes();
+    /// assert_eq!(bytes, &[b'f', b'o', b'o']);
+    /// ```
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.inner[..self.inner.len() - 1]
+    }
+
+    /// Equivalent to the [`as_bytes`] function except that the returned slice
+    /// includes the trailing nul terminator.
+    ///
+    /// [`as_bytes`]: #method.as_bytes
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let c_string = CString::new("foo").unwrap();
+    /// let bytes = c_string.as_bytes_with_nul();
+    /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']);
+    /// ```
+    #[inline]
+    pub fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.inner
+    }
+
+    /// Extracts a [`CStr`] slice containing the entire string.
+    ///
+    /// [`CStr`]: struct.CStr.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::{CString, CStr};
+    ///
+    /// let c_string = CString::new(b"foo".to_vec()).unwrap();
+    /// let c_str = c_string.as_c_str();
+    /// assert_eq!(c_str, CStr::from_bytes_with_nul(b"foo\0").unwrap());
+    /// ```
+    #[inline]
+    pub fn as_c_str(&self) -> &CStr {
+        &*self
+    }
+
+    /// Converts this `CString` into a boxed [`CStr`].
+    ///
+    /// [`CStr`]: struct.CStr.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::{CString, CStr};
+    ///
+    /// let c_string = CString::new(b"foo".to_vec()).unwrap();
+    /// let boxed = c_string.into_boxed_c_str();
+    /// assert_eq!(&*boxed, CStr::from_bytes_with_nul(b"foo\0").unwrap());
+    /// ```
+    pub fn into_boxed_c_str(self) -> Box<CStr> {
+        unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) }
+    }
+
+    // Bypass "move out of struct which implements [`Drop`] trait" restriction.
+    ///
+    /// [`Drop`]: ../ops/trait.Drop.html
+    fn into_inner(self) -> Box<[u8]> {
+        unsafe {
+            let result = ptr::read(&self.inner);
+            mem::forget(self);
+            result
+        }
+    }
+}
+
+// Turns this `CString` into an empty string to prevent
+// memory unsafe code from working by accident. Inline
+// to prevent LLVM from optimizing it away in debug builds.
+impl Drop for CString {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            *self.inner.get_unchecked_mut(0) = 0;
+        }
+    }
+}
+
+impl ops::Deref for CString {
+    type Target = CStr;
+
+    #[inline]
+    fn deref(&self) -> &CStr {
+        unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
+    }
+}
+
+impl fmt::Debug for CString {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+impl From<CString> for Vec<u8> {
+    /// Converts a [`CString`] into a [`Vec`]`<u8>`.
+    ///
+    /// The conversion consumes the [`CString`], and removes the terminating NUL byte.
+    ///
+    /// [`Vec`]: ../vec/struct.Vec.html
+    /// [`CString`]: ../ffi/struct.CString.html
+    #[inline]
+    fn from(s: CString) -> Vec<u8> {
+        s.into_bytes()
+    }
+}
+
+impl fmt::Debug for CStr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "\"")?;
+        for byte in self
+            .to_bytes()
+            .iter()
+            .flat_map(|&b| ascii::escape_default(b))
+        {
+            f.write_char(byte as char)?;
+        }
+        write!(f, "\"")
+    }
+}
+
+impl<'a> Default for &'a CStr {
+    fn default() -> &'a CStr {
+        const SLICE: &[c_char] = &[0];
+        unsafe { CStr::from_ptr(SLICE.as_ptr()) }
+    }
+}
+
+impl Default for CString {
+    /// Creates an empty `CString`.
+    fn default() -> CString {
+        let a: &CStr = Default::default();
+        a.to_owned()
+    }
+}
+
+impl Borrow<CStr> for CString {
+    #[inline]
+    fn borrow(&self) -> &CStr {
+        self
+    }
+}
+
+impl<'a> From<Cow<'a, CStr>> for CString {
+    #[inline]
+    fn from(s: Cow<'a, CStr>) -> Self {
+        s.into_owned()
+    }
+}
+
+impl<'a> From<&'a CStr> for Box<CStr> {
+    fn from(s: &'a CStr) -> Box<CStr> {
+        let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
+        unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
+    }
+}
+
+impl From<Box<CStr>> for CString {
+    /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+    ///
+    /// [`Box`]: ../boxed/struct.Box.html
+    /// [`CString`]: ../ffi/struct.CString.html
+    #[inline]
+    fn from(s: Box<CStr>) -> CString {
+        s.into_c_string()
+    }
+}
+
+impl Clone for Box<CStr> {
+    #[inline]
+    fn clone(&self) -> Self {
+        (**self).into()
+    }
+}
+
+impl From<CString> for Box<CStr> {
+    /// Converts a [`CString`] into a [`Box`]`<CStr>` without copying or allocating.
+    ///
+    /// [`CString`]: ../ffi/struct.CString.html
+    /// [`Box`]: ../boxed/struct.Box.html
+    #[inline]
+    fn from(s: CString) -> Box<CStr> {
+        s.into_boxed_c_str()
+    }
+}
+
+impl<'a> From<CString> for Cow<'a, CStr> {
+    #[inline]
+    fn from(s: CString) -> Cow<'a, CStr> {
+        Cow::Owned(s)
+    }
+}
+
+impl<'a> From<&'a CStr> for Cow<'a, CStr> {
+    #[inline]
+    fn from(s: &'a CStr) -> Cow<'a, CStr> {
+        Cow::Borrowed(s)
+    }
+}
+
+impl<'a> From<&'a CString> for Cow<'a, CStr> {
+    #[inline]
+    fn from(s: &'a CString) -> Cow<'a, CStr> {
+        Cow::Borrowed(s.as_c_str())
+    }
+}
+
+impl From<CString> for Arc<CStr> {
+    /// Converts a [`CString`] into a [`Arc`]`<CStr>` without copying or allocating.
+    ///
+    /// [`CString`]: ../ffi/struct.CString.html
+    /// [`Arc`]: ../sync/struct.Arc.html
+    #[inline]
+    fn from(s: CString) -> Arc<CStr> {
+        let arc: Arc<[u8]> = Arc::from(s.into_inner());
+        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
+    }
+}
+
+impl<'a> From<&'a CStr> for Arc<CStr> {
+    #[inline]
+    fn from(s: &CStr) -> Arc<CStr> {
+        let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
+        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
+    }
+}
+
+impl From<CString> for Rc<CStr> {
+    /// Converts a [`CString`] into a [`Rc`]`<CStr>` without copying or allocating.
+    ///
+    /// [`CString`]: ../ffi/struct.CString.html
+    /// [`Rc`]: ../rc/struct.Rc.html
+    #[inline]
+    fn from(s: CString) -> Rc<CStr> {
+        let rc: Rc<[u8]> = Rc::from(s.into_inner());
+        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
+    }
+}
+
+impl<'a> From<&'a CStr> for Rc<CStr> {
+    #[inline]
+    fn from(s: &CStr) -> Rc<CStr> {
+        let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
+        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
+    }
+}
+
+impl Default for Box<CStr> {
+    fn default() -> Box<CStr> {
+        let boxed: Box<[u8]> = Box::from([0]);
+        unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
+    }
+}
+
+impl NulError {
+    /// Returns the position of the nul byte in the slice that caused
+    /// [`CString::new`] to fail.
+    ///
+    /// [`CString::new`]: struct.CString.html#method.new
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let nul_error = CString::new("foo\0bar").unwrap_err();
+    /// assert_eq!(nul_error.nul_position(), 3);
+    ///
+    /// let nul_error = CString::new("foo bar\0").unwrap_err();
+    /// assert_eq!(nul_error.nul_position(), 7);
+    /// ```
+    pub fn nul_position(&self) -> usize {
+        self.0
+    }
+
+    /// Consumes this error, returning the underlying vector of bytes which
+    /// generated the error in the first place.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let nul_error = CString::new("foo\0bar").unwrap_err();
+    /// assert_eq!(nul_error.into_vec(), b"foo\0bar");
+    /// ```
+    pub fn into_vec(self) -> Vec<u8> {
+        self.1
+    }
+}
+
+impl fmt::Display for NulError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "nul byte found in provided data at position: {}", self.0)
+    }
+}
+
+impl fmt::Display for FromBytesWithNulError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.description())?;
+        if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
+            write!(f, " at byte pos {}", pos)?;
+        }
+        Ok(())
+    }
+}
+
+impl IntoStringError {
+    /// Consumes this error, returning original [`CString`] which generated the
+    /// error.
+    ///
+    /// [`CString`]: struct.CString.html
+    pub fn into_cstring(self) -> CString {
+        self.inner
+    }
+
+    /// Access the underlying UTF-8 error that was the cause of this error.
+    pub fn utf8_error(&self) -> Utf8Error {
+        self.error
+    }
+
+    fn description(&self) -> &str {
+        "C string contained non-utf8 bytes"
+    }
+}
+
+impl fmt::Display for IntoStringError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.description().fmt(f)
+    }
+}
+
+impl CStr {
+    /// Wraps a raw C string with a safe C string wrapper.
+    ///
+    /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
+    /// allows inspection and interoperation of non-owned C strings. This method
+    /// is unsafe for a number of reasons:
+    ///
+    /// * There is no guarantee to the validity of `ptr`.
+    /// * The returned lifetime is not guaranteed to be the actual lifetime of
+    ///   `ptr`.
+    /// * There is no guarantee that the memory pointed to by `ptr` contains a
+    ///   valid nul terminator byte at the end of the string.
+    /// * It is not guaranteed that the memory pointed by `ptr` won't change
+    ///   before the `CStr` has been destroyed.
+    ///
+    /// > **Note**: This operation is intended to be a 0-cost cast but it is
+    /// > currently implemented with an up-front calculation of the length of
+    /// > the string. This is not guaranteed to always be the case.
+    ///
+    /// # Examples
+    ///
+    /// ```ignore (extern-declaration)
+    /// # fn main() {
+    /// use std::ffi::CStr;
+    /// use std::os::raw::c_char;
+    ///
+    /// extern {
+    ///     fn my_string() -> *const c_char;
+    /// }
+    ///
+    /// unsafe {
+    ///     let slice = CStr::from_ptr(my_string());
+    ///     println!("string returned: {}", slice.to_str().unwrap());
+    /// }
+    /// # }
+    /// ```
+    pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
+        let len = strlen(ptr);
+        let ptr = ptr as *const u8;
+        CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+    }
+
+    /// Creates a C string wrapper from a byte slice.
+    ///
+    /// This function will cast the provided `bytes` to a `CStr`
+    /// wrapper after ensuring that the byte slice is nul-terminated
+    /// and does not contain any interior nul bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let cstr = CStr::from_bytes_with_nul(b"hello\0");
+    /// assert!(cstr.is_ok());
+    /// ```
+    ///
+    /// Creating a `CStr` without a trailing nul terminator is an error:
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let c_str = CStr::from_bytes_with_nul(b"hello");
+    /// assert!(c_str.is_err());
+    /// ```
+    ///
+    /// Creating a `CStr` with an interior nul byte is an error:
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let c_str = CStr::from_bytes_with_nul(b"he\0llo\0");
+    /// assert!(c_str.is_err());
+    /// ```
+    pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> {
+        let nul_pos = memchr(0, bytes);
+        if let Some(nul_pos) = nul_pos {
+            if nul_pos + 1 != bytes.len() {
+                return Err(FromBytesWithNulError::interior_nul(nul_pos));
+            }
+            Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) })
+        } else {
+            Err(FromBytesWithNulError::not_nul_terminated())
+        }
+    }
+
+    /// Unsafely creates a C string wrapper from a byte slice.
+    ///
+    /// This function will cast the provided `bytes` to a `CStr` wrapper without
+    /// performing any sanity checks. The provided slice **must** be nul-terminated
+    /// and not contain any interior nul bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::{CStr, CString};
+    ///
+    /// unsafe {
+    ///     let cstring = CString::new("hello").unwrap();
+    ///     let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
+    ///     assert_eq!(cstr, &*cstring);
+    /// }
+    /// ```
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        &*(bytes as *const [u8] as *const CStr)
+    }
+
+    /// Returns the inner pointer to this C string.
+    ///
+    /// The returned pointer will be valid for as long as `self` is, and points
+    /// to a contiguous region of memory terminated with a 0 byte to represent
+    /// the end of the string.
+    ///
+    /// **WARNING**
+    ///
+    /// It is your responsibility to make sure that the underlying memory is not
+    /// freed too early. For example, the following code will cause undefined
+    /// behavior when `ptr` is used inside the `unsafe` block:
+    ///
+    /// ```no_run
+    /// # #![allow(unused_must_use)]
+    /// use std::ffi::{CString};
+    ///
+    /// let ptr = CString::new("Hello").unwrap().as_ptr();
+    /// unsafe {
+    ///     // `ptr` is dangling
+    ///     *ptr;
+    /// }
+    /// ```
+    ///
+    /// This happens because the pointer returned by `as_ptr` does not carry any
+    /// lifetime information and the [`CString`] is deallocated immediately after
+    /// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated.
+    /// To fix the problem, bind the `CString` to a local variable:
+    ///
+    /// ```no_run
+    /// # #![allow(unused_must_use)]
+    /// use std::ffi::{CString};
+    ///
+    /// let hello = CString::new("Hello").unwrap();
+    /// let ptr = hello.as_ptr();
+    /// unsafe {
+    ///     // `ptr` is valid because `hello` is in scope
+    ///     *ptr;
+    /// }
+    /// ```
+    ///
+    /// This way, the lifetime of the `CString` in `hello` encompasses
+    /// the lifetime of `ptr` and the `unsafe` block.
+    ///
+    /// [`CString`]: struct.CString.html
+    #[inline]
+    pub fn as_ptr(&self) -> *const c_char {
+        self.inner.as_ptr()
+    }
+
+    /// Converts this C string to a byte slice.
+    ///
+    /// The returned slice will **not** contain the trailing nul terminator that this C
+    /// string has.
+    ///
+    /// > **Note**: This method is currently implemented as a constant-time
+    /// > cast, but it is planned to alter its definition in the future to
+    /// > perform the length calculation whenever this method is called.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(c_str.to_bytes(), b"foo");
+    /// ```
+    #[inline]
+    pub fn to_bytes(&self) -> &[u8] {
+        let bytes = self.to_bytes_with_nul();
+        &bytes[..bytes.len() - 1]
+    }
+
+    /// Converts this C string to a byte slice containing the trailing 0 byte.
+    ///
+    /// This function is the equivalent of [`to_bytes`] except that it will retain
+    /// the trailing nul terminator instead of chopping it off.
+    ///
+    /// > **Note**: This method is currently implemented as a 0-cost cast, but
+    /// > it is planned to alter its definition in the future to perform the
+    /// > length calculation whenever this method is called.
+    ///
+    /// [`to_bytes`]: #method.to_bytes
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(c_str.to_bytes_with_nul(), b"foo\0");
+    /// ```
+    #[inline]
+    pub fn to_bytes_with_nul(&self) -> &[u8] {
+        unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
+    }
+
+    /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8.
+    ///
+    /// If the contents of the `CStr` are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// > **Note**: This method is currently implemented to check for validity
+    /// > after a constant-time cast, but it is planned to alter its definition
+    /// > in the future to perform the length calculation in addition to the
+    /// > UTF-8 check whenever this method is called.
+    ///
+    /// [`&str`]: ../primitive.str.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(c_str.to_str(), Ok("foo"));
+    /// ```
+    pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
+        // NB: When CStr is changed to perform the length check in .to_bytes()
+        // instead of in from_ptr(), it may be worth considering if this should
+        // be rewritten to do the UTF-8 check inline with the length calculation
+        // instead of doing it afterwards.
+        str::from_utf8(self.to_bytes())
+    }
+
+    /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`.
+    ///
+    /// If the contents of the `CStr` are valid UTF-8 data, this
+    /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)`
+    /// with the the corresponding [`&str`] slice. Otherwise, it will
+    /// replace any invalid UTF-8 sequences with
+    /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
+    /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
+    ///
+    /// > **Note**: This method is currently implemented to check for validity
+    /// > after a constant-time cast, but it is planned to alter its definition
+    /// > in the future to perform the length calculation in addition to the
+    /// > UTF-8 check whenever this method is called.
+    ///
+    /// [`Cow`]: ../borrow/enum.Cow.html
+    /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
+    /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned
+    /// [`str`]: ../primitive.str.html
+    /// [`String`]: ../string/struct.String.html
+    /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
+    ///
+    /// # Examples
+    ///
+    /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8:
+    ///
+    /// ```
+    /// use std::borrow::Cow;
+    /// use std::ffi::CStr;
+    ///
+    /// let c_str = CStr::from_bytes_with_nul(b"Hello World\0").unwrap();
+    /// assert_eq!(c_str.to_string_lossy(), Cow::Borrowed("Hello World"));
+    /// ```
+    ///
+    /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8:
+    ///
+    /// ```
+    /// use std::borrow::Cow;
+    /// use std::ffi::CStr;
+    ///
+    /// let c_str = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0").unwrap();
+    /// assert_eq!(
+    ///     c_str.to_string_lossy(),
+    ///     Cow::Owned(String::from("Hello �World")) as Cow<str>
+    /// );
+    /// ```
+    pub fn to_string_lossy(&self) -> Cow<str> {
+        String::from_utf8_lossy(self.to_bytes())
+    }
+
+    /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+    ///
+    /// [`Box`]: ../boxed/struct.Box.html
+    /// [`CString`]: struct.CString.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let c_string = CString::new(b"foo".to_vec()).unwrap();
+    /// let boxed = c_string.into_boxed_c_str();
+    /// assert_eq!(boxed.into_c_string(), CString::new("foo").unwrap());
+    /// ```
+    pub fn into_c_string(self: Box<CStr>) -> CString {
+        let raw = Box::into_raw(self) as *mut [u8];
+        CString {
+            inner: unsafe { Box::from_raw(raw) },
+        }
+    }
+}
+
+impl PartialEq for CStr {
+    fn eq(&self, other: &CStr) -> bool {
+        self.to_bytes().eq(other.to_bytes())
+    }
+}
+
+impl Eq for CStr {}
+
+impl PartialOrd for CStr {
+    fn partial_cmp(&self, other: &CStr) -> Option<Ordering> {
+        self.to_bytes().partial_cmp(&other.to_bytes())
+    }
+}
+
+impl Ord for CStr {
+    fn cmp(&self, other: &CStr) -> Ordering {
+        self.to_bytes().cmp(&other.to_bytes())
+    }
+}
+
+impl ToOwned for CStr {
+    type Owned = CString;
+
+    fn to_owned(&self) -> CString {
+        CString {
+            inner: self.to_bytes_with_nul().into(),
+        }
+    }
+}
+
+impl<'a> From<&'a CStr> for CString {
+    fn from(s: &'a CStr) -> CString {
+        s.to_owned()
+    }
+}
+
+impl ops::Index<ops::RangeFull> for CString {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &CStr {
+        self
+    }
+}
+
+impl AsRef<CStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &CStr {
+        self
+    }
+}
+
+impl AsRef<CStr> for CString {
+    #[inline]
+    fn as_ref(&self) -> &CStr {
+        self
+    }
+}

+ 289 - 0
src/c_vec.rs

@@ -0,0 +1,289 @@
+use crate::{
+    io::{self, Write},
+    platform::{self, types::*, WriteByte},
+};
+use core::{
+    cmp, fmt,
+    iter::IntoIterator,
+    mem,
+    ops::{Deref, DerefMut},
+    ptr::{self, NonNull},
+    slice,
+};
+
+/// Error that occurs when an allocation fails
+#[derive(Debug, Default, Hash, PartialEq, Eq, Clone, Copy)]
+pub struct AllocError;
+
+/// A normal vector allocated in Rust needs to be dropped from Rust
+/// too, in order to avoid UB. This CVec is an abstraction that works
+/// using only C allocations functions and can therefore be dropped
+/// from C. Just like the Rust Vec, this does bounds checks to assure
+/// you never reach isize::MAX. Unless you need to drop something from
+/// C, prefer Rust's builtin Vec.
+pub struct CVec<T> {
+    ptr: NonNull<T>,
+    len: usize,
+    cap: usize,
+}
+impl<T> CVec<T> {
+    pub fn new() -> Self {
+        Self {
+            ptr: NonNull::dangling(),
+            len: 0,
+            cap: 0,
+        }
+    }
+    fn check_bounds(i: usize) -> Result<usize, AllocError> {
+        if i > core::isize::MAX as usize {
+            Err(AllocError)
+        } else {
+            Ok(i)
+        }
+    }
+    fn check_mul(x: usize, y: usize) -> Result<usize, AllocError> {
+        x.checked_mul(y)
+            .ok_or(AllocError)
+            .and_then(Self::check_bounds)
+    }
+    pub fn with_capacity(cap: usize) -> Result<Self, AllocError> {
+        if cap == 0 {
+            return Ok(Self::new());
+        }
+        let size = Self::check_mul(cap, mem::size_of::<T>())?;
+        let ptr = NonNull::new(unsafe { platform::alloc(size) as *mut T }).ok_or(AllocError)?;
+        Ok(Self { ptr, len: 0, cap })
+    }
+    unsafe fn resize(&mut self, cap: usize) -> Result<(), AllocError> {
+        let size = Self::check_mul(cap, mem::size_of::<T>())?;
+        let ptr = if cap == 0 {
+            NonNull::dangling()
+        } else if self.cap > 0 {
+            NonNull::new(platform::realloc(self.ptr.as_ptr() as *mut c_void, size) as *mut T)
+                .ok_or(AllocError)?
+        } else {
+            NonNull::new((platform::alloc(size)) as *mut T).ok_or(AllocError)?
+        };
+        self.ptr = ptr;
+        self.cap = cap;
+        Ok(())
+    }
+    unsafe fn drop_range(&mut self, start: usize, end: usize) {
+        let mut start = self.ptr.as_ptr().add(start);
+        let end = self.ptr.as_ptr().add(end);
+        while start < end {
+            ptr::drop_in_place(start);
+            start = start.add(1);
+        }
+    }
+
+    // Push stuff
+
+    pub fn reserve(&mut self, required: usize) -> Result<(), AllocError> {
+        let required_len = self
+            .len
+            .checked_add(required)
+            .ok_or(AllocError)
+            .and_then(Self::check_bounds)?;
+        if required_len > self.cap {
+            let new_cap = cmp::min(required_len.next_power_of_two(), core::isize::MAX as usize);
+            unsafe {
+                self.resize(new_cap)?;
+            }
+        }
+        Ok(())
+    }
+    pub fn push(&mut self, elem: T) -> Result<(), AllocError> {
+        self.reserve(1)?;
+        unsafe {
+            ptr::write(self.ptr.as_ptr().add(self.len), elem);
+        }
+        self.len += 1; // no need to bounds check, as new len <= cap
+        Ok(())
+    }
+    pub fn extend_from_slice(&mut self, elems: &[T]) -> Result<(), AllocError>
+    where
+        T: Copy,
+    {
+        self.reserve(elems.len())?;
+        unsafe {
+            ptr::copy_nonoverlapping(elems.as_ptr(), self.ptr.as_ptr().add(self.len), elems.len());
+        }
+        self.len += elems.len(); // no need to bounds check, as new len <= cap
+        Ok(())
+    }
+    pub fn append(&mut self, other: &mut Self) -> Result<(), AllocError> {
+        let len = other.len;
+        other.len = 0; // move
+        self.reserve(len)?;
+        unsafe {
+            ptr::copy_nonoverlapping(other.as_ptr(), self.ptr.as_ptr().add(self.len), len);
+        }
+        self.len += other.len(); // no need to bounds check, as new len <= cap
+        Ok(())
+    }
+
+    // Pop stuff
+
+    pub fn truncate(&mut self, len: usize) {
+        if len < self.len {
+            unsafe {
+                let old_len = self.len;
+                self.drop_range(len, old_len);
+            }
+            self.len = len;
+        }
+    }
+    pub fn shrink_to_fit(&mut self) -> Result<(), AllocError> {
+        if self.len < self.cap {
+            unsafe {
+                let new_cap = self.len;
+                self.resize(new_cap)?;
+            }
+        }
+        Ok(())
+    }
+    pub fn pop(&mut self) -> Option<T> {
+        if self.is_empty() {
+            None
+        } else {
+            let elem = unsafe { ptr::read(self.as_ptr().add(self.len - 1)) };
+            self.len -= 1;
+            Some(elem)
+        }
+    }
+
+    // Misc stuff
+
+    pub fn capacity(&self) -> usize {
+        self.cap
+    }
+    pub fn as_ptr(&self) -> *const T {
+        self.ptr.as_ptr()
+    }
+    pub fn as_mut_ptr(&mut self) -> *mut T {
+        self.ptr.as_ptr()
+    }
+    /// Leaks the inner data. This is safe to drop from C!
+    pub fn leak(mut self) -> *mut T {
+        let ptr = self.as_mut_ptr();
+        mem::forget(self);
+        ptr
+    }
+}
+impl<T> Deref for CVec<T> {
+    type Target = [T];
+
+    fn deref(&self) -> &Self::Target {
+        unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
+    }
+}
+impl<T> DerefMut for CVec<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
+    }
+}
+impl<T> Drop for CVec<T> {
+    fn drop(&mut self) {
+        unsafe {
+            let len = self.len;
+            self.drop_range(0, len);
+        }
+    }
+}
+impl<'a, T> IntoIterator for &'a CVec<T> {
+    type Item = <&'a [T] as IntoIterator>::Item;
+    type IntoIter = <&'a [T] as IntoIterator>::IntoIter;
+    fn into_iter(self) -> Self::IntoIter {
+        <&[T]>::into_iter(&*self)
+    }
+}
+impl<'a, T> IntoIterator for &'a mut CVec<T> {
+    type Item = <&'a mut [T] as IntoIterator>::Item;
+    type IntoIter = <&'a mut [T] as IntoIterator>::IntoIter;
+    fn into_iter(self) -> Self::IntoIter {
+        <&mut [T]>::into_iter(&mut *self)
+    }
+}
+
+impl Write for CVec<u8> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.extend_from_slice(buf).map_err(|err| {
+            io::Error::new(
+                io::ErrorKind::Other,
+                "AllocStringWriter::write failed to allocate",
+            )
+        })?;
+        Ok(buf.len())
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+impl fmt::Write for CVec<u8> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.write(s.as_bytes()).map_err(|_| fmt::Error)?;
+        Ok(())
+    }
+}
+impl WriteByte for CVec<u8> {
+    fn write_u8(&mut self, byte: u8) -> fmt::Result {
+        self.write(&[byte]).map_err(|_| fmt::Error)?;
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::CVec;
+
+    #[test]
+    fn push_pop() {
+        let mut vec = CVec::new();
+        vec.push(1).unwrap();
+        vec.push(2).unwrap();
+        vec.push(3).unwrap();
+        assert_eq!(&vec[..], &[1, 2, 3]);
+        assert_eq!(vec.pop().unwrap(), 3);
+        assert_eq!(&vec[..], &[1, 2]);
+    }
+    #[test]
+    fn extend_from_slice() {
+        use core_io::Write;
+
+        let mut vec = CVec::new();
+        vec.extend_from_slice(&[1, 2, 3]).unwrap();
+        vec.extend_from_slice(&[4, 5, 6]).unwrap();
+        assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6]);
+        assert_eq!(vec.write(&[7, 8, 9]).unwrap(), 3);
+        assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
+    }
+    #[test]
+    fn dropped() {
+        use alloc::rc::Rc;
+
+        let counter = Rc::new(());
+        let mut vec = CVec::with_capacity(3).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+        assert_eq!(Rc::strong_count(&counter), 4);
+
+        let popped = vec.pop().unwrap();
+        assert_eq!(Rc::strong_count(&counter), 4);
+        drop(popped);
+        assert_eq!(Rc::strong_count(&counter), 3);
+
+        vec.push(Rc::clone(&counter)).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+
+        assert_eq!(vec.len(), 5);
+        assert_eq!(Rc::strong_count(&counter), 6);
+        vec.truncate(1);
+        assert_eq!(Rc::strong_count(&counter), 2);
+
+        drop(vec);
+        assert_eq!(Rc::strong_count(&counter), 1);
+    }
+}

+ 81 - 0
src/crt0/mod.rs

@@ -0,0 +1,81 @@
+use core::arch::asm;
+use core::arch::global_asm;
+
+// #[cfg(target_arch = "x86_64")]
+// global_asm!(
+//     "
+//     .globl _start
+//     .type _start, @function
+// _start:
+//     mov rdi, rsp
+//     and rsp, 0xFFFFFFFFFFFFFFF0
+
+//     sub rsp, 8
+
+//     mov DWORD PTR [rsp], 0x00001F80
+//     ldmxcsr [rsp]
+//     mov WORD PTR [rsp], 0x037F
+//     fldcw [rsp]
+
+//     add rsp, 8
+
+//     call relibc_start
+//     .size _start, . - _start
+// "
+// );
+
+#[cfg(target_arch = "x86_64")]
+#[naked]
+#[no_mangle]
+#[start]
+pub unsafe extern "C" fn _start() -> ! {
+    asm!(
+        concat!(
+            "
+        mov rdi, rsp
+        and rsp, 0xFFFFFFFFFFFFFFF0
+
+        sub rsp, 8
+
+        mov DWORD PTR [rsp], 0x00001F80
+        ldmxcsr [rsp]
+        mov WORD PTR [rsp], 0x037F
+        fldcw [rsp]
+
+        add rsp, 8
+
+        call relibc_start
+        .size _start, . - _start"
+        ),
+        options(noreturn)
+    )
+}
+
+#[cfg(target_arch = "x86_64")]
+global_asm!(
+    r#"
+    .section .init
+    .global _init
+    _init:
+        push rbp
+        mov rbp, rsp
+        // Created a new stack frame and updated the stack pointer
+        // Body will be filled in by gcc and ended by crtn.o
+        // This happens after crti.o and gcc has inserted code
+        // Pop the stack frame
+        pop rbp
+        ret
+
+    .section .fini
+    .global _fini
+    _fini:
+        push rbp
+        mov rbp, rsp
+        // Created a new stack frame and updated the stack pointer
+        // Body will be filled in by gcc and ended by crtn.o
+        // This happens after crti.o and gcc has inserted code
+        // Pop the stack frame
+        pop rbp
+        ret
+"#
+);

+ 145 - 0
src/fs.rs

@@ -0,0 +1,145 @@
+use crate::{
+    header::{
+        fcntl::O_CREAT,
+        unistd::{SEEK_CUR, SEEK_END, SEEK_SET},
+    },
+    io,
+    platform::{types::*, Pal, Sys}, c_str::CStr
+};
+use core::ops::Deref;
+
+pub struct File {
+    pub fd: c_int,
+    /// To avoid self referential FILE struct that needs both a reader and a writer,
+    /// make "reference" files that share fd but don't close on drop.
+    pub reference: bool,
+}
+
+impl File {
+    pub fn new(fd: c_int) -> Self {
+        Self {
+            fd,
+            reference: false,
+        }
+    }
+
+    pub fn open(path: &CStr, oflag: c_int) -> io::Result<Self> {
+        match Sys::open(path, oflag, 0) {
+            -1 => Err(io::last_os_error()),
+            ok => Ok(Self::new(ok)),
+        }
+    }
+
+    pub fn create(path: &CStr, oflag: c_int, mode: mode_t) -> io::Result<Self> {
+        match Sys::open(path, oflag | O_CREAT, mode) {
+            -1 => Err(io::last_os_error()),
+            ok => Ok(Self::new(ok)),
+        }
+    }
+
+    pub fn sync_all(&self) -> io::Result<()> {
+        match Sys::fsync(self.fd) {
+            -1 => Err(io::last_os_error()),
+            _ok => Ok(()),
+        }
+    }
+
+    pub fn set_len(&self, size: u64) -> io::Result<()> {
+        match Sys::ftruncate(self.fd, size as off_t) {
+            -1 => Err(io::last_os_error()),
+            _ok => Ok(()),
+        }
+    }
+
+    pub fn try_clone(&self) -> io::Result<Self> {
+        match Sys::dup(self.fd) {
+            -1 => Err(io::last_os_error()),
+            ok => Ok(Self::new(ok)),
+        }
+    }
+
+    /// Create a new file pointing to the same underlying descriptor. This file
+    /// will know it's a "reference" and won't close the fd. It will, however,
+    /// not prevent the original file from closing the fd.
+    pub unsafe fn get_ref(&self) -> Self {
+        Self {
+            fd: self.fd,
+            reference: true,
+        }
+    }
+}
+
+impl io::Read for &File {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        match Sys::read(self.fd, buf) {
+            -1 => Err(io::last_os_error()),
+            ok => Ok(ok as usize),
+        }
+    }
+}
+
+impl io::Write for &File {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match Sys::write(self.fd, buf) {
+            -1 => Err(io::last_os_error()),
+            ok => Ok(ok as usize),
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl io::Seek for &File {
+    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
+        let (offset, whence) = match pos {
+            io::SeekFrom::Start(start) => (start as off_t, SEEK_SET),
+            io::SeekFrom::Current(current) => (current as off_t, SEEK_CUR),
+            io::SeekFrom::End(end) => (end as off_t, SEEK_END),
+        };
+
+        match Sys::lseek(self.fd, offset, whence) {
+            -1 => Err(io::last_os_error()),
+            ok => Ok(ok as u64),
+        }
+    }
+}
+
+impl io::Read for File {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (&mut &*self).read(buf)
+    }
+}
+
+impl io::Write for File {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        (&mut &*self).write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        (&mut &*self).flush()
+    }
+}
+
+impl io::Seek for File {
+    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
+        (&mut &*self).seek(pos)
+    }
+}
+
+impl Deref for File {
+    type Target = c_int;
+
+    fn deref(&self) -> &Self::Target {
+        &self.fd
+    }
+}
+
+impl Drop for File {
+    fn drop(&mut self) {
+        if !self.reference {
+            let _ = Sys::close(self.fd);
+        }
+    }
+}

+ 9 - 0
src/header/ctype/cbindgen.toml

@@ -0,0 +1,9 @@
+sys_includes = ["bits/ctype.h"]
+include_guard = "_RELIBC_CTYPE_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 105 - 0
src/header/ctype/mod.rs

@@ -0,0 +1,105 @@
+//! ctype implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/ctype.h.html
+
+use crate::platform::types::*;
+
+#[no_mangle]
+pub extern "C" fn isalnum(c: c_int) -> c_int {
+    c_int::from(isdigit(c) != 0 || isalpha(c) != 0)
+}
+
+#[no_mangle]
+pub extern "C" fn isalpha(c: c_int) -> c_int {
+    c_int::from(islower(c) != 0 || isupper(c) != 0)
+}
+
+#[no_mangle]
+pub extern "C" fn isascii(c: c_int) -> c_int {
+    c_int::from((c & !0x7f) == 0)
+}
+
+#[no_mangle]
+pub extern "C" fn isblank(c: c_int) -> c_int {
+    c_int::from(c == c_int::from(b' ') || c == c_int::from(b'\t'))
+}
+
+#[no_mangle]
+pub extern "C" fn iscntrl(c: c_int) -> c_int {
+    c_int::from((c >= 0x00 && c <= 0x1f) || c == 0x7f)
+}
+
+#[no_mangle]
+pub extern "C" fn isdigit(c: c_int) -> c_int {
+    c_int::from(c >= c_int::from(b'0') && c <= c_int::from(b'9'))
+}
+
+#[no_mangle]
+pub extern "C" fn isgraph(c: c_int) -> c_int {
+    c_int::from(c >= 0x21 && c <= 0x7e)
+}
+
+#[no_mangle]
+pub extern "C" fn islower(c: c_int) -> c_int {
+    c_int::from(c >= c_int::from(b'a') && c <= c_int::from(b'z'))
+}
+
+#[no_mangle]
+pub extern "C" fn isprint(c: c_int) -> c_int {
+    c_int::from(c >= 0x20 && c < 0x7f)
+}
+
+#[no_mangle]
+pub extern "C" fn ispunct(c: c_int) -> c_int {
+    c_int::from(
+        (c >= c_int::from(b'!') && c <= c_int::from(b'/'))
+            || (c >= c_int::from(b':') && c <= c_int::from(b'@'))
+            || (c >= c_int::from(b'[') && c <= c_int::from(b'`'))
+            || (c >= c_int::from(b'{') && c <= c_int::from(b'~')),
+    )
+}
+
+#[no_mangle]
+pub extern "C" fn isspace(c: c_int) -> c_int {
+    c_int::from(
+        c == c_int::from(b' ')
+            || c == c_int::from(b'\t')
+            || c == c_int::from(b'\n')
+            || c == c_int::from(b'\r')
+            || c == 0x0b
+            || c == 0x0c,
+    )
+}
+
+#[no_mangle]
+pub extern "C" fn isupper(c: c_int) -> c_int {
+    c_int::from(c >= c_int::from(b'A') && c <= c_int::from(b'Z'))
+}
+
+#[no_mangle]
+pub extern "C" fn isxdigit(c: c_int) -> c_int {
+    c_int::from(isdigit(c) != 0 || (c | 32 >= c_int::from(b'a') && c | 32 <= c_int::from(b'f')))
+}
+
+#[no_mangle]
+/// The comment in musl:
+/// "nonsense function that should NEVER be used!"
+pub extern "C" fn toascii(c: c_int) -> c_int {
+    c & 0x7f
+}
+
+#[no_mangle]
+pub extern "C" fn tolower(c: c_int) -> c_int {
+    if isupper(c) != 0 {
+        c | 0x20
+    } else {
+        c
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn toupper(c: c_int) -> c_int {
+    if islower(c) != 0 {
+        c & !0x20
+    } else {
+        c
+    }
+}

+ 10 - 0
src/header/dirent/cbindgen.toml

@@ -0,0 +1,10 @@
+sys_includes = ["sys/types.h"]
+include_guard = "_RELIBC_DIRENT_H"
+language = "C"
+style = "Both"
+trailer = "#include <bits/dirent.h>"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 189 - 2
src/header/dirent/mod.rs

@@ -1,4 +1,30 @@
-use crate::platform::types::{ino_t, off_t, c_ushort, c_uchar,c_char};
+//! dirent implementation following http://pubs.opengroup.org/onlinepubs/009695399/basedefs/dirent.h.html
+
+use alloc::boxed::Box;
+use core::{mem, ptr};
+
+use crate::{
+    c_str::CStr,
+    c_vec::CVec,
+    fs::File,
+    header::{errno, fcntl, stdlib, string},
+    io::{Seek, SeekFrom},
+    platform::{self, types::*, Pal, Sys},
+};
+
+const DIR_BUF_SIZE: usize = mem::size_of::<dirent>() * 3;
+
+// No repr(C) needed, C won't see the content
+pub struct DIR {
+    file: File,
+    buf: [c_char; DIR_BUF_SIZE],
+    // index and len are specified in bytes
+    index: usize,
+    len: usize,
+
+    // The last value of d_off, used by telldir
+    offset: usize,
+}
 
 #[repr(C)]
 #[derive(Clone)]
@@ -8,4 +34,165 @@ pub struct dirent {
     pub d_reclen: c_ushort,
     pub d_type: c_uchar,
     pub d_name: [c_char; 256],
-}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendir(path: *const c_char) -> *mut DIR {
+    let path = CStr::from_ptr(path);
+    let file = match File::open(
+        path,
+        fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC,
+    ) {
+        Ok(file) => file,
+        Err(_) => return ptr::null_mut(),
+    };
+
+    Box::into_raw(Box::new(DIR {
+        file,
+        buf: [0; DIR_BUF_SIZE],
+        index: 0,
+        len: 0,
+        offset: 0,
+    }))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int {
+    let mut dir = Box::from_raw(dir);
+
+    let ret = Sys::close(*dir.file);
+
+    // Reference files aren't closed when dropped
+    dir.file.reference = true;
+
+    ret
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn dirfd(dir: *mut DIR) -> c_int {
+    *((*dir).file)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent {
+    if (*dir).index >= (*dir).len {
+        let read = Sys::getdents(
+            *(*dir).file,
+            (*dir).buf.as_mut_ptr() as *mut dirent,
+            (*dir).buf.len(),
+        );
+        if read <= 0 {
+            if read != 0 && read != -errno::ENOENT {
+                platform::errno = -read;
+            }
+            return ptr::null_mut();
+        }
+
+        (*dir).index = 0;
+        (*dir).len = read as usize;
+    }
+
+    let ptr = (*dir).buf.as_mut_ptr().add((*dir).index) as *mut dirent;
+
+    (*dir).offset = (*ptr).d_off as usize;
+    (*dir).index += (*ptr).d_reclen as usize;
+    ptr
+}
+// #[no_mangle]
+pub extern "C" fn readdir_r(
+    _dir: *mut DIR,
+    _entry: *mut dirent,
+    _result: *mut *mut dirent,
+) -> *mut dirent {
+    unimplemented!(); // plus, deprecated
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn telldir(dir: *mut DIR) -> c_long {
+    (*dir).offset as c_long
+}
+#[no_mangle]
+pub unsafe extern "C" fn seekdir(dir: *mut DIR, off: c_long) {
+    let _ = (*dir).file.seek(SeekFrom::Start(off as u64));
+    (*dir).offset = off as usize;
+    (*dir).index = 0;
+    (*dir).len = 0;
+}
+#[no_mangle]
+pub unsafe extern "C" fn rewinddir(dir: *mut DIR) {
+    seekdir(dir, 0)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn alphasort(first: *mut *const dirent, second: *mut *const dirent) -> c_int {
+    string::strcoll((**first).d_name.as_ptr(), (**second).d_name.as_ptr())
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn scandir(
+    dirp: *const c_char,
+    namelist: *mut *mut *mut dirent,
+    filter: Option<extern "C" fn(_: *const dirent) -> c_int>,
+    compare: Option<extern "C" fn(_: *mut *const dirent, _: *mut *const dirent) -> c_int>,
+) -> c_int {
+    let dir = opendir(dirp);
+    if dir.is_null() {
+        return -1;
+    }
+
+    let mut vec = match CVec::with_capacity(4) {
+        Ok(vec) => vec,
+        Err(err) => return -1,
+    };
+
+    let old_errno = platform::errno;
+    platform::errno = 0;
+
+    loop {
+        let entry: *mut dirent = readdir(dir);
+        if entry.is_null() {
+            break;
+        }
+
+        if let Some(filter) = filter {
+            if filter(entry) == 0 {
+                continue;
+            }
+        }
+
+        let copy = platform::alloc(mem::size_of::<dirent>()) as *mut dirent;
+        if copy.is_null() {
+            break;
+        }
+        ptr::write(copy, (*entry).clone());
+        if let Err(_) = vec.push(copy) {
+            break;
+        }
+    }
+
+    closedir(dir);
+
+    let len = vec.len();
+    if let Err(_) = vec.shrink_to_fit() {
+        return -1;
+    }
+
+    if platform::errno != 0 {
+        for ptr in &mut vec {
+            platform::free(*ptr as *mut c_void);
+        }
+        -1
+    } else {
+        *namelist = vec.leak();
+
+        platform::errno = old_errno;
+        stdlib::qsort(
+            *namelist as *mut c_void,
+            len as size_t,
+            mem::size_of::<*mut dirent>(),
+            mem::transmute(compare),
+        );
+
+        len as c_int
+    }
+}

+ 9 - 0
src/header/dl_tls/cbindgen.toml

@@ -0,0 +1,9 @@
+sys_includes = []
+include_guard = "_DL_TLS_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 47 - 0
src/header/dl_tls/mod.rs

@@ -0,0 +1,47 @@
+//! dl-tls implementation for Redox
+
+use crate::{ld_so::tcb::Tcb, platform::types::*, trace};
+
+#[repr(C)]
+pub struct dl_tls_index {
+    pub ti_module: u64,
+    pub ti_offset: u64,
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
+    trace!(
+        "__tls_get_addr({:p}: {:#x}, {:#x})",
+        ti,
+        (*ti).ti_module,
+        (*ti).ti_offset
+    );
+    if let Some(tcb) = Tcb::current() {
+        if let Some(masters) = tcb.masters() {
+            if let Some(master) = masters.get((*ti).ti_module as usize) {
+                let addr = tcb.tls_end.sub(master.offset).add((*ti).ti_offset as usize);
+                trace!(
+                    "__tls_get_addr({:p}: {:#x}, {:#x}) = {:p}",
+                    ti,
+                    (*ti).ti_module,
+                    (*ti).ti_offset,
+                    addr
+                );
+                return addr as *mut c_void;
+            }
+        }
+    }
+    panic!(
+        "__tls_get_addr({:p}: {:#x}, {:#x}) failed",
+        ti,
+        (*ti).ti_module,
+        (*ti).ti_offset
+    );
+}
+
+// x86 can define a version that does not require stack alignment
+#[cfg(target_arch = "x86")]
+#[no_mangle]
+pub unsafe extern "C" fn ___tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
+    __tls_get_addr(ti)
+}

+ 9 - 0
src/header/errno/cbindgen.toml

@@ -0,0 +1,9 @@
+sys_includes = ["bits/errno.h"]
+include_guard = "_RELIBC_ERRNO_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 300 - 0
src/header/errno/mod.rs

@@ -0,0 +1,300 @@
+//! errno implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/errno.h.html
+
+use crate::platform::{self, types::*};
+
+//TODO: Consider removing, provided for compatibility with newlib
+#[no_mangle]
+pub unsafe extern "C" fn __errno() -> *mut c_int {
+    __errno_location()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __errno_location() -> *mut c_int {
+    &mut platform::errno
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __program_invocation_name() -> *mut *mut c_char {
+    &mut platform::program_invocation_name
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __program_invocation_short_name() -> *mut *mut c_char {
+    &mut platform::program_invocation_short_name
+}
+
+pub const EPERM: c_int = 1; /* Operation not permitted */
+pub const ENOENT: c_int = 2; /* No such file or directory */
+pub const ESRCH: c_int = 3; /* No such process */
+pub const EINTR: c_int = 4; /* Interrupted system call */
+pub const EIO: c_int = 5; /* I/O error */
+pub const ENXIO: c_int = 6; /* No such device or address */
+pub const E2BIG: c_int = 7; /* Argument list too long */
+pub const ENOEXEC: c_int = 8; /* Exec format error */
+pub const EBADF: c_int = 9; /* Bad file number */
+pub const ECHILD: c_int = 10; /* No child processes */
+pub const EAGAIN: c_int = 11; /* Try again */
+pub const ENOMEM: c_int = 12; /* Out of memory */
+pub const EACCES: c_int = 13; /* Permission denied */
+pub const EFAULT: c_int = 14; /* Bad address */
+pub const ENOTBLK: c_int = 15; /* Block device required */
+pub const EBUSY: c_int = 16; /* Device or resource busy */
+pub const EEXIST: c_int = 17; /* File exists */
+pub const EXDEV: c_int = 18; /* Cross-device link */
+pub const ENODEV: c_int = 19; /* No such device */
+pub const ENOTDIR: c_int = 20; /* Not a directory */
+pub const EISDIR: c_int = 21; /* Is a directory */
+pub const EINVAL: c_int = 22; /* Invalid argument */
+pub const ENFILE: c_int = 23; /* File table overflow */
+pub const EMFILE: c_int = 24; /* Too many open files */
+pub const ENOTTY: c_int = 25; /* Not a typewriter */
+pub const ETXTBSY: c_int = 26; /* Text file busy */
+pub const EFBIG: c_int = 27; /* File too large */
+pub const ENOSPC: c_int = 28; /* No space left on device */
+pub const ESPIPE: c_int = 29; /* Illegal seek */
+pub const EROFS: c_int = 30; /* Read-only file system */
+pub const EMLINK: c_int = 31; /* Too many links */
+pub const EPIPE: c_int = 32; /* Broken pipe */
+pub const EDOM: c_int = 33; /* Math argument out of domain of func */
+pub const ERANGE: c_int = 34; /* Math result not representable */
+pub const EDEADLK: c_int = 35; /* Resource deadlock would occur */
+pub const ENAMETOOLONG: c_int = 36; /* File name too long */
+pub const ENOLCK: c_int = 37; /* No record locks available */
+pub const ENOSYS: c_int = 38; /* Function not implemented */
+pub const ENOTEMPTY: c_int = 39; /* Directory not empty */
+pub const ELOOP: c_int = 40; /* Too many symbolic links encountered */
+#[cfg(not(target_os = "dragonos"))]
+pub const EWOULDBLOCK: c_int = 41; /* Operation would block */
+#[cfg(target_os = "dragonos")]
+pub const EWOULDBLOCK: c_int = EAGAIN; /* Operation would block */
+pub const ENOMSG: c_int = 42; /* No message of desired type */
+pub const EIDRM: c_int = 43; /* Identifier removed */
+pub const ECHRNG: c_int = 44; /* Channel number out of range */
+pub const EL2NSYNC: c_int = 45; /* Level 2 not synchronized */
+pub const EL3HLT: c_int = 46; /* Level 3 halted */
+pub const EL3RST: c_int = 47; /* Level 3 reset */
+pub const ELNRNG: c_int = 48; /* Link number out of range */
+pub const EUNATCH: c_int = 49; /* Protocol driver not attached */
+pub const ENOCSI: c_int = 50; /* No CSI structure available */
+pub const EL2HLT: c_int = 51; /* Level 2 halted */
+pub const EBADE: c_int = 52; /* Invalid exchange */
+pub const EBADR: c_int = 53; /* Invalid request descriptor */
+pub const EXFULL: c_int = 54; /* Exchange full */
+pub const ENOANO: c_int = 55; /* No anode */
+pub const EBADRQC: c_int = 56; /* Invalid request code */
+pub const EBADSLT: c_int = 57; /* Invalid slot */
+pub const EDEADLOCK: c_int = 58; /* Resource deadlock would occur */
+pub const EBFONT: c_int = 59; /* Bad font file format */
+pub const ENOSTR: c_int = 60; /* Device not a stream */
+pub const ENODATA: c_int = 61; /* No data available */
+pub const ETIME: c_int = 62; /* Timer expired */
+pub const ENOSR: c_int = 63; /* Out of streams resources */
+pub const ENONET: c_int = 64; /* Machine is not on the network */
+pub const ENOPKG: c_int = 65; /* Package not installed */
+pub const EREMOTE: c_int = 66; /* Object is remote */
+pub const ENOLINK: c_int = 67; /* Link has been severed */
+pub const EADV: c_int = 68; /* Advertise error */
+pub const ESRMNT: c_int = 69; /* Srmount error */
+pub const ECOMM: c_int = 70; /* Communication error on send */
+pub const EPROTO: c_int = 71; /* Protocol error */
+pub const EMULTIHOP: c_int = 72; /* Multihop attempted */
+pub const EDOTDOT: c_int = 73; /* RFS specific error */
+pub const EBADMSG: c_int = 74; /* Not a data message */
+pub const EOVERFLOW: c_int = 75; /* Value too large for defined data type */
+pub const ENOTUNIQ: c_int = 76; /* Name not unique on network */
+pub const EBADFD: c_int = 77; /* File descriptor in bad state */
+pub const EREMCHG: c_int = 78; /* Remote address changed */
+pub const ELIBACC: c_int = 79; /* Can not access a needed shared library */
+pub const ELIBBAD: c_int = 80; /* Accessing a corrupted shared library */
+pub const ELIBSCN: c_int = 81; /* .lib section in a.out corrupted */
+pub const ELIBMAX: c_int = 82; /* Attempting to link in too many shared libraries */
+pub const ELIBEXEC: c_int = 83; /* Cannot exec a shared library directly */
+pub const EILSEQ: c_int = 84; /* Illegal byte sequence */
+pub const ERESTART: c_int = 85; /* Interrupted system call should be restarted */
+pub const ESTRPIPE: c_int = 86; /* Streams pipe error */
+pub const EUSERS: c_int = 87; /* Too many users */
+pub const ENOTSOCK: c_int = 88; /* Socket operation on non-socket */
+pub const EDESTADDRREQ: c_int = 89; /* Destination address required */
+pub const EMSGSIZE: c_int = 90; /* Message too long */
+pub const EPROTOTYPE: c_int = 91; /* Protocol wrong type for socket */
+pub const ENOPROTOOPT: c_int = 92; /* Protocol not available */
+pub const EPROTONOSUPPORT: c_int = 93; /* Protocol not supported */
+pub const ESOCKTNOSUPPORT: c_int = 94; /* Socket type not supported */
+pub const EOPNOTSUPP: c_int = 95; /* Operation not supported on transport endpoint */
+pub const EPFNOSUPPORT: c_int = 96; /* Protocol family not supported */
+pub const EAFNOSUPPORT: c_int = 97; /* Address family not supported by protocol */
+pub const EADDRINUSE: c_int = 98; /* Address already in use */
+pub const EADDRNOTAVAIL: c_int = 99; /* Cannot assign requested address */
+pub const ENETDOWN: c_int = 100; /* Network is down */
+pub const ENETUNREACH: c_int = 101; /* Network is unreachable */
+pub const ENETRESET: c_int = 102; /* Network dropped connection because of reset */
+pub const ECONNABORTED: c_int = 103; /* Software caused connection abort */
+pub const ECONNRESET: c_int = 104; /* Connection reset by peer */
+pub const ENOBUFS: c_int = 105; /* No buffer space available */
+pub const EISCONN: c_int = 106; /* Transport endpoint is already connected */
+pub const ENOTCONN: c_int = 107; /* Transport endpoint is not connected */
+pub const ESHUTDOWN: c_int = 108; /* Cannot send after transport endpoint shutdown */
+pub const ETOOMANYREFS: c_int = 109; /* Too many references: cannot splice */
+pub const ETIMEDOUT: c_int = 110; /* Connection timed out */
+pub const ECONNREFUSED: c_int = 111; /* Connection refused */
+pub const EHOSTDOWN: c_int = 112; /* Host is down */
+pub const EHOSTUNREACH: c_int = 113; /* No route to host */
+pub const EALREADY: c_int = 114; /* Operation already in progress */
+pub const EINPROGRESS: c_int = 115; /* Operation now in progress */
+pub const ESTALE: c_int = 116; /* Stale NFS file handle */
+pub const EUCLEAN: c_int = 117; /* Structure needs cleaning */
+pub const ENOTNAM: c_int = 118; /* Not a XENIX named type file */
+pub const ENAVAIL: c_int = 119; /* No XENIX semaphores available */
+pub const EISNAM: c_int = 120; /* Is a named type file */
+pub const EREMOTEIO: c_int = 121; /* Remote I/O error */
+pub const EDQUOT: c_int = 122; /* Quota exceeded */
+pub const ENOMEDIUM: c_int = 123; /* No medium found */
+pub const EMEDIUMTYPE: c_int = 124; /* Wrong medium type */
+pub const ECANCELED: c_int = 125; /* Operation Canceled */
+pub const ENOKEY: c_int = 126; /* Required key not available */
+pub const EKEYEXPIRED: c_int = 127; /* Key has expired */
+pub const EKEYREVOKED: c_int = 128; /* Key has been revoked */
+pub const EKEYREJECTED: c_int = 129; /* Key was rejected by service */
+pub const EOWNERDEAD: c_int = 130; /* Owner died */
+pub const ENOTRECOVERABLE: c_int = 131; /* State not recoverable */
+
+pub static STR_ERROR: [&'static str; 132] = [
+    "Success",
+    "Operation not permitted",
+    "No such file or directory",
+    "No such process",
+    "Interrupted system call",
+    "I/O error",
+    "No such device or address",
+    "Argument list too long",
+    "Exec format error",
+    "Bad file number",
+    "No child processes",
+    #[cfg(not(target_os = "dragonos"))]
+    "Try again",
+    #[cfg(target_os = "dragonos")]
+    "Try again or operation would block",
+    "Out of memory",
+    "Permission denied",
+    "Bad address",
+    "Block device required",
+    "Device or resource busy",
+    "File exists",
+    "Cross-device link",
+    "No such device",
+    "Not a directory",
+    "Is a directory",
+    "Invalid argument",
+    "File table overflow",
+    "Too many open files",
+    "Not a typewriter",
+    "Text file busy",
+    "File too large",
+    "No space left on device",
+    "Illegal seek",
+    "Read-only file system",
+    "Too many links",
+    "Broken pipe",
+    "Math argument out of domain of func",
+    "Math result not representable",
+    "Resource deadlock would occur",
+    "File name too long",
+    "No record locks available",
+    "Function not implemented",
+    "Directory not empty",
+    "Too many symbolic links encountered",
+    #[cfg(not(target_os = "dragonos"))]
+    "Operation would block",
+    "No message of desired type",
+    "Identifier removed",
+    "Channel number out of range",
+    "Level 2 not synchronized",
+    "Level 3 halted",
+    "Level 3 reset",
+    "Link number out of range",
+    "Protocol driver not attached",
+    "No CSI structure available",
+    "Level 2 halted",
+    "Invalid exchange",
+    "Invalid request descriptor",
+    "Exchange full",
+    "No anode",
+    "Invalid request code",
+    "Invalid slot",
+    "Resource deadlock would occur",
+    "Bad font file format",
+    "Device not a stream",
+    "No data available",
+    "Timer expired",
+    "Out of streams resources",
+    "Machine is not on the network",
+    "Package not installed",
+    "Object is remote",
+    "Link has been severed",
+    "Advertise error",
+    "Srmount error",
+    "Communication error on send",
+    "Protocol error",
+    "Multihop attempted",
+    "RFS specific error",
+    "Not a data message",
+    "Value too large for defined data type",
+    "Name not unique on network",
+    "File descriptor in bad state",
+    "Remote address changed",
+    "Can not access a needed shared library",
+    "Accessing a corrupted shared library",
+    ".lib section in a.out corrupted",
+    "Attempting to link in too many shared libraries",
+    "Cannot exec a shared library directly",
+    "Illegal byte sequence",
+    "Interrupted system call should be restarted",
+    "Streams pipe error",
+    "Too many users",
+    "Socket operation on non-socket",
+    "Destination address required",
+    "Message too long",
+    "Protocol wrong type for socket",
+    "Protocol not available",
+    "Protocol not supported",
+    "Socket type not supported",
+    "Operation not supported on transport endpoint",
+    "Protocol family not supported",
+    "Address family not supported by protocol",
+    "Address already in use",
+    "Cannot assign requested address",
+    "Network is down",
+    "Network is unreachable",
+    "Network dropped connection because of reset",
+    "Software caused connection abort",
+    "Connection reset by peer",
+    "No buffer space available",
+    "Transport endpoint is already connected",
+    "Transport endpoint is not connected",
+    "Cannot send after transport endpoint shutdown",
+    "Too many references: cannot splice",
+    "Connection timed out",
+    "Connection refused",
+    "Host is down",
+    "No route to host",
+    "Operation already in progress",
+    "Operation now in progress",
+    "Stale NFS file handle",
+    "Structure needs cleaning",
+    "Not a XENIX named type file",
+    "No XENIX semaphores available",
+    "Is a named type file",
+    "Remote I/O error",
+    "Quota exceeded",
+    "No medium found",
+    "Wrong medium type",
+    "Operation Canceled",
+    "Required key not available",
+    "Key has expired",
+    "Key has been revoked",
+    "Key was rejected by service",
+    "Owner died",
+    "State not recoverable",
+    #[cfg(target_os = "dragonos")]
+    "Unknown",
+];

+ 15 - 0
src/header/fcntl/cbindgen.toml

@@ -0,0 +1,15 @@
+sys_includes = ["stdarg.h", "sys/types.h"]
+include_guard = "_RELIBC_FCNTL_H"
+trailer = "#include <bits/fcntl.h>"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[defines]
+"target_os=linux" = "__linux__"
+"target_os=redox" = "__redox__"
+"target_os=dragonos" = "__dragonos__"
+
+[enum]
+prefix_with_name = true

+ 17 - 0
src/header/fcntl/dragonos.rs

@@ -0,0 +1,17 @@
+use crate::platform::types::*;
+
+pub const O_RDONLY: c_int = 0x0000;
+pub const O_WRONLY: c_int = 0x0001;
+pub const O_RDWR: c_int = 0x0002;
+pub const O_ACCMODE: c_int = 0x0003;
+pub const O_CREAT: c_int = 0x0040;
+pub const O_EXCL: c_int = 0x0080;
+pub const O_TRUNC: c_int = 0x0200;
+pub const O_APPEND: c_int = 0x0400;
+pub const O_NONBLOCK: c_int = 0x0800;
+pub const O_DIRECTORY: c_int = 0x1_0000;
+pub const O_NOFOLLOW: c_int = 0x2_0000;
+pub const O_CLOEXEC: c_int = 0x8_0000;
+pub const O_PATH: c_int = 0x20_0000;
+
+pub const FD_CLOEXEC: c_int = 0x8_0000;

+ 17 - 0
src/header/fcntl/linux.rs

@@ -0,0 +1,17 @@
+use crate::platform::types::*;
+
+pub const O_RDONLY: c_int = 0x0000;
+pub const O_WRONLY: c_int = 0x0001;
+pub const O_RDWR: c_int = 0x0002;
+pub const O_ACCMODE: c_int = 0x0003;
+pub const O_CREAT: c_int = 0x0040;
+pub const O_EXCL: c_int = 0x0080;
+pub const O_TRUNC: c_int = 0x0200;
+pub const O_APPEND: c_int = 0x0400;
+pub const O_NONBLOCK: c_int = 0x0800;
+pub const O_DIRECTORY: c_int = 0x1_0000;
+pub const O_NOFOLLOW: c_int = 0x2_0000;
+pub const O_CLOEXEC: c_int = 0x8_0000;
+pub const O_PATH: c_int = 0x20_0000;
+
+pub const FD_CLOEXEC: c_int = 0x8_0000;

+ 58 - 0
src/header/fcntl/mod.rs

@@ -0,0 +1,58 @@
+//! fcntl implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/fcntl.h.html
+
+use crate::c_str::CStr;
+
+use crate::platform::{types::*, Pal, Sys};
+
+pub use self::sys::*;
+
+#[cfg(target_os = "linux")]
+#[path = "linux.rs"]
+pub mod sys;
+
+#[cfg(target_os = "dragonos")]
+#[path = "dragonos.rs"]
+pub mod sys;
+
+#[cfg(target_os = "redox")]
+#[path = "redox.rs"]
+pub mod sys;
+
+pub const F_DUPFD: c_int = 0;
+pub const F_GETFD: c_int = 1;
+pub const F_SETFD: c_int = 2;
+pub const F_GETFL: c_int = 3;
+pub const F_SETFL: c_int = 4;
+pub const F_GETLK: c_int = 5;
+pub const F_SETLK: c_int = 6;
+pub const F_SETLKW: c_int = 7;
+
+pub const F_RDLCK: c_int = 0;
+pub const F_WRLCK: c_int = 1;
+pub const F_UNLCK: c_int = 2;
+
+#[no_mangle]
+pub unsafe extern "C" fn creat(path: *const c_char, mode: mode_t) -> c_int {
+    sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode)
+}
+#[repr(C)]
+pub struct flock {
+    pub l_type: c_short,
+    pub l_whence: c_short,
+    pub l_start: off_t,
+    pub l_len: off_t,
+    pub l_pid: pid_t,
+}
+#[no_mangle]
+pub extern "C" fn sys_fcntl(fildes: c_int, cmd: c_int, arg: c_int) -> c_int {
+    Sys::fcntl(fildes, cmd, arg)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sys_open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int {
+    let path = CStr::from_ptr(path);
+    Sys::open(path, oflag, mode)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn cbindgen_stupid_struct_user_for_fcntl(a: flock) {}

+ 23 - 0
src/header/fcntl/redox.rs

@@ -0,0 +1,23 @@
+use crate::platform::types::*;
+
+pub const O_RDONLY: c_int = 0x0001_0000;
+pub const O_WRONLY: c_int = 0x0002_0000;
+pub const O_RDWR: c_int = 0x0003_0000;
+pub const O_ACCMODE: c_int = 0x0003_0000;
+pub const O_NONBLOCK: c_int = 0x0004_0000;
+pub const O_APPEND: c_int = 0x0008_0000;
+pub const O_SHLOCK: c_int = 0x0010_0000;
+pub const O_EXLOCK: c_int = 0x0020_0000;
+pub const O_ASYNC: c_int = 0x0040_0000;
+pub const O_FSYNC: c_int = 0x0080_0000;
+pub const O_CLOEXEC: c_int = 0x0100_0000;
+pub const O_CREAT: c_int = 0x0200_0000;
+pub const O_TRUNC: c_int = 0x0400_0000;
+pub const O_EXCL: c_int = 0x0800_0000;
+pub const O_DIRECTORY: c_int = 0x1000_0000;
+pub const O_PATH: c_int = 0x2000_0000;
+pub const O_SYMLINK: c_int = 0x4000_0000;
+// Negative to allow it to be used as int
+pub const O_NOFOLLOW: c_int = -0x8000_0000;
+
+pub const FD_CLOEXEC: c_int = 0x0100_0000;

+ 9 - 0
src/header/getopt/cbindgen.toml

@@ -0,0 +1,9 @@
+sys_includes = ["unistd.h"]
+include_guard = "_RELIBC_GETOPT_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 219 - 0
src/header/getopt/mod.rs

@@ -0,0 +1,219 @@
+//! getopt implementation for relibc
+
+use crate::{
+    header::{
+        stdio, string,
+        unistd::{optarg, opterr, optind, optopt},
+    },
+    platform::types::*, c_str,
+};
+use core::ptr;
+
+static mut CURRENT_OPT: *mut c_char = ptr::null_mut();
+
+pub const no_argument: c_int = 0;
+pub const required_argument: c_int = 1;
+pub const optional_argument: c_int = 2;
+
+#[repr(C)]
+pub struct option {
+    name: *const c_char,
+    has_arg: c_int,
+    flag: *mut c_int,
+    val: c_int,
+}
+
+#[no_mangle]
+#[linkage = "weak"] // often redefined in GNU programs
+pub unsafe extern "C" fn getopt_long(
+    argc: c_int,
+    argv: *const *mut c_char,
+    optstring: *const c_char,
+    longopts: *const option,
+    longindex: *mut c_int,
+) -> c_int {
+    // if optarg is not set, we still don't want the previous value leaking
+    optarg = ptr::null_mut();
+
+    // handle reinitialization request
+    if optind == 0 {
+        optind = 1;
+        CURRENT_OPT = ptr::null_mut();
+    }
+
+    if CURRENT_OPT.is_null() || *CURRENT_OPT == 0 {
+        if optind >= argc {
+            -1
+        } else {
+            let current_arg = *argv.offset(optind as isize);
+            if current_arg.is_null()
+                || *current_arg != b'-' as c_char
+                || *current_arg.offset(1) == 0
+            {
+                -1
+            } else if string::strcmp(current_arg, c_str!("--").as_ptr()) == 0 {
+                optind += 1;
+                -1
+            } else {
+                // remove the '-'
+                let current_arg = current_arg.offset(1);
+
+                if *current_arg == b'-' as c_char && !longopts.is_null() {
+                    let current_arg = current_arg.offset(1);
+                    // is a long option
+                    for i in 0.. {
+                        let opt = &*longopts.offset(i);
+                        if opt.name.is_null() {
+                            break;
+                        }
+
+                        let mut end = 0;
+                        while {
+                            let c = *current_arg.offset(end);
+                            c != 0 && c != b'=' as c_char
+                        } {
+                            end += 1;
+                        }
+
+                        if string::strncmp(current_arg, opt.name, end as size_t) == 0 {
+                            optind += 1;
+                            *longindex = i as c_int;
+
+                            if opt.has_arg == optional_argument {
+                                if *current_arg.offset(end) == b'=' as c_char {
+                                    optarg = current_arg.offset(end + 1);
+                                }
+                            } else if opt.has_arg == required_argument {
+                                if *current_arg.offset(end) == b'=' as c_char {
+                                    optarg = current_arg.offset(end + 1);
+                                } else if optind < argc {
+                                    optarg = *argv.offset(optind as isize);
+                                    optind += 1;
+                                } else if *optstring == b':' as c_char {
+                                    return b':' as c_int;
+                                } else {
+                                    stdio::fputs(*argv as _, &mut *stdio::stderr);
+                                    stdio::fputs(
+                                        ": option '--\0".as_ptr() as _,
+                                        &mut *stdio::stderr,
+                                    );
+                                    stdio::fputs(current_arg, &mut *stdio::stderr);
+                                    stdio::fputs(
+                                        "' requires an argument\n\0".as_ptr() as _,
+                                        &mut *stdio::stderr,
+                                    );
+                                    return b'?' as c_int;
+                                }
+                            }
+
+                            if opt.flag.is_null() {
+                                return opt.val;
+                            } else {
+                                *opt.flag = opt.val;
+                                return 0;
+                            }
+                        }
+                    }
+                }
+
+                parse_arg(argc, argv, current_arg, optstring)
+            }
+        }
+    } else {
+        parse_arg(argc, argv, CURRENT_OPT, optstring)
+    }
+}
+
+unsafe fn parse_arg(
+    argc: c_int,
+    argv: *const *mut c_char,
+    current_arg: *mut c_char,
+    optstring: *const c_char,
+) -> c_int {
+    let update_current_opt = || {
+        CURRENT_OPT = current_arg.offset(1);
+        if *CURRENT_OPT == 0 {
+            optind += 1;
+        }
+    };
+
+    let print_error = |desc: &[u8]| {
+        // NOTE: we don't use fprintf to get around the usage of va_list
+        stdio::fputs(*argv as _, &mut *stdio::stderr);
+        stdio::fputs(desc.as_ptr() as _, &mut *stdio::stderr);
+        stdio::fputc(*current_arg as _, &mut *stdio::stderr);
+        stdio::fputc(b'\n' as _, &mut *stdio::stderr);
+    };
+
+    match find_option(*current_arg, optstring) {
+        Some(GetoptOption::Flag) => {
+            update_current_opt();
+
+            *current_arg as c_int
+        }
+        Some(GetoptOption::OptArg) => {
+            CURRENT_OPT = b"\0".as_ptr() as _;
+            if *current_arg.offset(1) == 0 {
+                optind += 2;
+                if optind > argc {
+                    CURRENT_OPT = ptr::null_mut();
+
+                    optopt = *current_arg as c_int;
+                    let errch = if *optstring == b':' as c_char {
+                        b':'
+                    } else {
+                        if opterr != 0 {
+                            print_error(b": option requries an argument -- \0");
+                        }
+
+                        b'?'
+                    };
+                    errch as c_int
+                } else {
+                    optarg = *argv.offset(optind as isize - 1);
+
+                    *current_arg as c_int
+                }
+            } else {
+                optarg = current_arg.offset(1);
+                optind += 1;
+
+                *current_arg as c_int
+            }
+        }
+        None => {
+            // couldn't find the given option in optstring
+            if opterr != 0 {
+                print_error(b": illegal option -- \0");
+            }
+
+            update_current_opt();
+
+            optopt = *current_arg as c_int;
+            b'?' as c_int
+        }
+    }
+}
+
+enum GetoptOption {
+    Flag,
+    OptArg,
+}
+
+unsafe fn find_option(ch: c_char, optstring: *const c_char) -> Option<GetoptOption> {
+    let mut i = 0;
+
+    while *optstring.offset(i) != 0 {
+        if *optstring.offset(i) == ch {
+            let result = if *optstring.offset(i + 1) == b':' as c_char {
+                GetoptOption::OptArg
+            } else {
+                GetoptOption::Flag
+            };
+            return Some(result);
+        }
+        i += 1;
+    }
+
+    None
+}

+ 9 - 0
src/header/libgen/cbindgen.toml

@@ -0,0 +1,9 @@
+sys_includes = []
+include_guard = "_RELIBC_LIBGEN_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 47 - 0
src/header/libgen/mod.rs

@@ -0,0 +1,47 @@
+//! libgen implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/libgen.h.html
+
+use crate::platform::types::c_char;
+
+use crate::header::string::strlen;
+
+#[no_mangle]
+pub unsafe extern "C" fn basename(str: *mut c_char) -> *mut c_char {
+    if str.is_null() || strlen(str) == 0 {
+        return ".\0".as_ptr() as *mut c_char;
+    }
+    let mut end = strlen(str) as isize - 1;
+    while end >= 0 && *str.offset(end) == b'/' as c_char {
+        end -= 1;
+    }
+    if end == -1 {
+        return "/\0".as_ptr() as *mut c_char;
+    }
+    let mut begin = end;
+    while begin >= 0 && *str.offset(begin) != b'/' as c_char {
+        begin -= 1;
+    }
+    *str.offset(end + 1) = 0;
+    str.offset(begin + 1) as *mut c_char
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn dirname(str: *mut c_char) -> *mut c_char {
+    if str.is_null() || strlen(str) == 0 {
+        return ".\0".as_ptr() as *mut c_char;
+    }
+    let mut end = strlen(str) as isize - 1;
+    while end > 0 && *str.offset(end) == b'/' as c_char {
+        end -= 1;
+    }
+    while end >= 0 && *str.offset(end) != b'/' as c_char {
+        end -= 1;
+    }
+    while end > 0 && *str.offset(end) == b'/' as c_char {
+        end -= 1;
+    }
+    if end == -1 {
+        return ".\0".as_ptr() as *mut c_char;
+    }
+    *str.offset(end + 1) = 0;
+    str
+}

+ 10 - 0
src/header/limits/cbindgen.toml

@@ -0,0 +1,10 @@
+sys_includes = []
+include_guard = "_RELIBC_LIMITS_H"
+trailer = "#include <bits/limits.h>"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 3 - 0
src/header/limits/mod.rs

@@ -0,0 +1,3 @@
+//! limits.h implementation for relibc
+
+pub const PATH_MAX: usize = 4096;

+ 22 - 4
src/header/mod.rs

@@ -1,7 +1,25 @@
-pub mod time;
-pub mod sys_stat;
-pub mod sys_statvfs;
 pub mod dirent;
 pub mod sys_resource;
+pub mod sys_stat;
+pub mod sys_statvfs;
 pub mod sys_time;
-pub mod sys_utsname;
+pub mod sys_utsname;
+pub mod time;
+pub mod libgen;
+pub mod stdio;
+pub mod stdlib;
+pub mod string;
+pub mod errno;
+pub mod fcntl;
+pub mod unistd;
+pub mod getopt;
+pub mod limits;
+pub mod sys_ioctl;
+pub mod termios;
+pub mod ctype;
+pub mod signal;
+pub mod wchar;
+pub mod wctype;
+pub mod sys_mman;
+pub mod dl_tls;
+pub mod sys_auxv;

+ 15 - 0
src/header/signal/cbindgen.toml

@@ -0,0 +1,15 @@
+sys_includes = ["stdint.h", "sys/types.h"]
+include_guard = "_RELIBC_SIGNAL_H"
+trailer = "#include <bits/signal.h>"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[defines]
+"target_os=linux" = "__linux__"
+"target_os=redox" = "__redox__"
+"target_os=dragonos" = "__dragonos__"
+
+[enum]
+prefix_with_name = true

+ 76 - 0
src/header/signal/dragonos.rs

@@ -0,0 +1,76 @@
+use core::arch::global_asm;
+
+// Needs to be defined in assembly because it can't have a function prologue
+// rax is register, 25 is RT_SIGRETURN
+#[cfg(target_arch = "x86_64")]
+global_asm!(
+    "
+    .global __restore_rt
+    __restore_rt:
+        mov rax, 25
+        int 0x80
+"
+);
+
+// x8 is register, 139 is RT_SIGRETURN
+#[cfg(target_arch = "aarch64")]
+global_asm!(
+    "
+    .global __restore_rt
+    __restore_rt:
+        mov x8, #139
+        svc 0
+"
+);
+
+pub const SIGHUP: usize = 1;
+pub const SIGINT: usize = 2;
+pub const SIGQUIT: usize = 3;
+pub const SIGILL: usize = 4;
+pub const SIGTRAP: usize = 5;
+pub const SIGABRT: usize = 6;
+pub const SIGIOT: usize = SIGABRT;
+pub const SIGBUS: usize = 7;
+pub const SIGFPE: usize = 8;
+pub const SIGKILL: usize = 9;
+pub const SIGUSR1: usize = 10;
+pub const SIGSEGV: usize = 11;
+pub const SIGUSR2: usize = 12;
+pub const SIGPIPE: usize = 13;
+pub const SIGALRM: usize = 14;
+pub const SIGTERM: usize = 15;
+pub const SIGSTKFLT: usize = 16;
+pub const SIGCHLD: usize = 17;
+pub const SIGCONT: usize = 18;
+pub const SIGSTOP: usize = 19;
+pub const SIGTSTP: usize = 20;
+pub const SIGTTIN: usize = 21;
+pub const SIGTTOU: usize = 22;
+pub const SIGURG: usize = 23;
+pub const SIGXCPU: usize = 24;
+pub const SIGXFSZ: usize = 25;
+pub const SIGVTALRM: usize = 26;
+pub const SIGPROF: usize = 27;
+pub const SIGWINCH: usize = 28;
+pub const SIGIO: usize = 29;
+pub const SIGPOLL: usize = SIGIO;
+pub const SIGPWR: usize = 30;
+pub const SIGSYS: usize = 31;
+pub const SIGUNUSED: usize = SIGSYS;
+pub const NSIG: usize = 32;
+
+pub const SA_NOCLDSTOP: usize = 1;
+pub const SA_NOCLDWAIT: usize = 2;
+pub const SA_SIGINFO: usize = 4;
+pub const SA_ONSTACK: usize = 0x0800_0000;
+pub const SA_RESTART: usize = 0x1000_0000;
+pub const SA_NODEFER: usize = 0x4000_0000;
+pub const SA_RESETHAND: usize = 0x8000_0000;
+pub const SA_RESTORER: usize = 0x0400_0000;
+
+pub const SS_ONSTACK: usize = 1;
+pub const SS_DISABLE: usize = 2;
+
+// Those two should be updated from kernel headers
+pub const MINSIGSTKSZ: usize = 2048;
+pub const SIGSTKSZ: usize = 8096;

+ 75 - 0
src/header/signal/linux.rs

@@ -0,0 +1,75 @@
+use core::arch::global_asm;
+
+// Needs to be defined in assembly because it can't have a function prologue
+// rax is register, 15 is RT_SIGRETURN
+#[cfg(target_arch = "x86_64")]
+global_asm!(
+    "
+    .global __restore_rt
+    __restore_rt:
+        mov rax, 15
+        syscall
+"
+);
+// x8 is register, 139 is RT_SIGRETURN
+#[cfg(target_arch = "aarch64")]
+global_asm!(
+    "
+    .global __restore_rt
+    __restore_rt:
+        mov x8, #139
+        svc 0
+"
+);
+
+pub const SIGHUP: usize = 1;
+pub const SIGINT: usize = 2;
+pub const SIGQUIT: usize = 3;
+pub const SIGILL: usize = 4;
+pub const SIGTRAP: usize = 5;
+pub const SIGABRT: usize = 6;
+pub const SIGIOT: usize = SIGABRT;
+pub const SIGBUS: usize = 7;
+pub const SIGFPE: usize = 8;
+pub const SIGKILL: usize = 9;
+pub const SIGUSR1: usize = 10;
+pub const SIGSEGV: usize = 11;
+pub const SIGUSR2: usize = 12;
+pub const SIGPIPE: usize = 13;
+pub const SIGALRM: usize = 14;
+pub const SIGTERM: usize = 15;
+pub const SIGSTKFLT: usize = 16;
+pub const SIGCHLD: usize = 17;
+pub const SIGCONT: usize = 18;
+pub const SIGSTOP: usize = 19;
+pub const SIGTSTP: usize = 20;
+pub const SIGTTIN: usize = 21;
+pub const SIGTTOU: usize = 22;
+pub const SIGURG: usize = 23;
+pub const SIGXCPU: usize = 24;
+pub const SIGXFSZ: usize = 25;
+pub const SIGVTALRM: usize = 26;
+pub const SIGPROF: usize = 27;
+pub const SIGWINCH: usize = 28;
+pub const SIGIO: usize = 29;
+pub const SIGPOLL: usize = SIGIO;
+pub const SIGPWR: usize = 30;
+pub const SIGSYS: usize = 31;
+pub const SIGUNUSED: usize = SIGSYS;
+pub const NSIG: usize = 32;
+
+pub const SA_NOCLDSTOP: usize = 1;
+pub const SA_NOCLDWAIT: usize = 2;
+pub const SA_SIGINFO: usize = 4;
+pub const SA_ONSTACK: usize = 0x0800_0000;
+pub const SA_RESTART: usize = 0x1000_0000;
+pub const SA_NODEFER: usize = 0x4000_0000;
+pub const SA_RESETHAND: usize = 0x8000_0000;
+pub const SA_RESTORER: usize = 0x0400_0000;
+
+pub const SS_ONSTACK: usize = 1;
+pub const SS_DISABLE: usize = 2;
+
+// Those two should be updated from kernel headers
+pub const MINSIGSTKSZ: usize = 2048;
+pub const SIGSTKSZ: usize = 8096;

+ 285 - 0
src/header/signal/mod.rs

@@ -0,0 +1,285 @@
+//! signal implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/signal.h.html
+
+use core::mem;
+
+use cbitset::BitSet;
+
+use crate::{
+    header::errno,
+    platform::{self, types::*, Sys,PalSignal},
+};
+pub use self::sys::*;
+
+#[cfg(target_os = "linux")]
+#[path = "linux.rs"]
+pub mod sys;
+
+#[cfg(target_os = "dragonos")]
+#[path = "dragonos.rs"]
+pub mod sys;
+
+#[cfg(target_os = "redox")]
+#[path = "redox.rs"]
+pub mod sys;
+
+type SigSet = BitSet<[c_ulong; 1]>;
+
+pub const SIG_DFL: usize = 0;
+pub const SIG_IGN: usize = 1;
+pub const SIG_ERR: isize = -1;
+
+pub const SIG_BLOCK: c_int = 0;
+pub const SIG_UNBLOCK: c_int = 1;
+pub const SIG_SETMASK: c_int = 2;
+
+#[repr(C)]
+#[derive(Clone, Debug)]
+pub struct sigaction {
+    pub sa_handler: Option<extern "C" fn(c_int)>,
+    pub sa_flags: c_ulong,
+    pub sa_restorer: Option<unsafe extern "C" fn()>,
+    pub sa_mask: sigset_t,
+}
+
+#[repr(C)]
+#[derive(Clone)]
+pub struct sigaltstack {
+    pub ss_sp: *mut c_void,
+    pub ss_flags: c_int,
+    pub ss_size: size_t,
+}
+
+pub type sigset_t = c_ulong;
+
+pub type stack_t = sigaltstack;
+
+#[no_mangle]
+pub extern "C" fn kill(pid: pid_t, sig: c_int) -> c_int {
+    Sys::kill(pid, sig)
+}
+
+#[no_mangle]
+pub extern "C" fn killpg(pgrp: pid_t, sig: c_int) -> c_int {
+    Sys::killpg(pgrp, sig)
+}
+
+#[no_mangle]
+pub extern "C" fn pthread_sigmask(
+    how: c_int,
+    set: *const sigset_t,
+    oldset: *mut sigset_t,
+) -> c_int {
+    // On Linux and Redox, pthread_sigmask and sigprocmask are equivalent
+    if sigprocmask(how, set, oldset) == 0 {
+        0
+    } else {
+        //TODO: Fix race
+        unsafe { platform::errno }
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn raise(sig: c_int) -> c_int {
+    Sys::raise(sig)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sigaction(
+    sig: c_int,
+    act: *const sigaction,
+    oact: *mut sigaction,
+) -> c_int {
+    let act_opt = act.as_ref().map(|act| {
+        let mut act_clone = act.clone();
+        act_clone.sa_flags |= SA_RESTORER as c_ulong;
+        act_clone.sa_restorer = Some(__restore_rt);
+        act_clone
+    });
+    Sys::sigaction(sig, act_opt.as_ref(), oact.as_mut())
+}
+
+#[no_mangle]
+pub extern "C" fn sigaddset(set: *mut sigset_t, signo: c_int) -> c_int {
+    if signo <= 0 || signo as usize > NSIG {
+        unsafe {
+            platform::errno = errno::EINVAL;
+        }
+        return -1;
+    }
+
+    if let Some(set) = unsafe { (set as *mut SigSet).as_mut() } {
+        set.insert(signo as usize - 1); // 0-indexed usize, please!
+    }
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int {
+    if !ss.is_null() {
+        if (*ss).ss_flags != SS_DISABLE as c_int {
+            return errno::EINVAL;
+        }
+        if (*ss).ss_size < MINSIGSTKSZ {
+            return errno::ENOMEM;
+        }
+    }
+
+    Sys::sigaltstack(ss, old_ss)
+}
+
+#[no_mangle]
+pub extern "C" fn sigdelset(set: *mut sigset_t, signo: c_int) -> c_int {
+    if signo <= 0 || signo as usize > NSIG {
+        unsafe {
+            platform::errno = errno::EINVAL;
+        }
+        return -1;
+    }
+
+    if let Some(set) = unsafe { (set as *mut SigSet).as_mut() } {
+        set.remove(signo as usize - 1); // 0-indexed usize, please!
+    }
+    0
+}
+
+#[no_mangle]
+pub extern "C" fn sigemptyset(set: *mut sigset_t) -> c_int {
+    if let Some(set) = unsafe { (set as *mut SigSet).as_mut() } {
+        set.clear();
+    }
+    0
+}
+
+#[no_mangle]
+pub extern "C" fn sigfillset(set: *mut sigset_t) -> c_int {
+    if let Some(set) = unsafe { (set as *mut SigSet).as_mut() } {
+        set.fill(.., true);
+    }
+    0
+}
+
+// #[no_mangle]
+pub extern "C" fn sighold(sig: c_int) -> c_int {
+    unimplemented!();
+}
+
+// #[no_mangle]
+pub extern "C" fn sigignore(sig: c_int) -> c_int {
+    unimplemented!();
+}
+
+// #[no_mangle]
+pub extern "C" fn siginterrupt(sig: c_int, flag: c_int) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn sigismember(set: *const sigset_t, signo: c_int) -> c_int {
+    if signo <= 0 || signo as usize > NSIG {
+        unsafe {
+            platform::errno = errno::EINVAL;
+        }
+        return -1;
+    }
+
+    if let Some(set) = unsafe { (set as *mut SigSet).as_mut() } {
+        if set.contains(signo as usize - 1) {
+            return 1;
+        }
+    }
+    0
+}
+
+extern "C" {
+    // Defined in assembly inside platform/x/mod.rs
+    fn __restore_rt();
+}
+
+#[no_mangle]
+pub extern "C" fn signal(
+    sig: c_int,
+    func: Option<extern "C" fn(c_int)>,
+) -> Option<extern "C" fn(c_int)> {
+    let sa = sigaction {
+        sa_handler: func,
+        sa_flags: SA_RESTART as c_ulong,
+        sa_restorer: Some(__restore_rt),
+        sa_mask: sigset_t::default(),
+    };
+    let mut old_sa = mem::MaybeUninit::uninit();
+    if unsafe { sigaction(sig, &sa, old_sa.as_mut_ptr()) } < 0 {
+        mem::forget(old_sa);
+        return unsafe { mem::transmute(SIG_ERR) };
+    }
+    unsafe { old_sa.assume_init() }.sa_handler
+}
+
+// #[no_mangle]
+pub extern "C" fn sigpause(sig: c_int) -> c_int {
+    unimplemented!();
+}
+
+// #[no_mangle]
+pub extern "C" fn sigpending(set: *mut sigset_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int {
+    Sys::sigprocmask(how, set, oset)
+}
+
+// #[no_mangle]
+pub extern "C" fn sigrelse(sig: c_int) -> c_int {
+    unimplemented!();
+}
+
+// #[no_mangle]
+pub extern "C" fn sigset(sig: c_int, func: fn(c_int)) -> fn(c_int) {
+    unimplemented!();
+}
+
+// #[no_mangle]
+pub extern "C" fn sigsuspend(sigmask: *const sigset_t) -> c_int {
+    unimplemented!();
+}
+
+// #[no_mangle]
+pub extern "C" fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int {
+    unimplemented!();
+}
+
+pub const _signal_strings: [&str; 32] = [
+    "Unknown signal\0",
+    "Hangup\0",
+    "Interrupt\0",
+    "Quit\0",
+    "Illegal instruction\0",
+    "Trace/breakpoint trap\0",
+    "Aborted\0",
+    "Bus error\0",
+    "Arithmetic exception\0",
+    "Killed\0",
+    "User defined signal 1\0",
+    "Segmentation fault\0",
+    "User defined signal 2\0",
+    "Broken pipe\0",
+    "Alarm clock\0",
+    "Terminated\0",
+    "Stack fault\0",
+    "Child process status\0",
+    "Continued\0",
+    "Stopped (signal)\0",
+    "Stopped\0",
+    "Stopped (tty input)\0",
+    "Stopped (tty output)\0",
+    "Urgent I/O condition\0",
+    "CPU time limit exceeded\0",
+    "File size limit exceeded\0",
+    "Virtual timer expired\0",
+    "Profiling timer expired\0",
+    "Window changed\0",
+    "I/O possible\0",
+    "Power failure\0",
+    "Bad system call\0",
+];

+ 83 - 0
src/header/signal/redox.rs

@@ -0,0 +1,83 @@
+use core::arch::global_asm;
+
+// x8 is register, 119 is SIGRETURN
+#[cfg(target_arch = "aarch64")]
+global_asm!(
+    "
+    .global __restore_rt
+    __restore_rt:
+        mov x8, #119
+        svc 0
+"
+);
+// Needs to be defined in assembly because it can't have a function prologue
+// eax is register, 119 is SIGRETURN
+#[cfg(target_arch = "x86")]
+global_asm!(
+    "
+    .global __restore_rt
+    __restore_rt:
+        mov eax, 119
+        int 0x80
+"
+);
+// Needs to be defined in assembly because it can't have a function prologue
+// rax is register, 119 is SIGRETURN
+#[cfg(target_arch = "x86_64")]
+global_asm!(
+    "
+    .global __restore_rt
+    __restore_rt:
+        mov rax, 119
+        syscall
+"
+);
+
+pub const SIGHUP: usize = 1;
+pub const SIGINT: usize = 2;
+pub const SIGQUIT: usize = 3;
+pub const SIGILL: usize = 4;
+pub const SIGTRAP: usize = 5;
+pub const SIGABRT: usize = 6;
+pub const SIGBUS: usize = 7;
+pub const SIGFPE: usize = 8;
+pub const SIGKILL: usize = 9;
+pub const SIGUSR1: usize = 10;
+pub const SIGSEGV: usize = 11;
+pub const SIGUSR2: usize = 12;
+pub const SIGPIPE: usize = 13;
+pub const SIGALRM: usize = 14;
+pub const SIGTERM: usize = 15;
+pub const SIGSTKFLT: usize = 16;
+pub const SIGCHLD: usize = 17;
+pub const SIGCONT: usize = 18;
+pub const SIGSTOP: usize = 19;
+pub const SIGTSTP: usize = 20;
+pub const SIGTTIN: usize = 21;
+pub const SIGTTOU: usize = 22;
+pub const SIGURG: usize = 23;
+pub const SIGXCPU: usize = 24;
+pub const SIGXFSZ: usize = 25;
+pub const SIGVTALRM: usize = 26;
+pub const SIGPROF: usize = 27;
+pub const SIGWINCH: usize = 28;
+pub const SIGIO: usize = 29;
+pub const SIGPWR: usize = 30;
+pub const SIGSYS: usize = 31;
+pub const NSIG: usize = 32;
+
+pub const SA_NOCLDSTOP: usize = 0x00000001;
+pub const SA_NOCLDWAIT: usize = 0x00000002;
+pub const SA_SIGINFO: usize = 0x00000004;
+pub const SA_RESTORER: usize = 0x04000000;
+pub const SA_ONSTACK: usize = 0x08000000;
+pub const SA_RESTART: usize = 0x10000000;
+pub const SA_NODEFER: usize = 0x40000000;
+pub const SA_RESETHAND: usize = 0x80000000;
+
+pub const SS_ONSTACK: usize = 0x00000001;
+pub const SS_DISABLE: usize = 0x00000002;
+
+// TODO: It's just a guess based on Linux
+pub const MINSIGSTKSZ: usize = 2048;
+pub const SIGSTKSZ: usize = 8096;

+ 13 - 0
src/header/stdio/cbindgen.toml

@@ -0,0 +1,13 @@
+sys_includes = ["stdarg.h", "stddef.h", "stdint.h", "sys/types.h"]
+include_guard = "_RELIBC_STDIO_H"
+trailer = "#include <bits/stdio.h>"
+language = "C"
+style = "Type"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true
+
+[export.rename]
+"AtomicBool" = "volatile char"

+ 37 - 0
src/header/stdio/constants.rs

@@ -0,0 +1,37 @@
+use crate::platform::types::*;
+
+pub const EOF: c_int = -1;
+pub const BUFSIZ: c_int = 1024;
+
+pub const UNGET: c_int = 8;
+
+pub const FILENAME_MAX: c_int = 4096;
+
+pub const F_PERM: c_int = 1;
+pub const F_NORD: c_int = 4;
+pub const F_NOWR: c_int = 8;
+pub const F_EOF: c_int = 16;
+pub const F_ERR: c_int = 32;
+pub const F_SVB: c_int = 64;
+pub const F_APP: c_int = 128;
+pub const F_BADJ: c_int = 256;
+
+pub const SEEK_SET: c_int = 0;
+pub const SEEK_CUR: c_int = 1;
+pub const SEEK_END: c_int = 2;
+
+pub const _IOFBF: c_int = 0;
+pub const _IOLBF: c_int = 1;
+pub const _IONBF: c_int = 2;
+
+// form of name is /XXXXXX, so 7
+pub const L_tmpnam: c_int = 7;
+// 36^6 (26 letters + 10 digits) is larger than i32::MAX, so just set to that
+// for now
+pub const TMP_MAX: int32_t = 2_147_483_647;
+// XXX: defined manually in bits/stdio.h as well because cbindgen can't handle
+//      string constants in any form AFAICT
+pub const P_tmpdir: &[u8; 5] = b"/tmp\0";
+
+#[allow(non_camel_case_types)]
+pub type fpos_t = off_t;

+ 52 - 0
src/header/stdio/default.rs

@@ -0,0 +1,52 @@
+use super::{constants, Buffer, BUFSIZ, FILE};
+use core::{cell::UnsafeCell, ptr};
+
+use crate::{fs::File, io::LineWriter, platform::types::*, sync::Mutex};
+use alloc::{boxed::Box, vec::Vec};
+
+pub struct GlobalFile(UnsafeCell<FILE>);
+impl GlobalFile {
+    fn new(file: c_int, flags: c_int) -> Self {
+        let file = File::new(file);
+        let writer = Box::new(LineWriter::new(unsafe { file.get_ref() }));
+        GlobalFile(UnsafeCell::new(FILE {
+            lock: Mutex::new(()),
+
+            file,
+            flags: constants::F_PERM | flags,
+            read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]),
+            read_pos: 0,
+            read_size: 0,
+            unget: Vec::new(),
+            writer,
+
+            pid: None,
+
+            orientation: 0,
+        }))
+    }
+    pub fn get(&self) -> *mut FILE {
+        self.0.get()
+    }
+}
+// statics need to be Sync
+unsafe impl Sync for GlobalFile {}
+
+use lazy_static::lazy_static;
+lazy_static! {
+    #[allow(non_upper_case_globals)]
+    pub static ref default_stdin: GlobalFile = GlobalFile::new(0, constants::F_NOWR);
+
+    #[allow(non_upper_case_globals)]
+    pub static ref default_stdout: GlobalFile = GlobalFile::new(1, constants::F_NORD);
+
+    #[allow(non_upper_case_globals)]
+    pub static ref default_stderr: GlobalFile = GlobalFile::new(2, constants::F_NORD);
+}
+
+#[no_mangle]
+pub static mut stdin: *mut FILE = ptr::null_mut();
+#[no_mangle]
+pub static mut stdout: *mut FILE = ptr::null_mut();
+#[no_mangle]
+pub static mut stderr: *mut FILE = ptr::null_mut();

+ 41 - 0
src/header/stdio/ext.rs

@@ -0,0 +1,41 @@
+use crate::{
+    header::stdio::{FILE, F_NORD, F_NOWR},
+    platform::types::*,
+};
+
+#[no_mangle]
+pub extern "C" fn __fpending(stream: *mut FILE) -> size_t {
+    let stream = unsafe { &mut *stream }.lock();
+
+    stream.writer.pending()
+}
+
+#[no_mangle]
+pub extern "C" fn __freadable(stream: *mut FILE) -> c_int {
+    let stream = unsafe { &mut *stream }.lock();
+
+    (stream.flags & F_NORD == 0) as c_int
+}
+
+#[no_mangle]
+pub extern "C" fn __fwritable(stream: *mut FILE) -> c_int {
+    let stream = unsafe { &mut *stream }.lock();
+
+    (stream.flags & F_NOWR == 0) as c_int
+}
+
+//TODO: Check last operation when read-write
+#[no_mangle]
+pub extern "C" fn __freading(stream: *mut FILE) -> c_int {
+    let stream = unsafe { &mut *stream }.lock();
+
+    (stream.flags & F_NORD == 0) as c_int
+}
+
+//TODO: Check last operation when read-write
+#[no_mangle]
+pub extern "C" fn __fwriting(stream: *mut FILE) -> c_int {
+    let stream = unsafe { &mut *stream }.lock();
+
+    (stream.flags & F_NOWR == 0) as c_int
+}

+ 55 - 0
src/header/stdio/getdelim.rs

@@ -0,0 +1,55 @@
+use alloc::vec::Vec;
+use core::ptr;
+
+use crate::{
+    header::{stdio::FILE, stdlib},
+    io::BufRead,
+    platform::types::*,
+};
+
+#[no_mangle]
+pub unsafe extern "C" fn __getline(
+    lineptr: *mut *mut c_char,
+    n: *mut size_t,
+    stream: *mut FILE,
+) -> ssize_t {
+    __getdelim(lineptr, n, b'\n' as c_int, stream)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __getdelim(
+    lineptr: *mut *mut c_char,
+    n: *mut size_t,
+    delim: c_int,
+    stream: *mut FILE,
+) -> ssize_t {
+    let lineptr = &mut *lineptr;
+    let n = &mut *n;
+    let delim = delim as u8;
+
+    //TODO: More efficient algorithm using lineptr and n instead of this vec
+    let mut buf = Vec::new();
+    let count = {
+        let mut stream = (*stream).lock();
+        match stream.read_until(delim, &mut buf) {
+            Ok(ok) => ok,
+            Err(err) => return -1,
+        }
+    };
+
+    //TODO: Check errors and improve safety
+    {
+        // Allocate lineptr to size of buf and set n to size of lineptr
+        *n = count + 1;
+        *lineptr = stdlib::realloc(*lineptr as *mut c_void, *n) as *mut c_char;
+
+        // Copy buf to lineptr
+        ptr::copy(buf.as_ptr(), *lineptr as *mut u8, count);
+
+        // NUL terminate lineptr
+        *lineptr.offset(count as isize) = 0;
+
+        // Return allocated size
+        *n as ssize_t
+    }
+}

+ 82 - 0
src/header/stdio/helpers.rs

@@ -0,0 +1,82 @@
+use alloc::boxed::Box;
+
+use super::{constants::*, Buffer, FILE};
+use crate::{
+    fs::File,
+    header::{errno, fcntl::*, string::strchr},
+    io::BufWriter,
+    platform::{self, types::*},
+    sync::Mutex,
+};
+use alloc::vec::Vec;
+
+/// Parse mode flags as a string and output a mode flags integer
+pub unsafe fn parse_mode_flags(mode_str: *const c_char) -> i32 {
+    let mut flags = if !strchr(mode_str, b'+' as i32).is_null() {
+        O_RDWR
+    } else if (*mode_str) == b'r' as i8 {
+        O_RDONLY
+    } else {
+        O_WRONLY
+    };
+    if !strchr(mode_str, b'x' as i32).is_null() {
+        flags |= O_EXCL;
+    }
+    if !strchr(mode_str, b'e' as i32).is_null() {
+        flags |= O_CLOEXEC;
+    }
+    if (*mode_str) != b'r' as i8 {
+        flags |= O_CREAT;
+    }
+    if (*mode_str) == b'w' as i8 {
+        flags |= O_TRUNC;
+    } else if (*mode_str) == b'a' as i8 {
+        flags |= O_APPEND;
+    }
+
+    flags
+}
+
+/// Open a file with the file descriptor `fd` in the mode `mode`
+pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> Option<*mut FILE> {
+    if *mode != b'r' as i8 && *mode != b'w' as i8 && *mode != b'a' as i8 {
+        platform::errno = errno::EINVAL;
+        return None;
+    }
+
+    let mut flags = 0;
+    if strchr(mode, b'+' as i32).is_null() {
+        flags |= if *mode == b'r' as i8 { F_NOWR } else { F_NORD };
+    }
+
+    if !strchr(mode, b'e' as i32).is_null() {
+        sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
+    }
+
+    if *mode == 'a' as i8 {
+        let f = sys_fcntl(fd, F_GETFL, 0);
+        if (f & O_APPEND) == 0 {
+            sys_fcntl(fd, F_SETFL, f | O_APPEND);
+        }
+        flags |= F_APP;
+    }
+
+    let file = File::new(fd);
+    let writer = Box::new(BufWriter::new(file.get_ref()));
+
+    Some(Box::into_raw(Box::new(FILE {
+        lock: Mutex::new(()),
+
+        file,
+        flags,
+        read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]),
+        read_pos: 0,
+        read_size: 0,
+        unget: Vec::new(),
+        writer,
+
+        pid: None,
+
+        orientation: 0,
+    })))
+}

+ 100 - 0
src/header/stdio/lookaheadreader.rs

@@ -0,0 +1,100 @@
+use super::{fseek_locked, ftell_locked, FILE, SEEK_SET};
+use core_io::Read;
+use crate::platform::types::off_t;
+struct LookAheadBuffer {
+    buf: *const u8,
+    pos: isize,
+    look_ahead: isize,
+}
+impl LookAheadBuffer {
+    fn look_ahead(&mut self) -> Result<Option<u8>, i32> {
+        let byte = unsafe { *self.buf.offset(self.look_ahead) };
+        if byte == 0 {
+            Ok(None)
+        } else {
+            self.look_ahead += 1;
+            Ok(Some(byte))
+        }
+    }
+
+    fn commit(&mut self) {
+        self.pos = self.look_ahead;
+    }
+}
+
+impl From<*const u8> for LookAheadBuffer {
+    fn from(buff: *const u8) -> LookAheadBuffer {
+        LookAheadBuffer {
+            buf: buff,
+            pos: 0,
+            look_ahead: 0,
+        }
+    }
+}
+
+struct LookAheadFile<'a> {
+    f: &'a mut FILE,
+    look_ahead: i64,
+}
+
+impl<'a> LookAheadFile<'a> {
+    fn look_ahead(&mut self) -> Result<Option<u8>, i32> {
+        let buf = &mut [0];
+        let seek = unsafe { ftell_locked(self.f) };
+        unsafe { fseek_locked(self.f, self.look_ahead as off_t, SEEK_SET) };
+        let ret = match self.f.read(buf) {
+            Ok(0) => Ok(None),
+            Ok(_) => Ok(Some(buf[0])),
+            Err(_) => Err(-1),
+        };
+        unsafe { fseek_locked(self.f, seek, SEEK_SET) };
+        self.look_ahead += 1;
+        ret
+    }
+
+    fn commit(&mut self) {
+        unsafe { fseek_locked(self.f, self.look_ahead as off_t, SEEK_SET) };
+    }
+}
+
+impl<'a> From<&'a mut FILE> for LookAheadFile<'a> {
+    fn from(f: &'a mut FILE) -> LookAheadFile<'a> {
+        let look_ahead = unsafe { ftell_locked(f) } as i64;
+        LookAheadFile { f, look_ahead }
+    }
+}
+
+enum LookAheadReaderEnum<'a> {
+    FILE(LookAheadFile<'a>),
+    // (buffer, location)
+    BUFFER(LookAheadBuffer),
+}
+
+pub struct LookAheadReader<'a>(LookAheadReaderEnum<'a>);
+
+impl<'a> LookAheadReader<'a> {
+    pub fn lookahead1(&mut self) -> Result<Option<u8>, i32> {
+        match &mut self.0 {
+            LookAheadReaderEnum::FILE(f) => f.look_ahead(),
+            LookAheadReaderEnum::BUFFER(b) => b.look_ahead(),
+        }
+    }
+    pub fn commit(&mut self) {
+        match &mut self.0 {
+            LookAheadReaderEnum::FILE(f) => f.commit(),
+            LookAheadReaderEnum::BUFFER(b) => b.commit(),
+        }
+    }
+}
+
+impl<'a> From<&'a mut FILE> for LookAheadReader<'a> {
+    fn from(f: &'a mut FILE) -> LookAheadReader {
+        LookAheadReader(LookAheadReaderEnum::FILE(f.into()))
+    }
+}
+
+impl<'a> From<*const u8> for LookAheadReader<'a> {
+    fn from(buff: *const u8) -> LookAheadReader<'a> {
+        LookAheadReader(LookAheadReaderEnum::BUFFER(buff.into()))
+    }
+}

+ 1208 - 0
src/header/stdio/mod.rs

@@ -0,0 +1,1208 @@
+//! stdio implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdio.h.html
+
+use alloc::{
+    borrow::{Borrow, BorrowMut},
+    boxed::Box,
+    vec::Vec,
+};
+use crate::c_str::CStr;
+use core::{
+    cmp,
+    ffi::{VaList as va_list},
+    fmt::{self, Write as WriteFmt},
+    i32, mem,
+    ops::{Deref, DerefMut},
+    ptr, slice, str,
+};
+
+use crate::{
+    fs::File,
+    header::{
+        errno::{self, STR_ERROR},
+        fcntl, stdlib,
+        string::{self, strlen},
+        unistd,
+    },
+    io::{self, BufRead, BufWriter, LineWriter, Read, Write},
+    platform::{self, errno, types::*, Pal, Sys, WriteByte},
+    sync::Mutex, c_str, c_vec::CVec,
+};
+
+pub use self::constants::*;
+mod constants;
+
+pub use self::default::*;
+mod default;
+
+pub use self::getdelim::*;
+use self::printf::printf;
+mod getdelim;
+
+mod ext;
+mod helpers;
+mod lookaheadreader;
+mod printf;
+mod scanf;
+use lookaheadreader::LookAheadReader;
+static mut TMPNAM_BUF: [c_char; L_tmpnam as usize + 1] = [0; L_tmpnam as usize + 1];
+
+enum Buffer<'a> {
+    Borrowed(&'a mut [u8]),
+    Owned(Vec<u8>),
+}
+impl<'a> Deref for Buffer<'a> {
+    type Target = [u8];
+
+    fn deref(&self) -> &Self::Target {
+        match self {
+            Buffer::Borrowed(inner) => inner,
+            Buffer::Owned(inner) => inner.borrow(),
+        }
+    }
+}
+impl<'a> DerefMut for Buffer<'a> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        match self {
+            Buffer::Borrowed(inner) => inner,
+            Buffer::Owned(inner) => inner.borrow_mut(),
+        }
+    }
+}
+
+pub trait Pending {
+    fn pending(&self) -> size_t;
+}
+
+impl<W: core_io::Write> Pending for BufWriter<W> {
+    fn pending(&self) -> size_t {
+        self.buf.len() as size_t
+    }
+}
+
+impl<W: core_io::Write> Pending for LineWriter<W> {
+    fn pending(&self) -> size_t {
+        self.inner.buf.len() as size_t
+    }
+}
+
+pub trait Writer: Write + Pending {
+    fn purge(&mut self);
+}
+
+impl<W: core_io::Write> Writer for BufWriter<W> {
+    fn purge(&mut self) {
+        self.buf.clear();
+    }
+}
+impl<W: core_io::Write> Writer for LineWriter<W> {
+    fn purge(&mut self) {
+        self.inner.buf.clear();
+    }
+}
+
+/// This struct gets exposed to the C API.
+pub struct FILE {
+    lock: Mutex<()>,
+
+    file: File,
+    // pub for stdio_ext
+    pub(crate) flags: c_int,
+    read_buf: Buffer<'static>,
+    read_pos: usize,
+    read_size: usize,
+    unget: Vec<u8>,
+    // pub for stdio_ext
+    pub(crate) writer: Box<dyn Writer + Send>,
+
+    // Optional pid for use with popen/pclose
+    pid: Option<c_int>,
+
+    // wchar support
+    pub(crate) orientation: c_int,
+}
+
+impl Read for FILE {
+    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
+        let unget_read_size = cmp::min(out.len(), self.unget.len());
+        for i in 0..unget_read_size {
+            out[i] = self.unget.pop().unwrap();
+        }
+        if unget_read_size != 0 {
+            return Ok(unget_read_size);
+        }
+
+        let len = {
+            let buf = self.fill_buf()?;
+            let len = buf.len().min(out.len());
+
+            out[..len].copy_from_slice(&buf[..len]);
+            len
+        };
+        self.consume(len);
+        Ok(len)
+    }
+}
+impl BufRead for FILE {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> {
+        if self.read_pos == self.read_size {
+            self.read_size = match self.file.read(&mut self.read_buf) {
+                Ok(0) => {
+                    self.flags |= F_EOF;
+                    0
+                }
+                Ok(n) => n,
+                Err(err) => {
+                    self.flags |= F_ERR;
+                    return Err(err);
+                }
+            };
+            self.read_pos = 0;
+        }
+        Ok(&self.read_buf[self.read_pos..self.read_size])
+    }
+    fn consume(&mut self, i: usize) {
+        self.read_pos = (self.read_pos + i).min(self.read_size);
+    }
+}
+impl Write for FILE {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match self.writer.write(buf) {
+            Ok(n) => Ok(n),
+            Err(err) => {
+                self.flags |= F_ERR;
+                Err(err)
+            }
+        }
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        match self.writer.flush() {
+            Ok(()) => Ok(()),
+            Err(err) => {
+                self.flags |= F_ERR;
+                Err(err)
+            }
+        }
+    }
+}
+impl WriteFmt for FILE {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.write_all(s.as_bytes())
+            .map(|_| ())
+            .map_err(|_| fmt::Error)
+    }
+}
+impl WriteByte for FILE {
+    fn write_u8(&mut self, c: u8) -> fmt::Result {
+        self.write_all(&[c]).map(|_| ()).map_err(|_| fmt::Error)
+    }
+}
+impl FILE {
+    pub fn lock(&mut self) -> LockGuard {
+        unsafe {
+            flockfile(self);
+        }
+        LockGuard(self)
+    }
+
+    pub fn try_set_orientation(&mut self, mode: c_int) -> c_int {
+        let stream = self.lock();
+        stream.0.try_set_orientation_unlocked(mode)
+    }
+
+    pub fn try_set_orientation_unlocked(&mut self, mode: c_int) -> c_int {
+        if self.orientation == 0 {
+            self.orientation = match mode {
+                1..=i32::MAX => 1,
+                i32::MIN..=-1 => -1,
+                0 => self.orientation,
+            };
+        }
+        self.orientation
+    }
+
+    pub fn try_set_byte_orientation_unlocked(&mut self) -> core::result::Result<(), c_int> {
+        match self.try_set_orientation_unlocked(-1) {
+            i32::MIN..=-1 => Ok(()),
+            x => Err(x),
+        }
+    }
+
+    pub fn purge(&mut self) {
+        // Purge read buffer
+        self.read_pos = 0;
+        self.read_size = 0;
+        // Purge unget
+        self.unget.clear();
+        // Purge write buffer
+        self.writer.purge();
+    }
+}
+
+pub struct LockGuard<'a>(&'a mut FILE);
+impl<'a> Deref for LockGuard<'a> {
+    type Target = FILE;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl<'a> DerefMut for LockGuard<'a> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.0
+    }
+}
+impl<'a> Drop for LockGuard<'a> {
+    fn drop(&mut self) {
+        unsafe {
+            funlockfile(self.0);
+        }
+    }
+}
+
+/// Clears EOF and ERR indicators on a stream
+#[no_mangle]
+pub unsafe extern "C" fn clearerr(stream: *mut FILE) {
+    let mut stream = (*stream).lock();
+    stream.flags &= !(F_EOF | F_ERR);
+}
+
+// #[no_mangle]
+pub extern "C" fn ctermid(_s: *mut c_char) -> *mut c_char {
+    unimplemented!();
+}
+
+// #[no_mangle]
+pub extern "C" fn cuserid(_s: *mut c_char) -> *mut c_char {
+    unimplemented!();
+}
+
+/// Close a file
+/// This function does not guarentee that the file buffer will be flushed or that the file
+/// descriptor will be closed, so if it is important that the file be written to, use `fflush()`
+/// prior to using this function.
+#[no_mangle]
+pub unsafe extern "C" fn fclose(stream: *mut FILE) -> c_int {
+    let stream = &mut *stream;
+    flockfile(stream);
+
+    let mut r = stream.flush().is_err();
+    let close = Sys::close(*stream.file) < 0;
+    r = r || close;
+
+    if stream.flags & constants::F_PERM == 0 {
+        // Not one of stdin, stdout or stderr
+        let mut stream = Box::from_raw(stream);
+        // Reference files aren't closed on drop, so pretend to be a reference
+        stream.file.reference = true;
+    } else {
+        funlockfile(stream);
+    }
+
+    r as c_int
+}
+
+/// Open a file from a file descriptor
+#[no_mangle]
+pub unsafe extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE {
+    if let Some(f) = helpers::_fdopen(fildes, mode) {
+        f
+    } else {
+        ptr::null_mut()
+    }
+}
+
+/// Check for EOF
+#[no_mangle]
+pub unsafe extern "C" fn feof(stream: *mut FILE) -> c_int {
+    let stream = (*stream).lock();
+    stream.flags & F_EOF
+}
+
+/// Check for ERR
+#[no_mangle]
+pub unsafe extern "C" fn ferror(stream: *mut FILE) -> c_int {
+    let stream = (*stream).lock();
+    stream.flags & F_ERR
+}
+
+/// Flush output to stream, or sync read position
+/// Ensure the file is unlocked before calling this function, as it will attempt to lock the file
+/// itself.
+#[no_mangle]
+pub unsafe extern "C" fn fflush(stream: *mut FILE) -> c_int {
+    if stream.is_null() {
+        //TODO: flush all files!
+
+        if fflush(stdout) != 0 {
+            return EOF;
+        }
+
+        if fflush(stderr) != 0 {
+            return EOF;
+        }
+    } else {
+        let mut stream = (*stream).lock();
+        if stream.flush().is_err() {
+            return EOF;
+        }
+    }
+
+    0
+}
+
+/// Get a single char from a stream
+#[no_mangle]
+pub unsafe extern "C" fn fgetc(stream: *mut FILE) -> c_int {
+    let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
+    getc_unlocked(&mut *stream)
+}
+
+/// Get the position of the stream and store it in pos
+#[no_mangle]
+pub unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int {
+    let off = ftello(stream);
+    if off < 0 {
+        return -1;
+    }
+    *pos = off;
+    0
+}
+
+/// Get a string from the stream
+#[no_mangle]
+pub unsafe extern "C" fn fgets(
+    original: *mut c_char,
+    max: c_int,
+    stream: *mut FILE,
+) -> *mut c_char {
+    let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return ptr::null_mut();
+    }
+
+    let mut out = original;
+    let max = max as usize;
+    let mut left = max.saturating_sub(1); // Make space for the terminating NUL-byte
+    let mut wrote = false;
+
+    if left >= 1 {
+        let unget_read_size = cmp::min(left, stream.unget.len());
+        for _ in 0..unget_read_size {
+            *out = stream.unget.pop().unwrap() as i8;
+            out = out.offset(1);
+        }
+        left -= unget_read_size;
+    }
+
+    loop {
+        if left == 0 {
+            break;
+        }
+
+        // TODO: When NLL is a thing, this block can be flattened out
+        let (read, exit) = {
+            let buf = match stream.fill_buf() {
+                Ok(buf) => buf,
+                Err(_) => return ptr::null_mut(),
+            };
+            if buf.is_empty() {
+                break;
+            }
+            wrote = true;
+            let len = buf.len().min(left);
+
+            let newline = buf[..len].iter().position(|&c| c == b'\n');
+            let len = newline.map(|i| i + 1).unwrap_or(len);
+
+            ptr::copy_nonoverlapping(buf.as_ptr(), out as *mut u8, len);
+
+            (len, newline.is_some())
+        };
+
+        stream.consume(read);
+
+        out = out.add(read);
+        left -= read;
+
+        if exit {
+            break;
+        }
+    }
+
+    if max >= 1 {
+        // Write the NUL byte
+        *out = 0;
+    }
+    if wrote {
+        original
+    } else {
+        ptr::null_mut()
+    }
+}
+
+/// Get the underlying file descriptor
+#[no_mangle]
+pub unsafe extern "C" fn fileno(stream: *mut FILE) -> c_int {
+    let stream = (*stream).lock();
+    *stream.file
+}
+
+/// Lock the file
+/// Do not call any functions other than those with the `_unlocked` postfix while the file is
+/// locked
+#[no_mangle]
+pub unsafe extern "C" fn flockfile(file: *mut FILE) {
+    (*file).lock.manual_lock();
+}
+
+/// Open the file in mode `mode`
+#[no_mangle]
+pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE {
+    let initial_mode = *mode;
+    if initial_mode != b'r' as i8 && initial_mode != b'w' as i8 && initial_mode != b'a' as i8 {
+        platform::errno = errno::EINVAL;
+        return ptr::null_mut();
+    }
+
+    let flags = helpers::parse_mode_flags(mode);
+
+    let new_mode = if flags & fcntl::O_CREAT == fcntl::O_CREAT {
+        0o666
+    } else {
+        0
+    };
+
+    let fd = fcntl::sys_open(filename, flags, new_mode);
+    if fd < 0 {
+        return ptr::null_mut();
+    }
+
+    if flags & fcntl::O_CLOEXEC > 0 {
+        fcntl::sys_fcntl(fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
+    }
+
+    if let Some(f) = helpers::_fdopen(fd, mode) {
+        f
+    } else {
+        Sys::close(fd);
+        ptr::null_mut()
+    }
+}
+
+/// Clear the buffers of a stream
+/// Ensure the file is unlocked before calling this function, as it will attempt to lock the file
+/// itself.
+#[no_mangle]
+pub unsafe extern "C" fn __fpurge(stream: *mut FILE) {
+    if !stream.is_null() {
+        let mut stream = (*stream).lock();
+        stream.purge();
+    }
+}
+
+/// Insert a character into the stream
+#[no_mangle]
+pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int {
+    let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
+    putc_unlocked(c, &mut *stream)
+}
+
+/// Insert a string into a stream
+#[no_mangle]
+pub unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int {
+    let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
+    let buf = slice::from_raw_parts(s as *mut u8, strlen(s));
+
+    if stream.write_all(&buf).is_ok() {
+        0
+    } else {
+        -1
+    }
+}
+
+/// Read `nitems` of size `size` into `ptr` from `stream`
+#[no_mangle]
+pub unsafe extern "C" fn fread(
+    ptr: *mut c_void,
+    size: size_t,
+    nitems: size_t,
+    stream: *mut FILE,
+) -> size_t {
+    if size == 0 || nitems == 0 {
+        return 0;
+    }
+
+    let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return 0;
+    }
+
+    let buf = slice::from_raw_parts_mut(ptr as *mut u8, size as usize * nitems as usize);
+    let mut read = 0;
+    while read < buf.len() {
+        match stream.read(&mut buf[read..]) {
+            Ok(0) | Err(_) => break,
+            Ok(n) => read += n,
+        }
+    }
+    (read / size as usize) as size_t
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn freopen(
+    filename: *const c_char,
+    mode: *const c_char,
+    stream: &mut FILE,
+) -> *mut FILE {
+    let mut flags = helpers::parse_mode_flags(mode);
+    flockfile(stream);
+
+    let _ = stream.flush();
+    if filename.is_null() {
+        // Reopen stream in new mode
+        if flags & fcntl::O_CLOEXEC > 0 {
+            fcntl::sys_fcntl(*stream.file, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
+        }
+        flags &= !(fcntl::O_CREAT | fcntl::O_EXCL | fcntl::O_CLOEXEC);
+        if fcntl::sys_fcntl(*stream.file, fcntl::F_SETFL, flags) < 0 {
+            funlockfile(stream);
+            fclose(stream);
+            return ptr::null_mut();
+        }
+    } else {
+        let new = fopen(filename, mode);
+        if new.is_null() {
+            funlockfile(stream);
+            fclose(stream);
+            return ptr::null_mut();
+        }
+        let new = &mut *new; // Should be safe, new is not null
+        if *new.file == *stream.file {
+            new.file.fd = -1;
+        } else if Sys::dup2(*new.file, *stream.file) < 0
+            || fcntl::sys_fcntl(*stream.file, fcntl::F_SETFL, flags & fcntl::O_CLOEXEC) < 0
+        {
+            funlockfile(stream);
+            fclose(new);
+            fclose(stream);
+            return ptr::null_mut();
+        }
+        stream.flags = (stream.flags & constants::F_PERM) | new.flags;
+        fclose(new);
+    }
+    stream.orientation = 0;
+    funlockfile(stream);
+    stream
+}
+
+/// Seek to an offset `offset` from `whence`
+#[no_mangle]
+pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int {
+    fseeko(stream, offset as off_t, whence)
+}
+
+/// Seek to an offset `offset` from `whence`
+#[no_mangle]
+pub unsafe extern "C" fn fseeko(stream: *mut FILE, off: off_t, whence: c_int) -> c_int {
+    let mut stream = (*stream).lock();
+    fseek_locked(&mut *stream, off, whence)
+}
+
+pub unsafe fn fseek_locked(stream: &mut FILE, mut off: off_t, whence: c_int) -> c_int {
+    if whence == SEEK_CUR {
+        // Since it's a buffered writer, our actual cursor isn't where the user
+        // thinks
+        off -= (stream.read_size - stream.read_pos) as off_t;
+    }
+
+    // Flush write buffer before seek
+    if stream.flush().is_err() {
+        return -1;
+    }
+
+    let err = Sys::lseek(*stream.file, off, whence);
+    if err < 0 {
+        return err as c_int;
+    }
+
+    stream.flags &= !(F_EOF | F_ERR);
+    stream.read_pos = 0;
+    stream.read_size = 0;
+    stream.unget = Vec::new();
+    0
+}
+
+/// Seek to a position `pos` in the file from the beginning of the file
+#[no_mangle]
+pub unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const fpos_t) -> c_int {
+    fseeko(stream, *pos, SEEK_SET)
+}
+
+/// Get the current position of the cursor in the file
+#[no_mangle]
+pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long {
+    ftello(stream) as c_long
+}
+
+/// Get the current position of the cursor in the file
+#[no_mangle]
+pub unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t {
+    let mut stream = (*stream).lock();
+    ftell_locked(&mut *stream)
+}
+pub unsafe extern "C" fn ftell_locked(stream: &mut FILE) -> off_t {
+    let pos = Sys::lseek(*stream.file, 0, SEEK_CUR);
+    if pos < 0 {
+        return -1;
+    }
+
+    pos - (stream.read_size - stream.read_pos) as off_t - stream.unget.len() as off_t
+}
+
+/// Try to lock the file. Returns 0 for success, 1 for failure
+#[no_mangle]
+pub unsafe extern "C" fn ftrylockfile(file: *mut FILE) -> c_int {
+    if (*file).lock.manual_try_lock().is_ok() {
+        0
+    } else {
+        1
+    }
+}
+
+/// Unlock the file
+#[no_mangle]
+pub unsafe extern "C" fn funlockfile(file: *mut FILE) {
+    (*file).lock.manual_unlock();
+}
+
+/// Write `nitems` of size `size` from `ptr` to `stream`
+#[no_mangle]
+pub unsafe extern "C" fn fwrite(
+    ptr: *const c_void,
+    size: size_t,
+    nitems: size_t,
+    stream: *mut FILE,
+) -> size_t {
+    if size == 0 || nitems == 0 {
+        return 0;
+    }
+    let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return 0;
+    }
+
+    let buf = slice::from_raw_parts(ptr as *const u8, size as usize * nitems as usize);
+    let mut written = 0;
+    while written < buf.len() {
+        match stream.write(&buf[written..]) {
+            Ok(0) | Err(_) => break,
+            Ok(n) => written += n,
+        }
+    }
+    (written / size as usize) as size_t
+}
+
+/// Get a single char from a stream
+#[no_mangle]
+pub unsafe extern "C" fn getc(stream: *mut FILE) -> c_int {
+    let mut stream = (*stream).lock();
+    getc_unlocked(&mut *stream)
+}
+
+/// Get a single char from `stdin`
+#[no_mangle]
+pub unsafe extern "C" fn getchar() -> c_int {
+    fgetc(&mut *stdin)
+}
+
+/// Get a char from a stream without locking the stream
+#[no_mangle]
+pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int {
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
+    let mut buf = [0];
+
+    match (*stream).read(&mut buf) {
+        Ok(0) | Err(_) => EOF,
+        Ok(_) => buf[0] as c_int,
+    }
+}
+
+/// Get a char from `stdin` without locking `stdin`
+#[no_mangle]
+pub unsafe extern "C" fn getchar_unlocked() -> c_int {
+    getc_unlocked(&mut *stdin)
+}
+
+/// Get a string from `stdin`
+#[no_mangle]
+pub unsafe extern "C" fn gets(s: *mut c_char) -> *mut c_char {
+    fgets(s, c_int::max_value(), &mut *stdin)
+}
+
+/// Get an integer from `stream`
+#[no_mangle]
+pub unsafe extern "C" fn getw(stream: *mut FILE) -> c_int {
+    let mut ret: c_int = 0;
+    if fread(
+        &mut ret as *mut _ as *mut c_void,
+        mem::size_of_val(&ret),
+        1,
+        stream,
+    ) > 0
+    {
+        ret
+    } else {
+        -1
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn pclose(stream: *mut FILE) -> c_int {
+    let pid = {
+        let mut stream = (*stream).lock();
+
+        if let Some(pid) = stream.pid.take() {
+            pid
+        } else {
+            errno = errno::ECHILD;
+            return -1;
+        }
+    };
+
+    fclose(stream);
+
+    let mut wstatus = 0;
+    if Sys::waitpid(pid, &mut wstatus, 0) < 0 {
+        return -1;
+    }
+
+    wstatus
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn perror(s: *const c_char) {
+    let s_cstr = CStr::from_ptr(s);
+    let s_str = str::from_utf8_unchecked(s_cstr.to_bytes());
+
+    let mut w = platform::FileWriter(2);
+    if errno >= 0 && errno < STR_ERROR.len() as c_int {
+        w.write_fmt(format_args!("{}: {}\n", s_str, STR_ERROR[errno as usize]))
+            .unwrap();
+    } else {
+        w.write_fmt(format_args!("{}: Unknown error {}\n", s_str, errno))
+            .unwrap();
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn popen(command: *const c_char, mode: *const c_char) -> *mut FILE {
+    //TODO: share code with system
+
+    let mode = CStr::from_ptr(mode);
+
+    let mut cloexec = false;
+    let mut write_opt = None;
+    for b in mode.to_bytes().iter() {
+        match b {
+            b'e' => cloexec = true,
+            b'r' if write_opt.is_none() => write_opt = Some(false),
+            b'w' if write_opt.is_none() => write_opt = Some(true),
+            _ => {
+                errno = errno::EINVAL;
+                return ptr::null_mut();
+            }
+        }
+    }
+
+    let write = match write_opt {
+        Some(some) => some,
+        None => {
+            errno = errno::EINVAL;
+            return ptr::null_mut();
+        }
+    };
+
+    let mut pipes = [-1, -1];
+    if unistd::pipe(pipes.as_mut_ptr()) != 0 {
+        return ptr::null_mut();
+    }
+
+    let child_pid = unistd::fork();
+    if child_pid == 0 {
+        let command_nonnull = if command.is_null() {
+            "exit 0\0".as_ptr()
+        } else {
+            command as *const u8
+        };
+
+        let shell = "/bin/sh\0".as_ptr();
+
+        let args = [
+            "sh\0".as_ptr(),
+            "-c\0".as_ptr(),
+            command_nonnull,
+            ptr::null(),
+        ];
+
+        // Setup up stdin or stdout
+        //TODO: dup errors are ignored, should they be?
+        {
+            if write {
+                unistd::dup2(0, pipes[0]);
+            } else {
+                unistd::dup2(1, pipes[1]);
+            }
+
+            unistd::close(pipes[0]);
+            unistd::close(pipes[1]);
+        }
+
+        unistd::execv(shell as *const c_char, args.as_ptr() as *const *mut c_char);
+
+        stdlib::exit(127);
+
+        unreachable!();
+    } else if child_pid > 0 {
+        let (fd, fd_mode) = if write {
+            unistd::close(pipes[0]);
+            (pipes[1], if cloexec { c_str!("we") } else { c_str!("w") })
+        } else {
+            unistd::close(pipes[1]);
+            (pipes[0], if cloexec { c_str!("re") } else { c_str!("r") })
+        };
+
+        if let Some(f) = helpers::_fdopen(fd, fd_mode.as_ptr()) {
+            (*f).pid = Some(child_pid);
+            f
+        } else {
+            ptr::null_mut()
+        }
+    } else {
+        ptr::null_mut()
+    }
+}
+
+/// Put a character `c` into `stream`
+#[no_mangle]
+pub unsafe extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int {
+    let mut stream = (*stream).lock();
+    putc_unlocked(c, &mut *stream)
+}
+
+/// Put a character `c` into `stdout`
+#[no_mangle]
+pub unsafe extern "C" fn putchar(c: c_int) -> c_int {
+    fputc(c, &mut *stdout)
+}
+
+/// Put a character `c` into `stream` without locking `stream`
+#[no_mangle]
+pub unsafe extern "C" fn putc_unlocked(c: c_int, stream: *mut FILE) -> c_int {
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
+    match (*stream).write(&[c as u8]) {
+        Ok(0) | Err(_) => EOF,
+        Ok(_) => c,
+    }
+}
+
+/// Put a character `c` into `stdout` without locking `stdout`
+#[no_mangle]
+pub unsafe extern "C" fn putchar_unlocked(c: c_int) -> c_int {
+    putc_unlocked(c, stdout)
+}
+
+/// Put a string `s` into `stdout`
+#[no_mangle]
+pub unsafe extern "C" fn puts(s: *const c_char) -> c_int {
+    let mut stream = (&mut *stdout).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
+    let buf = slice::from_raw_parts(s as *mut u8, strlen(s));
+
+    if stream.write_all(&buf).is_err() {
+        return -1;
+    }
+    if stream.write(&[b'\n']).is_err() {
+        return -1;
+    }
+    0
+}
+
+/// Put an integer `w` into `stream`
+#[no_mangle]
+pub unsafe extern "C" fn putw(w: c_int, stream: *mut FILE) -> c_int {
+    fwrite(&w as *const c_int as _, mem::size_of_val(&w), 1, stream) as i32 - 1
+}
+
+/// Delete file or directory `path`
+#[no_mangle]
+pub unsafe extern "C" fn remove(path: *const c_char) -> c_int {
+    let path = CStr::from_ptr(path);
+    let r = Sys::unlink(path);
+    if r == -errno::EISDIR {
+        Sys::rmdir(path)
+    } else {
+        r
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rename(oldpath: *const c_char, newpath: *const c_char) -> c_int {
+    let oldpath = CStr::from_ptr(oldpath);
+    let newpath = CStr::from_ptr(newpath);
+    Sys::rename(oldpath, newpath)
+}
+
+/// Rewind `stream` back to the beginning of it
+#[no_mangle]
+pub unsafe extern "C" fn rewind(stream: *mut FILE) {
+    fseeko(stream, 0, SEEK_SET);
+}
+
+/// Reset `stream` to use buffer `buf`. Buffer must be `BUFSIZ` in length
+#[no_mangle]
+pub unsafe extern "C" fn setbuf(stream: *mut FILE, buf: *mut c_char) {
+    setvbuf(
+        stream,
+        buf,
+        if buf.is_null() { _IONBF } else { _IOFBF },
+        BUFSIZ as usize,
+    );
+}
+
+/// Reset `stream` to use buffer `buf` of size `size`
+/// If this isn't the meaning of unsafe, idk what is
+#[no_mangle]
+pub unsafe extern "C" fn setvbuf(
+    stream: *mut FILE,
+    buf: *mut c_char,
+    mode: c_int,
+    mut size: size_t,
+) -> c_int {
+    let mut stream = (*stream).lock();
+    // Set a buffer of size `size` if no buffer is given
+    stream.read_buf = if buf.is_null() || size == 0 {
+        if size == 0 {
+            size = BUFSIZ as usize;
+        }
+        // TODO: Make it unbuffered if _IONBF
+        // if mode == _IONBF {
+        // } else {
+        Buffer::Owned(vec![0; size as usize])
+    // }
+    } else {
+        Buffer::Borrowed(slice::from_raw_parts_mut(buf as *mut u8, size))
+    };
+    stream.flags |= F_SVB;
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn tempnam(dir: *const c_char, pfx: *const c_char) -> *mut c_char {
+    unsafe fn is_appropriate(pos_dir: *const c_char) -> bool {
+        !pos_dir.is_null() && unistd::access(pos_dir, unistd::W_OK) == 0
+    }
+
+    // directory search order is env!(TMPDIR), dir, P_tmpdir, "/tmp"
+    let dirname = {
+        let tmpdir = stdlib::getenv(b"TMPDIR\0".as_ptr() as _);
+        [tmpdir, dir, P_tmpdir.as_ptr() as _]
+            .iter()
+            .copied()
+            .skip_while(|&d| !is_appropriate(d))
+            .next()
+            .unwrap_or(b"/tmp\0".as_ptr() as _)
+    };
+    let dirname_len = string::strlen(dirname);
+
+    let prefix_len = string::strnlen_s(pfx, 5);
+
+    // allocate enough for dirname "/" prefix "XXXXXX\0"
+    let mut out_buf =
+        platform::alloc(dirname_len + 1 + prefix_len + L_tmpnam as usize + 1) as *mut c_char;
+
+    if !out_buf.is_null() {
+        // copy the directory name and prefix into the allocated buffer
+        out_buf.copy_from_nonoverlapping(dirname, dirname_len);
+        *out_buf.add(dirname_len) = b'/' as _;
+        out_buf
+            .add(dirname_len + 1)
+            .copy_from_nonoverlapping(pfx, prefix_len);
+
+        // use the same mechanism as tmpnam to get the file name
+        if tmpnam_inner(out_buf, dirname_len + 1 + prefix_len).is_null() {
+            // failed to find a valid file name, so we need to free the buffer
+            platform::free(out_buf as _);
+            out_buf = ptr::null_mut();
+        }
+    }
+
+    out_buf
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn tmpfile() -> *mut FILE {
+    let mut file_name = *b"/tmp/tmpfileXXXXXX\0";
+    let file_name = file_name.as_mut_ptr() as *mut c_char;
+    let fd = stdlib::mkstemp(file_name);
+
+    if fd < 0 {
+        return ptr::null_mut();
+    }
+
+    let fp = fdopen(fd, c_str!("w+").as_ptr());
+    {
+        let file_name = CStr::from_ptr(file_name);
+        Sys::unlink(file_name);
+    }
+
+    if fp.is_null() {
+        Sys::close(fd);
+    }
+
+    fp
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn tmpnam(s: *mut c_char) -> *mut c_char {
+    let buf = if s.is_null() {
+        TMPNAM_BUF.as_mut_ptr()
+    } else {
+        s
+    };
+
+    *buf = b'/' as _;
+    tmpnam_inner(buf, 1)
+}
+
+unsafe extern "C" fn tmpnam_inner(buf: *mut c_char, offset: usize) -> *mut c_char {
+    const TEMPLATE: &[u8] = b"XXXXXX\0";
+
+    buf.add(offset)
+        .copy_from_nonoverlapping(TEMPLATE.as_ptr() as _, TEMPLATE.len());
+
+    let err = platform::errno;
+    stdlib::mktemp(buf);
+    platform::errno = err;
+
+    if *buf == 0 {
+        ptr::null_mut()
+    } else {
+        buf
+    }
+}
+
+/// Push character `c` back onto `stream` so it'll be read next
+#[no_mangle]
+pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
+    let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
+    stream.unget.push(c as u8);
+    c
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn vfprintf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int {
+    let mut file = (*file).lock();
+    if let Err(_) = file.try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
+    printf::printf(&mut *file, format, ap)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn vprintf(format: *const c_char, ap: va_list) -> c_int {
+    vfprintf(&mut *stdout, format, ap)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn vasprintf(
+    strp: *mut *mut c_char,
+    format: *const c_char,
+    ap: va_list,
+) -> c_int {
+    let mut alloc_writer = CVec::new();
+    let ret = printf::printf(&mut alloc_writer, format, ap);
+    alloc_writer.push(0).unwrap();
+    alloc_writer.shrink_to_fit().unwrap();
+    *strp = alloc_writer.leak() as *mut c_char;
+    ret
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn vsnprintf(
+    s: *mut c_char,
+    n: size_t,
+    format: *const c_char,
+    ap: va_list,
+) -> c_int {
+    printf::printf(
+        &mut platform::StringWriter(s as *mut u8, n as usize),
+        format,
+        ap,
+    )
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_list) -> c_int {
+    printf::printf(&mut platform::UnsafeStringWriter(s as *mut u8), format, ap)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn vfscanf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int {
+    let ret = {
+        let mut file = (*file).lock();
+        if let Err(_) = file.try_set_byte_orientation_unlocked() {
+            return -1;
+        }
+
+        let f: &mut FILE = &mut *file;
+        let reader: LookAheadReader = f.into();
+        scanf::scanf(reader, format, ap)
+    };
+    ret
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int {
+    vfscanf(&mut *stdin, format, ap)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va_list) -> c_int {
+    let reader = (s as *const u8).into();
+    scanf::scanf(reader, format, ap)
+}
+
+pub unsafe fn flush_io_streams() {
+    let flush = |stream: *mut FILE| {
+        let stream = &mut *stream;
+        stream.flush()
+    };
+    flush(stdout);
+    flush(stderr);
+}

+ 986 - 0
src/header/stdio/printf.rs

@@ -0,0 +1,986 @@
+use crate::io::{self, Write};
+use alloc::{
+    collections::BTreeMap,
+    string::{String, ToString},
+    vec::Vec, format,
+};
+use core::{char, cmp, f64, ffi::VaList, fmt, num::FpCategory, ops::Range, slice};
+
+use crate::{
+    header::errno::EILSEQ,
+    platform::{self, types::*},
+};
+
+//  ____        _ _                 _       _
+// | __ )  ___ (_) | ___ _ __ _ __ | | __ _| |_ ___ _
+// |  _ \ / _ \| | |/ _ \ '__| '_ \| |/ _` | __/ _ (_)
+// | |_) | (_) | | |  __/ |  | |_) | | (_| | ||  __/_
+// |____/ \___/|_|_|\___|_|  | .__/|_|\__,_|\__\___(_)
+//                           |_|
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+enum IntKind {
+    Byte,
+    Short,
+    Int,
+    Long,
+    LongLong,
+    IntMax,
+    PtrDiff,
+    Size,
+}
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+enum FmtKind {
+    Percent,
+
+    Signed,
+    Unsigned,
+
+    Scientific,
+    Decimal,
+    AnyNotation,
+
+    String,
+    Char,
+    Pointer,
+    GetWritten,
+}
+#[derive(Clone, Copy, Debug)]
+enum Number {
+    Static(usize),
+    Index(usize),
+    Next,
+}
+impl Number {
+    unsafe fn resolve(self, varargs: &mut VaListCache, ap: &mut VaList) -> usize {
+        let arg = match self {
+            Number::Static(num) => return num,
+            Number::Index(i) => varargs.get(i - 1, ap, None),
+            Number::Next => {
+                let i = varargs.i;
+                varargs.i += 1;
+                varargs.get(i, ap, None)
+            }
+        };
+        match arg {
+            VaArg::c_char(i) => i as usize,
+            VaArg::c_double(i) => i as usize,
+            VaArg::c_int(i) => i as usize,
+            VaArg::c_long(i) => i as usize,
+            VaArg::c_longlong(i) => i as usize,
+            VaArg::c_short(i) => i as usize,
+            VaArg::intmax_t(i) => i as usize,
+            VaArg::pointer(i) => i as usize,
+            VaArg::ptrdiff_t(i) => i as usize,
+            VaArg::ssize_t(i) => i as usize,
+            VaArg::wint_t(i) => i as usize,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug)]
+enum VaArg {
+    c_char(c_char),
+    c_double(c_double),
+    c_int(c_int),
+    c_long(c_long),
+    c_longlong(c_longlong),
+    c_short(c_short),
+    intmax_t(intmax_t),
+    pointer(*const c_void),
+    ptrdiff_t(ptrdiff_t),
+    ssize_t(ssize_t),
+    wint_t(wint_t),
+}
+impl VaArg {
+    unsafe fn arg_from(fmtkind: FmtKind, intkind: IntKind, ap: &mut VaList) -> VaArg {
+        // Per the C standard using va_arg with a type with a size
+        // less than that of an int for integers and double for floats
+        // is invalid. As a result any arguments smaller than an int or
+        // double passed to a function will be promoted to the smallest
+        // possible size. The VaList::arg function will handle this
+        // automagically.
+
+        match (fmtkind, intkind) {
+            (FmtKind::Percent, _) => panic!("Can't call arg_from on %"),
+
+            (FmtKind::Char, IntKind::Long) | (FmtKind::Char, IntKind::LongLong) => {
+                VaArg::wint_t(ap.arg::<wint_t>())
+            }
+
+            (FmtKind::Char, _)
+            | (FmtKind::Unsigned, IntKind::Byte)
+            | (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(ap.arg::<c_char>()),
+            (FmtKind::Unsigned, IntKind::Short) | (FmtKind::Signed, IntKind::Short) => {
+                VaArg::c_short(ap.arg::<c_short>())
+            }
+            (FmtKind::Unsigned, IntKind::Int) | (FmtKind::Signed, IntKind::Int) => {
+                VaArg::c_int(ap.arg::<c_int>())
+            }
+            (FmtKind::Unsigned, IntKind::Long) | (FmtKind::Signed, IntKind::Long) => {
+                VaArg::c_long(ap.arg::<c_long>())
+            }
+            (FmtKind::Unsigned, IntKind::LongLong) | (FmtKind::Signed, IntKind::LongLong) => {
+                VaArg::c_longlong(ap.arg::<c_longlong>())
+            }
+            (FmtKind::Unsigned, IntKind::IntMax) | (FmtKind::Signed, IntKind::IntMax) => {
+                VaArg::intmax_t(ap.arg::<intmax_t>())
+            }
+            (FmtKind::Unsigned, IntKind::PtrDiff) | (FmtKind::Signed, IntKind::PtrDiff) => {
+                VaArg::ptrdiff_t(ap.arg::<ptrdiff_t>())
+            }
+            (FmtKind::Unsigned, IntKind::Size) | (FmtKind::Signed, IntKind::Size) => {
+                VaArg::ssize_t(ap.arg::<ssize_t>())
+            }
+
+            (FmtKind::AnyNotation, _) | (FmtKind::Decimal, _) | (FmtKind::Scientific, _) => {
+                VaArg::c_double(ap.arg::<c_double>())
+            }
+
+            (FmtKind::GetWritten, _) | (FmtKind::Pointer, _) | (FmtKind::String, _) => {
+                VaArg::pointer(ap.arg::<*const c_void>())
+            }
+        }
+    }
+    unsafe fn transmute(&self, fmtkind: FmtKind, intkind: IntKind) -> VaArg {
+        // At this point, there are conflicting printf arguments. An
+        // example of this is:
+        // ```c
+        // printf("%1$d %1$lf\n", 5, 0.1);
+        // ```
+        // We handle it just like glibc: We read it from the VaList
+        // using the *last* argument type, but we transmute it when we
+        // try to access the other ones.
+        union Untyped {
+            c_char: c_char,
+            c_double: c_double,
+            c_int: c_int,
+            c_long: c_long,
+            c_longlong: c_longlong,
+            c_short: c_short,
+            intmax_t: intmax_t,
+            pointer: *const c_void,
+            ptrdiff_t: ptrdiff_t,
+            ssize_t: ssize_t,
+            wint_t: wint_t,
+        }
+        let untyped = match *self {
+            VaArg::c_char(i) => Untyped { c_char: i },
+            VaArg::c_double(i) => Untyped { c_double: i },
+            VaArg::c_int(i) => Untyped { c_int: i },
+            VaArg::c_long(i) => Untyped { c_long: i },
+            VaArg::c_longlong(i) => Untyped { c_longlong: i },
+            VaArg::c_short(i) => Untyped { c_short: i },
+            VaArg::intmax_t(i) => Untyped { intmax_t: i },
+            VaArg::pointer(i) => Untyped { pointer: i },
+            VaArg::ptrdiff_t(i) => Untyped { ptrdiff_t: i },
+            VaArg::ssize_t(i) => Untyped { ssize_t: i },
+            VaArg::wint_t(i) => Untyped { wint_t: i },
+        };
+        match (fmtkind, intkind) {
+            (FmtKind::Percent, _) => panic!("Can't call transmute on %"),
+
+            (FmtKind::Char, IntKind::Long) | (FmtKind::Char, IntKind::LongLong) => {
+                VaArg::wint_t(untyped.wint_t)
+            }
+
+            (FmtKind::Char, _)
+            | (FmtKind::Unsigned, IntKind::Byte)
+            | (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(untyped.c_char),
+            (FmtKind::Unsigned, IntKind::Short) | (FmtKind::Signed, IntKind::Short) => {
+                VaArg::c_short(untyped.c_short)
+            }
+            (FmtKind::Unsigned, IntKind::Int) | (FmtKind::Signed, IntKind::Int) => {
+                VaArg::c_int(untyped.c_int)
+            }
+            (FmtKind::Unsigned, IntKind::Long) | (FmtKind::Signed, IntKind::Long) => {
+                VaArg::c_long(untyped.c_long)
+            }
+            (FmtKind::Unsigned, IntKind::LongLong) | (FmtKind::Signed, IntKind::LongLong) => {
+                VaArg::c_longlong(untyped.c_longlong)
+            }
+            (FmtKind::Unsigned, IntKind::IntMax) | (FmtKind::Signed, IntKind::IntMax) => {
+                VaArg::intmax_t(untyped.intmax_t)
+            }
+            (FmtKind::Unsigned, IntKind::PtrDiff) | (FmtKind::Signed, IntKind::PtrDiff) => {
+                VaArg::ptrdiff_t(untyped.ptrdiff_t)
+            }
+            (FmtKind::Unsigned, IntKind::Size) | (FmtKind::Signed, IntKind::Size) => {
+                VaArg::ssize_t(untyped.ssize_t)
+            }
+
+            (FmtKind::AnyNotation, _) | (FmtKind::Decimal, _) | (FmtKind::Scientific, _) => {
+                VaArg::c_double(untyped.c_double)
+            }
+
+            (FmtKind::GetWritten, _) | (FmtKind::Pointer, _) | (FmtKind::String, _) => {
+                VaArg::pointer(untyped.pointer)
+            }
+        }
+    }
+}
+#[derive(Default)]
+struct VaListCache {
+    args: Vec<VaArg>,
+    i: usize,
+}
+impl VaListCache {
+    unsafe fn get(
+        &mut self,
+        i: usize,
+        ap: &mut VaList,
+        default: Option<(FmtKind, IntKind)>,
+    ) -> VaArg {
+        if let Some(&arg) = self.args.get(i) {
+            // This value is already cached
+            let mut arg = arg;
+            if let Some((fmtkind, intkind)) = default {
+                // ...but as a different type
+                arg = arg.transmute(fmtkind, intkind);
+            }
+            return arg;
+        }
+
+        // Get all values before this value
+        while self.args.len() < i {
+            // We can't POSSIBLY know the type if we reach this
+            // point. Reaching here means there are unused gaps in the
+            // arguments. Ultimately we'll have to settle down with
+            // defaulting to c_int.
+            self.args.push(VaArg::c_int(ap.arg::<c_int>()))
+        }
+
+        // Add the value to the cache
+        self.args.push(match default {
+            Some((fmtkind, intkind)) => VaArg::arg_from(fmtkind, intkind, ap),
+            None => VaArg::c_int(ap.arg::<c_int>()),
+        });
+
+        // Return the value
+        self.args[i]
+    }
+}
+
+//  ___                 _                           _        _   _
+// |_ _|_ __ ___  _ __ | | ___ _ __ ___   ___ _ __ | |_ __ _| |_(_) ___  _ __  _
+//  | || '_ ` _ \| '_ \| |/ _ \ '_ ` _ \ / _ \ '_ \| __/ _` | __| |/ _ \| '_ \(_)
+//  | || | | | | | |_) | |  __/ | | | | |  __/ | | | || (_| | |_| | (_) | | | |_
+// |___|_| |_| |_| .__/|_|\___|_| |_| |_|\___|_| |_|\__\__,_|\__|_|\___/|_| |_(_)
+//               |_|
+
+enum FmtCase {
+    Lower,
+    Upper,
+}
+
+// The spelled-out "infinity"/"INFINITY" is also permitted by the standard
+static INF_STR_LOWER: &str = "inf";
+static INF_STR_UPPER: &str = "INF";
+
+static NAN_STR_LOWER: &str = "nan";
+static NAN_STR_UPPER: &str = "NAN";
+
+unsafe fn pop_int_raw(format: &mut *const u8) -> Option<usize> {
+    let mut int = None;
+    while let Some(digit) = (**format as char).to_digit(10) {
+        *format = format.add(1);
+        if int.is_none() {
+            int = Some(0);
+        }
+        *int.as_mut().unwrap() *= 10;
+        *int.as_mut().unwrap() += digit as usize;
+    }
+    int
+}
+unsafe fn pop_index(format: &mut *const u8) -> Option<usize> {
+    // Peek ahead for a positional argument:
+    let mut format2 = *format;
+    if let Some(i) = pop_int_raw(&mut format2) {
+        if *format2 == b'$' {
+            *format = format2.add(1);
+            return Some(i);
+        }
+    }
+    None
+}
+unsafe fn pop_int(format: &mut *const u8) -> Option<Number> {
+    if **format == b'*' {
+        *format = format.add(1);
+        Some(pop_index(format).map(Number::Index).unwrap_or(Number::Next))
+    } else {
+        pop_int_raw(format).map(Number::Static)
+    }
+}
+
+unsafe fn fmt_int<I>(fmt: u8, i: I) -> String
+where
+    I: fmt::Display + fmt::Octal + fmt::LowerHex + fmt::UpperHex,
+{
+    match fmt {
+        b'o' => format!("{:o}", i),
+        b'u' => i.to_string(),
+        b'x' => format!("{:x}", i),
+        b'X' => format!("{:X}", i),
+        _ => panic!(
+            "fmt_int should never be called with the fmt {:?}",
+            fmt as char
+        ),
+    }
+}
+
+fn pad<W: Write>(
+    w: &mut W,
+    current_side: bool,
+    pad_char: u8,
+    range: Range<usize>,
+) -> io::Result<()> {
+    if current_side {
+        for _ in range {
+            w.write_all(&[pad_char])?;
+        }
+    }
+    Ok(())
+}
+
+fn abs(float: c_double) -> c_double {
+    // Don't ask me whe float.abs() seems absent...
+    if float.is_sign_negative() {
+        -float
+    } else {
+        float
+    }
+}
+
+fn float_string(float: c_double, precision: usize, trim: bool) -> String {
+    let mut string = format!("{:.p$}", float, p = precision);
+    if trim && string.contains('.') {
+        let truncate = {
+            let slice = string.trim_end_matches('0');
+            let mut truncate = slice.len();
+            if slice.ends_with('.') {
+                truncate -= 1;
+            }
+            truncate
+        };
+        string.truncate(truncate);
+    }
+    string
+}
+
+fn float_exp(mut float: c_double) -> (c_double, isize) {
+    let mut exp: isize = 0;
+    while abs(float) >= 10.0 {
+        float /= 10.0;
+        exp += 1;
+    }
+    while f64::EPSILON < abs(float) && abs(float) < 1.0 {
+        float *= 10.0;
+        exp -= 1;
+    }
+    (float, exp)
+}
+
+fn fmt_float_exp<W: Write>(
+    w: &mut W,
+    exp_fmt: u8,
+    trim: bool,
+    precision: usize,
+    float: c_double,
+    exp: isize,
+    left: bool,
+    pad_space: usize,
+    pad_zero: usize,
+) -> io::Result<()> {
+    let mut exp2 = exp;
+    let mut exp_len = 1;
+    while exp2 >= 10 {
+        exp2 /= 10;
+        exp_len += 1;
+    }
+
+    let string = float_string(float, precision, trim);
+    let len = string.len() + 2 + 2.max(exp_len);
+
+    pad(w, !left, b' ', len..pad_space)?;
+    let bytes = if string.starts_with('-') {
+        w.write_all(&[b'-'])?;
+        &string.as_bytes()[1..]
+    } else {
+        string.as_bytes()
+    };
+    pad(w, !left, b'0', len..pad_zero)?;
+    w.write_all(bytes)?;
+    write!(w, "{}{:+03}", exp_fmt as char, exp)?;
+    pad(w, left, b' ', len..pad_space)?;
+
+    Ok(())
+}
+
+fn fmt_float_normal<W: Write>(
+    w: &mut W,
+    trim: bool,
+    precision: usize,
+    float: c_double,
+    left: bool,
+    pad_space: usize,
+    pad_zero: usize,
+) -> io::Result<usize> {
+    let string = float_string(float, precision, trim);
+
+    pad(w, !left, b' ', string.len()..pad_space)?;
+    let bytes = if string.starts_with('-') {
+        w.write_all(&[b'-'])?;
+        &string.as_bytes()[1..]
+    } else {
+        string.as_bytes()
+    };
+    pad(w, true, b'0', string.len()..pad_zero)?;
+    w.write_all(bytes)?;
+    pad(w, left, b' ', string.len()..pad_space)?;
+
+    Ok(string.len())
+}
+
+/// Write ±infinity or ±NaN representation for any floating-point style
+fn fmt_float_nonfinite<W: Write>(w: &mut W, float: c_double, case: FmtCase) -> io::Result<()> {
+    if float.is_sign_negative() {
+        w.write_all(&[b'-'])?;
+    }
+
+    let nonfinite_str = match float.classify() {
+        FpCategory::Infinite => match case {
+            FmtCase::Lower => INF_STR_LOWER,
+            FmtCase::Upper => INF_STR_UPPER,
+        },
+        FpCategory::Nan => match case {
+            FmtCase::Lower => NAN_STR_LOWER,
+            FmtCase::Upper => NAN_STR_UPPER,
+        },
+        _ => {
+            // This function should only be called with infinite or NaN value.
+            panic!("this should not be possible")
+        }
+    };
+
+    w.write_all(nonfinite_str.as_bytes())?;
+
+    Ok(())
+}
+
+#[derive(Clone, Copy)]
+struct PrintfIter {
+    format: *const u8,
+}
+#[derive(Clone, Copy, Debug)]
+struct PrintfArg {
+    index: Option<usize>,
+    alternate: bool,
+    zero: bool,
+    left: bool,
+    sign_reserve: bool,
+    sign_always: bool,
+    min_width: Number,
+    precision: Option<Number>,
+    intkind: IntKind,
+    fmt: u8,
+    fmtkind: FmtKind,
+}
+#[derive(Debug)]
+enum PrintfFmt {
+    Plain(&'static [u8]),
+    Arg(PrintfArg),
+}
+impl Iterator for PrintfIter {
+    type Item = Result<PrintfFmt, ()>;
+    fn next(&mut self) -> Option<Self::Item> {
+        unsafe {
+            // Send PrintfFmt::Plain until the next %
+            let mut len = 0;
+            while *self.format.add(len) != 0 && *self.format.add(len) != b'%' {
+                len += 1;
+            }
+            if len > 0 {
+                let slice = slice::from_raw_parts(self.format as *const u8, len);
+                self.format = self.format.add(len);
+                return Some(Ok(PrintfFmt::Plain(slice)));
+            }
+            self.format = self.format.add(len);
+            if *self.format == 0 {
+                return None;
+            }
+
+            // *self.format is guaranteed to be '%' at this point
+            self.format = self.format.add(1);
+
+            let mut peekahead = self.format;
+            let index = pop_index(&mut peekahead).map(|i| {
+                self.format = peekahead;
+                i
+            });
+
+            // Flags:
+            let mut alternate = false;
+            let mut zero = false;
+            let mut left = false;
+            let mut sign_reserve = false;
+            let mut sign_always = false;
+
+            loop {
+                match *self.format {
+                    b'#' => alternate = true,
+                    b'0' => zero = true,
+                    b'-' => left = true,
+                    b' ' => sign_reserve = true,
+                    b'+' => sign_always = true,
+                    _ => break,
+                }
+                self.format = self.format.add(1);
+            }
+
+            // Width and precision:
+            let min_width = pop_int(&mut self.format).unwrap_or(Number::Static(0));
+            let precision = if *self.format == b'.' {
+                self.format = self.format.add(1);
+                match pop_int(&mut self.format) {
+                    int @ Some(_) => int,
+                    None => return Some(Err(())),
+                }
+            } else {
+                None
+            };
+
+            // Integer size:
+            let mut intkind = IntKind::Int;
+            loop {
+                intkind = match *self.format {
+                    b'h' => {
+                        if intkind == IntKind::Short || intkind == IntKind::Byte {
+                            IntKind::Byte
+                        } else {
+                            IntKind::Short
+                        }
+                    }
+                    b'j' => IntKind::IntMax,
+                    b'l' => {
+                        if intkind == IntKind::Long || intkind == IntKind::LongLong {
+                            IntKind::LongLong
+                        } else {
+                            IntKind::Long
+                        }
+                    }
+                    b'q' | b'L' => IntKind::LongLong,
+                    b't' => IntKind::PtrDiff,
+                    b'z' => IntKind::Size,
+                    _ => break,
+                };
+
+                self.format = self.format.add(1);
+            }
+            let fmt = *self.format;
+            let fmtkind = match fmt {
+                b'%' => FmtKind::Percent,
+                b'd' | b'i' => FmtKind::Signed,
+                b'o' | b'u' | b'x' | b'X' => FmtKind::Unsigned,
+                b'e' | b'E' => FmtKind::Scientific,
+                b'f' | b'F' => FmtKind::Decimal,
+                b'g' | b'G' => FmtKind::AnyNotation,
+                b's' => FmtKind::String,
+                b'c' => FmtKind::Char,
+                b'p' => FmtKind::Pointer,
+                b'n' => FmtKind::GetWritten,
+                _ => return Some(Err(())),
+            };
+            self.format = self.format.add(1);
+
+            Some(Ok(PrintfFmt::Arg(PrintfArg {
+                index,
+                alternate,
+                zero,
+                left,
+                sign_reserve,
+                sign_always,
+                min_width,
+                precision,
+                intkind,
+                fmt,
+                fmtkind,
+            })))
+        }
+    }
+}
+
+unsafe fn inner_printf<W: Write>(w: W, format: *const c_char, mut ap: VaList) -> io::Result<c_int> {
+    let w = &mut platform::CountingWriter::new(w);
+
+    let iterator = PrintfIter {
+        format: format as *const u8,
+    };
+
+    // Pre-fetch vararg types
+    let mut varargs = VaListCache::default();
+    let mut positional = BTreeMap::new();
+    // ^ NOTE: This depends on the sorted order, do not change to HashMap or whatever
+
+    for section in iterator {
+        let arg = match section {
+            Ok(PrintfFmt::Plain(text)) => continue,
+            Ok(PrintfFmt::Arg(arg)) => arg,
+            Err(()) => return Ok(-1),
+        };
+        if arg.fmtkind == FmtKind::Percent {
+            continue;
+        }
+        for num in &[arg.min_width, arg.precision.unwrap_or(Number::Static(0))] {
+            match num {
+                Number::Next => varargs.args.push(VaArg::c_int(ap.arg::<c_int>())),
+                Number::Index(i) => {
+                    positional.insert(i - 1, (FmtKind::Signed, IntKind::Int));
+                }
+                Number::Static(_) => (),
+            }
+        }
+        match arg.index {
+            Some(i) => {
+                positional.insert(i - 1, (arg.fmtkind, arg.intkind));
+            }
+            None => varargs
+                .args
+                .push(VaArg::arg_from(arg.fmtkind, arg.intkind, &mut ap)),
+        }
+    }
+
+    // Make sure, in order, the positional arguments exist with the specified type
+    for (i, arg) in positional {
+        varargs.get(i, &mut ap, Some(arg));
+    }
+
+    // Main loop
+    for section in iterator {
+        let arg = match section {
+            Ok(PrintfFmt::Plain(text)) => {
+                w.write_all(text)?;
+                continue;
+            }
+            Ok(PrintfFmt::Arg(arg)) => arg,
+            Err(()) => return Ok(-1),
+        };
+        let alternate = arg.alternate;
+        let zero = arg.zero;
+        let mut left = arg.left;
+        let sign_reserve = arg.sign_reserve;
+        let sign_always = arg.sign_always;
+        let min_width = arg.min_width.resolve(&mut varargs, &mut ap);
+        let precision = arg.precision.map(|n| n.resolve(&mut varargs, &mut ap));
+        let pad_zero = if zero { min_width } else { 0 };
+        let signed_space = match pad_zero {
+            0 => min_width as isize,
+            _ => 0,
+        };
+        let pad_space = if signed_space < 0 {
+            left = true;
+            -signed_space as usize
+        } else {
+            signed_space as usize
+        };
+        let intkind = arg.intkind;
+        let fmt = arg.fmt;
+        let fmtkind = arg.fmtkind;
+        let fmtcase = match fmt {
+            b'x' | b'f' | b'e' | b'g' => Some(FmtCase::Lower),
+            b'X' | b'F' | b'E' | b'G' => Some(FmtCase::Upper),
+            _ => None,
+        };
+
+        let index = arg.index.map(|i| i - 1).unwrap_or_else(|| {
+            if fmtkind == FmtKind::Percent {
+                0
+            } else {
+                let i = varargs.i;
+                varargs.i += 1;
+                i
+            }
+        });
+
+        match fmtkind {
+            FmtKind::Percent => w.write_all(&[b'%'])?,
+            FmtKind::Signed => {
+                let string = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
+                    VaArg::c_char(i) => i.to_string(),
+                    VaArg::c_double(i) => panic!("this should not be possible"),
+                    VaArg::c_int(i) => i.to_string(),
+                    VaArg::c_long(i) => i.to_string(),
+                    VaArg::c_longlong(i) => i.to_string(),
+                    VaArg::c_short(i) => i.to_string(),
+                    VaArg::intmax_t(i) => i.to_string(),
+                    VaArg::pointer(i) => (i as usize).to_string(),
+                    VaArg::ptrdiff_t(i) => i.to_string(),
+                    VaArg::ssize_t(i) => i.to_string(),
+                    VaArg::wint_t(_) => unreachable!("this should not be possible"),
+                };
+                let positive = !string.starts_with('-');
+                let zero = precision == Some(0) && string == "0";
+
+                let mut len = string.len();
+                let mut final_len = string.len().max(precision.unwrap_or(0));
+                if positive && (sign_reserve || sign_always) {
+                    final_len += 1;
+                }
+                if zero {
+                    len = 0;
+                    final_len = 0;
+                }
+
+                pad(w, !left, b' ', final_len..pad_space)?;
+
+                let bytes = if positive {
+                    if sign_reserve {
+                        w.write_all(&[b' '])?;
+                    } else if sign_always {
+                        w.write_all(&[b'+'])?;
+                    }
+                    string.as_bytes()
+                } else {
+                    w.write_all(&[b'-'])?;
+                    &string.as_bytes()[1..]
+                };
+                pad(w, true, b'0', len..precision.unwrap_or(pad_zero))?;
+
+                if !zero {
+                    w.write_all(bytes)?;
+                }
+
+                pad(w, left, b' ', final_len..pad_space)?;
+            }
+            FmtKind::Unsigned => {
+                let string = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
+                    VaArg::c_char(i) => fmt_int(fmt, i as c_uchar),
+                    VaArg::c_double(i) => panic!("this should not be possible"),
+                    VaArg::c_int(i) => fmt_int(fmt, i as c_uint),
+                    VaArg::c_long(i) => fmt_int(fmt, i as c_ulong),
+                    VaArg::c_longlong(i) => fmt_int(fmt, i as c_ulonglong),
+                    VaArg::c_short(i) => fmt_int(fmt, i as c_ushort),
+                    VaArg::intmax_t(i) => fmt_int(fmt, i as uintmax_t),
+                    VaArg::pointer(i) => fmt_int(fmt, i as usize),
+                    VaArg::ptrdiff_t(i) => fmt_int(fmt, i as size_t),
+                    VaArg::ssize_t(i) => fmt_int(fmt, i as size_t),
+                    VaArg::wint_t(_) => unreachable!("this should not be possible"),
+                };
+                let zero = precision == Some(0) && string == "0";
+
+                // If this int is padded out to be larger than it is, don't
+                // add an extra zero if octal.
+                let no_precision = precision.map(|pad| pad < string.len()).unwrap_or(true);
+
+                let len;
+                let final_len = if zero {
+                    len = 0;
+                    0
+                } else {
+                    len = string.len();
+                    len.max(precision.unwrap_or(0))
+                        + if alternate && string != "0" {
+                            match fmt {
+                                b'o' if no_precision => 1,
+                                b'x' | b'X' => 2,
+                                _ => 0,
+                            }
+                        } else {
+                            0
+                        }
+                };
+
+                pad(w, !left, b' ', final_len..pad_space)?;
+
+                if alternate && string != "0" {
+                    match fmt {
+                        b'o' if no_precision => w.write_all(&[b'0'])?,
+                        b'x' => w.write_all(&[b'0', b'x'])?,
+                        b'X' => w.write_all(&[b'0', b'X'])?,
+                        _ => (),
+                    }
+                }
+                pad(w, true, b'0', len..precision.unwrap_or(pad_zero))?;
+
+                if !zero {
+                    w.write_all(string.as_bytes())?;
+                }
+
+                pad(w, left, b' ', final_len..pad_space)?;
+            }
+            FmtKind::Scientific => {
+                let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
+                    VaArg::c_double(i) => i,
+                    _ => panic!("this should not be possible"),
+                };
+                if float.is_finite() {
+                    let (float, exp) = float_exp(float);
+                    let precision = precision.unwrap_or(6);
+
+                    fmt_float_exp(
+                        w, fmt, false, precision, float, exp, left, pad_space, pad_zero,
+                    )?;
+                } else {
+                    fmt_float_nonfinite(w, float, fmtcase.unwrap())?;
+                }
+            }
+            FmtKind::Decimal => {
+                let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
+                    VaArg::c_double(i) => i,
+                    _ => panic!("this should not be possible"),
+                };
+                if float.is_finite() {
+                    let precision = precision.unwrap_or(6);
+
+                    fmt_float_normal(w, false, precision, float, left, pad_space, pad_zero)?;
+                } else {
+                    fmt_float_nonfinite(w, float, fmtcase.unwrap())?;
+                }
+            }
+            FmtKind::AnyNotation => {
+                let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
+                    VaArg::c_double(i) => i,
+                    _ => panic!("this should not be possible"),
+                };
+                if float.is_finite() {
+                    let (log, exp) = float_exp(float);
+                    let exp_fmt = b'E' | (fmt & 32);
+                    let precision = precision.unwrap_or(6);
+                    let use_exp_format = exp < -4 || exp >= precision as isize;
+
+                    if use_exp_format {
+                        // Length of integral part will always be 1 here,
+                        // because that's how x/floor(log10(x)) works
+                        let precision = precision.saturating_sub(1);
+                        fmt_float_exp(
+                            w, exp_fmt, true, precision, log, exp, left, pad_space, pad_zero,
+                        )?;
+                    } else {
+                        // Length of integral part will be the exponent of
+                        // the unused logarithm, unless the exponent is
+                        // negative which in case the integral part must
+                        // of course be 0, 1 in length
+                        let len = 1 + cmp::max(0, exp) as usize;
+                        let precision = precision.saturating_sub(len);
+                        fmt_float_normal(w, true, precision, float, left, pad_space, pad_zero)?;
+                    }
+                } else {
+                    fmt_float_nonfinite(w, float, fmtcase.unwrap())?;
+                }
+            }
+            FmtKind::String => {
+                let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
+                    VaArg::pointer(p) => p,
+                    _ => panic!("this should not be possible"),
+                } as *const c_char;
+
+                if ptr.is_null() {
+                    w.write_all(b"(null)")?;
+                } else {
+                    let max = precision.unwrap_or(::core::usize::MAX);
+
+                    if intkind == IntKind::Long || intkind == IntKind::LongLong {
+                        // Handle wchar_t
+                        let mut ptr = ptr as *const wchar_t;
+                        let mut string = String::new();
+
+                        while *ptr != 0 {
+                            let c = match char::from_u32(*ptr as _) {
+                                Some(c) => c,
+                                None => {
+                                    platform::errno = EILSEQ;
+                                    return Err(io::last_os_error());
+                                }
+                            };
+                            if string.len() + c.len_utf8() >= max {
+                                break;
+                            }
+                            string.push(c);
+                            ptr = ptr.add(1);
+                        }
+
+                        pad(w, !left, b' ', string.len()..pad_space)?;
+                        w.write_all(string.as_bytes())?;
+                        pad(w, left, b' ', string.len()..pad_space)?;
+                    } else {
+                        let mut len = 0;
+                        while *ptr.add(len) != 0 && len < max {
+                            len += 1;
+                        }
+
+                        pad(w, !left, b' ', len..pad_space)?;
+                        w.write_all(slice::from_raw_parts(ptr as *const u8, len))?;
+                        pad(w, left, b' ', len..pad_space)?;
+                    }
+                }
+            }
+            FmtKind::Char => match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
+                VaArg::c_char(c) => {
+                    pad(w, !left, b' ', 1..pad_space)?;
+                    w.write_all(&[c as u8])?;
+                    pad(w, left, b' ', 1..pad_space)?;
+                }
+                VaArg::wint_t(c) => {
+                    let c = match char::from_u32(c as _) {
+                        Some(c) => c,
+                        None => {
+                            platform::errno = EILSEQ;
+                            return Err(io::last_os_error());
+                        }
+                    };
+                    let mut buf = [0; 4];
+
+                    pad(w, !left, b' ', 1..pad_space)?;
+                    w.write_all(c.encode_utf8(&mut buf).as_bytes())?;
+                    pad(w, left, b' ', 1..pad_space)?;
+                }
+                _ => unreachable!("this should not be possible"),
+            },
+            FmtKind::Pointer => {
+                let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
+                    VaArg::pointer(p) => p,
+                    _ => panic!("this should not be possible"),
+                };
+
+                let mut len = 1;
+                if ptr.is_null() {
+                    len = "(nil)".len();
+                } else {
+                    let mut ptr = ptr as usize;
+                    while ptr >= 10 {
+                        ptr /= 10;
+                        len += 1;
+                    }
+                }
+
+                pad(w, !left, b' ', len..pad_space)?;
+                if ptr.is_null() {
+                    write!(w, "(nil)")?;
+                } else {
+                    write!(w, "0x{:x}", ptr as usize)?;
+                }
+                pad(w, left, b' ', len..pad_space)?;
+            }
+            FmtKind::GetWritten => {
+                let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
+                    VaArg::pointer(p) => p,
+                    _ => panic!("this should not be possible"),
+                };
+
+                match intkind {
+                    IntKind::Byte => *(ptr as *mut c_char) = w.written as c_char,
+                    IntKind::Short => *(ptr as *mut c_short) = w.written as c_short,
+                    IntKind::Int => *(ptr as *mut c_int) = w.written as c_int,
+                    IntKind::Long => *(ptr as *mut c_long) = w.written as c_long,
+                    IntKind::LongLong => *(ptr as *mut c_longlong) = w.written as c_longlong,
+                    IntKind::IntMax => *(ptr as *mut intmax_t) = w.written as intmax_t,
+                    IntKind::PtrDiff => *(ptr as *mut ptrdiff_t) = w.written as ptrdiff_t,
+                    IntKind::Size => *(ptr as *mut size_t) = w.written as size_t,
+                }
+            }
+        }
+    }
+    Ok(w.written as c_int)
+}
+
+pub unsafe fn printf<W: Write>(w: W, format: *const c_char, ap: VaList) -> c_int {
+    inner_printf(w, format, ap).unwrap_or(-1)
+}

+ 463 - 0
src/header/stdio/scanf.rs

@@ -0,0 +1,463 @@
+use super::lookaheadreader::LookAheadReader;
+use crate::platform::types::*;
+use alloc::{string::String, vec::Vec};
+use core::ffi::VaList as va_list;
+
+#[derive(PartialEq, Eq)]
+enum IntKind {
+    Byte,
+    Short,
+    Int,
+    Long,
+    LongLong,
+    IntMax,
+    PtrDiff,
+    Size,
+}
+
+/// Helper function for progressing a C string
+unsafe fn next_byte(string: &mut *const c_char) -> Result<u8, c_int> {
+    let c = **string as u8;
+    *string = string.offset(1);
+    if c == 0 {
+        Err(-1)
+    } else {
+        Ok(c)
+    }
+}
+
+unsafe fn inner_scanf(
+    mut r: LookAheadReader,
+    mut format: *const c_char,
+    mut ap: va_list,
+) -> Result<c_int, c_int> {
+    let mut matched = 0;
+    let mut byte = 0;
+    let mut skip_read = false;
+    let mut count = 0;
+
+    macro_rules! read {
+        () => {{
+            match r.lookahead1() {
+                Ok(None) => false,
+                Ok(Some(b)) => {
+                    byte = b;
+                    count += 1;
+                    true
+                }
+                Err(x) => return Err(x),
+            }
+        }};
+    }
+
+    macro_rules! maybe_read {
+        () => {
+            maybe_read!(inner false);
+        };
+        (noreset) => {
+            maybe_read!(inner);
+        };
+        (inner $($placeholder:expr)*) => {
+            if !skip_read && !read!() {
+                match matched {
+                    0 => return Ok(-1),
+                    a => return Ok(a),
+                }
+            }
+            $(else {
+                // Hacky way of having this optional
+                skip_read = $placeholder;
+            })*
+        }
+    }
+
+    while *format != 0 {
+        let mut c = next_byte(&mut format)?;
+
+        if c == b' ' {
+            maybe_read!(noreset);
+
+            while (byte as char).is_whitespace() {
+                if !read!() {
+                    return Ok(matched);
+                }
+            }
+
+            skip_read = true;
+        } else if c != b'%' {
+            maybe_read!();
+            if c != byte {
+                return Ok(matched);
+            }
+            r.commit();
+        } else {
+            c = next_byte(&mut format)?;
+
+            let mut ignore = false;
+            if c == b'*' {
+                ignore = true;
+                c = next_byte(&mut format)?;
+            }
+
+            let mut width = String::new();
+            while c >= b'0' && c <= b'9' {
+                width.push(c as char);
+                c = next_byte(&mut format)?;
+            }
+            let mut width = if width.is_empty() {
+                None
+            } else {
+                match width.parse::<usize>() {
+                    Ok(n) => Some(n),
+                    Err(_) => return Err(-1),
+                }
+            };
+
+            // When an EOF occurs, eof is set, stuff is marked matched
+            // as usual, and finally it is returned
+            let mut eof = false;
+
+            let mut kind = IntKind::Int;
+            loop {
+                kind = match c {
+                    b'h' => {
+                        if kind == IntKind::Short || kind == IntKind::Byte {
+                            IntKind::Byte
+                        } else {
+                            IntKind::Short
+                        }
+                    }
+                    b'j' => IntKind::IntMax,
+                    b'l' => {
+                        if kind == IntKind::Long || kind == IntKind::LongLong {
+                            IntKind::LongLong
+                        } else {
+                            IntKind::Long
+                        }
+                    }
+                    b'q' | b'L' => IntKind::LongLong,
+                    b't' => IntKind::PtrDiff,
+                    b'z' => IntKind::Size,
+                    _ => break,
+                };
+
+                c = next_byte(&mut format)?;
+            }
+
+            if c != b'n' {
+                maybe_read!(noreset);
+            }
+            match c {
+                b'%' => {
+                    while (byte as char).is_whitespace() {
+                        if !read!() {
+                            return Ok(matched);
+                        }
+                    }
+
+                    if byte != b'%' {
+                        return Err(matched);
+                    } else if !read!() {
+                        return Ok(matched);
+                    }
+                }
+                b'd' | b'i' | b'o' | b'u' | b'x' | b'X' | b'f' | b'e' | b'g' | b'E' | b'a'
+                | b'p' => {
+                    while (byte as char).is_whitespace() {
+                        if !read!() {
+                            return Ok(matched);
+                        }
+                    }
+
+                    let pointer = c == b'p';
+                    // Pointers aren't automatic, but we do want to parse "0x"
+                    let auto = c == b'i' || pointer;
+                    let float = c == b'f' || c == b'e' || c == b'g' || c == b'E' || c == b'a';
+
+                    let mut radix = match c {
+                        b'o' => 8,
+                        b'x' | b'X' | b'p' => 16,
+                        _ => 10,
+                    };
+
+                    let mut n = String::new();
+                    let mut dot = false;
+
+                    while width.map(|w| w > 0).unwrap_or(true)
+                        && ((byte >= b'0' && byte <= b'7')
+                            || (radix >= 10 && (byte >= b'8' && byte <= b'9'))
+                            || (float && !dot && byte == b'.')
+                            || (radix == 16
+                                && ((byte >= b'a' && byte <= b'f')
+                                    || (byte >= b'A' && byte <= b'F'))))
+                    {
+                        if auto
+                            && n.is_empty()
+                            && byte == b'0'
+                            && width.map(|w| w > 0).unwrap_or(true)
+                        {
+                            if !pointer {
+                                radix = 8;
+                            }
+                            width = width.map(|w| w - 1);
+                            if !read!() {
+                                return Ok(matched);
+                            }
+                            if width.map(|w| w > 0).unwrap_or(true)
+                                && (byte == b'x' || byte == b'X')
+                            {
+                                radix = 16;
+                                width = width.map(|w| w - 1);
+                                if width.map(|w| w > 0).unwrap_or(true) && !read!() {
+                                    return Ok(matched);
+                                }
+                            }
+                            continue;
+                        }
+                        if byte == b'.' {
+                            // Don't allow another dot
+                            dot = true;
+                        }
+                        n.push(byte as char);
+                        r.commit();
+                        width = width.map(|w| w - 1);
+                        if width.map(|w| w > 0).unwrap_or(true) && !read!() {
+                            break;
+                        }
+                    }
+
+                    macro_rules! parse_type {
+                        (noformat $type:ident) => {{
+                            let n = if n.is_empty() {
+                                0 as $type
+                            } else {
+                                n.parse::<$type>().map_err(|_| 0)?
+                            };
+                            if !ignore {
+                                *ap.arg::<*mut $type>() = n;
+                                matched += 1;
+                            }
+                        }};
+                        (c_double) => {
+                            parse_type!(noformat c_double);
+                        };
+                        (c_float) => {
+                            parse_type!(noformat c_float);
+                        };
+                        ($type:ident) => {
+                            parse_type!($type, $type);
+                        };
+                        ($type:ident, $final:ty) => {{
+                            let n = if n.is_empty() {
+                                0 as $type
+                            } else {
+                                $type::from_str_radix(&n, radix).map_err(|_| 0)?
+                            };
+                            if !ignore {
+                                *ap.arg::<*mut $final>() = n as $final;
+                                matched += 1;
+                            }
+                        }};
+                    }
+
+                    if float {
+                        if kind == IntKind::Long || kind == IntKind::LongLong {
+                            parse_type!(c_double);
+                        } else {
+                            parse_type!(c_float);
+                        }
+                    } else if c == b'p' {
+                        parse_type!(size_t, *mut c_void);
+                    } else {
+                        let unsigned = c == b'o' || c == b'u' || c == b'x' || c == b'X';
+
+                        match kind {
+                            IntKind::Byte => {
+                                if unsigned {
+                                    parse_type!(c_uchar);
+                                } else {
+                                    parse_type!(c_char);
+                                }
+                            }
+                            IntKind::Short => {
+                                if unsigned {
+                                    parse_type!(c_ushort)
+                                } else {
+                                    parse_type!(c_short)
+                                }
+                            }
+                            IntKind::Int => {
+                                if unsigned {
+                                    parse_type!(c_uint)
+                                } else {
+                                    parse_type!(c_int)
+                                }
+                            }
+                            IntKind::Long => {
+                                if unsigned {
+                                    parse_type!(c_ulong)
+                                } else {
+                                    parse_type!(c_long)
+                                }
+                            }
+                            IntKind::LongLong => {
+                                if unsigned {
+                                    parse_type!(c_ulonglong)
+                                } else {
+                                    parse_type!(c_longlong)
+                                }
+                            }
+                            IntKind::IntMax => {
+                                if unsigned {
+                                    parse_type!(uintmax_t)
+                                } else {
+                                    parse_type!(intmax_t)
+                                }
+                            }
+                            IntKind::PtrDiff => parse_type!(ptrdiff_t),
+                            IntKind::Size => {
+                                if unsigned {
+                                    parse_type!(size_t)
+                                } else {
+                                    parse_type!(ssize_t)
+                                }
+                            }
+                        }
+                    }
+                }
+                b's' => {
+                    while (byte as char).is_whitespace() {
+                        if !read!() {
+                            return Ok(matched);
+                        }
+                    }
+
+                    let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.arg()) };
+
+                    while width.map(|w| w > 0).unwrap_or(true) && !(byte as char).is_whitespace() {
+                        if let Some(ref mut ptr) = ptr {
+                            **ptr = byte as c_char;
+                            *ptr = ptr.offset(1);
+                        }
+                        width = width.map(|w| w - 1);
+                        if width.map(|w| w > 0).unwrap_or(true) && !read!() {
+                            eof = true;
+                            break;
+                        }
+                    }
+
+                    if let Some(ptr) = ptr {
+                        *ptr = 0;
+                        matched += 1;
+                        r.commit();
+                    }
+                }
+                b'c' => {
+                    let ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.arg()) };
+
+                    for i in 0..width.unwrap_or(1) {
+                        if let Some(ptr) = ptr {
+                            *ptr.add(i) = byte as c_char;
+                        }
+                        width = width.map(|w| w - 1);
+                        if width.map(|w| w > 0).unwrap_or(true) && !read!() {
+                            eof = true;
+                            break;
+                        }
+                    }
+
+                    if ptr.is_some() {
+                        matched += 1;
+                        r.commit();
+                    }
+                }
+                b'[' => {
+                    c = next_byte(&mut format)?;
+
+                    let mut matches = Vec::new();
+                    let invert = if c == b'^' {
+                        c = next_byte(&mut format)?;
+                        true
+                    } else {
+                        false
+                    };
+
+                    let mut prev;
+                    loop {
+                        matches.push(c);
+                        prev = c;
+                        c = next_byte(&mut format)?;
+                        if c == b'-' {
+                            if prev == b']' {
+                                continue;
+                            }
+                            c = next_byte(&mut format)?;
+                            if c == b']' {
+                                matches.push(b'-');
+                                break;
+                            }
+                            prev += 1;
+                            while prev < c {
+                                matches.push(prev);
+                                prev += 1;
+                            }
+                        } else if c == b']' {
+                            break;
+                        }
+                    }
+
+                    let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.arg()) };
+
+                    // While we haven't used up all the width, and it matches
+                    let mut data_stored = false;
+                    while width.map(|w| w > 0).unwrap_or(true) && !invert == matches.contains(&byte)
+                    {
+                        if let Some(ref mut ptr) = ptr {
+                            **ptr = byte as c_char;
+                            *ptr = ptr.offset(1);
+                            data_stored = true;
+                        }
+                        r.commit();
+                        // Decrease the width, and read a new character unless the width is 0
+                        width = width.map(|w| w - 1);
+                        if width.map(|w| w > 0).unwrap_or(true) && !read!() {
+                            // Reading a new character has failed, return after
+                            // actually marking this as matched
+                            eof = true;
+                            break;
+                        }
+                    }
+
+                    if data_stored {
+                        *ptr.unwrap() = 0;
+                        matched += 1;
+                    }
+                }
+                b'n' => {
+                    if !ignore {
+                        *ap.arg::<*mut c_int>() = count as c_int;
+                    }
+                }
+                _ => return Err(-1),
+            }
+
+            if eof {
+                return Ok(matched);
+            }
+
+            if width != Some(0) && c != b'n' {
+                // It didn't hit the width, so an extra character was read and matched.
+                // But this character did not match so let's reuse it.
+                skip_read = true;
+            }
+        }
+    }
+    Ok(matched)
+}
+
+pub unsafe fn scanf(r: LookAheadReader, format: *const c_char, ap: va_list) -> c_int {
+    match inner_scanf(r, format, ap) {
+        Ok(n) => n,
+        Err(n) => n,
+    }
+}

+ 13 - 0
src/header/stdlib/cbindgen.toml

@@ -0,0 +1,13 @@
+sys_includes = ["stddef.h", "alloca.h"]
+include_guard = "_RELIBC_STDLIB_H"
+trailer = "#include <bits/stdlib.h>"
+language = "C"
+style = "Type"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true
+
+[fn]
+no_return = "__attribute__((noreturn))"

+ 1256 - 0
src/header/stdlib/mod.rs

@@ -0,0 +1,1256 @@
+//! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html
+
+use core::{convert::TryFrom, intrinsics, iter, mem, ptr, slice};
+use lazy_static::lazy_static;
+use rand::{
+    distributions::{Alphanumeric, Distribution, Uniform},
+    prng::XorShiftRng,
+    rngs::JitterRng,
+    Rng, SeedableRng,
+};
+
+use crate::{
+    fs::File,
+    header::{
+        ctype,
+        errno::{self, *},
+        fcntl::*,
+        limits,
+        stdio::flush_io_streams,
+        string::*,
+        time::constants::CLOCK_MONOTONIC,
+        unistd::{self, sysconf, _SC_PAGESIZE},
+        wchar::*,
+    },
+    ld_so,
+    platform::{self, types::*, Pal, Sys}, strto_float_impl, eprintln, c_str::CStr,
+};
+
+use crate::strto_impl;
+
+mod rand48;
+mod random;
+mod sort;
+
+pub const EXIT_FAILURE: c_int = 1;
+pub const EXIT_SUCCESS: c_int = 0;
+pub const RAND_MAX: c_int = 2_147_483_647;
+
+//Maximum number of bytes in a multibyte character for the current locale
+pub const MB_CUR_MAX: c_int = 4;
+//Maximum number of bytes in a multibyte characters for any locale
+pub const MB_LEN_MAX: c_int = 4;
+
+static mut ATEXIT_FUNCS: [Option<extern "C" fn()>; 32] = [None; 32];
+static mut L64A_BUFFER: [c_char; 7] = [0; 7]; // up to 6 digits plus null terminator
+static mut RNG: Option<XorShiftRng> = None;
+
+lazy_static!{static ref RNG_SAMPLER: Uniform<c_int> = Uniform::new_inclusive(0, RAND_MAX);}
+
+#[no_mangle]
+pub extern "C" fn _Exit(status: c_int) {
+    unistd::_exit(status);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn a64l(s: *const c_char) -> c_long {
+    // Early return upon null pointer argument
+    if s.is_null() {
+        return 0;
+    }
+
+    // POSIX says only the low-order 32 bits are used.
+    let mut l: i32 = 0;
+
+    // Handle up to 6 input characters (excl. null terminator)
+    for i in 0..6 {
+        let digit_char = *s.offset(i);
+
+        let digit_value = match digit_char {
+            0 => break, // Null terminator encountered
+            46..=57 => {
+                // ./0123456789 represents values 0 to 11. b'.' == 46
+                digit_char - 46
+            }
+            65..=90 => {
+                // A-Z for values 12 to 37. b'A' == 65, 65-12 == 53
+                digit_char - 53
+            }
+            97..=122 => {
+                // a-z for values 38 to 63. b'a' == 97, 97-38 == 59
+                digit_char - 59
+            }
+            _ => return 0, // Early return for anything else
+        };
+
+        l |= i32::from(digit_value) << 6 * i;
+    }
+
+    c_long::from(l)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn abort() -> ! {
+    eprintln!("Abort");
+    intrinsics::abort();
+}
+
+#[no_mangle]
+pub extern "C" fn abs(i: c_int) -> c_int {
+    i.abs()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void {
+    if size % alignment == 0 {
+        /* The size-is-multiple-of-alignment requirement is the only
+         * difference between aligned_alloc() and memalign(). */
+        memalign(alignment, size)
+    } else {
+        platform::errno = EINVAL;
+        ptr::null_mut()
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn atexit(func: Option<extern "C" fn()>) -> c_int {
+    for i in 0..ATEXIT_FUNCS.len() {
+        if ATEXIT_FUNCS[i] == None {
+            ATEXIT_FUNCS[i] = func;
+            return 0;
+        }
+    }
+
+    1
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn atof(s: *const c_char) -> c_double {
+    strtod(s, ptr::null_mut())
+}
+
+macro_rules! dec_num_from_ascii {
+    ($s:expr, $t:ty) => {
+        unsafe {
+            let mut s = $s;
+            // Iterate past whitespace
+            while ctype::isspace(*s as c_int) != 0 {
+                s = s.offset(1);
+            }
+
+            // Find out if there is a - sign
+            let neg_sign = match *s {
+                0x2d => {
+                    s = s.offset(1);
+                    true
+                }
+                // '+' increment s and continue parsing
+                0x2b => {
+                    s = s.offset(1);
+                    false
+                }
+                _ => false,
+            };
+
+            let mut n: $t = 0;
+            while ctype::isdigit(*s as c_int) != 0 {
+                n = 10 * n - (*s as $t - 0x30);
+                s = s.offset(1);
+            }
+
+            if neg_sign {
+                n
+            } else {
+                -n
+            }
+        }
+    };
+}
+
+#[no_mangle]
+pub extern "C" fn atoi(s: *const c_char) -> c_int {
+    dec_num_from_ascii!(s, c_int)
+}
+
+#[no_mangle]
+pub extern "C" fn atol(s: *const c_char) -> c_long {
+    dec_num_from_ascii!(s, c_long)
+}
+
+#[no_mangle]
+pub extern "C" fn atoll(s: *const c_char) -> c_longlong {
+    dec_num_from_ascii!(s, c_longlong)
+}
+
+unsafe extern "C" fn void_cmp(a: *const c_void, b: *const c_void) -> c_int {
+    *(a as *const i32) - *(b as *const i32) as c_int
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn bsearch(
+    key: *const c_void,
+    base: *const c_void,
+    nel: size_t,
+    width: size_t,
+    compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
+) -> *mut c_void {
+    let mut start = base;
+    let mut len = nel;
+    let cmp_fn = compar.unwrap_or(void_cmp);
+    while len > 0 {
+        let med = (start as size_t + (len >> 1) * width) as *const c_void;
+        let diff = cmp_fn(key, med);
+        if diff == 0 {
+            return med as *mut c_void;
+        } else if diff > 0 {
+            start = (med as usize + width) as *const c_void;
+            len -= 1;
+        }
+        len >>= 1;
+    }
+    ptr::null_mut()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn calloc(nelem: size_t, elsize: size_t) -> *mut c_void {
+    //Handle possible integer overflow in size calculation
+    match nelem.checked_mul(elsize) {
+        Some(size) => {
+            /* If allocation fails here, errno setting will be handled
+             * by malloc() */
+            let ptr = malloc(size);
+            if !ptr.is_null() {
+                intrinsics::write_bytes(ptr as *mut u8, 0, size);
+            }
+            ptr
+        }
+        None => {
+            // For overflowing multiplication, we have to set errno here
+            platform::errno = ENOMEM;
+            ptr::null_mut()
+        }
+    }
+}
+
+#[repr(C)]
+pub struct div_t {
+    quot: c_int,
+    rem: c_int,
+}
+
+#[no_mangle]
+pub extern "C" fn div(numer: c_int, denom: c_int) -> div_t {
+    div_t {
+        quot: numer / denom,
+        rem: numer % denom,
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn drand48() -> c_double {
+    let new_xsubi_value = rand48::generator_step(&mut rand48::DEFAULT_XSUBI);
+    rand48::f64_from_x(new_xsubi_value)
+}
+
+// #[no_mangle]
+pub extern "C" fn ecvt(
+    value: c_double,
+    ndigit: c_int,
+    decpt: *mut c_int,
+    sign: *mut c_int,
+) -> *mut c_char {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn erand48(xsubi: *mut c_ushort) -> c_double {
+    let new_xsubi_value = rand48::generator_step(&mut *(xsubi as *mut [c_ushort; 3]));
+    rand48::f64_from_x(new_xsubi_value)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn exit(status: c_int) {
+    extern "C" {
+        static __fini_array_start: extern "C" fn();
+        static __fini_array_end: extern "C" fn();
+
+        fn pthread_terminate();
+        fn _fini();
+    }
+
+    for i in (0..ATEXIT_FUNCS.len()).rev() {
+        if let Some(func) = ATEXIT_FUNCS[i] {
+            (func)();
+        }
+    }
+
+    // Look for the neighbor functions in memory until the end
+    let mut f = &__fini_array_end as *const _;
+    #[allow(clippy::op_ref)]
+    while f > &__fini_array_start {
+        f = f.offset(-1);
+        (*f)();
+    }
+
+    _fini();
+
+    ld_so::fini();
+
+    //pthread_terminate();
+
+    flush_io_streams();
+
+    Sys::exit(status);
+}
+
+// #[no_mangle]
+pub extern "C" fn fcvt(
+    value: c_double,
+    ndigit: c_int,
+    decpt: *mut c_int,
+    sign: *mut c_int,
+) -> *mut c_char {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn free(ptr: *mut c_void) {
+    platform::free(ptr);
+}
+
+// #[no_mangle]
+pub extern "C" fn gcvt(value: c_double, ndigit: c_int, buf: *mut c_char) -> *mut c_char {
+    unimplemented!();
+}
+
+unsafe fn find_env(search: *const c_char) -> Option<(usize, *mut c_char)> {
+    for (i, mut item) in platform::environ_iter().enumerate() {
+        let mut search = search;
+        loop {
+            let end_of_query = *search == 0 || *search == b'=' as c_char;
+            assert_ne!(*item, 0, "environ has an item without value");
+            if *item == b'=' as c_char || end_of_query {
+                if *item == b'=' as c_char && end_of_query {
+                    // Both keys env here
+                    return Some((i, item.add(1)));
+                } else {
+                    break;
+                }
+            }
+
+            if *item != *search {
+                break;
+            }
+
+            item = item.add(1);
+            search = search.add(1);
+        }
+    }
+
+    None
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn getenv(name: *const c_char) -> *mut c_char {
+    find_env(name).map(|val| val.1).unwrap_or(ptr::null_mut())
+}
+
+// #[no_mangle]
+pub extern "C" fn getsubopt(
+    optionp: *mut *mut c_char,
+    tokens: *const *mut c_char,
+    valuep: *mut *mut c_char,
+) -> c_int {
+    unimplemented!();
+}
+
+// #[no_mangle]
+pub extern "C" fn grantpt(fildes: c_int) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: size_t) -> *mut c_char {
+    // Ported from musl
+
+    if size < 8 {
+        ptr::null_mut()
+    } else {
+        // TODO: lock?
+        let old_state = random::save_state();
+        random::N = match size {
+            0..=7 => unreachable!(), // ensured above
+            8..=31 => 0,
+            32..=63 => 7,
+            64..=127 => 15,
+            128..=255 => 31,
+            _ => 63,
+        };
+
+        random::X_PTR = (state.cast::<[u8; 4]>()).offset(1);
+        random::seed(seed);
+        random::save_state();
+        // TODO: unlock?
+
+        old_state.cast::<_>()
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn jrand48(xsubi: *mut c_ushort) -> c_long {
+    let new_xsubi_value = rand48::generator_step(&mut *(xsubi as *mut [c_ushort; 3]));
+    rand48::i32_from_x(new_xsubi_value)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn l64a(value: c_long) -> *mut c_char {
+    // POSIX says we should only consider the lower 32 bits of value.
+    let value_as_i32 = value as i32;
+
+    /* If we pretend to extend the 32-bit value with 4 binary zeros, we
+     * would get a 36-bit integer. The number of base-64 digits to be
+     * left unused can then be found by taking the number of leading
+     * zeros, dividing by 6 and rounding down (i.e. using integer
+     * division). */
+    let num_output_digits = usize::try_from(6 - (value_as_i32.leading_zeros() + 4) / 6).unwrap();
+
+    // Reset buffer (and have null terminator in place for any result)
+    L64A_BUFFER = [0; 7];
+
+    for i in 0..num_output_digits {
+        // Conversion to c_char always succeeds for the range 0..=63
+        let digit_value = c_char::try_from((value_as_i32 >> 6 * i) & 63).unwrap();
+
+        L64A_BUFFER[i] = match digit_value {
+            0..=11 => {
+                // ./0123456789 for values 0 to 11. b'.' == 46
+                46 + digit_value
+            }
+            12..=37 => {
+                // A-Z for values 12 to 37. b'A' == 65, 65-12 == 53
+                53 + digit_value
+            }
+            38..=63 => {
+                // a-z for values 38 to 63. b'a' == 97, 97-38 == 59
+                59 + digit_value
+            }
+            _ => unreachable!(), // Guaranteed by taking "& 63" above
+        };
+    }
+
+    L64A_BUFFER.as_mut_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn labs(i: c_long) -> c_long {
+    i.abs()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lcong48(param: *mut c_ushort) {
+    // Set DEFAULT_XSUBI buffer from elements 0-2
+    let xsubi_value = rand48::u48_from_ushort_arr3(&*(param as *const [c_ushort; 3]));
+    rand48::DEFAULT_XSUBI = rand48::ushort_arr3_from_u48(xsubi_value);
+
+    // Set multiplier from elements 3-5
+    rand48::A = rand48::u48_from_ushort_arr3(&*(param.offset(3) as *const [c_ushort; 3]));
+
+    /* Set addend from element 6. Note that c_ushort may be more than 16
+     * bits, thus the cast. */
+    rand48::C = *param.offset(6) as u16;
+}
+
+#[repr(C)]
+pub struct ldiv_t {
+    quot: c_long,
+    rem: c_long,
+}
+
+#[no_mangle]
+pub extern "C" fn ldiv(numer: c_long, denom: c_long) -> ldiv_t {
+    ldiv_t {
+        quot: numer / denom,
+        rem: numer % denom,
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn llabs(i: c_longlong) -> c_longlong {
+    i.abs()
+}
+
+#[repr(C)]
+pub struct lldiv_t {
+    quot: c_longlong,
+    rem: c_longlong,
+}
+
+#[no_mangle]
+pub extern "C" fn lldiv(numer: c_longlong, denom: c_longlong) -> lldiv_t {
+    lldiv_t {
+        quot: numer / denom,
+        rem: numer % denom,
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lrand48() -> c_long {
+    let new_xsubi_value = rand48::generator_step(&mut rand48::DEFAULT_XSUBI);
+    rand48::u31_from_x(new_xsubi_value)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
+    let ptr = platform::alloc(size);
+    if ptr.is_null() {
+        platform::errno = ENOMEM;
+    }
+    ptr
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memalign(alignment: size_t, size: size_t) -> *mut c_void {
+    if alignment.is_power_of_two() {
+        let ptr = platform::alloc_align(size, alignment);
+        if ptr.is_null() {
+            platform::errno = ENOMEM;
+        }
+        ptr
+    } else {
+        platform::errno = EINVAL;
+        ptr::null_mut()
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mblen(s: *const c_char, n: size_t) -> c_int {
+    let mut wc: wchar_t = 0;
+    let mut state: mbstate_t = mbstate_t {};
+    let result: usize = mbrtowc(&mut wc, s, n, &mut state);
+
+    if result == -1isize as usize {
+        return -1;
+    }
+    if result == -2isize as usize {
+        return -1;
+    }
+
+    result as i32
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mbstowcs(pwcs: *mut wchar_t, mut s: *const c_char, n: size_t) -> size_t {
+    let mut state: mbstate_t = mbstate_t {};
+    mbsrtowcs(pwcs, &mut s, n, &mut state)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mbtowc(pwc: *mut wchar_t, s: *const c_char, n: size_t) -> c_int {
+    let mut state: mbstate_t = mbstate_t {};
+    mbrtowc(pwc, s, n, &mut state) as c_int
+}
+
+fn inner_mktemp<T, F>(name: *mut c_char, suffix_len: c_int, mut attempt: F) -> Option<T>
+where
+    F: FnMut() -> Option<T>,
+{
+    let len = unsafe { strlen(name) as c_int };
+
+    if len < 6 || suffix_len > len - 6 {
+        unsafe { platform::errno = errno::EINVAL };
+        return None;
+    }
+
+    for i in (len - suffix_len - 6)..(len - suffix_len) {
+        if unsafe { *name.offset(i as isize) } != b'X' as c_char {
+            unsafe { platform::errno = errno::EINVAL };
+            return None;
+        }
+    }
+
+    let mut rng = JitterRng::new_with_timer(get_nstime);
+    let _ = rng.test_timer();
+
+    for _ in 0..100 {
+        let char_iter = iter::repeat(())
+            .map(|()| rng.sample(Alphanumeric))
+            .take(6)
+            .enumerate();
+        unsafe {
+            for (i, c) in char_iter {
+                *name.offset((len as isize) - (suffix_len as isize) - (i as isize) - 1) =
+                    c as c_char
+            }
+        }
+
+        if let result @ Some(_) = attempt() {
+            return result;
+        }
+    }
+
+    unsafe { platform::errno = errno::EEXIST }
+
+    None
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mktemp(name: *mut c_char) -> *mut c_char {
+    if inner_mktemp(name, 0, || {
+        let name = CStr::from_ptr(name);
+        if Sys::access(name, 0) != 0 && platform::errno == ENOENT {
+            Some(())
+        } else {
+            None
+        }
+    })
+    .is_none()
+    {
+        *name = 0;
+    }
+    name
+}
+
+fn get_nstime() -> u64 {
+    let mut ts = mem::MaybeUninit::uninit();
+    Sys::clock_gettime(CLOCK_MONOTONIC, ts.as_mut_ptr());
+    unsafe { ts.assume_init() }.tv_nsec as u64
+}
+
+#[no_mangle]
+pub extern "C" fn mkostemps(name: *mut c_char, suffix_len: c_int, mut flags: c_int) -> c_int {
+    flags &= !O_ACCMODE;
+    flags |= O_RDWR | O_CREAT | O_EXCL;
+
+    inner_mktemp(name, suffix_len, || {
+        let name = unsafe { CStr::from_ptr(name) };
+        let fd = Sys::open(name, flags, 0o600);
+
+        if fd >= 0 {
+            Some(fd)
+        } else {
+            None
+        }
+    })
+    .unwrap_or(-1)
+}
+
+#[no_mangle]
+pub extern "C" fn mkstemp(name: *mut c_char) -> c_int {
+    mkostemps(name, 0, 0)
+}
+#[no_mangle]
+pub extern "C" fn mkostemp(name: *mut c_char, flags: c_int) -> c_int {
+    mkostemps(name, 0, flags)
+}
+#[no_mangle]
+pub extern "C" fn mkstemps(name: *mut c_char, suffix_len: c_int) -> c_int {
+    mkostemps(name, suffix_len, 0)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mrand48() -> c_long {
+    let new_xsubi_value = rand48::generator_step(&mut rand48::DEFAULT_XSUBI);
+    rand48::i32_from_x(new_xsubi_value)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn nrand48(xsubi: *mut c_ushort) -> c_long {
+    let new_xsubi_value = rand48::generator_step(&mut *(xsubi as *mut [c_ushort; 3]));
+    rand48::u31_from_x(new_xsubi_value)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn posix_memalign(
+    memptr: *mut *mut c_void,
+    alignment: size_t,
+    size: size_t,
+) -> c_int {
+    const VOID_PTR_SIZE: usize = mem::size_of::<*mut c_void>();
+
+    if alignment % VOID_PTR_SIZE == 0 && alignment.is_power_of_two() {
+        let ptr = platform::alloc_align(size, alignment);
+        *memptr = ptr;
+        if ptr.is_null() {
+            ENOMEM
+        } else {
+            0
+        }
+    } else {
+        *memptr = ptr::null_mut();
+        EINVAL
+    }
+}
+
+// #[no_mangle]
+pub extern "C" fn ptsname(fildes: c_int) -> *mut c_char {
+    unimplemented!();
+}
+
+unsafe fn put_new_env(insert: *mut c_char) {
+    // XXX: Another problem is that `environ` can be set to any pointer, which means there is a
+    // chance of a memory leak. But we can check if it was the same as before, like musl does.
+    if platform::environ == platform::OUR_ENVIRON.as_mut_ptr() {
+        *platform::OUR_ENVIRON.last_mut().unwrap() = insert;
+        platform::OUR_ENVIRON.push(core::ptr::null_mut());
+        // Likely a no-op but is needed due to Stacked Borrows.
+        platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
+    } else {
+        platform::OUR_ENVIRON.clear();
+        platform::OUR_ENVIRON.extend(platform::environ_iter());
+        platform::OUR_ENVIRON.push(insert);
+        platform::OUR_ENVIRON.push(core::ptr::null_mut());
+        platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn putenv(insert: *mut c_char) -> c_int {
+    assert_ne!(insert, ptr::null_mut(), "putenv(NULL)");
+    if let Some((i, _)) = find_env(insert) {
+        // XXX: The POSIX manual states that environment variables can be *set* via the `environ`
+        // global variable. While we can check if a pointer belongs to our allocator, or check
+        // `environ` against a vector which we control, it is likely not worth the effort.
+        platform::environ.add(i).write(insert);
+    } else {
+        put_new_env(insert);
+    }
+    0
+}
+
+#[no_mangle]
+pub extern "C" fn qsort(
+    base: *mut c_void,
+    nel: size_t,
+    width: size_t,
+    compar: Option<extern "C" fn(*const c_void, *const c_void) -> c_int>,
+) {
+    if let Some(comp) = compar {
+        // XXX: check width too?  not specified
+        if nel > 0 {
+            // XXX: maybe try to do mergesort/timsort first and fallback to introsort if memory
+            //      allocation fails?  not sure what is ideal
+            sort::introsort(base as *mut c_char, nel, width, comp);
+        }
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rand() -> c_int {
+    match RNG {
+        Some(ref mut rng) => RNG_SAMPLER.sample(rng),
+        None => {
+            let mut rng = XorShiftRng::from_seed([1; 16]);
+            let ret = RNG_SAMPLER.sample(&mut rng);
+            RNG = Some(rng);
+            ret
+        }
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rand_r(seed: *mut c_uint) -> c_int {
+    if seed.is_null() {
+        errno::EINVAL
+    } else {
+        // set the type explicitly so this will fail if the array size for XorShiftRng changes
+        let seed_arr: [u8; 16] = mem::transmute([*seed; 16 / mem::size_of::<c_uint>()]);
+
+        let mut rng = XorShiftRng::from_seed(seed_arr);
+        let ret = RNG_SAMPLER.sample(&mut rng);
+
+        *seed = ret as _;
+
+        ret
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn random() -> c_long {
+    // Ported from musl
+
+    let k: u32;
+    // TODO: lock?
+    random::ensure_x_ptr_init();
+
+    if random::N == 0 {
+        let x_old = u32::from_ne_bytes(*random::X_PTR);
+        let x_new = random::lcg31_step(x_old);
+        *random::X_PTR = x_new.to_ne_bytes();
+        k = x_new;
+    } else {
+        // The non-u32-aligned way of saying x[i] += x[j]...
+        let x_i_old = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::I)));
+        let x_j = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::J)));
+        let x_i_new = x_i_old.wrapping_add(x_j);
+        *random::X_PTR.add(usize::from(random::I)) = x_i_new.to_ne_bytes();
+
+        k = x_i_new >> 1;
+
+        random::I += 1;
+        if random::I == random::N {
+            random::I = 0;
+        }
+
+        random::J += 1;
+        if random::J == random::N {
+            random::J = 0;
+        }
+    }
+    // TODO: unlock?
+
+    /* Both branches of this function result in a "u31", which will
+     * always fit in a c_long. */
+    c_long::try_from(k).unwrap()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
+    let new_ptr = platform::realloc(ptr, size);
+    if new_ptr.is_null() {
+        platform::errno = ENOMEM;
+    }
+    new_ptr
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn reallocarray(ptr: *mut c_void, m: size_t, n: size_t) -> *mut c_void {
+    //Handle possible integer overflow in size calculation
+    match m.checked_mul(n) {
+        Some(size) => realloc(ptr, size),
+        None => {
+            // For overflowing multiplication, we have to set errno here
+            platform::errno = ENOMEM;
+            ptr::null_mut()
+        }
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn realpath(pathname: *const c_char, resolved: *mut c_char) -> *mut c_char {
+    let ptr = if resolved.is_null() {
+        malloc(limits::PATH_MAX) as *mut c_char
+    } else {
+        resolved
+    };
+
+    let out = slice::from_raw_parts_mut(ptr as *mut u8, limits::PATH_MAX);
+    {
+        let file = match File::open(&CStr::from_ptr(pathname), O_PATH | O_CLOEXEC) {
+            Ok(file) => file,
+            Err(_) => return ptr::null_mut(),
+        };
+
+        let len = out.len();
+        let read = Sys::fpath(*file, &mut out[..len - 1]);
+        if read < 0 {
+            return ptr::null_mut();
+        }
+        out[read as usize] = 0;
+    }
+
+    ptr
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn seed48(seed16v: *mut c_ushort) -> *mut c_ushort {
+    rand48::reset_a_and_c();
+
+    // Stash current DEFAULT_XSUBI value in SEED48_XSUBI
+    rand48::SEED48_XSUBI = rand48::DEFAULT_XSUBI;
+
+    // Set DEFAULT_XSUBI from the argument provided
+    let xsubi_value = rand48::u48_from_ushort_arr3(&*(seed16v as *const [c_ushort; 3]));
+    rand48::DEFAULT_XSUBI = rand48::ushort_arr3_from_u48(xsubi_value);
+
+    // Return the stashed value
+    rand48::SEED48_XSUBI.as_mut_ptr()
+}
+
+unsafe fn copy_kv(
+    existing: *mut c_char,
+    key: *const c_char,
+    value: *const c_char,
+    key_len: usize,
+    value_len: usize,
+) {
+    core::ptr::copy_nonoverlapping(key, existing, key_len);
+    core::ptr::write(existing.add(key_len), b'=' as c_char);
+    core::ptr::copy_nonoverlapping(value, existing.add(key_len + 1), value_len);
+    core::ptr::write(existing.add(key_len + 1 + value_len), 0);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn setenv(
+    key: *const c_char,
+    value: *const c_char,
+    overwrite: c_int,
+) -> c_int {
+    let key_len = strlen(key);
+    let value_len = strlen(value);
+
+    if let Some((i, existing)) = find_env(key) {
+        if overwrite == 0 {
+            return 0;
+        }
+
+        let existing_len = strlen(existing);
+
+        if existing_len >= value_len {
+            // Reuse existing element's allocation
+            core::ptr::copy_nonoverlapping(value, existing, value_len);
+            //TODO: fill to end with zeroes
+            core::ptr::write(existing.add(value_len), 0);
+        } else {
+            // Reuse platform::environ slot, but allocate a new pointer.
+            let ptr = platform::alloc(key_len as usize + 1 + value_len as usize + 1) as *mut c_char;
+            copy_kv(ptr, key, value, key_len, value_len);
+            platform::environ.add(i).write(ptr);
+        }
+    } else {
+        // Expand platform::environ and allocate a new pointer.
+        let ptr = platform::alloc(key_len as usize + 1 + value_len as usize + 1) as *mut c_char;
+        copy_kv(ptr, key, value, key_len, value_len);
+        put_new_env(ptr);
+    }
+
+    //platform::free(platform::inner_environ[index] as *mut c_void);
+
+    0
+}
+
+// #[no_mangle]
+pub extern "C" fn setkey(key: *const c_char) {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn setstate(state: *mut c_char) -> *mut c_char {
+    /* Ported from musl. The state parameter is no longer const in newer
+     * versions of POSIX. */
+
+    // TODO: lock?
+    let old_state = random::save_state();
+    random::load_state(state.cast::<_>());
+    // TODO: unlock?
+    old_state.cast::<_>()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn srand(seed: c_uint) {
+    RNG = Some(XorShiftRng::from_seed([seed as u8; 16]));
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn srand48(seedval: c_long) {
+    rand48::reset_a_and_c();
+
+    /* Set the high 32 bits of the 48-bit X_i value to the lower 32 bits
+     * of the input argument, and the lower 16 bits to 0x330e, as
+     * specified in POSIX. */
+    let xsubi_value = (u64::from(seedval as u32) << 16) | 0x330e;
+    rand48::DEFAULT_XSUBI = rand48::ushort_arr3_from_u48(xsubi_value);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn srandom(seed: c_uint) {
+    // Ported from musl
+
+    // TODO: lock?
+    random::seed(seed);
+    // TODO: unlock?
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double {
+    strto_float_impl!(c_double, s, endptr)
+}
+#[no_mangle]
+pub unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> c_float {
+    strto_float_impl!(c_float, s, endptr)
+}
+
+pub fn is_positive(ch: c_char) -> Option<(bool, isize)> {
+    match ch {
+        0 => None,
+        ch if ch == b'+' as c_char => Some((true, 1)),
+        ch if ch == b'-' as c_char => Some((false, 1)),
+        _ => Some((true, 0)),
+    }
+}
+
+pub unsafe fn detect_base(s: *const c_char) -> Option<(c_int, isize)> {
+    let first = *s as u8;
+    match first {
+        0 => None,
+        b'0' => {
+            let second = *s.offset(1) as u8;
+            if second == b'X' || second == b'x' {
+                Some((16, 2))
+            } else if second >= b'0' && second <= b'7' {
+                Some((8, 1))
+            } else {
+                // in this case, the prefix (0) is going to be the number
+                Some((8, 0))
+            }
+        }
+        _ => Some((10, 0)),
+    }
+}
+
+pub unsafe fn convert_octal(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
+    if *s != 0 && *s == b'0' as c_char {
+        if let Some((val, idx, overflow)) = convert_integer(s.offset(1), 8) {
+            Some((val, idx + 1, overflow))
+        } else {
+            // in case the prefix is not actually a prefix
+            Some((0, 1, false))
+        }
+    } else {
+        None
+    }
+}
+
+pub unsafe fn convert_hex(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
+    if (*s != 0 && *s == b'0' as c_char)
+        && (*s.offset(1) != 0 && (*s.offset(1) == b'x' as c_char || *s.offset(1) == b'X' as c_char))
+    {
+        convert_integer(s.offset(2), 16).map(|(val, idx, overflow)| (val, idx + 2, overflow))
+    } else {
+        convert_integer(s, 16).map(|(val, idx, overflow)| (val, idx, overflow))
+    }
+}
+
+pub unsafe fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize, bool)> {
+    // -1 means the character is invalid
+    #[rustfmt::skip]
+    const LOOKUP_TABLE: [c_long; 256] = [
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+         0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+        -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+        25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+        -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+        25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    ];
+
+    let mut num: c_ulong = 0;
+    let mut idx = 0;
+    let mut overflowed = false;
+
+    loop {
+        // `-1 as usize` is usize::MAX
+        // `-1 as u8 as usize` is u8::MAX
+        // It extends by the sign bit unless we cast it to unsigned first.
+        let val = LOOKUP_TABLE[*s.offset(idx) as u8 as usize];
+        if val == -1 || val as c_int >= base {
+            break;
+        } else {
+            if let Some(res) = num
+                .checked_mul(base as c_ulong)
+                .and_then(|num| num.checked_add(val as c_ulong))
+            {
+                num = res;
+            } else {
+                platform::errno = ERANGE;
+                num = c_ulong::max_value();
+                overflowed = true;
+            }
+
+            idx += 1;
+        }
+    }
+
+    if idx > 0 {
+        Some((num, idx, overflowed))
+    } else {
+        None
+    }
+}
+
+// #[no_mangle]
+// pub unsafe extern "C" fn strtoul(
+//     s: *const c_char,
+//     endptr: *mut *mut c_char,
+//     base: c_int,
+// ) -> c_ulong {
+//     strto_impl!(
+//         c_ulong,
+//         false,
+//         c_ulong::max_value(),
+//         c_ulong::min_value(),
+//         s,
+//         endptr,
+//         base
+//     )
+// }
+
+// #[no_mangle]
+// pub unsafe extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
+//     strto_impl!(
+//         c_long,
+//         true,
+//         c_long::max_value(),
+//         c_long::min_value(),
+//         s,
+//         endptr,
+//         base
+//     )
+// }
+
+// #[no_mangle]
+// pub unsafe extern "C" fn strtoull(
+//     s: *const c_char,
+//     endptr: *mut *mut c_char,
+//     base: c_int,
+// ) -> c_ulonglong {
+//     strto_impl!(
+//         c_ulonglong,
+//         false,
+//         c_ulonglong::max_value(),
+//         c_ulonglong::min_value(),
+//         s,
+//         endptr,
+//         base
+//     )
+// }
+
+// #[no_mangle]
+// pub unsafe extern "C" fn strtoll(
+//     s: *const c_char,
+//     endptr: *mut *mut c_char,
+//     base: c_int,
+// ) -> c_longlong {
+//     strto_impl!(
+//         c_longlong,
+//         true,
+//         c_longlong::max_value(),
+//         c_longlong::min_value(),
+//         s,
+//         endptr,
+//         base
+//     )
+// }
+
+#[no_mangle]
+pub unsafe extern "C" fn system(command: *const c_char) -> c_int {
+    //TODO: share code with popen
+
+    let child_pid = unistd::fork();
+    if child_pid == 0 {
+        let command_nonnull = if command.is_null() {
+            "exit 0\0".as_ptr()
+        } else {
+            command as *const u8
+        };
+
+        let shell = "/bin/sh\0".as_ptr();
+
+        let args = [
+            "sh\0".as_ptr(),
+            "-c\0".as_ptr(),
+            command_nonnull,
+            ptr::null(),
+        ];
+
+        unistd::execv(shell as *const c_char, args.as_ptr() as *const *mut c_char);
+
+        exit(127);
+
+        unreachable!();
+    } else if child_pid > 0 {
+        let mut wstatus = 0;
+        if Sys::waitpid(child_pid, &mut wstatus, 0) == !0 {
+            return -1;
+        }
+
+        wstatus
+    } else {
+        -1
+    }
+}
+
+// #[no_mangle]
+pub extern "C" fn ttyslot() -> c_int {
+    unimplemented!();
+}
+
+// #[no_mangle]
+pub extern "C" fn unlockpt(fildes: c_int) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn unsetenv(key: *const c_char) -> c_int {
+    if let Some((i, _)) = find_env(key) {
+        if platform::environ == platform::OUR_ENVIRON.as_mut_ptr() {
+            // No need to worry about updating the pointer, this does not
+            // reallocate in any way. And the final null is already shifted back.
+            platform::OUR_ENVIRON.remove(i);
+
+            // My UB paranoia.
+            platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
+        } else {
+            platform::OUR_ENVIRON.clear();
+            platform::OUR_ENVIRON.extend(
+                platform::environ_iter()
+                    .enumerate()
+                    .filter(|&(j, _)| j != i)
+                    .map(|(_, v)| v),
+            );
+            platform::OUR_ENVIRON.push(core::ptr::null_mut());
+            platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
+        }
+    }
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn valloc(size: size_t) -> *mut c_void {
+    /* sysconf(_SC_PAGESIZE) is a c_long and may in principle not
+     * convert correctly to a size_t. */
+    match size_t::try_from(sysconf(_SC_PAGESIZE)) {
+        Ok(page_size) => {
+            /* valloc() is not supposed to be able to set errno to
+             * EINVAL, hence no call to memalign(). */
+            let ptr = platform::alloc_align(size, page_size);
+            if ptr.is_null() {
+                platform::errno = ENOMEM;
+            }
+            ptr
+        }
+        Err(_) => {
+            // A corner case. No errno setting.
+            ptr::null_mut()
+        }
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn wcstombs(s: *mut c_char, mut pwcs: *const wchar_t, n: size_t) -> size_t {
+    let mut state: mbstate_t = mbstate_t {};
+    wcsrtombs(s, &mut pwcs, n, &mut state)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wctomb(s: *mut c_char, wc: wchar_t) -> c_int {
+    let mut state: mbstate_t = mbstate_t {};
+    let result: usize = wcrtomb(s, wc, &mut state);
+
+    if result == -1isize as usize {
+        return -1;
+    }
+    if result == -2isize as usize {
+        return -1;
+    }
+
+    result as c_int
+}

+ 90 - 0
src/header/stdlib/rand48.rs

@@ -0,0 +1,90 @@
+//! Helper functions for pseudorandom number generation using LCG, see https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/drand48.html
+
+use crate::platform::types::*;
+
+/* The default element buffer for the linear congruential generator's
+ * sequence. Implemented using a c_ushort array for consistency between
+ * the drand48()/lrand48()/mrand48() and erand48()/nrand48()/jrand48()
+ * functions, and with SEED48_XSUBI (see below). */
+pub static mut DEFAULT_XSUBI: [c_ushort; 3] = [0; 3];
+
+// Used by seed48() (returns a pointer to this array).
+pub static mut SEED48_XSUBI: [c_ushort; 3] = [0; 3];
+
+/* Multiplier and addend, which may be set through lcong48(). Default
+ * values as specified in POSIX. */
+const A_DEFAULT_VALUE: u64 = 0x5deece66d;
+const C_DEFAULT_VALUE: u16 = 0xb;
+
+pub static mut A: u64 = A_DEFAULT_VALUE;
+pub static mut C: u16 = C_DEFAULT_VALUE;
+
+/// Used by `srand48()` and `seed48()`.
+pub unsafe fn reset_a_and_c() {
+    A = A_DEFAULT_VALUE;
+    C = C_DEFAULT_VALUE;
+}
+
+/// Build a 48-bit integer from a size-3 array of unsigned short.
+///
+/// Pointers to c_ushort can be converted to &[c_ushort; 3] by taking
+/// &*(YOUR_C_USHORT_POINTER as *const [c_ushort; 3])
+///
+/// See also this cbindgen issue for why the stdlib functions can't just
+/// have an xsubi: *mut [c_ushort; 3] parameter:
+/// https://github.com/eqrion/cbindgen/issues/171
+pub fn u48_from_ushort_arr3(arr: &[c_ushort; 3]) -> u64 {
+    /* Cast via u16 to ensure we get only the lower 16 bits of each
+     * element, as specified by POSIX. */
+    u64::from(arr[0] as u16) | (u64::from(arr[1] as u16) << 16) | (u64::from(arr[2] as u16) << 32)
+}
+
+/// Make a size-3 array of unsigned short from a 48-bit integer.
+pub fn ushort_arr3_from_u48(value: u64) -> [c_ushort; 3] {
+    [
+        c_ushort::from(value as u16),
+        c_ushort::from((value >> 16) as u16),
+        c_ushort::from((value >> 32) as u16),
+    ]
+}
+
+/// Advances the buffer from the input argument to the next element in
+/// the linear congruential generator's sequence.
+///
+/// Modifies the passed argument in-place and returns the new value as a
+/// u64.
+pub unsafe fn generator_step(xsubi: &mut [c_ushort; 3]) -> u64 {
+    let old_xsubi_value: u64 = u48_from_ushort_arr3(xsubi);
+
+    /* The recurrence relation of the linear congruential generator,
+     * X_(n+1) = (a * X_n + c) % m,
+     * with m = 2**48. The multiplication and addition can overflow a
+     * u64, but we just let it wrap since we take mod 2**48 anyway. */
+    let new_xsubi_value: u64 =
+        A.wrapping_mul(old_xsubi_value).wrapping_add(u64::from(C)) & 0xffff_ffff_ffff;
+
+    *xsubi = ushort_arr3_from_u48(new_xsubi_value);
+    new_xsubi_value
+}
+
+/// Get a C `double` from a 48-bit integer (for `drand48()` and
+/// `erand48()`).
+pub fn f64_from_x(x: u64) -> c_double {
+    /* We set the exponent to 0, and the 48-bit integer is copied into the high
+     * 48 of the 52 significand bits. The value then lies in the range
+     * [1.0, 2.0), from which we simply subtract 1.0. */
+    f64::from_bits(0x3ff0_0000_0000_0000_u64 | (x << 4)) - 1.0
+}
+
+/// Get the high 31 bits of a 48-bit integer (for `lrand48()` and
+/// `nrand48()`).
+pub fn u31_from_x(x: u64) -> c_long {
+    (x >> 17) as c_long
+}
+
+/// Get the high 32 bits, signed, of a 48-bit integer (for `mrand48()`
+/// and `jrand48()`).
+pub fn i32_from_x(x: u64) -> c_long {
+    // Cast via i32 to ensure we get the sign correct
+    c_long::from((x >> 16) as i32)
+}

+ 97 - 0
src/header/stdlib/random.rs

@@ -0,0 +1,97 @@
+//! Helper functions for random() and friends, see https://pubs.opengroup.org/onlinepubs/7908799/xsh/initstate.html
+/* Ported from musl's implementation (src/prng/random.c). Does not
+ * currently implement locking, though. */
+
+use crate::platform::types::*;
+use core::{convert::TryFrom, ptr};
+
+#[rustfmt::skip]
+static mut X_INIT: [u32; 32] = [
+    0x00000000, 0x5851f42d, 0xc0b18ccf, 0xcbb5f646,
+    0xc7033129, 0x30705b04, 0x20fd5db4, 0x9a8b7f78,
+    0x502959d8, 0xab894868, 0x6c0356a7, 0x88cdb7ff,
+    0xb477d43f, 0x70a3a52b, 0xa8e4baf1, 0xfd8341fc,
+    0x8ae16fd9, 0x742d2f7a, 0x0d1f0796, 0x76035e09,
+    0x40f7702c, 0x6fa72ca5, 0xaaa84157, 0x58a0df74,
+    0xc74a0364, 0xae533cc4, 0x04185faf, 0x6de3b115,
+    0x0cab8628, 0xf043bfa4, 0x398150e9, 0x37521657,
+];
+
+/* N needs to accommodate values up to 63, corresponding to the maximum
+ * state array size of 256 bytes. I and J must be able to accommodate
+ * values less than or equal to N. */
+pub static mut N: u8 = 31;
+pub static mut I: u8 = 3;
+pub static mut J: u8 = 0;
+
+/* As such, random() and related functions work on u32 values, but POSIX
+ * allows the user to supply a custom state data array as a `char *`
+ * with no requirements on alignment. Thus, we must assume the worst in
+ * terms of alignment and convert back and forth from [u8; 4].
+ *
+ * Also, unlike in C, we can't take the address of the initializing
+ * array outside of a function. */
+pub static mut X_PTR: *mut [u8; 4] = ptr::null_mut();
+
+// To be called in any function that may read from X_PTR
+pub unsafe fn ensure_x_ptr_init() {
+    if X_PTR.is_null() {
+        let x_u32_ptr: *mut u32 = &mut X_INIT[1];
+        X_PTR = x_u32_ptr.cast::<[u8; 4]>();
+    }
+}
+
+pub fn lcg31_step(x: u32) -> u32 {
+    1103515245_u32.wrapping_mul(x).wrapping_add(12345_u32) & 0x7fffffff
+}
+
+pub fn lcg64_step(x: u64) -> u64 {
+    6364136223846793005_u64.wrapping_mul(x).wrapping_add(1_u64)
+}
+
+pub unsafe fn save_state() -> *mut [u8; 4] {
+    ensure_x_ptr_init();
+
+    let stash_value: u32 = (u32::from(N) << 16) | (u32::from(I) << 8) | u32::from(J);
+    *X_PTR.offset(-1) = stash_value.to_ne_bytes();
+    X_PTR.offset(-1)
+}
+
+pub unsafe fn load_state(state_ptr: *mut [u8; 4]) {
+    let stash_value = u32::from_ne_bytes(*state_ptr);
+    X_PTR = state_ptr.offset(1);
+
+    /* This calculation of N does not have a bit mask in the musl
+     * original, in principle resulting in a u16, but obtaining a value
+     * larger than 63 can probably be dismissed as pathological. */
+    N = u8::try_from((stash_value >> 16) & 0xff).unwrap();
+
+    // I and J calculations are straight from musl
+    I = u8::try_from((stash_value >> 8) & 0xff).unwrap();
+    J = u8::try_from(stash_value & 0xff).unwrap();
+}
+
+pub unsafe fn seed(seed: c_uint) {
+    ensure_x_ptr_init();
+
+    let mut s = seed as u64;
+
+    if N == 0 {
+        *X_PTR = (s as u32).to_ne_bytes();
+    } else {
+        I = if N == 31 || N == 7 { 3 } else { 1 };
+
+        J = 0;
+
+        for k in 0..usize::from(N) {
+            s = lcg64_step(s);
+
+            // Conversion will always succeed (value is a 32-bit right-
+            // shift of a 64-bit integer).
+            *X_PTR.add(k) = u32::try_from(s >> 32).unwrap().to_ne_bytes();
+        }
+
+        // ensure X contains at least one odd number
+        *X_PTR = (u32::from_ne_bytes(*X_PTR) | 1).to_ne_bytes();
+    }
+}

+ 242 - 0
src/header/stdlib/sort.rs

@@ -0,0 +1,242 @@
+use crate::platform::types::*;
+
+pub fn introsort(
+    base: *mut c_char,
+    nel: size_t,
+    width: size_t,
+    comp: extern "C" fn(*const c_void, *const c_void) -> c_int,
+) {
+    let maxdepth = 2 * log2(nel);
+    introsort_helper(base, nel, width, maxdepth, comp);
+}
+
+// NOTE: if num is 0, the result should be considered undefined
+fn log2(num: size_t) -> size_t {
+    const IS_32_BIT: bool = size_t::max_value() as u32 as size_t == size_t::max_value();
+
+    let max_bits = if IS_32_BIT {
+        31
+    } else {
+        // assuming we are 64-bit (this may or may not need to be updated in the future)
+        63
+    };
+
+    max_bits - num.to_le().leading_zeros() as size_t
+}
+
+fn introsort_helper(
+    mut base: *mut c_char,
+    mut nel: size_t,
+    width: size_t,
+    mut maxdepth: size_t,
+    comp: extern "C" fn(*const c_void, *const c_void) -> c_int,
+) {
+    const THRESHOLD: size_t = 8;
+
+    // this loop is a trick to save stack space because TCO is not a thing in Rustland
+    // basically, we just change the arguments and loop rather than recursing for the second call
+    // to introsort_helper()
+    loop {
+        if nel < THRESHOLD {
+            insertion_sort(base, nel, width, comp);
+            break;
+        } else if nel > 1 {
+            if maxdepth == 0 {
+                heapsort(base, nel, width, comp);
+                break;
+            } else {
+                let (left, right) = partition(base, nel, width, comp);
+                let right_base = unsafe { base.add((right + 1) * width) };
+                let right_nel = nel - (right + 1);
+                maxdepth -= 1;
+                if left < nel - right {
+                    introsort_helper(base, left, width, maxdepth, comp);
+                    base = right_base;
+                    nel = right_nel;
+                } else {
+                    introsort_helper(right_base, right_nel, width, maxdepth, comp);
+                    nel = left;
+                }
+            }
+        }
+    }
+}
+
+fn insertion_sort(
+    base: *mut c_char,
+    nel: size_t,
+    width: size_t,
+    comp: extern "C" fn(*const c_void, *const c_void) -> c_int,
+) {
+    for i in 0..nel {
+        for j in (0..i).rev() {
+            let current = unsafe { base.add(j * width) };
+            let prev = unsafe { base.add((j + 1) * width) };
+            if comp(current as *const c_void, prev as *const c_void) > 0 {
+                swap(current, prev, width);
+            } else {
+                break;
+            }
+        }
+    }
+}
+
+fn heapsort(
+    base: *mut c_char,
+    nel: size_t,
+    width: size_t,
+    comp: extern "C" fn(*const c_void, *const c_void) -> c_int,
+) {
+    heapify(base, nel, width, comp);
+
+    let mut end = nel - 1;
+    while end > 0 {
+        let end_ptr = unsafe { base.add(end * width) };
+        swap(end_ptr, base, width);
+        end -= 1;
+        heap_sift_down(base, 0, end, width, comp);
+    }
+}
+
+fn heapify(
+    base: *mut c_char,
+    nel: size_t,
+    width: size_t,
+    comp: extern "C" fn(*const c_void, *const c_void) -> c_int,
+) {
+    // we start at the last parent in the heap (the parent of the last child)
+    let last_parent = (nel - 2) / 2;
+
+    for start in (0..=last_parent).rev() {
+        heap_sift_down(base, start, nel - 1, width, comp);
+    }
+}
+
+fn heap_sift_down(
+    base: *mut c_char,
+    start: size_t,
+    end: size_t,
+    width: size_t,
+    comp: extern "C" fn(*const c_void, *const c_void) -> c_int,
+) {
+    // get the left child of the node at the given index
+    let left_child = |idx| 2 * idx + 1;
+
+    let mut root = start;
+
+    while left_child(root) <= end {
+        let child = left_child(root);
+        let mut swap_idx = root;
+
+        let root_ptr = unsafe { base.add(root * width) };
+        let mut swap_ptr = unsafe { base.add(swap_idx * width) };
+        let first_child_ptr = unsafe { base.add(child * width) };
+        let second_child_ptr = unsafe { base.add((child + 1) * width) };
+
+        if comp(swap_ptr as *const c_void, first_child_ptr as *const c_void) < 0 {
+            swap_idx = child;
+            swap_ptr = first_child_ptr;
+        }
+        if child < end && comp(swap_ptr as *const c_void, second_child_ptr as *const c_void) < 0 {
+            swap_idx = child + 1;
+            swap_ptr = second_child_ptr;
+        }
+
+        if swap_idx == root {
+            break;
+        } else {
+            swap(root_ptr, swap_ptr, width);
+            root = swap_idx;
+        }
+    }
+}
+
+#[inline]
+fn partition(
+    base: *mut c_char,
+    nel: size_t,
+    width: size_t,
+    comp: extern "C" fn(*const c_void, *const c_void) -> c_int,
+) -> (size_t, size_t) {
+    // calculate the median of the first, middle, and last elements and use it as the pivot
+    // to do fewer comparisons, also swap the elements into their correct positions
+    let mut pivot = median_of_three(base, nel, width, comp);
+
+    let mut i = 1;
+    let mut j = 1;
+    let mut n = nel - 2;
+
+    // use this to deal with the Dutch national flag problem
+    while j <= n {
+        let i_ptr = unsafe { base.add(i * width) };
+        let j_ptr = unsafe { base.add(j * width) };
+        let n_ptr = unsafe { base.add(n * width) };
+        let pivot_ptr = unsafe { base.add(pivot * width) };
+
+        let comparison = comp(j_ptr as *const c_void, pivot_ptr as *const c_void);
+        if comparison < 0 {
+            swap(i_ptr, j_ptr, width);
+            if i == pivot {
+                pivot = j;
+            }
+            i += 1;
+            j += 1;
+        } else if comparison > 0 {
+            swap(j_ptr, n_ptr, width);
+            if n == pivot {
+                pivot = j;
+            }
+            n -= 1;
+        } else {
+            j += 1;
+        }
+    }
+
+    (i, n)
+}
+
+fn median_of_three(
+    base: *mut c_char,
+    nel: size_t,
+    width: size_t,
+    comp: extern "C" fn(*const c_void, *const c_void) -> c_int,
+) -> size_t {
+    let pivot = nel / 2;
+
+    let mid = unsafe { base.add(pivot * width) };
+    let last = unsafe { base.add((nel - 1) * width) };
+    if comp(mid as *const c_void, base as *const c_void) < 0 {
+        swap(mid, base, width);
+    }
+    if comp(last as *const c_void, mid as *const c_void) < 0 {
+        swap(mid, last, width);
+        if comp(mid as *const c_void, base as *const c_void) < 0 {
+            swap(mid, base, width);
+        }
+    }
+
+    pivot
+}
+
+#[inline]
+fn swap(mut ptr1: *mut c_char, mut ptr2: *mut c_char, mut width: size_t) {
+    use core::mem;
+
+    const BUFSIZE: usize = 128;
+
+    let mut buffer = mem::MaybeUninit::<[c_char; BUFSIZE]>::uninit();
+    while width > 0 {
+        let copy_size = BUFSIZE.min(width as usize);
+        let buf = buffer.as_mut_ptr() as *mut c_char;
+
+        unsafe {
+            buf.copy_from_nonoverlapping(ptr1, copy_size);
+            ptr1.copy_from_nonoverlapping(ptr2, copy_size);
+            ptr2.copy_from_nonoverlapping(buf, copy_size);
+
+            ptr1 = ptr1.add(copy_size);
+            ptr2 = ptr2.add(copy_size);
+        }
+        width -= copy_size as size_t;
+    }
+}

+ 9 - 0
src/header/string/cbindgen.toml

@@ -0,0 +1,9 @@
+sys_includes = ["stddef.h", "stdint.h", "strings.h"]
+include_guard = "_RELIBC_STRING_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 485 - 0
src/header/string/mod.rs

@@ -0,0 +1,485 @@
+//! string implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html
+
+use core::{mem, ptr, slice, usize};
+
+use cbitset::BitSet256;
+
+use crate::{
+    header::{errno::*, signal},
+    platform::{self, types::*},
+};
+
+#[no_mangle]
+pub unsafe extern "C" fn memccpy(
+    dest: *mut c_void,
+    src: *const c_void,
+    c: c_int,
+    n: size_t,
+) -> *mut c_void {
+    let to = memchr(src, c, n);
+    if to.is_null() {
+        return to;
+    }
+    let dist = (to as usize) - (src as usize);
+    if memcpy(dest, src, dist).is_null() {
+        return ptr::null_mut();
+    }
+    (dest as *mut u8).add(dist + 1) as *mut c_void
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memchr(
+    haystack: *const c_void,
+    needle: c_int,
+    len: size_t,
+) -> *mut c_void {
+    let haystack = slice::from_raw_parts(haystack as *const u8, len as usize);
+
+    match memchr::memchr(needle as u8, haystack) {
+        Some(index) => haystack[index..].as_ptr() as *mut c_void,
+        None => ptr::null_mut(),
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: size_t) -> c_int {
+    let (div, rem) = (n / mem::size_of::<usize>(), n % mem::size_of::<usize>());
+    let mut a = s1 as *const usize;
+    let mut b = s2 as *const usize;
+    for _ in 0..div {
+        if *a != *b {
+            for i in 0..mem::size_of::<usize>() {
+                let c = *(a as *const u8).add(i);
+                let d = *(b as *const u8).add(i);
+                if c != d {
+                    return c as c_int - d as c_int;
+                }
+            }
+            unreachable!()
+        }
+        a = a.offset(1);
+        b = b.offset(1);
+    }
+
+    let mut a = a as *const u8;
+    let mut b = b as *const u8;
+    for _ in 0..rem {
+        if *a != *b {
+            return *a as c_int - *b as c_int;
+        }
+        a = a.offset(1);
+        b = b.offset(1);
+    }
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memcpy(s1: *mut c_void, s2: *const c_void, n: size_t) -> *mut c_void {
+    let mut i = 0;
+    while i + 7 < n {
+        *(s1.add(i) as *mut u64) = *(s2.add(i) as *const u64);
+        i += 8;
+    }
+    while i < n {
+        *(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i);
+        i += 1;
+    }
+    s1
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memmove(s1: *mut c_void, s2: *const c_void, n: size_t) -> *mut c_void {
+    if s2 < s1 as *const c_void {
+        // copy from end
+        let mut i = n;
+        while i != 0 {
+            i -= 1;
+            *(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i);
+        }
+    } else {
+        // copy from beginning
+        let mut i = 0;
+        while i < n {
+            *(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i);
+            i += 1;
+        }
+    }
+    s1
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memrchr(
+    haystack: *const c_void,
+    needle: c_int,
+    len: size_t,
+) -> *mut c_void {
+    let haystack = slice::from_raw_parts(haystack as *const u8, len as usize);
+
+    match memchr::memrchr(needle as u8, haystack) {
+        Some(index) => haystack[index..].as_ptr() as *mut c_void,
+        None => ptr::null_mut(),
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: size_t) -> *mut c_void {
+    for i in 0..n {
+        *(s as *mut u8).add(i) = c as u8;
+    }
+    s
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char {
+    let c = c as c_char;
+    while *s != 0 {
+        if *s == c {
+            return s as *mut c_char;
+        }
+        s = s.offset(1);
+    }
+    ptr::null_mut()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int {
+    strncmp(s1, s2, usize::MAX)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int {
+    // relibc has no locale stuff (yet)
+    strcmp(s1, s2)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
+    let mut i = 0;
+
+    loop {
+        let byte = *src.offset(i);
+        *dst.offset(i) = byte;
+
+        if byte == 0 {
+            break;
+        }
+
+        i += 1;
+    }
+
+    dst
+}
+
+pub unsafe fn inner_strspn(s1: *const c_char, s2: *const c_char, cmp: bool) -> size_t {
+    let mut s1 = s1 as *const u8;
+    let mut s2 = s2 as *const u8;
+
+    // The below logic is effectively ripped from the musl implementation. It
+    // works by placing each byte as it's own bit in an array of numbers. Each
+    // number can hold up to 8 * mem::size_of::<usize>() bits. We need 256 bits
+    // in total, to fit one byte.
+
+    let mut set = BitSet256::new();
+
+    while *s2 != 0 {
+        set.insert(*s2 as usize);
+        s2 = s2.offset(1);
+    }
+
+    let mut i = 0;
+    while *s1 != 0 {
+        if set.contains(*s1 as usize) != cmp {
+            break;
+        }
+        i += 1;
+        s1 = s1.offset(1);
+    }
+    i
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strcspn(s1: *const c_char, s2: *const c_char) -> size_t {
+    inner_strspn(s1, s2, false)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char {
+    strndup(s1, usize::MAX)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strndup(s1: *const c_char, size: size_t) -> *mut c_char {
+    let len = strnlen(s1, size);
+
+    // the "+ 1" is to account for the NUL byte
+    let buffer = platform::alloc(len + 1) as *mut c_char;
+    if buffer.is_null() {
+        platform::errno = ENOMEM as c_int;
+    } else {
+        //memcpy(buffer, s1, len)
+        for i in 0..len {
+            *buffer.add(i) = *s1.add(i);
+        }
+        *buffer.add(len) = 0;
+    }
+
+    buffer
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
+    use core::fmt::Write;
+
+    static mut strerror_buf: [u8; 256] = [0; 256];
+
+    let mut w = platform::StringWriter(strerror_buf.as_mut_ptr(), strerror_buf.len());
+
+    if errnum >= 0 && errnum < STR_ERROR.len() as c_int {
+        let _ = w.write_str(STR_ERROR[errnum as usize]);
+    } else {
+        let _ = w.write_fmt(format_args!("Unknown error {}", errnum));
+    }
+
+    strerror_buf.as_mut_ptr() as *mut c_char
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
+    let msg = strerror(errnum);
+    let len = strlen(msg);
+
+    if len >= buflen {
+        if buflen != 0 {
+            memcpy(buf as *mut c_void, msg as *const c_void, buflen - 1);
+            *buf.add(buflen - 1) = 0;
+        }
+        return ERANGE as c_int;
+    }
+    memcpy(buf as *mut c_void, msg as *const c_void, len + 1);
+
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t {
+    strnlen(s, usize::MAX)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strnlen(s: *const c_char, size: size_t) -> size_t {
+    let mut i = 0;
+    while i < size {
+        if *s.add(i) == 0 {
+            break;
+        }
+        i += 1;
+    }
+    i as size_t
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strnlen_s(s: *const c_char, size: size_t) -> size_t {
+    if s.is_null() {
+        0
+    } else {
+        strnlen(s, size)
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
+    strncat(s1, s2, usize::MAX)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: size_t) -> *mut c_char {
+    let len = strlen(s1 as *const c_char);
+    let mut i = 0;
+    while i < n {
+        let b = *s2.add(i);
+        if b == 0 {
+            break;
+        }
+
+        *s1.add(len + i) = b;
+        i += 1;
+    }
+    *s1.add(len + i) = 0;
+
+    s1
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int {
+    let s1 = core::slice::from_raw_parts(s1 as *const c_uchar, n);
+    let s2 = core::slice::from_raw_parts(s2 as *const c_uchar, n);
+
+    for (&a, &b) in s1.iter().zip(s2.iter()) {
+        let val = (a as c_int) - (b as c_int);
+        if a != b || a == 0 {
+            return val;
+        }
+    }
+
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char {
+    let mut i = 0;
+
+    while *src.add(i) != 0 && i < n {
+        *dst.add(i) = *src.add(i);
+        i += 1;
+    }
+
+    for i in i..n {
+        *dst.add(i) = 0;
+    }
+
+    dst
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strpbrk(s1: *const c_char, s2: *const c_char) -> *mut c_char {
+    let p = s1.add(strcspn(s1, s2));
+    if *p != 0 {
+        p as *mut c_char
+    } else {
+        ptr::null_mut()
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strrchr(s: *const c_char, c: c_int) -> *mut c_char {
+    let len = strlen(s) as isize;
+    let c = c as i8;
+    let mut i = len - 1;
+    while i >= 0 {
+        if *s.offset(i) == c {
+            return s.offset(i) as *mut c_char;
+        }
+        i -= 1;
+    }
+    ptr::null_mut()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strsignal(sig: c_int) -> *const c_char {
+    signal::_signal_strings
+        .get(sig as usize)
+        .unwrap_or(&signal::_signal_strings[0]) // Unknown signal message
+        .as_ptr() as *const c_char
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strspn(s1: *const c_char, s2: *const c_char) -> size_t {
+    inner_strspn(s1, s2, true)
+}
+
+unsafe fn inner_strstr(
+    mut haystack: *const c_char,
+    needle: *const c_char,
+    mask: c_char,
+) -> *mut c_char {
+    while *haystack != 0 {
+        let mut i = 0;
+        loop {
+            if *needle.offset(i) == 0 {
+                // We reached the end of the needle, everything matches this far
+                return haystack as *mut c_char;
+            }
+            if *haystack.offset(i) & mask != *needle.offset(i) & mask {
+                break;
+            }
+
+            i += 1;
+        }
+
+        haystack = haystack.offset(1);
+    }
+    ptr::null_mut()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strstr(haystack: *const c_char, needle: *const c_char) -> *mut c_char {
+    inner_strstr(haystack, needle, !0)
+}
+#[no_mangle]
+pub unsafe extern "C" fn strcasestr(haystack: *const c_char, needle: *const c_char) -> *mut c_char {
+    inner_strstr(haystack, needle, !32)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strtok(s1: *mut c_char, delimiter: *const c_char) -> *mut c_char {
+    static mut HAYSTACK: *mut c_char = ptr::null_mut();
+    strtok_r(s1, delimiter, &mut HAYSTACK)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strtok_r(
+    s: *mut c_char,
+    delimiter: *const c_char,
+    lasts: *mut *mut c_char,
+) -> *mut c_char {
+    // Loosely based on GLIBC implementation
+    let mut haystack = s;
+    if haystack.is_null() {
+        if (*lasts).is_null() {
+            return ptr::null_mut();
+        }
+        haystack = *lasts;
+    }
+
+    // Skip past any extra delimiter left over from previous call
+    haystack = haystack.add(strspn(haystack, delimiter));
+    if *haystack == 0 {
+        *lasts = ptr::null_mut();
+        return ptr::null_mut();
+    }
+
+    // Build token by injecting null byte into delimiter
+    let token = haystack;
+    haystack = strpbrk(token, delimiter);
+    if !haystack.is_null() {
+        haystack.write(0);
+        haystack = haystack.add(1);
+        *lasts = haystack;
+    } else {
+        *lasts = ptr::null_mut();
+    }
+
+    token
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strxfrm(s1: *mut c_char, s2: *const c_char, n: size_t) -> size_t {
+    // relibc has no locale stuff (yet)
+    let len = strlen(s2);
+    if len < n {
+        strcpy(s1, s2);
+    }
+    len
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strlcpy(dst: *mut c_char, src: *const c_char, n: size_t) -> size_t {
+    let mut i = 0;
+
+    while *src.add(i) != 0 && i < n {
+        *dst.add(i) = *src.add(i);
+        i += 1;
+    }
+
+    *dst.add(i) = 0;
+
+    i as size_t
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strlcat(dst: *mut c_char, src: *const c_char, n: size_t) -> size_t {
+    let len = strlen(dst) as isize;
+    let mut d = dst.offset(len);
+
+    strlcpy(d, src, n)
+}

+ 8 - 0
src/header/sys_auxv/cbindgen.toml

@@ -0,0 +1,8 @@
+include_guard = "_SYS_AUXV_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 10 - 0
src/header/sys_auxv/mod.rs

@@ -0,0 +1,10 @@
+//! sys/auxv.h implementation
+
+use crate::platform::types::*;
+
+pub use crate::platform::auxv_defs::*;
+
+#[no_mangle]
+pub extern "C" fn getauxval(_t: c_ulong) -> c_ulong {
+    0
+}

+ 16 - 0
src/header/sys_ioctl/cbindgen.toml

@@ -0,0 +1,16 @@
+include_guard = "_SYS_IOCTL_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[defines]
+"target_os=linux" = "__linux__"
+"target_os=redox" = "__redox__"
+"target_os=dragonos" = "__dragonos__"
+
+[enum]
+prefix_with_name = true
+
+[export]
+include = ["sgttyb", "winsize"]

+ 197 - 0
src/header/sys_ioctl/dragonos.rs

@@ -0,0 +1,197 @@
+use crate::platform::{types::*, Sys};
+
+#[no_mangle]
+pub unsafe extern "C" fn ioctl(fd: c_int, request: c_ulong, out: *mut c_void) -> c_int {
+    // TODO: Somehow support varargs to syscall??
+    Sys::ioctl(fd, request, out);
+    //TODO:为了能够编译
+    return 0;
+}
+
+pub const TCGETS: c_ulong = 0x5401;
+pub const TCSETS: c_ulong = 0x5402;
+pub const TCSETSW: c_ulong = 0x5403;
+pub const TCSETSF: c_ulong = 0x5404;
+pub const TCGETA: c_ulong = 0x5405;
+pub const TCSETA: c_ulong = 0x5406;
+pub const TCSETAW: c_ulong = 0x5407;
+pub const TCSETAF: c_ulong = 0x5408;
+pub const TCSBRK: c_ulong = 0x5409;
+pub const TCXONC: c_ulong = 0x540A;
+pub const TCFLSH: c_ulong = 0x540B;
+pub const TIOCEXCL: c_ulong = 0x540C;
+pub const TIOCNXCL: c_ulong = 0x540D;
+pub const TIOCSCTTY: c_ulong = 0x540E;
+pub const TIOCGPGRP: c_ulong = 0x540F;
+pub const TIOCSPGRP: c_ulong = 0x5410;
+pub const TIOCOUTQ: c_ulong = 0x5411;
+pub const TIOCSTI: c_ulong = 0x5412;
+pub const TIOCGWINSZ: c_ulong = 0x5413;
+pub const TIOCSWINSZ: c_ulong = 0x5414;
+pub const TIOCMGET: c_ulong = 0x5415;
+pub const TIOCMBIS: c_ulong = 0x5416;
+pub const TIOCMBIC: c_ulong = 0x5417;
+pub const TIOCMSET: c_ulong = 0x5418;
+pub const TIOCGSOFTCAR: c_ulong = 0x5419;
+pub const TIOCSSOFTCAR: c_ulong = 0x541A;
+pub const FIONREAD: c_ulong = 0x541B;
+pub const TIOCINQ: c_ulong = FIONREAD;
+pub const TIOCLINUX: c_ulong = 0x541C;
+pub const TIOCCONS: c_ulong = 0x541D;
+pub const TIOCGSERIAL: c_ulong = 0x541E;
+pub const TIOCSSERIAL: c_ulong = 0x541F;
+pub const TIOCPKT: c_ulong = 0x5420;
+pub const FIONBIO: c_ulong = 0x5421;
+pub const TIOCNOTTY: c_ulong = 0x5422;
+pub const TIOCSETD: c_ulong = 0x5423;
+pub const TIOCGETD: c_ulong = 0x5424;
+pub const TCSBRKP: c_ulong = 0x5425;
+pub const TIOCSBRK: c_ulong = 0x5427;
+pub const TIOCCBRK: c_ulong = 0x5428;
+pub const TIOCGSID: c_ulong = 0x5429;
+pub const TIOCGRS485: c_ulong = 0x542E;
+pub const TIOCSRS485: c_ulong = 0x542F;
+pub const TIOCGPTN: c_ulong = 0x8004_5430;
+pub const TIOCSPTLCK: c_ulong = 0x4004_5431;
+pub const TIOCGDEV: c_ulong = 0x8004_5432;
+pub const TCGETX: c_ulong = 0x5432;
+pub const TCSETX: c_ulong = 0x5433;
+pub const TCSETXF: c_ulong = 0x5434;
+pub const TCSETXW: c_ulong = 0x5435;
+pub const TIOCSIG: c_ulong = 0x4004_5436;
+pub const TIOCVHANGUP: c_ulong = 0x5437;
+pub const TIOCGPKT: c_ulong = 0x8004_5438;
+pub const TIOCGPTLCK: c_ulong = 0x8004_5439;
+pub const TIOCGEXCL: c_ulong = 0x8004_5440;
+pub const TIOCGPTPEER: c_ulong = 0x5441;
+
+pub const FIONCLEX: c_ulong = 0x5450;
+pub const FIOCLEX: c_ulong = 0x5451;
+pub const FIOASYNC: c_ulong = 0x5452;
+pub const TIOCSERCONFIG: c_ulong = 0x5453;
+pub const TIOCSERGWILD: c_ulong = 0x5454;
+pub const TIOCSERSWILD: c_ulong = 0x5455;
+pub const TIOCGLCKTRMIOS: c_ulong = 0x5456;
+pub const TIOCSLCKTRMIOS: c_ulong = 0x5457;
+pub const TIOCSERGSTRUCT: c_ulong = 0x5458;
+pub const TIOCSERGETLSR: c_ulong = 0x5459;
+pub const TIOCSERGETMULTI: c_ulong = 0x545A;
+pub const TIOCSERSETMULTI: c_ulong = 0x545B;
+
+pub const TIOCMIWAIT: c_ulong = 0x545C;
+pub const TIOCGICOUNT: c_ulong = 0x545D;
+pub const FIOQSIZE: c_ulong = 0x5460;
+
+pub const TIOCPKT_DATA: c_ulong = 0;
+pub const TIOCPKT_FLUSHREAD: c_ulong = 1;
+pub const TIOCPKT_FLUSHWRITE: c_ulong = 2;
+pub const TIOCPKT_STOP: c_ulong = 4;
+pub const TIOCPKT_START: c_ulong = 8;
+pub const TIOCPKT_NOSTOP: c_ulong = 16;
+pub const TIOCPKT_DOSTOP: c_ulong = 32;
+pub const TIOCPKT_IOCTL: c_ulong = 64;
+
+pub const TIOCSER_TEMT: c_ulong = 0x01;
+
+pub const TIOCM_LE: c_ulong = 0x001;
+pub const TIOCM_DTR: c_ulong = 0x002;
+pub const TIOCM_RTS: c_ulong = 0x004;
+pub const TIOCM_ST: c_ulong = 0x008;
+pub const TIOCM_SR: c_ulong = 0x010;
+pub const TIOCM_CTS: c_ulong = 0x020;
+pub const TIOCM_CAR: c_ulong = 0x040;
+pub const TIOCM_RNG: c_ulong = 0x080;
+pub const TIOCM_DSR: c_ulong = 0x100;
+pub const TIOCM_CD: c_ulong = TIOCM_CAR;
+pub const TIOCM_RI: c_ulong = TIOCM_RNG;
+pub const TIOCM_OUT1: c_ulong = 0x2000;
+pub const TIOCM_OUT2: c_ulong = 0x4000;
+pub const TIOCM_LOOP: c_ulong = 0x8000;
+
+pub const N_TTY: c_ulong = 0;
+pub const N_SLIP: c_ulong = 1;
+pub const N_MOUSE: c_ulong = 2;
+pub const N_PPP: c_ulong = 3;
+pub const N_STRIP: c_ulong = 4;
+pub const N_AX25: c_ulong = 5;
+pub const N_X25: c_ulong = 6;
+pub const N_6PACK: c_ulong = 7;
+pub const N_MASC: c_ulong = 8;
+pub const N_R3964: c_ulong = 9;
+pub const N_PROFIBUS_FDL: c_ulong = 10;
+pub const N_IRDA: c_ulong = 11;
+pub const N_SMSBLOCK: c_ulong = 12;
+pub const N_HDLC: c_ulong = 13;
+pub const N_SYNC_PPP: c_ulong = 14;
+pub const N_HCI: c_ulong = 15;
+
+pub const FIOSETOWN: c_ulong = 0x8901;
+pub const SIOCSPGRP: c_ulong = 0x8902;
+pub const FIOGETOWN: c_ulong = 0x8903;
+pub const SIOCGPGRP: c_ulong = 0x8904;
+pub const SIOCATMARK: c_ulong = 0x8905;
+pub const SIOCGSTAMP: c_ulong = 0x8906;
+pub const SIOCGSTAMPNS: c_ulong = 0x8907;
+
+pub const SIOCADDRT: c_ulong = 0x890B;
+pub const SIOCDELRT: c_ulong = 0x890C;
+pub const SIOCRTMSG: c_ulong = 0x890D;
+
+pub const SIOCGIFNAME: c_ulong = 0x8910;
+pub const SIOCSIFLINK: c_ulong = 0x8911;
+pub const SIOCGIFCONF: c_ulong = 0x8912;
+pub const SIOCGIFFLAGS: c_ulong = 0x8913;
+pub const SIOCSIFFLAGS: c_ulong = 0x8914;
+pub const SIOCGIFADDR: c_ulong = 0x8915;
+pub const SIOCSIFADDR: c_ulong = 0x8916;
+pub const SIOCGIFDSTADDR: c_ulong = 0x8917;
+pub const SIOCSIFDSTADDR: c_ulong = 0x8918;
+pub const SIOCGIFBRDADDR: c_ulong = 0x8919;
+pub const SIOCSIFBRDADDR: c_ulong = 0x891a;
+pub const SIOCGIFNETMASK: c_ulong = 0x891b;
+pub const SIOCSIFNETMASK: c_ulong = 0x891c;
+pub const SIOCGIFMETRIC: c_ulong = 0x891d;
+pub const SIOCSIFMETRIC: c_ulong = 0x891e;
+pub const SIOCGIFMEM: c_ulong = 0x891f;
+pub const SIOCSIFMEM: c_ulong = 0x8920;
+pub const SIOCGIFMTU: c_ulong = 0x8921;
+pub const SIOCSIFMTU: c_ulong = 0x8922;
+pub const SIOCSIFNAME: c_ulong = 0x8923;
+pub const SIOCSIFHWADDR: c_ulong = 0x8924;
+pub const SIOCGIFENCAP: c_ulong = 0x8925;
+pub const SIOCSIFENCAP: c_ulong = 0x8926;
+pub const SIOCGIFHWADDR: c_ulong = 0x8927;
+pub const SIOCGIFSLAVE: c_ulong = 0x8929;
+pub const SIOCSIFSLAVE: c_ulong = 0x8930;
+pub const SIOCADDMULTI: c_ulong = 0x8931;
+pub const SIOCDELMULTI: c_ulong = 0x8932;
+pub const SIOCGIFINDEX: c_ulong = 0x8933;
+pub const SIOGIFINDEX: c_ulong = SIOCGIFINDEX;
+pub const SIOCSIFPFLAGS: c_ulong = 0x8934;
+pub const SIOCGIFPFLAGS: c_ulong = 0x8935;
+pub const SIOCDIFADDR: c_ulong = 0x8936;
+pub const SIOCSIFHWBROADCAST: c_ulong = 0x8937;
+pub const SIOCGIFCOUNT: c_ulong = 0x8938;
+
+pub const SIOCGIFBR: c_ulong = 0x8940;
+pub const SIOCSIFBR: c_ulong = 0x8941;
+
+pub const SIOCGIFTXQLEN: c_ulong = 0x8942;
+pub const SIOCSIFTXQLEN: c_ulong = 0x8943;
+
+pub const SIOCDARP: c_ulong = 0x8953;
+pub const SIOCGARP: c_ulong = 0x8954;
+pub const SIOCSARP: c_ulong = 0x8955;
+
+pub const SIOCDRARP: c_ulong = 0x8960;
+pub const SIOCGRARP: c_ulong = 0x8961;
+pub const SIOCSRARP: c_ulong = 0x8962;
+
+pub const SIOCGIFMAP: c_ulong = 0x8970;
+pub const SIOCSIFMAP: c_ulong = 0x8971;
+
+pub const SIOCADDDLCI: c_ulong = 0x8980;
+pub const SIOCDELDLCI: c_ulong = 0x8981;
+
+pub const SIOCDEVPRIVATE: c_ulong = 0x89F0;
+pub const SIOCPROTOPRIVATE: c_ulong = 0x89E0;

+ 198 - 0
src/header/sys_ioctl/linux.rs

@@ -0,0 +1,198 @@
+use crate::platform::{types::*, Sys};
+
+#[no_mangle]
+pub unsafe extern "C" fn ioctl(fd: c_int, request: c_ulong, out: *mut c_void) -> c_int {
+    // TODO: Somehow support varargs to syscall??
+    Sys::ioctl(fd, request, out);
+
+    //TODO:通过编译
+    return 0;
+}
+
+pub const TCGETS: c_ulong = 0x5401;
+pub const TCSETS: c_ulong = 0x5402;
+pub const TCSETSW: c_ulong = 0x5403;
+pub const TCSETSF: c_ulong = 0x5404;
+pub const TCGETA: c_ulong = 0x5405;
+pub const TCSETA: c_ulong = 0x5406;
+pub const TCSETAW: c_ulong = 0x5407;
+pub const TCSETAF: c_ulong = 0x5408;
+pub const TCSBRK: c_ulong = 0x5409;
+pub const TCXONC: c_ulong = 0x540A;
+pub const TCFLSH: c_ulong = 0x540B;
+pub const TIOCEXCL: c_ulong = 0x540C;
+pub const TIOCNXCL: c_ulong = 0x540D;
+pub const TIOCSCTTY: c_ulong = 0x540E;
+pub const TIOCGPGRP: c_ulong = 0x540F;
+pub const TIOCSPGRP: c_ulong = 0x5410;
+pub const TIOCOUTQ: c_ulong = 0x5411;
+pub const TIOCSTI: c_ulong = 0x5412;
+pub const TIOCGWINSZ: c_ulong = 0x5413;
+pub const TIOCSWINSZ: c_ulong = 0x5414;
+pub const TIOCMGET: c_ulong = 0x5415;
+pub const TIOCMBIS: c_ulong = 0x5416;
+pub const TIOCMBIC: c_ulong = 0x5417;
+pub const TIOCMSET: c_ulong = 0x5418;
+pub const TIOCGSOFTCAR: c_ulong = 0x5419;
+pub const TIOCSSOFTCAR: c_ulong = 0x541A;
+pub const FIONREAD: c_ulong = 0x541B;
+pub const TIOCINQ: c_ulong = FIONREAD;
+pub const TIOCLINUX: c_ulong = 0x541C;
+pub const TIOCCONS: c_ulong = 0x541D;
+pub const TIOCGSERIAL: c_ulong = 0x541E;
+pub const TIOCSSERIAL: c_ulong = 0x541F;
+pub const TIOCPKT: c_ulong = 0x5420;
+pub const FIONBIO: c_ulong = 0x5421;
+pub const TIOCNOTTY: c_ulong = 0x5422;
+pub const TIOCSETD: c_ulong = 0x5423;
+pub const TIOCGETD: c_ulong = 0x5424;
+pub const TCSBRKP: c_ulong = 0x5425;
+pub const TIOCSBRK: c_ulong = 0x5427;
+pub const TIOCCBRK: c_ulong = 0x5428;
+pub const TIOCGSID: c_ulong = 0x5429;
+pub const TIOCGRS485: c_ulong = 0x542E;
+pub const TIOCSRS485: c_ulong = 0x542F;
+pub const TIOCGPTN: c_ulong = 0x8004_5430;
+pub const TIOCSPTLCK: c_ulong = 0x4004_5431;
+pub const TIOCGDEV: c_ulong = 0x8004_5432;
+pub const TCGETX: c_ulong = 0x5432;
+pub const TCSETX: c_ulong = 0x5433;
+pub const TCSETXF: c_ulong = 0x5434;
+pub const TCSETXW: c_ulong = 0x5435;
+pub const TIOCSIG: c_ulong = 0x4004_5436;
+pub const TIOCVHANGUP: c_ulong = 0x5437;
+pub const TIOCGPKT: c_ulong = 0x8004_5438;
+pub const TIOCGPTLCK: c_ulong = 0x8004_5439;
+pub const TIOCGEXCL: c_ulong = 0x8004_5440;
+pub const TIOCGPTPEER: c_ulong = 0x5441;
+
+pub const FIONCLEX: c_ulong = 0x5450;
+pub const FIOCLEX: c_ulong = 0x5451;
+pub const FIOASYNC: c_ulong = 0x5452;
+pub const TIOCSERCONFIG: c_ulong = 0x5453;
+pub const TIOCSERGWILD: c_ulong = 0x5454;
+pub const TIOCSERSWILD: c_ulong = 0x5455;
+pub const TIOCGLCKTRMIOS: c_ulong = 0x5456;
+pub const TIOCSLCKTRMIOS: c_ulong = 0x5457;
+pub const TIOCSERGSTRUCT: c_ulong = 0x5458;
+pub const TIOCSERGETLSR: c_ulong = 0x5459;
+pub const TIOCSERGETMULTI: c_ulong = 0x545A;
+pub const TIOCSERSETMULTI: c_ulong = 0x545B;
+
+pub const TIOCMIWAIT: c_ulong = 0x545C;
+pub const TIOCGICOUNT: c_ulong = 0x545D;
+pub const FIOQSIZE: c_ulong = 0x5460;
+
+pub const TIOCPKT_DATA: c_ulong = 0;
+pub const TIOCPKT_FLUSHREAD: c_ulong = 1;
+pub const TIOCPKT_FLUSHWRITE: c_ulong = 2;
+pub const TIOCPKT_STOP: c_ulong = 4;
+pub const TIOCPKT_START: c_ulong = 8;
+pub const TIOCPKT_NOSTOP: c_ulong = 16;
+pub const TIOCPKT_DOSTOP: c_ulong = 32;
+pub const TIOCPKT_IOCTL: c_ulong = 64;
+
+pub const TIOCSER_TEMT: c_ulong = 0x01;
+
+pub const TIOCM_LE: c_ulong = 0x001;
+pub const TIOCM_DTR: c_ulong = 0x002;
+pub const TIOCM_RTS: c_ulong = 0x004;
+pub const TIOCM_ST: c_ulong = 0x008;
+pub const TIOCM_SR: c_ulong = 0x010;
+pub const TIOCM_CTS: c_ulong = 0x020;
+pub const TIOCM_CAR: c_ulong = 0x040;
+pub const TIOCM_RNG: c_ulong = 0x080;
+pub const TIOCM_DSR: c_ulong = 0x100;
+pub const TIOCM_CD: c_ulong = TIOCM_CAR;
+pub const TIOCM_RI: c_ulong = TIOCM_RNG;
+pub const TIOCM_OUT1: c_ulong = 0x2000;
+pub const TIOCM_OUT2: c_ulong = 0x4000;
+pub const TIOCM_LOOP: c_ulong = 0x8000;
+
+pub const N_TTY: c_ulong = 0;
+pub const N_SLIP: c_ulong = 1;
+pub const N_MOUSE: c_ulong = 2;
+pub const N_PPP: c_ulong = 3;
+pub const N_STRIP: c_ulong = 4;
+pub const N_AX25: c_ulong = 5;
+pub const N_X25: c_ulong = 6;
+pub const N_6PACK: c_ulong = 7;
+pub const N_MASC: c_ulong = 8;
+pub const N_R3964: c_ulong = 9;
+pub const N_PROFIBUS_FDL: c_ulong = 10;
+pub const N_IRDA: c_ulong = 11;
+pub const N_SMSBLOCK: c_ulong = 12;
+pub const N_HDLC: c_ulong = 13;
+pub const N_SYNC_PPP: c_ulong = 14;
+pub const N_HCI: c_ulong = 15;
+
+pub const FIOSETOWN: c_ulong = 0x8901;
+pub const SIOCSPGRP: c_ulong = 0x8902;
+pub const FIOGETOWN: c_ulong = 0x8903;
+pub const SIOCGPGRP: c_ulong = 0x8904;
+pub const SIOCATMARK: c_ulong = 0x8905;
+pub const SIOCGSTAMP: c_ulong = 0x8906;
+pub const SIOCGSTAMPNS: c_ulong = 0x8907;
+
+pub const SIOCADDRT: c_ulong = 0x890B;
+pub const SIOCDELRT: c_ulong = 0x890C;
+pub const SIOCRTMSG: c_ulong = 0x890D;
+
+pub const SIOCGIFNAME: c_ulong = 0x8910;
+pub const SIOCSIFLINK: c_ulong = 0x8911;
+pub const SIOCGIFCONF: c_ulong = 0x8912;
+pub const SIOCGIFFLAGS: c_ulong = 0x8913;
+pub const SIOCSIFFLAGS: c_ulong = 0x8914;
+pub const SIOCGIFADDR: c_ulong = 0x8915;
+pub const SIOCSIFADDR: c_ulong = 0x8916;
+pub const SIOCGIFDSTADDR: c_ulong = 0x8917;
+pub const SIOCSIFDSTADDR: c_ulong = 0x8918;
+pub const SIOCGIFBRDADDR: c_ulong = 0x8919;
+pub const SIOCSIFBRDADDR: c_ulong = 0x891a;
+pub const SIOCGIFNETMASK: c_ulong = 0x891b;
+pub const SIOCSIFNETMASK: c_ulong = 0x891c;
+pub const SIOCGIFMETRIC: c_ulong = 0x891d;
+pub const SIOCSIFMETRIC: c_ulong = 0x891e;
+pub const SIOCGIFMEM: c_ulong = 0x891f;
+pub const SIOCSIFMEM: c_ulong = 0x8920;
+pub const SIOCGIFMTU: c_ulong = 0x8921;
+pub const SIOCSIFMTU: c_ulong = 0x8922;
+pub const SIOCSIFNAME: c_ulong = 0x8923;
+pub const SIOCSIFHWADDR: c_ulong = 0x8924;
+pub const SIOCGIFENCAP: c_ulong = 0x8925;
+pub const SIOCSIFENCAP: c_ulong = 0x8926;
+pub const SIOCGIFHWADDR: c_ulong = 0x8927;
+pub const SIOCGIFSLAVE: c_ulong = 0x8929;
+pub const SIOCSIFSLAVE: c_ulong = 0x8930;
+pub const SIOCADDMULTI: c_ulong = 0x8931;
+pub const SIOCDELMULTI: c_ulong = 0x8932;
+pub const SIOCGIFINDEX: c_ulong = 0x8933;
+pub const SIOGIFINDEX: c_ulong = SIOCGIFINDEX;
+pub const SIOCSIFPFLAGS: c_ulong = 0x8934;
+pub const SIOCGIFPFLAGS: c_ulong = 0x8935;
+pub const SIOCDIFADDR: c_ulong = 0x8936;
+pub const SIOCSIFHWBROADCAST: c_ulong = 0x8937;
+pub const SIOCGIFCOUNT: c_ulong = 0x8938;
+
+pub const SIOCGIFBR: c_ulong = 0x8940;
+pub const SIOCSIFBR: c_ulong = 0x8941;
+
+pub const SIOCGIFTXQLEN: c_ulong = 0x8942;
+pub const SIOCSIFTXQLEN: c_ulong = 0x8943;
+
+pub const SIOCDARP: c_ulong = 0x8953;
+pub const SIOCGARP: c_ulong = 0x8954;
+pub const SIOCSARP: c_ulong = 0x8955;
+
+pub const SIOCDRARP: c_ulong = 0x8960;
+pub const SIOCGRARP: c_ulong = 0x8961;
+pub const SIOCSRARP: c_ulong = 0x8962;
+
+pub const SIOCGIFMAP: c_ulong = 0x8970;
+pub const SIOCSIFMAP: c_ulong = 0x8971;
+
+pub const SIOCADDDLCI: c_ulong = 0x8980;
+pub const SIOCDELDLCI: c_ulong = 0x8981;
+
+pub const SIOCDEVPRIVATE: c_ulong = 0x89F0;
+pub const SIOCPROTOPRIVATE: c_ulong = 0x89E0;

+ 36 - 0
src/header/sys_ioctl/mod.rs

@@ -0,0 +1,36 @@
+//! ioctl implementation for linux
+
+use crate::platform::types::*;
+
+// This is used from sgtty
+#[repr(C)]
+pub struct sgttyb {
+    sg_ispeed: c_char,
+    sg_ospeed: c_char,
+    sg_erase: c_char,
+    sg_kill: c_char,
+    sg_flags: c_ushort,
+}
+
+#[repr(C)]
+#[derive(Default)]
+pub struct winsize {
+    ws_row: c_ushort,
+    ws_col: c_ushort,
+    ws_xpixel: c_ushort,
+    ws_ypixel: c_ushort,
+}
+
+pub use self::sys::*;
+
+#[cfg(target_os = "linux")]
+#[path = "linux.rs"]
+pub mod sys;
+
+#[cfg(target_os = "dragonos")]
+#[path = "dragonos.rs"]
+pub mod sys;
+
+#[cfg(target_os = "redox")]
+#[path = "redox.rs"]
+pub mod sys;

+ 149 - 0
src/header/sys_ioctl/redox.rs

@@ -0,0 +1,149 @@
+use core::{mem, slice};
+use syscall;
+
+use crate::{
+    header::{errno, fcntl, termios},
+    platform::{self, e, types::*},
+};
+
+use super::winsize;
+
+pub const FIONREAD: c_ulong = 0x541B;
+pub const FIONBIO: c_ulong = 0x5421;
+
+pub const TCGETS: c_ulong = 0x5401;
+pub const TCSETS: c_ulong = 0x5402;
+pub const TCSETSW: c_ulong = 0x5403;
+pub const TCSETSF: c_ulong = 0x5404;
+pub const TCSBRK: c_ulong = 0x5409;
+
+pub const TCXONC: c_ulong = 0x540A;
+
+pub const TCFLSH: c_ulong = 0x540B;
+
+pub const TIOCGPGRP: c_ulong = 0x540F;
+pub const TIOCSPGRP: c_ulong = 0x5410;
+
+pub const TIOCGWINSZ: c_ulong = 0x5413;
+pub const TIOCSWINSZ: c_ulong = 0x5414;
+
+// TODO: some of the structs passed as T have padding bytes, so casting to a byte slice is UB
+
+fn dup_read<T>(fd: c_int, name: &str, t: &mut T) -> syscall::Result<usize> {
+    let dup = syscall::dup(fd as usize, name.as_bytes())?;
+
+    let size = mem::size_of::<T>();
+
+    let res = syscall::read(dup, unsafe {
+        slice::from_raw_parts_mut(t as *mut T as *mut u8, size)
+    });
+
+    let _ = syscall::close(dup);
+
+    res.map(|bytes| bytes / size)
+}
+
+fn dup_write<T>(fd: c_int, name: &str, t: &T) -> syscall::Result<usize> {
+    let dup = syscall::dup(fd as usize, name.as_bytes())?;
+
+    let size = mem::size_of::<T>();
+
+    let res = syscall::write(dup, unsafe {
+        slice::from_raw_parts(t as *const T as *const u8, size)
+    });
+
+    let _ = syscall::close(dup);
+
+    res.map(|bytes| bytes / size)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn ioctl(fd: c_int, request: c_ulong, out: *mut c_void) -> c_int {
+    match request {
+        FIONBIO => {
+            let mut flags = fcntl::sys_fcntl(fd, fcntl::F_GETFL, 0);
+            if flags < 0 {
+                return -1;
+            }
+            flags = if *(out as *mut c_int) == 0 {
+                flags & !fcntl::O_NONBLOCK
+            } else {
+                flags | fcntl::O_NONBLOCK
+            };
+            if fcntl::sys_fcntl(fd, fcntl::F_SETFL, flags) < 0 {
+                -1
+            } else {
+                0
+            }
+        }
+        TCGETS => {
+            let termios = &mut *(out as *mut termios::termios);
+            if e(dup_read(fd, "termios", termios)) == !0 {
+                -1
+            } else {
+                0
+            }
+        }
+        // TODO: give these different behaviors
+        TCSETS | TCSETSW | TCSETSF => {
+            let termios = &*(out as *const termios::termios);
+            if e(dup_write(fd, "termios", termios)) == !0 {
+                -1
+            } else {
+                0
+            }
+        }
+        TCFLSH => {
+            let queue = out as c_int;
+            if e(dup_write(fd, "flush", &queue)) == !0 {
+                -1
+            } else {
+                0
+            }
+        }
+        TIOCGPGRP => {
+            let pgrp = &mut *(out as *mut pid_t);
+            if e(dup_read(fd, "pgrp", pgrp)) == !0 {
+                -1
+            } else {
+                0
+            }
+        }
+        TIOCSPGRP => {
+            let pgrp = &*(out as *const pid_t);
+            if e(dup_write(fd, "pgrp", pgrp)) == !0 {
+                -1
+            } else {
+                0
+            }
+        }
+        TIOCGWINSZ => {
+            let winsize = &mut *(out as *mut winsize);
+            if e(dup_read(fd, "winsize", winsize)) == !0 {
+                -1
+            } else {
+                0
+            }
+        }
+        TIOCSWINSZ => {
+            let winsize = &*(out as *const winsize);
+            if e(dup_write(fd, "winsize", winsize)) == !0 {
+                -1
+            } else {
+                0
+            }
+        }
+        TCSBRK => {
+            // TODO
+            0
+        }
+        TCXONC => {
+            // TODO
+            0
+        }
+        _ => {
+            platform::errno = errno::EINVAL;
+            -1
+        }
+    }
+}

+ 15 - 0
src/header/sys_mman/cbindgen.toml

@@ -0,0 +1,15 @@
+sys_includes = ["stdint.h", "sys/types.h"]
+include_guard = "_SYS_MMAN_H"
+trailer = "#include <bits/sys/mman.h>"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[defines]
+"target_os=linux" = "__linux__"
+"target_os=redox" = "__redox__"
+"target_os=dragonos" = "__dragonos__"
+
+[enum]
+prefix_with_name = true

+ 9 - 0
src/header/sys_mman/dragonos.rs

@@ -0,0 +1,9 @@
+use crate::platform::types::*;
+
+pub const PROT_READ: c_int = 0x0001;
+pub const PROT_WRITE: c_int = 0x0002;
+pub const PROT_EXEC: c_int = 0x0004;
+pub const PROT_NONE: c_int = 0x0000;
+
+pub const MAP_FIXED: c_int = 0x0010;
+pub const MAP_FIXED_NOREPLACE: c_int = 0x100000;

+ 9 - 0
src/header/sys_mman/linux.rs

@@ -0,0 +1,9 @@
+use crate::platform::types::*;
+
+pub const PROT_READ: c_int = 0x0001;
+pub const PROT_WRITE: c_int = 0x0002;
+pub const PROT_EXEC: c_int = 0x0004;
+pub const PROT_NONE: c_int = 0x0000;
+
+pub const MAP_FIXED: c_int = 0x0010;
+pub const MAP_FIXED_NOREPLACE: c_int = 0x100000;

+ 132 - 0
src/header/sys_mman/mod.rs

@@ -0,0 +1,132 @@
+use crate::{
+    c_str::{CStr, CString},
+    header::{fcntl, unistd},
+    platform::{types::*, Pal, Sys},
+};
+
+pub use self::sys::*;
+
+#[cfg(target_os = "linux")]
+#[path = "linux.rs"]
+pub mod sys;
+
+#[cfg(target_os = "dragonos")]
+#[path = "dragonos.rs"]
+pub mod sys;
+
+#[cfg(target_os = "redox")]
+#[path = "redox.rs"]
+pub mod sys;
+
+pub const MADV_NORMAL: c_int = 0;
+pub const MADV_RANDOM: c_int = 1;
+pub const MADV_SEQUENTIAL: c_int = 2;
+pub const MADV_WILLNEED: c_int = 3;
+pub const MADV_DONTNEED: c_int = 4;
+
+pub const MAP_SHARED: c_int = 0x0001;
+pub const MAP_PRIVATE: c_int = 0x0002;
+pub const MAP_TYPE: c_int = 0x000F;
+pub const MAP_ANON: c_int = 0x0020;
+pub const MAP_ANONYMOUS: c_int = MAP_ANON;
+
+pub const MS_ASYNC: c_int = 0x0001;
+pub const MS_INVALIDATE: c_int = 0x0002;
+pub const MS_SYNC: c_int = 0x0004;
+
+pub const MCL_CURRENT: c_int = 1;
+pub const MCL_FUTURE: c_int = 2;
+
+pub const POSIX_MADV_NORMAL: c_int = 0;
+pub const POSIX_MADV_RANDOM: c_int = 1;
+pub const POSIX_MADV_SEQUENTIAL: c_int = 2;
+pub const POSIX_MADV_WILLNEED: c_int = 3;
+pub const POSIX_MADV_WONTNEED: c_int = 4;
+
+#[no_mangle]
+pub unsafe extern "C" fn mlock(addr: *const c_void, len: usize) -> c_int {
+    Sys::mlock(addr, len)
+}
+
+#[no_mangle]
+pub extern "C" fn mlockall(flags: c_int) -> c_int {
+    Sys::mlockall(flags)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mmap(
+    addr: *mut c_void,
+    len: size_t,
+    prot: c_int,
+    flags: c_int,
+    fildes: c_int,
+    off: off_t,
+) -> *mut c_void {
+    Sys::mmap(addr, len, prot, flags, fildes, off)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int {
+    Sys::mprotect(addr, len, prot)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int {
+    Sys::msync(addr, len, flags)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn munlock(addr: *const c_void, len: usize) -> c_int {
+    Sys::munlock(addr, len)
+}
+
+#[no_mangle]
+pub extern "C" fn munlockall() -> c_int {
+    Sys::munlockall()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn munmap(addr: *mut c_void, len: size_t) -> c_int {
+    Sys::munmap(addr, len)
+}
+
+#[cfg(target_os = "linux")]
+static SHM_PATH: &'static [u8] = b"/dev/shm/";
+
+#[cfg(target_os = "dragonos")]
+static SHM_PATH: &'static [u8] = b"/dev/shm/";
+
+#[cfg(target_os = "redox")]
+static SHM_PATH: &'static [u8] = b"shm:";
+
+unsafe fn shm_path(name: *const c_char) -> CString {
+    let name_c = CStr::from_ptr(name);
+
+    let mut path = SHM_PATH.to_vec();
+
+    let mut skip_slash = true;
+    for &b in name_c.to_bytes() {
+        if skip_slash {
+            if b == b'/' {
+                continue;
+            } else {
+                skip_slash = false;
+            }
+        }
+        path.push(b);
+    }
+
+    CString::from_vec_unchecked(path)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int {
+    let path = shm_path(name);
+    fcntl::sys_open(path.as_ptr(), oflag, mode)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn shm_unlink(name: *const c_char) -> c_int {
+    let path = shm_path(name);
+    unistd::unlink(path.as_ptr())
+}

+ 9 - 0
src/header/sys_mman/redox.rs

@@ -0,0 +1,9 @@
+use crate::platform::types::*;
+
+pub const PROT_NONE: c_int = 0x0000;
+pub const PROT_EXEC: c_int = 0x0001;
+pub const PROT_WRITE: c_int = 0x0002;
+pub const PROT_READ: c_int = 0x0004;
+
+pub const MAP_FIXED: c_int = 0x0004;
+pub const MAP_FIXED_NOREPLACE: c_int = 0x000C;

+ 18 - 0
src/header/sys_resource/cbindgen.toml

@@ -0,0 +1,18 @@
+sys_includes = ["sys/types.h", "stdint.h", "sys/time.h"]
+include_guard = "_SYS_RESOURCE_H"
+trailer = "#include <bits/sys/resource.h>"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[defines]
+"target_os=linux" = "__linux__"
+"target_os=redox" = "__redox__"
+"target_os=dragonos" = "__dragonos__"
+
+[enum]
+prefix_with_name = true
+
+[export.rename]
+"timeval" = "struct timeval"

+ 82 - 1
src/header/sys_resource/mod.rs

@@ -1,7 +1,88 @@
+//! sys/resource.h implementation for Redox, following
+//! http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysresource.h.html
+
+use crate::{
+    header::sys_time::timeval,
+    platform::{types::*, Pal, Sys},
+};
+
+// Exported in bits file
+// const RUSAGE_SELF: c_int = 0;
+// const RUSAGE_CHILDREN: c_int = -1;
+// const RUSAGE_BOTH: c_int = -2;
+// const RUSAGE_THREAD: c_int = 1;
+
+pub const RLIM_INFINITY: u64 = 0xFFFF_FFFF_FFFF_FFFF;
+pub const RLIM_SAVED_CUR: u64 = RLIM_INFINITY;
+pub const RLIM_SAVED_MAX: u64 = RLIM_INFINITY;
+
+pub const RLIMIT_CPU: u64 = 0;
+pub const RLIMIT_FSIZE: u64 = 1;
+pub const RLIMIT_DATA: u64 = 2;
+pub const RLIMIT_STACK: u64 = 3;
+pub const RLIMIT_CORE: u64 = 4;
+pub const RLIMIT_RSS: u64 = 5;
+pub const RLIMIT_NPROC: u64 = 6;
+pub const RLIMIT_NOFILE: u64 = 7;
+pub const RLIMIT_MEMLOCK: u64 = 8;
+pub const RLIMIT_AS: u64 = 9;
+pub const RLIMIT_LOCKS: u64 = 10;
+pub const RLIMIT_SIGPENDING: u64 = 11;
+pub const RLIMIT_MSGQUEUE: u64 = 12;
+pub const RLIMIT_NICE: u64 = 13;
+pub const RLIMIT_RTPRIO: u64 = 14;
+pub const RLIMIT_NLIMITS: u64 = 15;
+
 pub type rlim_t = u64;
 
 #[repr(C)]
 pub struct rlimit {
     pub rlim_cur: rlim_t,
     pub rlim_max: rlim_t,
-}
+}
+
+#[repr(C)]
+pub struct rusage {
+    pub ru_utime: timeval,
+    pub ru_stime: timeval,
+    pub ru_maxrss: c_long,
+    pub ru_ixrss: c_long,
+    pub ru_idrss: c_long,
+    pub ru_isrss: c_long,
+    pub ru_minflt: c_long,
+    pub ru_majflt: c_long,
+    pub ru_nswap: c_long,
+    pub ru_inblock: c_long,
+    pub ru_oublock: c_long,
+    pub ru_msgsnd: c_long,
+    pub ru_msgrcv: c_long,
+    pub ru_nsignals: c_long,
+    pub ru_nvcsw: c_long,
+    pub ru_nivcsw: c_long,
+}
+
+// #[no_mangle]
+// pub unsafe extern "C" fn getpriority(which: c_int, who: id_t) -> c_int {
+//     unimplemented!();
+// }
+
+#[no_mangle]
+pub unsafe extern "C" fn getrlimit(resource: c_int, rlp: *mut rlimit) -> c_int {
+    Sys::getrlimit(resource, rlp)
+}
+
+// #[no_mangle]
+// pub unsafe extern "C" fn getrusage(who: c_int, r_usage: *mut rusage) -> c_int {
+//     // Sys::getrusage(who, r_usage)
+//     unimplemented!();
+// }
+//
+// #[no_mangle]
+// pub unsafe extern "C" fn setpriority(which: c_int, who: id_t, nice: c_int) -> c_int {
+//     unimplemented!();
+// }
+//
+// #[no_mangle]
+// pub unsafe extern "C" fn setrlimit(resource: c_int, rlp: *const rlimit) -> c_int {
+//     unimplemented!();
+// }

+ 13 - 0
src/header/sys_stat/cbindgen.toml

@@ -0,0 +1,13 @@
+sys_includes = ["sys/types.h", "time.h"]
+include_guard = "_SYS_STAT_H"
+trailer = "#include <bits/sys/stat.h>"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true
+
+[export.rename]
+"timespec" = "struct timespec"

+ 116 - 3
src/header/sys_stat/mod.rs

@@ -1,6 +1,41 @@
-use crate::platform::types::*;
+//! stat implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysstat.h.html
 
-use super::time::timespec;
+use crate::{
+    c_str::CStr,
+    header::{
+        fcntl::{O_NOFOLLOW, O_PATH},
+        time::timespec,
+    },
+    platform::{types::*, Pal, Sys},
+};
+
+pub const S_IFMT: c_int = 0o0_170_000;
+
+pub const S_IFDIR: c_int = 0o040_000;
+pub const S_IFCHR: c_int = 0o020_000;
+pub const S_IFBLK: c_int = 0o060_000;
+pub const S_IFREG: c_int = 0o100_000;
+pub const S_IFIFO: c_int = 0o010_000;
+pub const S_IFLNK: c_int = 0o120_000;
+pub const S_IFSOCK: c_int = 0o140_000;
+
+pub const S_IRWXU: c_int = 0o0_700;
+pub const S_IRUSR: c_int = 0o0_400;
+pub const S_IWUSR: c_int = 0o0_200;
+pub const S_IXUSR: c_int = 0o0_100;
+
+pub const S_IRWXG: c_int = 0o0_070;
+pub const S_IRGRP: c_int = 0o0_040;
+pub const S_IWGRP: c_int = 0o0_020;
+pub const S_IXGRP: c_int = 0o0_010;
+
+pub const S_IRWXO: c_int = 0o0_007;
+pub const S_IROTH: c_int = 0o0_004;
+pub const S_IWOTH: c_int = 0o0_002;
+pub const S_IXOTH: c_int = 0o0_001;
+pub const S_ISUID: c_int = 0o4_000;
+pub const S_ISGID: c_int = 0o2_000;
+pub const S_ISVTX: c_int = 0o1_000;
 
 #[repr(C)]
 #[derive(Default)]
@@ -24,4 +59,82 @@ pub struct stat {
     // Accessing atime works, so clearly the struct isn't incorrect...
     // This works.
     pub _pad: [c_char; 24],
-}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn chmod(path: *const c_char, mode: mode_t) -> c_int {
+    let path = CStr::from_ptr(path);
+    Sys::chmod(path, mode)
+}
+
+#[no_mangle]
+pub extern "C" fn fchmod(fildes: c_int, mode: mode_t) -> c_int {
+    Sys::fchmod(fildes, mode)
+}
+
+#[no_mangle]
+pub extern "C" fn fstat(fildes: c_int, buf: *mut stat) -> c_int {
+    Sys::fstat(fildes, buf)
+}
+
+#[no_mangle]
+pub extern "C" fn __fxstat(_ver: c_int, fildes: c_int, buf: *mut stat) -> c_int {
+    fstat(fildes, buf)
+}
+
+#[no_mangle]
+pub extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int {
+    Sys::futimens(fd, times)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut stat) -> c_int {
+    let path = CStr::from_ptr(path);
+    let fd = Sys::open(path, O_PATH | O_NOFOLLOW, 0);
+    if fd < 0 {
+        return -1;
+    }
+
+    let res = Sys::fstat(fd, buf);
+
+    Sys::close(fd);
+
+    res
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mkdir(path: *const c_char, mode: mode_t) -> c_int {
+    let path = CStr::from_ptr(path);
+    Sys::mkdir(path, mode)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mkfifo(path: *const c_char, mode: mode_t) -> c_int {
+    let path = CStr::from_ptr(path);
+    Sys::mkfifo(path, mode)
+}
+
+// #[no_mangle]
+pub extern "C" fn mknod(path: *const c_char, mode: mode_t, dev: dev_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn stat(file: *const c_char, buf: *mut stat) -> c_int {
+    let file = CStr::from_ptr(file);
+    let fd = Sys::open(file, O_PATH, 0);
+    if fd < 0 {
+        return -1;
+    }
+
+    let res = Sys::fstat(fd, buf);
+
+    Sys::close(fd);
+
+    res
+}
+
+#[no_mangle]
+pub extern "C" fn umask(mask: mode_t) -> mode_t {
+    Sys::umask(mask)
+}

+ 9 - 0
src/header/sys_statvfs/cbindgen.toml

@@ -0,0 +1,9 @@
+sys_includes = ["sys/types.h"]
+include_guard = "_SYS_STATVFS_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 30 - 2
src/header/sys_statvfs/mod.rs

@@ -1,5 +1,13 @@
-use crate::platform::types::{c_ulong, fsblkcnt_t, fsfilcnt_t};
+//! statvfs implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysstatvfs.h.html
 
+use crate::{
+    c_str::CStr,
+    header::fcntl::O_PATH,
+    platform::{types::*, Pal, Sys},
+};
+
+//pub const ST_RDONLY
+//pub const ST_NOSUID
 
 #[repr(C)]
 #[derive(Default)]
@@ -15,4 +23,24 @@ pub struct statvfs {
     pub f_fsid: c_ulong,
     pub f_flag: c_ulong,
     pub f_namemax: c_ulong,
-}
+}
+
+#[no_mangle]
+pub extern "C" fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> c_int {
+    Sys::fstatvfs(fildes, buf)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn statvfs(file: *const c_char, buf: *mut statvfs) -> c_int {
+    let file = CStr::from_ptr(file);
+    let fd = Sys::open(file, O_PATH, 0);
+    if fd < 0 {
+        return -1;
+    }
+
+    let res = Sys::fstatvfs(fd, buf);
+
+    Sys::close(fd);
+
+    res
+}

+ 10 - 0
src/header/sys_time/cbindgen.toml

@@ -0,0 +1,10 @@
+sys_includes = ["sys/types.h"]
+include_guard = "_SYS_TIME_H"
+language = "C"
+trailer = "#include <bits/sys/time.h>"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 60 - 2
src/header/sys_time/mod.rs

@@ -1,4 +1,15 @@
-use crate::platform::types::{time_t, suseconds_t, c_int};
+//! sys/time implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/systime.h.html
+
+use crate::c_str::CStr;
+
+use crate::{
+    header::time::timespec,
+    platform::{types::*, Pal,PalSignal, Sys},
+};
+
+pub const ITIMER_REAL: c_int = 0;
+pub const ITIMER_VIRTUAL: c_int = 1;
+pub const ITIMER_PROF: c_int = 2;
 
 #[repr(C)]
 #[derive(Default)]
@@ -11,4 +22,51 @@ pub struct timeval {
 pub struct timezone {
     pub tz_minuteswest: c_int,
     pub tz_dsttime: c_int,
-}
+}
+
+#[repr(C)]
+#[derive(Default)]
+pub struct itimerval {
+    pub it_interval: timeval,
+    pub it_value: timeval,
+}
+
+#[repr(C)]
+pub struct fd_set {
+    pub fds_bits: [c_long; 16usize],
+}
+
+#[no_mangle]
+pub extern "C" fn getitimer(which: c_int, value: *mut itimerval) -> c_int {
+    Sys::getitimer(which, value)
+}
+
+#[no_mangle]
+pub extern "C" fn setitimer(
+    which: c_int,
+    value: *const itimerval,
+    ovalue: *mut itimerval,
+) -> c_int {
+    Sys::setitimer(which, value, ovalue)
+}
+
+#[no_mangle]
+pub extern "C" fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int {
+    Sys::gettimeofday(tp, tzp)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn utimes(path: *const c_char, times: *const timeval) -> c_int {
+    let path = CStr::from_ptr(path);
+    let times_spec = [
+        timespec {
+            tv_sec: (*times.offset(0)).tv_sec,
+            tv_nsec: ((*times.offset(0)).tv_usec as c_long) * 1000,
+        },
+        timespec {
+            tv_sec: (*times.offset(1)).tv_sec,
+            tv_nsec: ((*times.offset(1)).tv_usec as c_long) * 1000,
+        },
+    ];
+    Sys::utimens(path, times_spec.as_ptr())
+}

+ 8 - 0
src/header/sys_utsname/cbindgen.toml

@@ -0,0 +1,8 @@
+include_guard = "_SYS_UTSNAME_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true

+ 9 - 3
src/header/sys_utsname/mod.rs

@@ -1,4 +1,6 @@
-use crate::platform::types::c_char;
+//! sys/utsname implementation, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html
+
+use crate::platform::{types::*, Pal, Sys};
 
 pub const UTSLENGTH: usize = 65;
 
@@ -9,5 +11,9 @@ pub struct utsname {
     pub release: [c_char; UTSLENGTH],
     pub version: [c_char; UTSLENGTH],
     pub machine: [c_char; UTSLENGTH],
-    pub domainname: [c_char; UTSLENGTH],
-}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn uname(uts: *mut utsname) -> c_int {
+    Sys::uname(uts)
+}

+ 14 - 0
src/header/termios/cbindgen.toml

@@ -0,0 +1,14 @@
+sys_includes = ["stdint.h"]
+include_guard = "_RELIBC_TERMIOS_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[defines]
+"target_os=linux" = "__linux__"
+"target_os=redox" = "__redox__"
+"target_os=dragonos" = "__dragonos__"
+
+[enum]
+prefix_with_name = true

+ 113 - 0
src/header/termios/dragonos.rs

@@ -0,0 +1,113 @@
+/* c_cc { */
+pub const VINTR: usize = 0;
+pub const VQUIT: usize = 1;
+pub const VERASE: usize = 2;
+pub const VKILL: usize = 3;
+pub const VEOF: usize = 4;
+pub const VTIME: usize = 5;
+pub const VMIN: usize = 6;
+pub const VSWTC: usize = 7;
+pub const VSTART: usize = 8;
+pub const VSTOP: usize = 9;
+pub const VSUSP: usize = 10;
+pub const VEOL: usize = 11;
+pub const VREPRINT: usize = 12;
+pub const VDISCARD: usize = 13;
+pub const VWERASE: usize = 14;
+pub const VLNEXT: usize = 15;
+pub const VEOL2: usize = 16;
+pub const NCCS: usize = 32;
+/* } c_cc */
+
+/* c_iflag { */
+pub const IGNBRK: usize = 0o000_001;
+pub const BRKINT: usize = 0o000_002;
+pub const IGNPAR: usize = 0o000_004;
+pub const PARMRK: usize = 0o000_010;
+pub const INPCK: usize = 0o000_020;
+pub const ISTRIP: usize = 0o000_040;
+pub const INLCR: usize = 0o000_100;
+pub const IGNCR: usize = 0o000_200;
+pub const ICRNL: usize = 0o000_400;
+pub const IUCLC: usize = 0o001_000;
+pub const IXON: usize = 0o002_000;
+pub const IXANY: usize = 0o004_000;
+pub const IXOFF: usize = 0o010_000;
+pub const IMAXBEL: usize = 0o020_000;
+pub const IUTF8: usize = 0o040_000;
+/* } c_iflag */
+
+/* c_oflag { */
+pub const OPOST: usize = 0o000_001;
+pub const OLCUC: usize = 0o000_002;
+pub const ONLCR: usize = 0o000_004;
+pub const OCRNL: usize = 0o000_010;
+pub const ONOCR: usize = 0o000_020;
+pub const ONLRET: usize = 0o000_040;
+pub const OFILL: usize = 0o000_100;
+pub const OFDEL: usize = 0o000_200;
+
+pub const VTDLY: usize = 0o040_000;
+pub const VT0: usize = 0o000_000;
+pub const VT1: usize = 0o040_000;
+/* } c_oflag */
+
+/* c_cflag { */
+pub const B0: usize = 0o000_000;
+pub const B50: usize = 0o000_001;
+pub const B75: usize = 0o000_002;
+pub const B110: usize = 0o000_003;
+pub const B134: usize = 0o000_004;
+pub const B150: usize = 0o000_005;
+pub const B200: usize = 0o000_006;
+pub const B300: usize = 0o000_007;
+pub const B600: usize = 0o000_010;
+pub const B1200: usize = 0o000_011;
+pub const B1800: usize = 0o000_012;
+pub const B2400: usize = 0o000_013;
+pub const B4800: usize = 0o000_014;
+pub const B9600: usize = 0o000_015;
+pub const B19200: usize = 0o000_016;
+pub const B38400: usize = 0o000_017;
+
+pub const B57600: usize = 0o010_001;
+pub const B115200: usize = 0o010_002;
+pub const B230400: usize = 0o010_003;
+pub const B460800: usize = 0o010_004;
+pub const B500000: usize = 0o010_005;
+pub const B576000: usize = 0o010_006;
+pub const B921600: usize = 0o010_007;
+pub const B1000000: usize = 0o010_010;
+pub const B1152000: usize = 0o010_011;
+pub const B1500000: usize = 0o010_012;
+pub const B2000000: usize = 0o010_013;
+pub const B2500000: usize = 0o010_014;
+pub const B3000000: usize = 0o010_015;
+pub const B3500000: usize = 0o010_016;
+pub const B4000000: usize = 0o010_017;
+
+pub const CSIZE: usize = 0o000_060;
+pub const CS5: usize = 0o000_000;
+pub const CS6: usize = 0o000_020;
+pub const CS7: usize = 0o000_040;
+pub const CS8: usize = 0o000_060;
+
+pub const CSTOPB: usize = 0o000_100;
+pub const CREAD: usize = 0o000_200;
+pub const PARENB: usize = 0o000_400;
+pub const PARODD: usize = 0o001_000;
+pub const HUPCL: usize = 0o002_000;
+pub const CLOCAL: usize = 0o004_000;
+/* } c_clfag */
+
+/* c_lflag { */
+pub const ISIG: usize = 0o000_001;
+pub const ICANON: usize = 0o000_002;
+pub const ECHO: usize = 0o000_010;
+pub const ECHOE: usize = 0o000_020;
+pub const ECHOK: usize = 0o000_040;
+pub const ECHONL: usize = 0o000_100;
+pub const NOFLSH: usize = 0o000_200;
+pub const TOSTOP: usize = 0o000_400;
+pub const IEXTEN: usize = 0o100_000;
+/* } c_lflag */

Some files were not shown because too many files changed in this diff