diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,19 @@
+## Path IO 1.6.0
+
+* Changed how `copyDirRecur` and `copyDirRecur'` functions work. Previously,
+  the functions created empty directories in the destination directory when
+  the source directory contained directory symlinks. The symlinked
+  directories were not recursively traversed. It also copied symlinked files
+  creating normal regular files in the target directory as the result. This
+  is fixed so that the function now behaves much like the `cp` utility, not
+  traversing symlinked directories, but recreating symlinks in the target
+  directory according to their targets in the source directory.
+
+* Fixed a bug in `createDirLink` which would always fail complaining that
+  its destination location does not exist.
+
+* Dropped support for GHC 8.2.
+
 ## Path IO 1.5.0
 
 * Dropped support for GHC 8.0 and older.
diff --git a/Path/IO.hs b/Path/IO.hs
--- a/Path/IO.hs
+++ b/Path/IO.hs
@@ -113,6 +113,7 @@
 import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT)
 import Control.Monad.Trans.Writer.Lazy (WriterT, execWriterT, tell)
 import Data.Either (lefts, rights)
+import Data.Kind (Type)
 import Data.List ((\\))
 import Data.Time (UTCTime)
 import Path
@@ -383,6 +384,15 @@
 -- ones.
 --
 -- __Note__: before version /1.3.0/, this function followed symlinks.
+--
+-- __Note__: before version /1.6.0/, the function created empty directories
+-- in the destination directory when the source directory contained
+-- directory symlinks. The symlinked directories were not recursively
+-- traversed. It also copied symlinked files creating normal regular files
+-- in the target directory as the result. This was fixed in the version
+-- /1.6.0/ so that the function now behaves much like the @cp@ utility, not
+-- traversing symlinked directories, but recreating symlinks in the target
+-- directory according to their targets in the source directory.
 
 copyDirRecur :: (MonadIO m, MonadCatch m)
   => Path b0 Dir       -- ^ Source
@@ -397,6 +407,15 @@
 -- @since 1.1.0
 --
 -- __Note__: before version /1.3.0/, this function followed symlinks.
+--
+-- __Note__: before version /1.6.0/, the function created empty directories
+-- in the destination directory when the source directory contained
+-- directory symlinks. The symlinked directories were not recursively
+-- traversed. It also copied symlinked files creating normal regular files
+-- in the target directory as the result. This was fixed in the version
+-- /1.6.0/ so that the function now behaves much like the @cp@ utility, not
+-- traversing symlinked directories, but recreating symlinks in the target
+-- directory according to their targets in the source directory.
 
 copyDirRecur' :: (MonadIO m, MonadCatch m)
   => Path b0 Dir       -- ^ Source
@@ -406,16 +425,14 @@
 
 -- | Generic version of 'copyDirRecur'. The first argument controls whether
 -- to preserve directory permissions or not. /Does not/ follow symbolic
--- links.
---
--- __Note__: before version /1.3.0/, this function followed symlinks.
+-- links. Internal function.
 
 copyDirRecurGen :: MonadIO m
   => Bool              -- ^ Should we preserve directory permissions?
   -> Path b0 Dir       -- ^ Source
   -> Path b1 Dir       -- ^ Destination
   -> m ()
-copyDirRecurGen p src dest = liftIO $ do
+copyDirRecurGen preserveDirPermissions src dest = liftIO $ do
   bsrc  <- makeAbsolute src
   bdest <- makeAbsolute dest
   (dirs, files) <- listDirRecur bsrc
@@ -426,14 +443,28 @@
         -> IO (Path Abs t)
       swapParent old new path = (new </>) <$>
         stripProperPrefix old path
-  tdirs  <- mapM (swapParent bsrc bdest) dirs
-  tfiles <- mapM (swapParent bsrc bdest) files
   ensureDir bdest
-  mapM_ ensureDir tdirs
-  zipWithM_ copyFile files tfiles
-  when p $ do
+  forM_ dirs $ \srcDir -> do
+    destDir <- swapParent bsrc bdest srcDir
+    dirIsSymlink <- isSymlink srcDir
+    if dirIsSymlink
+      then do
+        target <- getSymlinkTarget srcDir
+        D.createDirectoryLink target $
+          F.dropTrailingPathSeparator (toFilePath destDir)
+      else ensureDir destDir
+    when preserveDirPermissions $
+      ignoringIOErrors (copyPermissions srcDir destDir)
+  forM_ files $ \srcFile -> do
+    destFile <- swapParent bsrc bdest srcFile
+    fileIsSymlink <- isSymlink srcFile
+    if fileIsSymlink
+      then do
+        target <- getSymlinkTarget srcFile
+        D.createFileLink target (toFilePath destFile)
+      else copyFile srcFile destFile
+  when preserveDirPermissions $
     ignoringIOErrors (copyPermissions bsrc bdest)
-    zipWithM_ (\s d -> ignoringIOErrors $ copyPermissions s d) dirs tdirs
 
 ----------------------------------------------------------------------------
 -- Walking directory trees
@@ -886,11 +917,11 @@
 
   -- | Type of absolute version of the given @path@.
 
-  type AbsPath path :: *
+  type AbsPath path :: Type
 
   -- | Type of relative version of the given @path@.
 
-  type RelPath path :: *
+  type RelPath path :: Type
 
   -- | Make a path absolute and remove as many indirections from it as
   -- possible. Indirections include the two special directories @.@ and
@@ -1239,7 +1270,10 @@
   => Path b0 Dir                -- ^ Path to the target directory
   -> Path b1 Dir                -- ^ Path to the link to be created
   -> m ()
-createDirLink = liftD2 D.createDirectoryLink
+createDirLink target' dest' = do
+  let target = toFilePath target'
+      dest = F.dropTrailingPathSeparator (toFilePath dest')
+  liftIO $ D.createDirectoryLink target dest
 
 -- | Remove an existing /directory/ symbolic link.
 --
@@ -1273,7 +1307,7 @@
   :: MonadIO m
   => Path b t                   -- ^ Symlink path
   -> m FilePath
-getSymlinkTarget = liftD D.getSymbolicLinkTarget
+getSymlinkTarget = liftD (D.getSymbolicLinkTarget . F.dropTrailingPathSeparator)
 
 -- | Check whether the path refers to a symbolic link.  An exception is thrown
 -- if the path does not exist or is inaccessible.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -7,13 +7,20 @@
 [![Build Status](https://travis-ci.org/mrkkrp/path-io.svg?branch=master)](https://travis-ci.org/mrkkrp/path-io)
 [![Build status](https://ci.appveyor.com/api/projects/status/q0orxo6856n18jvg/branch/master?svg=true)](https://ci.appveyor.com/project/mrkkrp/path-io/branch/master)
 
-This package provides an interface to
-the [`directory`](https://hackage.haskell.org/package/directory) package for
+This package provides an interface to the
+[`directory`](https://hackage.haskell.org/package/directory) package for
 users of Chris Done's [`path`](https://hackage.haskell.org/package/path). It
 also implements some missing stuff like recursive scanning and copying of
 directories, working with temporary files/directories, etc.
 
 Consult Haddocks for usage, which should be trivial.
+
+## Contribution
+
+Issues, bugs, and questions may be reported in [the GitHub issue tracker for
+this project](https://github.com/mrkkrp/path-io/issues).
+
+Pull requests are also welcome.
 
 ## License
 
diff --git a/path-io.cabal b/path-io.cabal
--- a/path-io.cabal
+++ b/path-io.cabal
@@ -1,7 +1,7 @@
 name:                 path-io
-version:              1.5.0
+version:              1.6.0
 cabal-version:        1.18
-tested-with:          GHC==8.2.2, GHC==8.4.4, GHC==8.6.5
+tested-with:          GHC==8.4.4, GHC==8.6.5, GHC==8.8.1
 license:              BSD3
 license-file:         LICENSE.md
 author:               Mark Karpov <markkarpov92@gmail.com>
@@ -21,7 +21,7 @@
   default:            False
 
 library
-  build-depends:      base         >= 4.10    && < 5.0
+  build-depends:      base         >= 4.11    && < 5.0
                     , containers
                     , directory    >= 1.3.2.0 && < 1.4
                     , dlist        >= 0.8     && < 0.9
@@ -29,7 +29,7 @@
                     , filepath     >= 1.2     && < 1.5
                     , path         >= 0.6     && < 0.7
                     , temporary    >= 1.1     && < 1.4
-                    , time         >= 1.4     && < 1.9
+                    , time         >= 1.4     && < 1.10
                     , transformers >= 0.3     && < 0.6
                     , unix-compat
   exposed-modules:    Path.IO
@@ -42,7 +42,6 @@
                       -Wincomplete-record-updates
                       -Wincomplete-uni-patterns
                       -Wnoncanonical-monad-instances
-                      -Wnoncanonical-monadfail-instances
   default-language:   Haskell2010
 
 test-suite tests
@@ -53,10 +52,11 @@
     ghc-options:      -Wall -Werror
   else
     ghc-options:      -O2 -Wall
-  build-depends:      base         >= 4.10    && < 5.0
+  build-depends:      base         >= 4.11    && < 5.0
                     , directory    >= 1.3.2.0 && < 1.4
                     , exceptions   >= 0.8     && < 0.11
                     , hspec        >= 2.0     && < 3.0
+                    , filepath     >= 1.2     && < 1.5
                     , path         >= 0.6     && < 0.7
                     , path-io
                     , transformers >= 0.3     && < 0.6
