diff --git a/src/modules/_Stdio/efuns.c b/src/modules/_Stdio/efuns.c
index 2438a21337ad5973fcaaa7beff4bf8e3d9782379..cf9dc5fbacb6357ac00180e25f7545b2c313f54a 100644
--- a/src/modules/_Stdio/efuns.c
+++ b/src/modules/_Stdio/efuns.c
@@ -1528,11 +1528,6 @@ void f_mv(INT32 args)
   INT32 i;
   struct pike_string *str1;
   struct pike_string *str2;
-#ifdef __NT__
-  int orig_errno = errno;
-  int err;
-  PIKE_STAT_T st;
-#endif
 
   VALID_FILE_IO("mv","write");
 
@@ -1560,170 +1555,7 @@ void f_mv(INT32 args)
     return;
   }
 
-#ifndef __NT__
-  i=rename(str1->str, str2->str);
-#else
-
-  /* Emulate the behavior of unix rename(2) when the destination exists. */
-
-  if (movefileex) {
-    if (MoveFileEx (str1->str, str2->str, 0)) {
-      i = 0;
-      goto no_nt_rename_kludge;
-    }
-    if ((i = GetLastError()) != ERROR_ALREADY_EXISTS)
-      goto no_nt_rename_kludge;
-  }
-  else {
-    /* Fall back to rename() for W98 and earlier. Unlike MoveFileEx,
-     * it can't move directories between directories. */
-    if (!rename (str1->str, str2->str)) {
-      i = 0;
-      goto no_nt_rename_kludge;
-    }
-    if ((i = errno) != EEXIST)
-      goto no_nt_rename_kludge;
-  }
-
-#ifdef HAVE_LSTAT
-  if (fd_lstat (str2->str, &st)) goto no_nt_rename_kludge;
-#else
-  if (fd_stat (str2->str, &st)) goto no_nt_rename_kludge;
-#endif
-
-  if ((st.st_mode & S_IFMT) != S_IFDIR && movefileex) {
-    /* MoveFileEx can overwrite a file but not a dir. */
-    if (!(st.st_mode & _S_IWRITE))
-      /* Like in f_rm, we got to handle the case that NT looks on the
-       * permissions on the file itself before removing it. */
-      if (chmod (str2->str, st.st_mode | _S_IWRITE))
-	goto no_nt_rename_kludge;
-    if (movefileex (str1->str, str2->str, MOVEFILE_REPLACE_EXISTING))
-      i = 0;			/* Success. */
-    else
-      chmod (str2->str, st.st_mode);
-  }
-
-  else {
-    char *s = malloc (str2->len + 2), *p;
-    if (!s) {
-      i = movefileex ? ERROR_NOT_ENOUGH_MEMORY : ENOMEM;
-      goto no_nt_rename_kludge;
-    }
-    memcpy (s, str2->str, str2->len);
-    p = s + str2->len;
-    p[2] = 0;
-
-    if ((st.st_mode & S_IFMT) == S_IFDIR) {
-      /* Check first that the target is empty if it's a directory, so
-       * that we won't even bother trying with the stunt below. */
-      WIN32_FIND_DATA *dir = malloc (sizeof (WIN32_FIND_DATA));
-      HANDLE h;
-      if (!dir) {
-	i = movefileex ? ERROR_NOT_ENOUGH_MEMORY : ENOMEM;
-	goto nt_rename_kludge_end;
-      }
-      p[0] = '/', p[1] = '*';
-      h = FindFirstFile (s, dir);
-      if (h != INVALID_HANDLE_VALUE) {
-	do {
-	  if (dir->cFileName[0] != '.' ||
-	      (dir->cFileName[1] &&
-	       (dir->cFileName[1] != '.' || dir->cFileName[2]))) {
-	    /* Target dir not empty. */
-	    FindClose (h);
-	    free (dir);
-	    goto nt_rename_kludge_end;
-	  }
-	} while (FindNextFile (h, dir));
-	FindClose (h);
-      }
-      free (dir);
-    }
-
-    /* Move away the target temporarily to do the move, then cleanup
-     * or undo depending on how it went. */
-    for (p[0] = 'A'; p[0] != 'Z'; p[0]++)
-      for (p[1] = 'A'; p[1] != 'Z'; p[1]++) {
-	if (movefileex) {
-	  if (!movefileex (str2->str, s, 0)) {
-	    if (GetLastError() == ERROR_ALREADY_EXISTS) continue;
-	    else goto nt_rename_kludge_end;
-	  }
-	}
-	else {
-	  if (rename (str2->str, s)) {
-	    if (errno == EEXIST) continue;
-	    else goto nt_rename_kludge_end;
-	  }
-	}
-	if (movefileex ?
-	    movefileex (str1->str, str2->str, MOVEFILE_REPLACE_EXISTING) :
-	    !rename (str1->str, str2->str)) {
-	  if (!(st.st_mode & _S_IWRITE))
-	    if (chmod (s, st.st_mode | _S_IWRITE))
-	      goto nt_rename_kludge_fail;
-	  if ((st.st_mode & S_IFMT) == S_IFDIR) {
-	    while ((err = rmdir (s)) && (errno == EINTR))
-	      ;
-	  } else {
-	    while ((err = unlink (s)) && (errno == EINTR))
-	      ;
-	  }
-	  if (!err) {		/* Success. */
-	    i = 0;
-	    goto nt_rename_kludge_end;
-	  }
-
-	nt_rename_kludge_fail:
-	  /* Couldn't remove the old target, perhaps the directory
-	   * grew files. */
-	  if (!(st.st_mode & _S_IWRITE))
-	    chmod (s, st.st_mode);
-	  if (movefileex ?
-	      !movefileex (str2->str, str1->str, MOVEFILE_REPLACE_EXISTING) :
-	      rename (str2->str, str1->str)) {
-	    /* Old target left behind but the rename is still
-	     * successful, so we claim success anyway in lack of
-	     * better error reporting capabilities. */
-	    i = 0;
-	    goto nt_rename_kludge_end;
-	  }
-	}
-
-	rename (s, str2->str);
-	goto nt_rename_kludge_end;
-      }
-
-  nt_rename_kludge_end:
-    free (s);
-  }
-
-no_nt_rename_kludge:
-  if (i) {
-    if (movefileex)
-      switch (i) {
-	/* Try to translate NT errors to errno codes that NT's rename()
-	 * would return. */
-	case ERROR_INVALID_NAME:
-	  errno = EINVAL;
-	  break;
-	case ERROR_NOT_ENOUGH_MEMORY:
-	  errno = ENOMEM;
-	  break;
-	case ERROR_FILE_NOT_FOUND:
-	case ERROR_PATH_NOT_FOUND:
-	  errno = ENOENT;
-	  break;
-	case ERROR_ALREADY_EXISTS:
-	  errno = EEXIST;
-	  break;
-	default:
-	  errno = EACCES;
-      }
-  }
-  else errno = orig_errno;
-#endif /* __NT__ */
+  i = fd_rename(str1->str, str2->str);
 
   pop_n_elems(args);
   push_int(!i);