base: TemporaryDir rm -rf directory in destructor

Recursively delete all contents in a temporary directory in the
destructor.

Test: compile
Bug: 119313545
Change-Id: I9570a8591f4e51f8f4f1157e75ccc1b781f8a19d
diff --git a/file.cpp b/file.cpp
index f362f94..7a14711 100644
--- a/file.cpp
+++ b/file.cpp
@@ -18,6 +18,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <ftw.h>
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -30,11 +31,6 @@
 #include <string>
 #include <vector>
 
-#include "android-base/logging.h"
-#include "android-base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
-#include "android-base/unique_fd.h"
-#include "android-base/utf8.h"
-
 #if defined(__APPLE__)
 #include <mach-o/dyld.h>
 #endif
@@ -47,6 +43,11 @@
 #define OS_PATH_SEPARATOR '/'
 #endif
 
+#include "android-base/logging.h"  // and must be after windows.h for ERROR
+#include "android-base/macros.h"   // For TEMP_FAILURE_RETRY on Darwin.
+#include "android-base/unique_fd.h"
+#include "android-base/utf8.h"
+
 #ifdef _WIN32
 int mkstemp(char* template_name) {
   if (_mktemp(template_name) == nullptr) {
@@ -133,7 +134,32 @@
 }
 
 TemporaryDir::~TemporaryDir() {
-  rmdir(path);
+  auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int {
+    switch (file_type) {
+      case FTW_D:
+      case FTW_DP:
+      case FTW_DNR:
+        if (rmdir(child) == -1) {
+          PLOG(ERROR) << "rmdir " << child;
+        }
+        break;
+      case FTW_NS:
+      default:
+        if (rmdir(child) != -1) break;
+        // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
+        FALLTHROUGH_INTENDED;
+      case FTW_F:
+      case FTW_SL:
+      case FTW_SLN:
+        if (unlink(child) == -1) {
+          PLOG(ERROR) << "unlink " << child;
+        }
+        break;
+    }
+    return 0;
+  };
+
+  nftw(path, callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
 }
 
 bool TemporaryDir::init(const std::string& tmp_dir) {