| 294 | } |
| 295 | |
| 296 | Status DeleteExcessFilesByPattern(Env* env, const string& pattern, int max_matches) { |
| 297 | // Negative numbers don't make sense for our interface. |
| 298 | DCHECK_GE(max_matches, 0); |
| 299 | |
| 300 | vector<string> matching_files; |
| 301 | RETURN_NOT_OK(env->Glob(pattern, &matching_files)); |
| 302 | |
| 303 | if (matching_files.size() <= max_matches) { |
| 304 | return Status::OK(); |
| 305 | } |
| 306 | |
| 307 | vector<pair<time_t, string>> matching_file_mtimes; |
| 308 | for (string& matching_file_path : matching_files) { |
| 309 | int64_t mtime; |
| 310 | RETURN_NOT_OK(env->GetFileModifiedTime(matching_file_path, &mtime)); |
| 311 | matching_file_mtimes.emplace_back(mtime, std::move(matching_file_path)); |
| 312 | } |
| 313 | |
| 314 | // Use mtime to determine which matching files to delete. This could |
| 315 | // potentially be ambiguous, depending on the resolution of last-modified |
| 316 | // timestamp in the filesystem, but that is part of the contract. |
| 317 | std::sort(matching_file_mtimes.begin(), matching_file_mtimes.end()); |
| 318 | matching_file_mtimes.resize(matching_file_mtimes.size() - max_matches); |
| 319 | |
| 320 | for (const auto& matching_file : matching_file_mtimes) { |
| 321 | RETURN_NOT_OK(env->DeleteFile(matching_file.second)); |
| 322 | } |
| 323 | |
| 324 | return Status::OK(); |
| 325 | } |
| 326 | |
| 327 | // Callback for DeleteTmpFilesRecursively(). |
| 328 | // |