diff --git a/lib/Filesystem/Path.hs b/lib/Filesystem/Path.hs
--- a/lib/Filesystem/Path.hs
+++ b/lib/Filesystem/Path.hs
@@ -270,6 +270,9 @@
 		       | otherwise -> (False, ts)
 	step (_, acc) c = (False, c:acc)
 
+-- | expand a FilePath into a list of the root name, directories, and file name
+--
+-- Since: 0.4.7
 splitDirectories :: FilePath -> [FilePath]
 splitDirectories p = rootName ++ dirNames ++ fileName where
 	rootName = case pathRoot p of
diff --git a/lib/Filesystem/Path/Internal.hs b/lib/Filesystem/Path/Internal.hs
--- a/lib/Filesystem/Path/Internal.hs
+++ b/lib/Filesystem/Path/Internal.hs
@@ -216,9 +216,13 @@
 parseFilename filename = parsed where
 	parsed = if null filename
 		then (Nothing, [])
-		else case splitBy (== '.') filename of
-			[] -> (Nothing, [])
-			(name':exts') -> (Just name', exts')
+		else case span (== '.') filename of
+			(leadingDots, baseAndExts) -> case splitBy (== '.') baseAndExts of
+				[] -> (joinDots leadingDots "", [])
+				(name':exts') -> (joinDots leadingDots name', exts')
+	joinDots leadingDots base = case leadingDots ++ base of
+		[] -> Nothing
+		joined -> Just joined
 
 maybeDecodeUtf8 :: B.ByteString -> Maybe T.Text
 maybeDecodeUtf8 = excToMaybe . TE.decodeUtf8 where
diff --git a/system-filepath.cabal b/system-filepath.cabal
--- a/system-filepath.cabal
+++ b/system-filepath.cabal
@@ -1,5 +1,5 @@
 name: system-filepath
-version: 0.4.7
+version: 0.4.8
 synopsis: High-level, byte-based file and directory path manipulations
 license: MIT
 license-file: license.txt
@@ -23,13 +23,13 @@
   tests/Tests.hs
 
 source-repository head
-  type: bzr
-  location: https://john-millikin.com/branches/system-filepath/0.4/
+  type: git
+  location: https://john-millikin.com/code/haskell-filesystem/
 
 source-repository this
-  type: bzr
-  location: https://john-millikin.com/branches/system-filepath/0.4/
-  tag: system-filepath_0.4.7
+  type: git
+  location: https://john-millikin.com/code/haskell-filesystem/
+  tag: system-filepath_0.4.8
 
 library
   ghc-options: -Wall -O2
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -33,6 +33,8 @@
 	test_Absolute
 	test_Relative
 	
+	test_LeadingDotSpecialCases
+	
 	-- Basic operations
 	test_Append
 	test_CommonPrefix
@@ -147,13 +149,9 @@
 	
 	$expect $ equal (basename_posix "/foo/bar") "bar"
 	$expect $ equal (basename_posix "/foo/bar.txt") "bar"
-	$expect $ equal (basename_posix ".") ""
-	$expect $ equal (basename_posix "..") ""
 	
 	$expect $ equal (basename_windows "c:\\foo\\bar") "bar"
 	$expect $ equal (basename_windows "c:\\foo\\bar.txt") "bar"
-	$expect $ equal (basename_windows ".") ""
-	$expect $ equal (basename_windows "..") ""
 
 test_Absolute :: Test
 test_Absolute = assertions "absolute" $ do
@@ -180,6 +178,36 @@
 	$expect $ relative (fromString "")
 	$expect $ relative (fromString "foo\\bar")
 	$expect . not $ relative (fromString "\\foo\\bar")
+
+test_LeadingDotSpecialCases :: Test
+test_LeadingDotSpecialCases = assertions "leading-dot-special-cases" $ do
+	let components_posix x = let p = fromChar8 x in
+		(toChar8 (P.directory p), toChar8 (basename p), P.extensions p)
+	let components_windows x = let p = fromString x in
+		(toString (P.directory p), toString (basename p), P.extensions p)
+	
+	-- The filenames "." and ".." are always considered to be directory
+	-- elements, because they are links to either the current or parent
+	-- directories.
+	--
+	-- On POSIX, filenames starting with '.' are hidden files and have
+	-- a basename starting with '.'.
+	--
+	-- On Windows there is no history of similar naming patterns. The case
+	-- could be made that a filename like ".txt.gz" ought to have a
+	-- basename of "", but different basename behavior in POSIX and Windows
+	-- would greatly complicate the implementation of 'dirname'.
+	$expect $ equal (components_posix ".") ("./", "", [])
+	$expect $ equal (components_posix "..") ("../", "", [])
+	$expect $ equal (components_posix "/foo/.") ("/foo/./", "", [])
+	$expect $ equal (components_posix "/foo/..") ("/foo/../", "", [])
+	$expect $ equal (components_posix "/foo/.foo.txt") ("/foo/", ".foo", ["txt"])
+	
+	$expect $ equal (components_windows ".") (".\\", "", [])
+	$expect $ equal (components_windows "..") ("..\\", "", [])
+	$expect $ equal (components_windows "\\foo\\.") ("\\foo\\.\\", "", [])
+	$expect $ equal (components_windows "\\foo\\..") ("\\foo\\..\\", "", [])
+	$expect $ equal (components_windows "\\foo\\.foo.txt") ("\\foo\\", ".foo", ["txt"])
 
 test_Identity :: String -> Rules a -> Gen FilePath -> Test
 test_Identity name r gen = property name $ forAll gen $ \p -> p == decode r (encode r p)
