#4489: Fix usage of fd-based functions to new api introduced earlier today

Also add an explicit test for safe implementation usage on supported platforms.

As a side effect, this commit adds a module-level attribute 'rmtree_is_safe'
which offers introspection whether the current rmtree implementation is safe
against symlink attacks.
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 1b05484..c41046a 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -362,9 +362,9 @@
             _rmtree_unsafe(fullname, onerror)
         else:
             try:
-                os.remove(fullname)
+                os.unlink(fullname)
             except os.error:
-                onerror(os.remove, fullname, sys.exc_info())
+                onerror(os.unlink, fullname, sys.exc_info())
     try:
         os.rmdir(path)
     except os.error:
@@ -374,21 +374,21 @@
 def _rmtree_safe_fd(topfd, path, onerror):
     names = []
     try:
-        names = os.flistdir(topfd)
+        names = os.listdir(topfd)
     except os.error:
-        onerror(os.flistdir, path, sys.exc_info())
+        onerror(os.listdir, path, sys.exc_info())
     for name in names:
         fullname = os.path.join(path, name)
         try:
-            orig_st = os.fstatat(topfd, name)
+            orig_st = os.stat(name, dir_fd=topfd)
             mode = orig_st.st_mode
         except os.error:
             mode = 0
         if stat.S_ISDIR(mode):
             try:
-                dirfd = os.openat(topfd, name, os.O_RDONLY)
+                dirfd = os.open(name, os.O_RDONLY, dir_fd=topfd)
             except os.error:
-                onerror(os.openat, fullname, sys.exc_info())
+                onerror(os.open, fullname, sys.exc_info())
             else:
                 try:
                     if os.path.samestat(orig_st, os.fstat(dirfd)):
@@ -397,21 +397,22 @@
                     os.close(dirfd)
         else:
             try:
-                os.unlinkat(topfd, name)
+                os.unlink(name, dir_fd=topfd)
             except os.error:
-                onerror(os.unlinkat, fullname, sys.exc_info())
+                onerror(os.unlink, fullname, sys.exc_info())
     try:
         os.rmdir(path)
     except os.error:
         onerror(os.rmdir, path, sys.exc_info())
 
-_use_fd_functions = hasattr(os, 'openat') and hasattr(os, 'unlinkat')
+rmtree_is_safe = _use_fd_functions = (os.unlink in os.supports_dir_fd and
+                                      os.open in os.supports_dir_fd)
 def rmtree(path, ignore_errors=False, onerror=None):
     """Recursively delete a directory tree.
 
     If ignore_errors is set, errors are ignored; otherwise, if onerror
     is set, it is called to handle the error with arguments (func,
-    path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
+    path, exc_info) where func is platform and implementation dependent;
     path is the argument to that function that caused it to fail; and
     exc_info is a tuple returned by sys.exc_info().  If ignore_errors
     is false and onerror is None, an exception is raised.