Merge "Use FileScanner to build static map."
diff --git a/src/traced/probes/filesystem/file_scanner.cc b/src/traced/probes/filesystem/file_scanner.cc
index 3fb9cfe..8369e50 100644
--- a/src/traced/probes/filesystem/file_scanner.cc
+++ b/src/traced/probes/filesystem/file_scanner.cc
@@ -48,7 +48,19 @@
       queue_(std::move(root_directories)),
       weak_factory_(this) {}
 
+FileScanner::FileScanner(std::vector<std::string> root_directories,
+                         Delegate* delegate)
+    : FileScanner(std::move(root_directories),
+                  delegate,
+                  0 /* scan_interval_ms */,
+                  0 /* scan_steps */) {}
+
+void FileScanner::Scan() {
+  while (!Done())
+    Step();
+}
 void FileScanner::Scan(base::TaskRunner* task_runner) {
+  PERFETTO_DCHECK(scan_interval_ms_ && scan_steps_);
   Steps(scan_steps_);
   if (Done())
     return delegate_->OnInodeScanDone();
diff --git a/src/traced/probes/filesystem/file_scanner.h b/src/traced/probes/filesystem/file_scanner.h
index 24475a4..bf193e4 100644
--- a/src/traced/probes/filesystem/file_scanner.h
+++ b/src/traced/probes/filesystem/file_scanner.h
@@ -44,10 +44,14 @@
               uint64_t scan_interval_ms,
               uint64_t scan_steps);
 
+  // Ctor when only the blocking version of Scan is used.
+  FileScanner(std::vector<std::string> root_directories, Delegate* delegate);
+
   FileScanner(const FileScanner&) = delete;
   FileScanner& operator=(const FileScanner&) = delete;
 
   void Scan(base::TaskRunner* task_runner);
+  void Scan();
 
  private:
   void NextDirectory();
diff --git a/src/traced/probes/filesystem/inode_file_data_source.cc b/src/traced/probes/filesystem/inode_file_data_source.cc
index da7c328..b75fc02 100644
--- a/src/traced/probes/filesystem/inode_file_data_source.cc
+++ b/src/traced/probes/filesystem/inode_file_data_source.cc
@@ -35,76 +35,37 @@
 namespace {
 const int kScanIntervalMs = 10000;  // 10s
 uint64_t kScanBatchSize = 15000;
-}
 
-void ScanFilesDFS(
-    const std::string& root_directory,
-    const std::function<bool(BlockDeviceID block_device_id,
-                             Inode inode_number,
-                             const std::string& path,
-                             protos::pbzero::InodeFileMap_Entry_Type type)>&
-        fn) {
-  std::vector<std::string> queue{root_directory};
-  while (!queue.empty()) {
-    struct dirent* entry;
-    std::string directory = queue.back();
-    queue.pop_back();
-    base::ScopedDir dir(opendir(directory.c_str()));
-    directory += "/";
-    if (!dir)
-      continue;
+class StaticMapDelegate : public FileScanner::Delegate {
+ public:
+  StaticMapDelegate(
+      std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>* map)
+      : map_(map) {}
+  ~StaticMapDelegate() {}
 
-    struct stat buf;
-    if (lstat(directory.c_str(), &buf) != 0) {
-      PERFETTO_DPLOG("lstat %s", directory.c_str());
-      continue;
-    }
-    if (S_ISLNK(buf.st_mode))
-      continue;
-
-    BlockDeviceID block_device_id = buf.st_dev;
-
-    while ((entry = readdir(dir.get())) != nullptr) {
-      std::string filename = entry->d_name;
-      if (filename == "." || filename == "..")
-        continue;
-      std::string filepath = directory + filename;
-
-      Inode inode_number = entry->d_ino;
-
-      protos::pbzero::InodeFileMap_Entry_Type type =
-          protos::pbzero::InodeFileMap_Entry_Type_UNKNOWN;
-      // Readdir and stat not guaranteed to have directory info for all systems
-      if (entry->d_type == DT_DIR) {
-        // Continue iterating through files if current entry is a directory
-        queue.push_back(filepath);
-        type = protos::pbzero::InodeFileMap_Entry_Type_DIRECTORY;
-      } else if (entry->d_type == DT_REG) {
-        type = protos::pbzero::InodeFileMap_Entry_Type_FILE;
-      }
-
-      if (!fn(block_device_id, inode_number, filepath, type))
-        return;
-    }
-    if (errno != 0)
-      PERFETTO_DPLOG("readdir %s", directory.c_str());
+ private:
+  bool OnInodeFound(BlockDeviceID block_device_id,
+                    Inode inode_number,
+                    const std::string& path,
+                    protos::pbzero::InodeFileMap_Entry_Type type) {
+    std::unordered_map<Inode, InodeMapValue>& inode_map =
+        (*map_)[block_device_id];
+    inode_map[inode_number].SetType(type);
+    inode_map[inode_number].AddPath(path);
+    return true;
   }
+  void OnInodeScanDone() {}
+  std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>* map_;
+};
 }
 
 void CreateStaticDeviceToInodeMap(
     const std::string& root_directory,
     std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>*
         static_file_map) {
-  ScanFilesDFS(root_directory,
-               [static_file_map](BlockDeviceID block_device_id,
-                                 Inode inode_number, const std::string& path,
-                                 protos::pbzero::InodeFileMap_Entry_Type type) {
-                 std::unordered_map<Inode, InodeMapValue>& inode_map =
-                     (*static_file_map)[block_device_id];
-                 inode_map[inode_number].SetType(type);
-                 inode_map[inode_number].AddPath(path);
-                 return true;
-               });
+  StaticMapDelegate delegate(static_file_map);
+  FileScanner scanner({root_directory}, &delegate);
+  scanner.Scan();
 }
 
 void FillInodeEntry(InodeFileMap* destination,