| 72 | } |
| 73 | |
| 74 | Status FileSystem::DeleteRecursively(const string& dirname, |
| 75 | int64* undeleted_files, |
| 76 | int64* undeleted_dirs) { |
| 77 | CHECK_NOTNULL(undeleted_files); |
| 78 | CHECK_NOTNULL(undeleted_dirs); |
| 79 | |
| 80 | *undeleted_files = 0; |
| 81 | *undeleted_dirs = 0; |
| 82 | // Make sure that dirname exists; |
| 83 | Status exists_status = FileExists(dirname); |
| 84 | if (!exists_status.ok()) { |
| 85 | (*undeleted_dirs)++; |
| 86 | return exists_status; |
| 87 | } |
| 88 | std::deque<string> dir_q; // Queue for the BFS |
| 89 | std::vector<string> dir_list; // List of all dirs discovered |
| 90 | dir_q.push_back(dirname); |
| 91 | Status ret; // Status to be returned. |
| 92 | // Do a BFS on the directory to discover all the sub-directories. Remove all |
| 93 | // children that are files along the way. Then cleanup and remove the |
| 94 | // directories in reverse order.; |
| 95 | while (!dir_q.empty()) { |
| 96 | string dir = dir_q.front(); |
| 97 | dir_q.pop_front(); |
| 98 | dir_list.push_back(dir); |
| 99 | std::vector<string> children; |
| 100 | // GetChildren might fail if we don't have appropriate permissions. |
| 101 | Status s = GetChildren(dir, &children); |
| 102 | ret.Update(s); |
| 103 | if (!s.ok()) { |
| 104 | (*undeleted_dirs)++; |
| 105 | continue; |
| 106 | } |
| 107 | for (const string& child : children) { |
| 108 | const string child_path = io::JoinPath(dir, child); |
| 109 | // If the child is a directory add it to the queue, otherwise delete it. |
| 110 | if (IsDirectory(child_path).ok()) { |
| 111 | dir_q.push_back(child_path); |
| 112 | } else { |
| 113 | // Delete file might fail because of permissions issues or might be |
| 114 | // unimplemented. |
| 115 | Status del_status = DeleteFile(child_path); |
| 116 | ret.Update(del_status); |
| 117 | if (!del_status.ok()) { |
| 118 | (*undeleted_files)++; |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | // Now reverse the list of directories and delete them. The BFS ensures that |
| 124 | // we can delete the directories in this order. |
| 125 | std::reverse(dir_list.begin(), dir_list.end()); |
| 126 | for (const string& dir : dir_list) { |
| 127 | // Delete dir might fail because of permissions issues or might be |
| 128 | // unimplemented. |
| 129 | Status s = DeleteDir(dir); |
| 130 | ret.Update(s); |
| 131 | if (!s.ok()) { |