diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,10 @@
+filepath-bytestring (1.4.2.1.3) unstable; urgency=medium
+
+  * Added equalFilePath.
+  * Added makeRelative.
+
+ -- Joey Hess <id@joeyh.name>  Mon, 30 Dec 2019 13:07:31 -0400
+
 filepath-bytestring (1.4.2.1.2) unstable; urgency=medium
 
   * Fix build with ghc 8.0 (pre-Semigroup Monoid transition)
diff --git a/System/FilePath/Internal.hs b/System/FilePath/Internal.hs
--- a/System/FilePath/Internal.hs
+++ b/System/FilePath/Internal.hs
@@ -126,8 +126,8 @@
     dropTrailingPathSeparator,
 
     -- * File name manipulations
-    normalise, --equalFilePath,
-    --makeRelative,
+    normalise, equalFilePath,
+    makeRelative,
     isRelative, isAbsolute,
     isValid, --makeValid
     )
@@ -136,7 +136,7 @@
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Char8 as B8
-import Data.Char(ord, chr, toUpper, isAsciiLower, isAsciiUpper)
+import Data.Char(ord, chr, toUpper, toLower, isAsciiLower, isAsciiUpper)
 import Data.Maybe(isJust)
 import Data.Word(Word8)
 #ifdef mingw32_HOST_OS
@@ -796,7 +796,7 @@
 -- > Posix:   "/directory" </> "file.ext" == "/directory/file.ext"
 -- > Windows: "/directory" </> "file.ext" == "/directory\\file.ext"
 -- >          "directory" </> "/file.ext" == "/file.ext"
--- > untested Valid x => (takeDirectory x </> takeFileName x) `equalFilePath` x
+-- > Valid x => (takeDirectory x </> takeFileName x) `equalFilePath` x
 --
 --   Combined:
 --
@@ -859,7 +859,7 @@
 -- >          splitDirectories "test/file" == ["test","file"]
 -- >          splitDirectories "/test/file" == ["/","test","file"]
 -- > Windows: splitDirectories "C:\\test\\file" == ["C:\\", "test", "file"]
--- > untested          Valid x => joinPath (splitDirectories x) `equalFilePath` x
+-- >          Valid x => joinPath (splitDirectories x) `equalFilePath` x
 -- >          splitDirectories "" == []
 -- > Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]
 -- >          splitDirectories "/test///file" == ["/","test","file"]
@@ -877,8 +877,6 @@
 -- Note that this definition on c:\\c:\\, join then split will give c:\\.
 joinPath = foldr combine mempty
 
-{-
-
 ---------------------------------------------------------------------
 -- File name manipulators
 
@@ -887,24 +885,21 @@
 --   first this has a much better chance of working.
 --   Note that this doesn't follow symlinks or DOSNAM~1s.
 --
--- > untested          x == y ==> equalFilePath x y
--- > untested          normalise x == normalise y ==> equalFilePath x y
--- > untested          equalFilePath "foo" "foo/"
--- > untested          not (equalFilePath "foo" "/foo")
--- > untested Posix:   not (equalFilePath "foo" "FOO")
--- > untested Windows: equalFilePath "foo" "FOO"
--- > untested Windows: not (equalFilePath "C:" "C:/")
+-- >          x == y ==> equalFilePath x y
+-- >          normalise x == normalise y ==> equalFilePath x y
+-- >          equalFilePath "foo" "foo/"
+-- >          not (equalFilePath "foo" "/foo")
+-- > Posix:   not (equalFilePath "foo" "FOO")
+-- > Windows: equalFilePath "foo" "FOO"
+-- > Windows: not (equalFilePath "C:" "C:/")
 equalFilePath :: RawFilePath -> RawFilePath -> Bool
 equalFilePath a b = f a == f b
   where
--- FIXME: B8.map will not lower-case non-ascii characters.
 	f x
-		| isWindows = dropTrailingPathSeparator $ B8.map toLower $ normalise x
+		| isWindows = dropTrailingPathSeparator $ encodeFilePath $
+			map toLower $ decodeFilePath $ normalise x
 		| otherwise = dropTrailingPathSeparator $ normalise x
--}
 
-{-
-
 -- | Contract a filename, based on a relative path. Note that the resulting path
 --   will never introduce @..@ paths, as the presence of symlinks means @..\/b@
 --   may not reach @a\/b@ if it starts from @a\/c@. For a worked example see
@@ -913,46 +908,46 @@
 --   The corresponding @makeAbsolute@ function can be found in
 --   @System.Directory@.
 --
--- > untested          makeRelative "/directory" "/directory/file.ext" == "file.ext"
--- > untested          Valid x => makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
--- > untested          makeRelative x x == "."
--- > untested          Valid x y => equalFilePath x y || (isRelative x && makeRelative y x == x) || equalFilePath (y </> makeRelative y x) x
--- > untested Windows: makeRelative "C:\\Home" "c:\\home\\bob" == "bob"
--- > untested Windows: makeRelative "C:\\Home" "c:/home/bob" == "bob"
--- > untested Windows: makeRelative "C:\\Home" "D:\\Home\\Bob" == "D:\\Home\\Bob"
--- > untested Windows: makeRelative "C:\\Home" "C:Home\\Bob" == "C:Home\\Bob"
--- > untested Windows: makeRelative "/Home" "/home/bob" == "bob"
--- > untested Windows: makeRelative "/" "//" == "//"
--- > untested Posix:   makeRelative "/Home" "/home/bob" == "/home/bob"
--- > untested Posix:   makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar"
--- > untested Posix:   makeRelative "/fred" "bob" == "bob"
--- > untested Posix:   makeRelative "/file/test" "/file/test/fred" == "fred"
--- > untested Posix:   makeRelative "/file/test" "/file/test/fred/" == "fred/"
--- > untested Posix:   makeRelative "some/path" "some/path/a/b/c" == "a/b/c"
-makeRelative :: FilePath -> FilePath -> FilePath
+-- >          makeRelative "/directory" "/directory/file.ext" == "file.ext"
+-- >          Valid x => makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
+-- >          makeRelative x x == "."
+-- >          Valid x y => equalFilePath x y || (isRelative x && makeRelative y x == x) || equalFilePath (y </> makeRelative y x) x
+-- > Windows: makeRelative "C:\\Home" "c:\\home\\bob" == "bob"
+-- > Windows: makeRelative "C:\\Home" "c:/home/bob" == "bob"
+-- > Windows: makeRelative "C:\\Home" "D:\\Home\\Bob" == "D:\\Home\\Bob"
+-- > Windows: makeRelative "C:\\Home" "C:Home\\Bob" == "C:Home\\Bob"
+-- > Windows: makeRelative "/Home" "/home/bob" == "bob"
+-- > Windows: makeRelative "/" "//" == "//"
+-- > Posix:   makeRelative "/Home" "/home/bob" == "/home/bob"
+-- > Posix:   makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar"
+-- > Posix:   makeRelative "/fred" "bob" == "bob"
+-- > Posix:   makeRelative "/file/test" "/file/test/fred" == "fred"
+-- > Posix:   makeRelative "/file/test" "/file/test/fred/" == "fred/"
+-- > Posix:   makeRelative "some/path" "some/path/a/b/c" == "a/b/c"
+makeRelative :: RawFilePath -> RawFilePath -> RawFilePath
 makeRelative root path
 	| equalFilePath root path = "."
 	| takeAbs root /= takeAbs path = path
 	| otherwise = f (dropAbs root) (dropAbs path)
   where
-	f "" y = dropWhile isPathSeparator y
+	f "" y = B.dropWhile isPathSeparator y
 	f x y =
 		let (x1,x2) = g x
 		    (y1,y2) = g y
 		in if equalFilePath x1 y1 then f x2 y2 else path
 
-	g x = (dropWhile isPathSeparator a, dropWhile isPathSeparator b)
+	g x = (B.dropWhile isPathSeparator a, B.dropWhile isPathSeparator b)
 	  where
-		(a,b) = break isPathSeparator $ dropWhile isPathSeparator x
+		(a,b) = B.break isPathSeparator $ B.dropWhile isPathSeparator x
 
 	-- on windows, need to drop '/' which is kind of absolute, but not a drive
-	dropAbs x | hasLeadingPathSeparator x && not (hasDrive x) = tail x
+	dropAbs x | hasLeadingPathSeparator x && not (hasDrive x) = B.tail x
 	dropAbs x = dropDrive x
 
-	takeAbs x | hasLeadingPathSeparator x && not (hasDrive x) = [pathSeparator]
-	takeAbs x = map (\y -> if isPathSeparator y then pathSeparator else toLower y) $ takeDrive x
-
--}
+	takeAbs x | hasLeadingPathSeparator x && not (hasDrive x) = B.singleton pathSeparator
+	-- A Windows drive letter is an ascii character, so it's safe to
+	-- operate on the ByteString containing it using B8.
+	takeAbs x = B8.map toLower $ takeDrive x
 
 -- | Normalise a file
 --
@@ -1074,7 +1069,7 @@
 		not (isJust (readDriveUNC x1) && not (hasTrailingPathSeparator x1))
   where
 	(x1,x2) = splitDrive path
-	f x = map toUpper (B8.unpack $ dropWhileEnd (== 32) $ dropExtensions x) `elem` badElements
+	f x = map toUpper (decodeFilePath $ dropWhileEnd (== 32) $ dropExtensions x) `elem` badElements
 
 {-
 
diff --git a/TODO b/TODO
--- a/TODO
+++ b/TODO
@@ -1,3 +1,3 @@
 * Some functions have not been ported from FilePath and are commented out:
-  splitSearchPath, getSearchPath, normalise, equalFilePath, makeRelative,
+  splitSearchPath, getSearchPath,
   makeValid. Implementations would be accepted if you need any of these.
diff --git a/filepath-bytestring.cabal b/filepath-bytestring.cabal
--- a/filepath-bytestring.cabal
+++ b/filepath-bytestring.cabal
@@ -1,6 +1,6 @@
 cabal-version:  >= 1.18
 name:           filepath-bytestring
-version:        1.4.2.1.2
+version:        1.4.2.1.3
 -- NOTE: Don't forget to update CHANGELOG and the filepath version below
 license:        BSD3
 license-file:   LICENSE
diff --git a/tests/TestGen.hs b/tests/TestGen.hs
--- a/tests/TestGen.hs
+++ b/tests/TestGen.hs
@@ -303,6 +303,8 @@
     ,("\"/directory\" W.</> \"file.ext\" == \"/directory\\\\file.ext\"", property $ "/directory" W.</> "file.ext" == "/directory\\file.ext")
     ,("\"directory\" P.</> \"/file.ext\" == \"/file.ext\"", property $ "directory" P.</> "/file.ext" == "/file.ext")
     ,("\"directory\" W.</> \"/file.ext\" == \"/file.ext\"", property $ "directory" W.</> "/file.ext" == "/file.ext")
+    ,("(P.takeDirectory x P.</> P.takeFileName x) `P.equalFilePath` x", property $ \(QFilePathValidP vx) -> let x = toRawFilePath vx in (P.takeDirectory x P.</> P.takeFileName x) `P.equalFilePath` x)
+    ,("(W.takeDirectory x W.</> W.takeFileName x) `W.equalFilePath` x", property $ \(QFilePathValidW vx) -> let x = toRawFilePath vx in (W.takeDirectory x W.</> W.takeFileName x) `W.equalFilePath` x)
     ,("\"/\" P.</> \"test\" == \"/test\"", property $ "/" P.</> "test" == "/test")
     ,("\"home\" P.</> \"bob\" == \"home/bob\"", property $ "home" P.</> "bob" == "home/bob")
     ,("\"x:\" P.</> \"foo\" == \"x:/foo\"", property $ "x:" P.</> "foo" == "x:/foo")
@@ -334,6 +336,8 @@
     ,("P.splitDirectories \"/test/file\" == [\"/\", \"test\", \"file\"]", property $ P.splitDirectories "/test/file" == ["/", "test", "file"])
     ,("W.splitDirectories \"/test/file\" == [\"/\", \"test\", \"file\"]", property $ W.splitDirectories "/test/file" == ["/", "test", "file"])
     ,("W.splitDirectories \"C:\\\\test\\\\file\" == [\"C:\\\\\", \"test\", \"file\"]", property $ W.splitDirectories "C:\\test\\file" == ["C:\\", "test", "file"])
+    ,("P.joinPath (P.splitDirectories x) `P.equalFilePath` x", property $ \(QFilePathValidP vx) -> let x = toRawFilePath vx in P.joinPath (P.splitDirectories x) `P.equalFilePath` x)
+    ,("W.joinPath (W.splitDirectories x) `W.equalFilePath` x", property $ \(QFilePathValidW vx) -> let x = toRawFilePath vx in W.joinPath (W.splitDirectories x) `W.equalFilePath` x)
     ,("P.splitDirectories \"\" == []", property $ P.splitDirectories "" == [])
     ,("W.splitDirectories \"\" == []", property $ W.splitDirectories "" == [])
     ,("W.splitDirectories \"C:\\\\test\\\\\\\\\\\\file\" == [\"C:\\\\\", \"test\", \"file\"]", property $ W.splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"])
@@ -346,6 +350,17 @@
     ,("P.joinPath [] == \"\"", property $ P.joinPath [] == "")
     ,("W.joinPath [] == \"\"", property $ W.joinPath [] == "")
     ,("P.joinPath [\"test\", \"file\", \"path\"] == \"test/file/path\"", property $ P.joinPath ["test", "file", "path"] == "test/file/path")
+    ,("x == y ==> P.equalFilePath x y", property $ \(QFilePath vx) (QFilePath vy) -> let y = toRawFilePath vy in let x = toRawFilePath vx in x == y ==> P.equalFilePath x y)
+    ,("x == y ==> W.equalFilePath x y", property $ \(QFilePath vx) (QFilePath vy) -> let y = toRawFilePath vy in let x = toRawFilePath vx in x == y ==> W.equalFilePath x y)
+    ,("P.normalise x == P.normalise y ==> P.equalFilePath x y", property $ \(QFilePath vx) (QFilePath vy) -> let y = toRawFilePath vy in let x = toRawFilePath vx in P.normalise x == P.normalise y ==> P.equalFilePath x y)
+    ,("W.normalise x == W.normalise y ==> W.equalFilePath x y", property $ \(QFilePath vx) (QFilePath vy) -> let y = toRawFilePath vy in let x = toRawFilePath vx in W.normalise x == W.normalise y ==> W.equalFilePath x y)
+    ,("P.equalFilePath \"foo\" \"foo/\"", property $ P.equalFilePath "foo" "foo/")
+    ,("W.equalFilePath \"foo\" \"foo/\"", property $ W.equalFilePath "foo" "foo/")
+    ,("not (P.equalFilePath \"foo\" \"/foo\")", property $ not (P.equalFilePath "foo" "/foo"))
+    ,("not (W.equalFilePath \"foo\" \"/foo\")", property $ not (W.equalFilePath "foo" "/foo"))
+    ,("not (P.equalFilePath \"foo\" \"FOO\")", property $ not (P.equalFilePath "foo" "FOO"))
+    ,("W.equalFilePath \"foo\" \"FOO\"", property $ W.equalFilePath "foo" "FOO")
+    ,("not (W.equalFilePath \"C:\" \"C:/\")", property $ not (W.equalFilePath "C:" "C:/"))
     ,("P.normalise \"/file/\\\\test////\" == \"/file/\\\\test/\"", property $ P.normalise "/file/\\test////" == "/file/\\test/")
     ,("P.normalise \"/file/./test\" == \"/file/test\"", property $ P.normalise "/file/./test" == "/file/test")
     ,("P.normalise \"/test/file/../bob/fred/\" == \"/test/file/../bob/fred/\"", property $ P.normalise "/test/file/../bob/fred/" == "/test/file/../bob/fred/")
