// Copyright 2015 The Crashpad Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "client/prune_crash_reports.h" #include #include #include #include #include "base/logging.h" #include "base/notreached.h" #include "build/build_config.h" namespace crashpad { size_t PruneCrashReportDatabase(CrashReportDatabase* database, PruneCondition* condition) { std::vector all_reports; CrashReportDatabase::OperationStatus status; status = database->GetPendingReports(&all_reports); if (status != CrashReportDatabase::kNoError) { LOG(ERROR) << "PruneCrashReportDatabase: Failed to get pending reports"; return 0; } std::vector completed_reports; status = database->GetCompletedReports(&completed_reports); if (status != CrashReportDatabase::kNoError) { LOG(ERROR) << "PruneCrashReportDatabase: Failed to get completed reports"; return 0; } all_reports.insert(all_reports.end(), completed_reports.begin(), completed_reports.end()); std::sort(all_reports.begin(), all_reports.end(), [](const CrashReportDatabase::Report& lhs, const CrashReportDatabase::Report& rhs) { return lhs.creation_time > rhs.creation_time; }); size_t num_pruned = 0; for (const auto& report : all_reports) { if (condition->ShouldPruneReport(report)) { status = database->DeleteReport(report.uuid); if (status != CrashReportDatabase::kNoError) { LOG(ERROR) << "Database Pruning: Failed to remove report " << report.uuid.ToString(); } else { num_pruned++; } } } return num_pruned; // TODO(rsesek): For databases that do not use a directory structure, it is // possible for the metadata sidecar to become corrupted and thus leave // orphaned crash report files on-disk. https://crashpad.chromium.org/bug/66 } // static std::unique_ptr PruneCondition::GetDefault() { // DatabaseSizePruneCondition must be the LHS so that it is always evaluated, // due to the short-circuting behavior of BinaryPruneCondition. return std::make_unique( BinaryPruneCondition::OR, new DatabaseSizePruneCondition(1024 * 128), new AgePruneCondition(365)); } static const time_t kSecondsInDay = 60 * 60 * 24; AgePruneCondition::AgePruneCondition(int max_age_in_days) : oldest_report_time_( ((time(nullptr) - (max_age_in_days * kSecondsInDay)) / kSecondsInDay) * kSecondsInDay) {} AgePruneCondition::~AgePruneCondition() {} bool AgePruneCondition::ShouldPruneReport( const CrashReportDatabase::Report& report) { return report.creation_time < oldest_report_time_; } DatabaseSizePruneCondition::DatabaseSizePruneCondition(size_t max_size_in_kb) : max_size_in_kb_(max_size_in_kb), measured_size_in_kb_(0) {} DatabaseSizePruneCondition::~DatabaseSizePruneCondition() {} bool DatabaseSizePruneCondition::ShouldPruneReport( const CrashReportDatabase::Report& report) { // Round up fractional KB to the next 1-KB boundary. measured_size_in_kb_ += static_cast((report.total_size + 1023) / 1024); return measured_size_in_kb_ > max_size_in_kb_; } BinaryPruneCondition::BinaryPruneCondition( Operator op, PruneCondition* lhs, PruneCondition* rhs) : op_(op), lhs_(lhs), rhs_(rhs) {} BinaryPruneCondition::~BinaryPruneCondition() {} bool BinaryPruneCondition::ShouldPruneReport( const CrashReportDatabase::Report& report) { switch (op_) { case AND: return lhs_->ShouldPruneReport(report) && rhs_->ShouldPruneReport(report); case OR: return lhs_->ShouldPruneReport(report) || rhs_->ShouldPruneReport(report); default: NOTREACHED(); return false; } } } // namespace crashpad