summaryrefslogtreecommitdiffstats
path: root/build/liblowercase
diff options
context:
space:
mode:
Diffstat (limited to 'build/liblowercase')
-rw-r--r--build/liblowercase/Cargo.lock237
-rw-r--r--build/liblowercase/Cargo.toml22
-rw-r--r--build/liblowercase/lib.rs252
3 files changed, 511 insertions, 0 deletions
diff --git a/build/liblowercase/Cargo.lock b/build/liblowercase/Cargo.lock
new file mode 100644
index 0000000000..4449d1ebc7
--- /dev/null
+++ b/build/liblowercase/Cargo.lock
@@ -0,0 +1,237 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "c2-chacha"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
+dependencies = [
+ "ppv-lite86",
+]
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "getrandom"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.67"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
+
+[[package]]
+name = "lowercase"
+version = "0.1.0"
+dependencies = [
+ "libc",
+ "once_cell",
+ "paste",
+ "path-dedot",
+ "tempfile",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
+
+[[package]]
+name = "paste"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e1afe738d71b1ebab5f1207c055054015427dbfc7bbe9ee1266894156ec046"
+dependencies = [
+ "paste-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "paste-impl"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d4dc4a7f6f743211c5aab239640a65091535d97d43d92a52bca435a640892bb"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "path-dedot"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cf32f6a3b529384739d9c11c230ad760aeb553061e7834f58de63a7c507f24f"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom",
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
+dependencies = [
+ "c2-chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.1.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "winapi"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/build/liblowercase/Cargo.toml b/build/liblowercase/Cargo.toml
new file mode 100644
index 0000000000..2f26edd718
--- /dev/null
+++ b/build/liblowercase/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "lowercase"
+version = "0.1.0"
+authors = ["Mike Hommey <mhommey@glandium.org>"]
+edition = "2018"
+license = "MPL-2.0"
+
+[lib]
+crate-type = ["cdylib"]
+path = "lib.rs"
+
+[dependencies]
+libc = "0.2"
+once_cell = "1"
+paste = "0.1"
+path-dedot = "1"
+
+[dev-dependencies]
+tempfile = "3"
+
+[profile.release]
+lto = true
diff --git a/build/liblowercase/lib.rs b/build/liblowercase/lib.rs
new file mode 100644
index 0000000000..9e068a8c38
--- /dev/null
+++ b/build/liblowercase/lib.rs
@@ -0,0 +1,252 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* LD_PRELOAD library that intercepts some libc functions and lowercases
+ * paths under a given set of directories before calling the real libc
+ * functions.
+ *
+ * The set of directories is defined with the LOWERCASE_DIRS environment
+ * variable, separated with a `:`.
+ *
+ * Only the parts of the directories below the LOWERCASE_DIRS directories
+ * are lowercased.
+ *
+ * For example, with LOWERCASE_DIRS=/Foo:/Bar:
+ * `/home/QuX` is unchanged.
+ * `/Foo/QuX` becomes `/Foo/qux`.
+ * `/foo/QuX` is unchanged.
+ * `/Bar/QuX` becomes `/Bar/qux`.
+ * etc.
+ *
+ * This is, by no means, supposed to be a generic LD_PRELOAD library. It
+ * only intercepts the libc functions that matter in order to build Firefox.
+ */
+
+use std::borrow::Cow;
+use std::env::{self, current_dir};
+use std::ffi::{c_void, CStr, CString, OsStr, OsString};
+use std::mem::transmute;
+use std::os::raw::{c_char, c_int};
+use std::os::unix::ffi::{OsStrExt, OsStringExt};
+use std::path::{Path, PathBuf};
+use std::ptr::null;
+
+use once_cell::sync::Lazy;
+use path_dedot::ParseDot;
+
+#[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))]
+compile_error!("Platform is not supported");
+
+static LOWERCASE_DIRS: Lazy<Vec<PathBuf>> = Lazy::new(|| match env::var_os("LOWERCASE_DIRS") {
+ None => Vec::new(),
+ Some(value) => value
+ .as_bytes()
+ .split(|&c| c == b':')
+ .map(|p| canonicalize_path(Path::new(OsStr::from_bytes(p))).into_owned())
+ .collect(),
+});
+
+fn canonicalize_path(path: &Path) -> Cow<Path> {
+ let path = if path.is_absolute() {
+ Cow::Borrowed(path)
+ } else {
+ match current_dir() {
+ Ok(cwd) => Cow::Owned(cwd.join(path)),
+ Err(_) => Cow::Borrowed(path),
+ }
+ };
+
+ // TODO: avoid allocation when the path doesn't need .. / . removals.
+ Cow::Owned(path.parse_dot().unwrap())
+}
+
+#[test]
+fn test_canonicalize_path() {
+ use std::env::set_current_dir;
+ use std::iter::repeat;
+ use tempfile::tempdir;
+
+ fn do_test(curdir: &Path) {
+ let foobarbaz = curdir.join("foo/bar/baz");
+
+ assert_eq!(foobarbaz, canonicalize_path(Path::new("foo/bar/baz")));
+ assert_eq!(foobarbaz, canonicalize_path(Path::new("./foo/bar/baz")));
+ assert_eq!(foobarbaz, canonicalize_path(Path::new("foo/./bar/baz")));
+ assert_eq!(foobarbaz, canonicalize_path(Path::new("foo/././bar/baz")));
+ assert_eq!(
+ foobarbaz,
+ canonicalize_path(Path::new("foo/././bar/qux/../baz"))
+ );
+ assert_eq!(
+ foobarbaz,
+ canonicalize_path(Path::new("foo/./bar/../qux/../bar/baz"))
+ );
+ assert_eq!(
+ foobarbaz,
+ canonicalize_path(Path::new("foo/bar/./../../foo/bar/baz"))
+ );
+
+ let depth = curdir.components().count();
+ for depth in depth..=depth + 1 {
+ let path = repeat("..").take(depth).collect::<Vec<_>>();
+ let mut path = path.join("/");
+ path.push_str("/foo/bar/baz");
+
+ assert_eq!(
+ Path::new("/foo/bar/baz"),
+ canonicalize_path(Path::new(&path))
+ );
+ }
+ }
+
+ let orig_curdir = current_dir().unwrap();
+
+ do_test(&orig_curdir);
+
+ let tempdir = tempdir().unwrap();
+ set_current_dir(&tempdir).unwrap();
+
+ do_test(tempdir.path());
+
+ set_current_dir(orig_curdir).unwrap();
+}
+
+fn normalize_path(path: &CStr) -> Cow<CStr> {
+ let orig_path = path;
+ let path = Path::new(OsStr::from_bytes(orig_path.to_bytes()));
+ match normalize_path_for_dirs(&path, &LOWERCASE_DIRS) {
+ Cow::Borrowed(_) => Cow::Borrowed(orig_path),
+ Cow::Owned(p) => Cow::Owned(CString::new(p.into_os_string().into_vec()).unwrap()),
+ }
+}
+
+fn normalize_path_for_dirs<'a>(path: &'a Path, dirs: &[PathBuf]) -> Cow<'a, Path> {
+ let orig_path = path;
+ let path = canonicalize_path(path);
+
+ for lowercase_dir in dirs.iter() {
+ if path.starts_with(lowercase_dir) {
+ // TODO: avoid allocation when the string doesn't actually need
+ // modification.
+ let mut lowercased_path = path.into_owned().into_os_string().into_vec();
+ lowercased_path[lowercase_dir.as_os_str().as_bytes().len()..].make_ascii_lowercase();
+ return Cow::Owned(OsString::from_vec(lowercased_path).into());
+ }
+ }
+
+ Cow::Borrowed(orig_path)
+}
+
+#[test]
+fn test_normalize_path() {
+ let paths = vec![
+ Path::new("/Foo/Bar").to_owned(),
+ Path::new("/Qux").to_owned(),
+ current_dir().unwrap().join("Fuga"),
+ ];
+
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("/foo/bar/Baz"), &paths),
+ Path::new("/foo/bar/Baz")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("/Foo/Bar/Baz"), &paths),
+ Path::new("/Foo/Bar/baz")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("/Foo/BarBaz"), &paths),
+ Path::new("/Foo/BarBaz")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("/Foo/Bar"), &paths),
+ Path::new("/Foo/Bar")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("/Foo/Bar/Baz/../Qux"), &paths),
+ Path::new("/Foo/Bar/qux")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("/Foo/Bar/Baz/../../Qux"), &paths),
+ Path::new("/Foo/Bar/Baz/../../Qux")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("/Qux/Foo/Bar/Baz"), &paths),
+ Path::new("/Qux/foo/bar/baz")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("/foo/../Qux/Baz"), &paths),
+ Path::new("/Qux/baz")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("fuga/Foo/Bar"), &paths),
+ Path::new("fuga/Foo/Bar")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("Fuga/Foo/Bar"), &paths),
+ current_dir().unwrap().join("Fuga/foo/bar")
+ );
+ assert_eq!(
+ normalize_path_for_dirs(Path::new("Fuga/../Foo/Bar"), &paths),
+ Path::new("Fuga/../Foo/Bar")
+ );
+}
+
+macro_rules! wrappers {
+ ($(fn $name:ident($( $a:ident : $t:ty ),*) $( -> $ret:ty)?;)*) => {
+ $(
+ paste::item! {
+ #[allow(non_upper_case_globals)]
+ static [< real $name >]: Lazy<extern "C" fn($($t),*) $( -> $ret)?> =
+ Lazy::new(|| unsafe {
+ transmute(libc::dlsym(
+ libc::RTLD_NEXT,
+ concat!(stringify!($name), "\0").as_ptr() as _
+ ))
+ });
+ #[no_mangle]
+ unsafe extern "C" fn $name($($a : $t),*) $(-> $ret)? {
+ $( wrappers!(@normalize ($a: $t)); )*
+ [< real $name >]($($a),*)
+ }
+ }
+ )*
+ };
+ (@normalize ($a:ident: *const c_char)) => {
+ let $a = if $a.is_null() {
+ None
+ } else {
+ Some(normalize_path(CStr::from_ptr($a)))
+ };
+ let $a = $a.as_ref().map(|p| p.as_ptr()).unwrap_or(null());
+ };
+ (@normalize ($a:ident: $t:ty)) => {}
+}
+
+// Note: actual definitions for e.g. fopen/fopen64 would be using c_char
+// instead of c_void for mode, but the wrappers macro treats all `*const c_char`s
+// as "to maybe be lowercased".
+wrappers! {
+ fn open(path: *const c_char, flags: c_int, mode: libc::mode_t) -> c_int;
+ fn open64(path: *const c_char, flags: c_int, mode: libc::mode_t) -> c_int;
+ fn fopen(path: *const c_char, mode: *const c_void) -> *mut libc::FILE;
+ fn fopen64(path: *const c_char, mode: *const c_void) -> *mut libc::FILE;
+
+ fn opendir(path: *const c_char) -> *mut libc::DIR;
+
+ fn __xstat(ver: c_int, path: *const c_char, buf: *mut libc::stat) -> c_int;
+ fn __xstat64(ver: c_int, path: *const c_char, buf: *mut libc::stat64) -> c_int;
+
+ fn __lxstat(ver: c_int, path: *const c_char, buf: *mut libc::stat) -> c_int;
+ fn __lxstat64(ver: c_int, path: *const c_char, buf: *mut libc::stat64) -> c_int;
+ fn __fxstatat(ver: c_int, fd: c_int, path: *const c_char, buf: *mut libc::stat, flag: c_int) -> c_int;
+ fn __fxstatat64(ver: c_int, fd: c_int, path: *const c_char, buf: *mut libc::stat64, flag: c_int) -> c_int;
+
+ fn access(path: *const c_char, mode: c_int) -> c_int;
+
+ fn mkdir(path: *const c_char, mode: libc::mode_t) -> c_int;
+
+ fn chdir(path: *const c_char) -> c_int;
+
+ fn symlink(target: *const c_char, linkpath: *const c_char) -> c_int;
+}