diff --git a/System/Directory.hs b/System/Directory.hs
--- a/System/Directory.hs
+++ b/System/Directory.hs
@@ -262,32 +262,32 @@
 
 The operation may fail with:
 
-* 'isPermissionError' \/ 'PermissionDenied'
+* 'isPermissionError'
 The process has insufficient privileges to perform the operation.
 @[EROFS, EACCES]@
 
-* 'isAlreadyExistsError' \/ 'AlreadyExists'
+* 'isAlreadyExistsError'
 The operand refers to a directory that already exists.
 @ [EEXIST]@
 
-* 'HardwareFault'
+* @HardwareFault@
 A physical I\/O error has occurred.
 @[EIO]@
 
-* 'InvalidArgument'
+* @InvalidArgument@
 The operand is not a valid directory name.
 @[ENAMETOOLONG, ELOOP]@
 
-* 'NoSuchThing'
+* 'isDoesNotExistError'
 There is no path to the directory.
 @[ENOENT, ENOTDIR]@
 
-* 'ResourceExhausted'
+* 'System.IO.isFullError'
 Insufficient resources (virtual memory, process file descriptors,
 physical disk space, etc.) are available to perform the operation.
 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
 
-* 'InappropriateType'
+* @InappropriateType@
 The path refers to an existing non-directory object.
 @[EEXIST]@
 
@@ -354,31 +354,31 @@
 
 The operation may fail with:
 
-* 'HardwareFault'
+* @HardwareFault@
 A physical I\/O error has occurred.
 @[EIO]@
 
-* 'InvalidArgument'
+* @InvalidArgument@
 The operand is not a valid directory name.
 @[ENAMETOOLONG, ELOOP]@
 
-* 'isDoesNotExistError' \/ 'NoSuchThing'
+* 'isDoesNotExistError'
 The directory does not exist.
 @[ENOENT, ENOTDIR]@
 
-* 'isPermissionError' \/ 'PermissionDenied'
+* 'isPermissionError'
 The process has insufficient privileges to perform the operation.
 @[EROFS, EACCES, EPERM]@
 
-* 'UnsatisfiedConstraints'
+* @UnsatisfiedConstraints@
 Implementation-dependent constraints are not satisfied.
 @[EBUSY, ENOTEMPTY, EEXIST]@
 
-* 'UnsupportedOperation'
+* @UnsupportedOperation@
 The implementation does not support removal in this situation.
 @[EINVAL]@
 
-* 'InappropriateType'
+* @InappropriateType@
 The operand refers to an existing non-directory object.
 @[ENOTDIR]@
 
@@ -405,7 +405,7 @@
         ioError (err `ioeSetErrorString` "not a directory")
   where err = mkIOError InappropriateType "" Nothing (Just path)
 
--- | @'removePathRecursive' path@ removes an existing file or directory at
+-- | @removePathRecursive path@ removes an existing file or directory at
 -- /path/ together with its contents and subdirectories. Symbolic links are
 -- removed without affecting their the targets.
 removePathRecursive :: FilePath -> IO ()
@@ -417,7 +417,7 @@
       DirectoryLink -> removeDirectory path
       _             -> removeFile path
 
--- | @'removeContentsRecursive' dir@ removes the contents of the directory
+-- | @removeContentsRecursive dir@ removes the contents of the directory
 -- /dir/ recursively. Symbolic links are removed without affecting their the
 -- targets.
 removeContentsRecursive :: FilePath -> IO ()
@@ -480,27 +480,27 @@
 
 The operation may fail with:
 
-* 'HardwareFault'
+* @HardwareFault@
 A physical I\/O error has occurred.
 @[EIO]@
 
-* 'InvalidArgument'
+* @InvalidArgument@
 The operand is not a valid file name.
 @[ENAMETOOLONG, ELOOP]@
 
-* 'isDoesNotExistError' \/ 'NoSuchThing'
+* 'isDoesNotExistError'
 The file does not exist.
 @[ENOENT, ENOTDIR]@
 
-* 'isPermissionError' \/ 'PermissionDenied'
+* 'isPermissionError'
 The process has insufficient privileges to perform the operation.
 @[EROFS, EACCES, EPERM]@
 
-* 'UnsatisfiedConstraints'
+* @UnsatisfiedConstraints@
 Implementation-dependent constraints are not satisfied.
 @[EBUSY]@
 
-* 'InappropriateType'
+* @InappropriateType@
 The operand refers to an existing directory.
 @[EPERM, EINVAL]@
 
@@ -524,35 +524,35 @@
 
 The operation may fail with:
 
-* 'HardwareFault'
+* @HardwareFault@
 A physical I\/O error has occurred.
 @[EIO]@
 
-* 'InvalidArgument'
+* @InvalidArgument@
 Either operand is not a valid directory name.
 @[ENAMETOOLONG, ELOOP]@
 
-* 'isDoesNotExistError' \/ 'NoSuchThing'
+* 'isDoesNotExistError'
 The original directory does not exist, or there is no path to the target.
 @[ENOENT, ENOTDIR]@
 
-* 'isPermissionError' \/ 'PermissionDenied'
+* 'isPermissionError'
 The process has insufficient privileges to perform the operation.
 @[EROFS, EACCES, EPERM]@
 
-* 'ResourceExhausted'
+* 'System.IO.isFullError'
 Insufficient resources are available to perform the operation.
 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
 
-* 'UnsatisfiedConstraints'
+* @UnsatisfiedConstraints@
 Implementation-dependent constraints are not satisfied.
 @[EBUSY, ENOTEMPTY, EEXIST]@
 
-* 'UnsupportedOperation'
+* @UnsupportedOperation@
 The implementation does not support renaming in this situation.
 @[EINVAL, EXDEV]@
 
-* 'InappropriateType'
+* @InappropriateType@
 Either path refers to an existing non-directory object.
 @[ENOTDIR, EISDIR]@
 
@@ -578,35 +578,35 @@
 
 The operation may fail with:
 
-* 'HardwareFault'
+* @HardwareFault@
 A physical I\/O error has occurred.
 @[EIO]@
 
-* 'InvalidArgument'
+* @InvalidArgument@
 Either operand is not a valid file name.
 @[ENAMETOOLONG, ELOOP]@
 
-* 'isDoesNotExistError' \/ 'NoSuchThing'
+* 'isDoesNotExistError'
 The original file does not exist, or there is no path to the target.
 @[ENOENT, ENOTDIR]@
 
-* 'isPermissionError' \/ 'PermissionDenied'
+* 'isPermissionError'
 The process has insufficient privileges to perform the operation.
 @[EROFS, EACCES, EPERM]@
 
-* 'ResourceExhausted'
+* 'System.IO.isFullError'
 Insufficient resources are available to perform the operation.
 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
 
-* 'UnsatisfiedConstraints'
+* @UnsatisfiedConstraints@
 Implementation-dependent constraints are not satisfied.
 @[EBUSY]@
 
-* 'UnsupportedOperation'
+* @UnsupportedOperation@
 The implementation does not support renaming in this situation.
 @[EXDEV]@
 
-* 'InappropriateType'
+* @InappropriateType@
 Either path refers to an existing directory.
 @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
 
@@ -642,35 +642,35 @@
 --
 -- The operation may fail with:
 --
--- * 'HardwareFault'
+-- * @HardwareFault@
 -- A physical I\/O error has occurred.
 -- @[EIO]@
 --
--- * 'InvalidArgument'
+-- * @InvalidArgument@
 -- Either operand is not a valid file name.
 -- @[ENAMETOOLONG, ELOOP]@
 --
--- * 'isDoesNotExistError' \/ 'NoSuchThing'
+-- * 'isDoesNotExistError'
 -- The original file does not exist, or there is no path to the target.
 -- @[ENOENT, ENOTDIR]@
 --
--- * 'isPermissionError' \/ 'PermissionDenied'
+-- * 'isPermissionError'
 -- The process has insufficient privileges to perform the operation.
 -- @[EROFS, EACCES, EPERM]@
 --
--- * 'ResourceExhausted'
+-- * 'System.IO.isFullError'
 -- Insufficient resources are available to perform the operation.
 -- @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
 --
--- * 'UnsatisfiedConstraints'
+-- * @UnsatisfiedConstraints@
 -- Implementation-dependent constraints are not satisfied.
 -- @[EBUSY]@
 --
--- * 'UnsupportedOperation'
+-- * @UnsupportedOperation@
 -- The implementation does not support renaming in this situation.
 -- @[EXDEV]@
 --
--- * 'InappropriateType'
+-- * @InappropriateType@
 -- Either the destination path refers to an existing directory, or one of the
 -- parent segments in the destination path is not a directory.
 -- @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
@@ -696,7 +696,7 @@
       (ignoreIOExceptions . copyPermissions fromFPath)
 
 -- | Copy the contents of a source file to a destination file, replacing the
--- destination file atomically via 'withReplacementFile', resetting the
+-- destination file atomically via @withReplacementFile@, resetting the
 -- attributes of the destination file to the defaults.
 atomicCopyFileContents :: FilePath            -- ^ Source filename
                        -> FilePath            -- ^ Destination filename
@@ -937,9 +937,10 @@
 -- give you the path to GHC.
 --
 -- The path returned by @'findExecutable' name@ corresponds to the program
--- that would be executed by 'System.Process.createProcess' when passed the
--- same string (as a @RawCommand@, not a @ShellCommand@), provided that @name@
--- is not a relative path with more than one segment.
+-- that would be executed by
+-- @<http://hackage.haskell.org/package/process/docs/System-Process.html#v:createProcess createProcess>@
+-- when passed the same string (as a @RawCommand@, not a @ShellCommand@),
+-- provided that @name@ is not a relative path with more than one segment.
 --
 -- On Windows, 'findExecutable' calls the Win32 function
 -- @<https://msdn.microsoft.com/en-us/library/aa365527.aspx SearchPath>@,
@@ -1089,27 +1090,27 @@
 --
 -- The operation may fail with:
 --
--- * 'HardwareFault'
+-- * @HardwareFault@
 --   A physical I\/O error has occurred.
 --   @[EIO]@
 --
--- * 'InvalidArgument'
+-- * @InvalidArgument@
 --   The operand is not a valid directory name.
 --   @[ENAMETOOLONG, ELOOP]@
 --
--- * 'isDoesNotExistError' \/ 'NoSuchThing'
+-- * 'isDoesNotExistError'
 --   The directory does not exist.
 --   @[ENOENT, ENOTDIR]@
 --
--- * 'isPermissionError' \/ 'PermissionDenied'
+-- * 'isPermissionError'
 --   The process has insufficient privileges to perform the operation.
 --   @[EACCES]@
 --
--- * 'ResourceExhausted'
+-- * 'System.IO.isFullError'
 --   Insufficient resources are available to perform the operation.
 --   @[EMFILE, ENFILE]@
 --
--- * 'InappropriateType'
+-- * @InappropriateType@
 --   The path refers to an existing non-directory object.
 --   @[ENOTDIR]@
 --
@@ -1128,22 +1129,22 @@
 --
 -- The operation may fail with:
 --
--- * 'HardwareFault'
+-- * @HardwareFault@
 -- A physical I\/O error has occurred.
 -- @[EIO]@
 --
--- * 'isDoesNotExistError' or 'NoSuchThing'
+-- * 'isDoesNotExistError'
 -- There is no path referring to the working directory.
 -- @[EPERM, ENOENT, ESTALE...]@
 --
--- * 'isPermissionError' or 'PermissionDenied'
+-- * 'isPermissionError'
 -- The process has insufficient privileges to perform the operation.
 -- @[EACCES]@
 --
--- * 'ResourceExhausted'
+-- * 'System.IO.isFullError'
 -- Insufficient resources are available to perform the operation.
 --
--- * 'UnsupportedOperation'
+-- * @UnsupportedOperation@
 -- The operating system has no notion of current working directory.
 --
 getCurrentDirectory :: IO FilePath
@@ -1163,27 +1164,27 @@
 --
 -- The operation may fail with:
 --
--- * 'HardwareFault'
+-- * @HardwareFault@
 -- A physical I\/O error has occurred.
 -- @[EIO]@
 --
--- * 'InvalidArgument'
+-- * @InvalidArgument@
 -- The operand is not a valid directory name.
 -- @[ENAMETOOLONG, ELOOP]@
 --
--- * 'isDoesNotExistError' or 'NoSuchThing'
+-- * 'isDoesNotExistError'
 -- The directory does not exist.
 -- @[ENOENT, ENOTDIR]@
 --
--- * 'isPermissionError' or 'PermissionDenied'
+-- * 'isPermissionError'
 -- The process has insufficient privileges to perform the operation.
 -- @[EACCES]@
 --
--- * 'UnsupportedOperation'
+-- * @UnsupportedOperation@
 -- The operating system has no notion of current working directory, or the
 -- working directory cannot be dynamically changed.
 --
--- * 'InappropriateType'
+-- * @InappropriateType@
 -- The path refers to an existing non-directory object.
 -- @[ENOTDIR]@
 --
@@ -1358,7 +1359,7 @@
 --
 -- On Windows systems, this calls @DeviceIoControl@ with
 -- @FSCTL_GET_REPARSE_POINT@.  In addition to symbolic links, the function
--- also works on junction points.  On POSIX systems, this calls `readlink`.
+-- also works on junction points.  On POSIX systems, this calls @readlink@.
 --
 -- Windows-specific errors: This operation may fail with
 -- 'illegalOperationErrorType' if the file system does not support symbolic
@@ -1485,7 +1486,7 @@
 
 The operation may fail with:
 
-* 'UnsupportedOperation'
+* @UnsupportedOperation@
 The operating system has no notion of home directory.
 
 * 'isDoesNotExistError'
@@ -1524,6 +1525,8 @@
   (`ioeAddLocation` "getXdgDirectory") `modifyIOError` do
     simplify . (</> suffix) <$> getXdgDirectoryInternal getHomeDirectory xdgDir
 
+-- | Similar to 'getXdgDirectory' but retrieves the entire list of XDG
+-- directories.
 getXdgDirectoryList :: XdgDirectoryList -- ^ which special directory list
                     -> IO [FilePath]
 getXdgDirectoryList xdgDirs =
@@ -1548,7 +1551,7 @@
 --
 --   The operation may fail with:
 --
---   * 'UnsupportedOperation'
+--   * @UnsupportedOperation@
 --     The operating system has no notion of application-specific data
 --     directory.
 --
@@ -1576,7 +1579,7 @@
 
 The operation may fail with:
 
-* 'UnsupportedOperation'
+* @UnsupportedOperation@
 The operating system has no notion of document directory.
 
 * 'isDoesNotExistError'
@@ -1609,7 +1612,7 @@
 
 The operation may fail with:
 
-* 'UnsupportedOperation'
+* @UnsupportedOperation@
 The operating system has no notion of temporary directory.
 
 The function doesn\'t verify whether the path exists.
diff --git a/System/Directory/Internal/Common.hs b/System/Directory/Internal/Common.hs
--- a/System/Directory/Internal/Common.hs
+++ b/System/Directory/Internal/Common.hs
@@ -185,7 +185,7 @@
 
 -- | Check whether the given 'FileType' is considered a directory by the
 -- operating system.  This affects the choice of certain functions
--- e.g. `removeDirectory` vs `removeFile`.
+-- e.g. 'System.Directory.removeDirectory' vs 'System.Directory.removeFile'.
 fileTypeIsDirectory :: FileType -> Bool
 fileTypeIsDirectory Directory     = True
 fileTypeIsDirectory DirectoryLink = True
diff --git a/System/Directory/Internal/Posix.hsc b/System/Directory/Internal/Posix.hsc
--- a/System/Directory/Internal/Posix.hsc
+++ b/System/Directory/Internal/Posix.hsc
@@ -41,7 +41,9 @@
 c_PATH_MAX | c_PATH_MAX' > toInteger maxValue = Nothing
            | otherwise                        = Just (fromInteger c_PATH_MAX')
   where c_PATH_MAX' = (#const PATH_MAX)
-        maxValue    = maxBound `asTypeOf` case c_PATH_MAX of ~(Just x) -> x
+        maxValue = maxBound `asTypeInMaybe` c_PATH_MAX
+        asTypeInMaybe :: a -> Maybe a -> a
+        asTypeInMaybe = const
 #else
 c_PATH_MAX = Nothing
 #endif
@@ -291,10 +293,8 @@
     get name fallback = do
       env <- lookupEnv name
       case env of
-        Nothing                     -> fallback'
-        Just path | isRelative path -> fallback'
-                  | otherwise       -> pure path
-      where fallback' = (</> fallback) <$> getHomeDirectory
+        Nothing   -> (</> fallback) <$> getHomeDirectory
+        Just path -> pure path
 
 getXdgDirectoryListInternal :: XdgDirectoryList -> IO [FilePath]
 getXdgDirectoryListInternal xdgDirs =
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,12 @@
 Changelog for the [`directory`][1] package
 ==========================================
 
+## 1.3.3.2 (January 2019)
+
+  * `getXdgDirectory` will no longer reject environment variables containing
+    relative paths.
+    ([#87](https://github.com/haskell/directory/issues/87))
+
 ## 1.3.3.1 (August 2018)
 
   * `doesDirectoryExist` and `doesPathExist` reject empty paths once again,
diff --git a/directory.cabal b/directory.cabal
--- a/directory.cabal
+++ b/directory.cabal
@@ -1,5 +1,5 @@
 name:           directory
-version:        1.3.3.1
+version:        1.3.3.2
 -- NOTE: Don't forget to update ./changelog.md
 license:        BSD3
 license-file:   LICENSE
diff --git a/tests/FileTime.hs b/tests/FileTime.hs
--- a/tests/FileTime.hs
+++ b/tests/FileTime.hs
@@ -42,9 +42,16 @@
     atime3 <- getAccessTime file
     mtime3 <- getModificationTime file
 
-    -- access time should be set with at worst 1 sec resolution
-    T(expectNearTime) file atime  atime3 1
+    when setAtime $ do
+      -- access time should be set with at worst 1 sec resolution
+      T(expectNearTime) file atime atime3 1
 
     -- modification time should not change, although it may lose some precision
     -- on POSIX systems without 'utimensat'
     T(expectNearTime) file mtime2 mtime3 1
+
+  where
+
+    testname = "FileTime"
+
+    setAtime = T.readArg _t testname "set-atime" True
diff --git a/tests/Xdg.hs b/tests/Xdg.hs
--- a/tests/Xdg.hs
+++ b/tests/Xdg.hs
@@ -25,6 +25,9 @@
   setEnv "XDG_CONFIG_DIRS" "/d:/e:/f"
   T(expectEq) () ["/a", "/b", "/c"] =<< getXdgDirectoryList XdgDataDirs
   T(expectEq) () ["/d", "/e", "/f"] =<< getXdgDirectoryList XdgConfigDirs
+
+  setEnv "XDG_CACHE_HOME" "g"
+  T(expectEq) () "g/h" =<< getXdgDirectory XdgCache "h"
 #endif
 
   return ()
