Raise an exception when src and dst refer to the same file via a hard link or a
symbolic link (bug #851123 / patch #854853, thanks Gregory Ball).
diff --git a/Lib/shutil.py b/Lib/shutil.py
index fde8c90..d361fa2 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -24,16 +24,22 @@
             break
         fdst.write(buf)
 
+def _samefile(src, dst):
+    # Macintosh, Unix.
+    if hasattr(os.path,'samefile'):
+        return os.path.samefile(src, dst)
+
+    # All other platforms: check for same pathname.
+    return (os.path.normcase(os.path.abspath(src)) ==
+            os.path.normcase(os.path.abspath(dst)))
 
 def copyfile(src, dst):
     """Copy data from src to dst"""
+    if _samefile(src, dst):
+        raise Error, "`%s` and `%s` are the same file" % (src, dst)
+
     fsrc = None
     fdst = None
-    # check for same pathname; all platforms
-    _src = os.path.normcase(os.path.abspath(src))
-    _dst = os.path.normcase(os.path.abspath(dst))
-    if _src == _dst:
-        return
     try:
         fsrc = open(src, 'rb')
         fdst = open(dst, 'wb')
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index bcae72f..083dbda 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -6,6 +6,7 @@
 import os
 import os.path
 from test import test_support
+from test.test_support import TESTFN
 
 class TestShutil(unittest.TestCase):
     def test_rmtree_errors(self):
@@ -26,6 +27,26 @@
             except:
                 pass
 
+    if hasattr(os, "symlink"):
+        def test_dont_copy_file_onto_link_to_itself(self):
+            # bug 851123.
+            os.mkdir(TESTFN)
+            src = os.path.join(TESTFN,'cheese')
+            dst = os.path.join(TESTFN,'shop')
+            try:
+                f = open(src,'w')
+                f.write('cheddar')
+                f.close()
+                for funcname in 'link','symlink':
+                    getattr(os, funcname)(src, dst)
+                    self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
+                    self.assertEqual(open(src,'r').read(), 'cheddar')
+                    os.remove(dst)
+            finally:
+                try:
+                    shutil.rmtree(TESTFN)
+                except OSError:
+                    pass
 
 
 def test_main():