| Index: client/prune_crash_reports.cc
|
| diff --git a/client/prune_crash_reports.cc b/client/prune_crash_reports.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dadb93d7423e3bbcb3690753ea8f91ee953f0f67
|
| --- /dev/null
|
| +++ b/client/prune_crash_reports.cc
|
| @@ -0,0 +1,132 @@
|
| +// Copyright 2015 The Crashpad Authors. All rights reserved.
|
| +//
|
| +// 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 <sys/stat.h>
|
| +
|
| +#include <algorithm>
|
| +#include <vector>
|
| +
|
| +#include "base/logging.h"
|
| +
|
| +namespace crashpad {
|
| +
|
| +void PruneCrashReportDatabase(CrashReportDatabase* database,
|
| + PruneCondition* condition) {
|
| + std::vector<CrashReportDatabase::Report> all_reports;
|
| + CrashReportDatabase::OperationStatus status;
|
| +
|
| + status = database->GetPendingReports(&all_reports);
|
| + if (status != CrashReportDatabase::kNoError) {
|
| + LOG(ERROR) << "PruneCrashReportDatabase: Failed to get pending reports";
|
| + return;
|
| + }
|
| +
|
| + std::vector<CrashReportDatabase::Report> completed_reports;
|
| + status = database->GetCompletedReports(&completed_reports);
|
| + if (status != CrashReportDatabase::kNoError) {
|
| + LOG(ERROR) << "PruneCrashReportDatabase: Failed to get completed reports";
|
| + return;
|
| + }
|
| + 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;
|
| + });
|
| +
|
| + 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();
|
| + }
|
| + }
|
| + }
|
| +
|
| + // 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://code.google.com/p/crashpad/issues/detail?id=66
|
| +}
|
| +
|
| +// static
|
| +scoped_ptr<PruneCondition> PruneCondition::GetDefault() {
|
| + // DatabaseSizePruneCondition must be the LHS so that it is always evaluated,
|
| + // due to the short-circuting behavior of BinaryPruneCondition.
|
| + return make_scoped_ptr(new BinaryPruneCondition(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) {
|
| +#if defined(OS_POSIX)
|
| + struct stat statbuf;
|
| + if (stat(report.file_path.value().c_str(), &statbuf) == 0) {
|
| +#elif defined(OS_WIN)
|
| + struct _stati64 statbuf;
|
| + if (_wstat64(report.file_path.value().c_str(), &statbuf) == 0) {
|
| +#else
|
| +#error "Not implemented"
|
| +#endif
|
| + // Round up fractional KB to the next 1-KB boundary.
|
| + measured_size_in_kb_ +=
|
| + static_cast<size_t>((statbuf.st_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
|
|
|