| OLD | NEW |
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 | 40 |
| 41 namespace { | 41 namespace { |
| 42 | 42 |
| 43 const char kWriteDirectory[] = "new"; | 43 const char kWriteDirectory[] = "new"; |
| 44 const char kUploadPendingDirectory[] = "pending"; | 44 const char kUploadPendingDirectory[] = "pending"; |
| 45 const char kCompletedDirectory[] = "completed"; | 45 const char kCompletedDirectory[] = "completed"; |
| 46 | 46 |
| 47 const char kSettings[] = "settings.dat"; | 47 const char kSettings[] = "settings.dat"; |
| 48 | 48 |
| 49 const char* const kReportDirectories[] = { | 49 const char* const kReportDirectories[] = { |
| 50 kWriteDirectory, | 50 kWriteDirectory, |
| 51 kUploadPendingDirectory, | 51 kUploadPendingDirectory, |
| 52 kCompletedDirectory, | 52 kCompletedDirectory, |
| 53 }; | 53 }; |
| 54 | 54 |
| 55 const char kCrashReportFileExtension[] = "dmp"; | 55 const char kCrashReportFileExtension[] = "dmp"; |
| 56 | 56 |
| 57 const char kXattrUUID[] = "uuid"; | 57 const char kXattrUUID[] = "uuid"; |
| 58 const char kXattrCollectorID[] = "id"; | 58 const char kXattrCollectorID[] = "id"; |
| 59 const char kXattrCreationTime[] = "creation_time"; | 59 const char kXattrCreationTime[] = "creation_time"; |
| 60 const char kXattrIsUploaded[] = "uploaded"; | 60 const char kXattrIsUploaded[] = "uploaded"; |
| 61 const char kXattrLastUploadTime[] = "last_upload_time"; | 61 const char kXattrLastUploadTime[] = "last_upload_time"; |
| 62 const char kXattrUploadAttemptCount[] = "upload_count"; | 62 const char kXattrUploadAttemptCount[] = "upload_count"; |
| 63 const char kXattrIsUploadExplicitlyRequested[] = "upload_explicitly_requested"; |
| 63 | 64 |
| 64 const char kXattrDatabaseInitialized[] = "initialized"; | 65 const char kXattrDatabaseInitialized[] = "initialized"; |
| 65 | 66 |
| 66 // Ensures that the node at |path| is a directory. If the |path| refers to a | 67 // Ensures that the node at |path| is a directory. If the |path| refers to a |
| 67 // file, rather than a directory, returns false. Otherwise, returns true, | 68 // file, rather than a directory, returns false. Otherwise, returns true, |
| 68 // indicating that |path| already was a directory. | 69 // indicating that |path| already was a directory. |
| 69 bool EnsureDirectoryExists(const base::FilePath& path) { | 70 bool EnsureDirectoryExists(const base::FilePath& path) { |
| 70 struct stat st; | 71 struct stat st; |
| 71 if (stat(path.value().c_str(), &st) != 0) { | 72 if (stat(path.value().c_str(), &st) != 0) { |
| 72 PLOG(ERROR) << "stat " << path.value(); | 73 PLOG(ERROR) << "stat " << path.value(); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 OperationStatus LookUpCrashReport(const UUID& uuid, Report* report) override; | 134 OperationStatus LookUpCrashReport(const UUID& uuid, Report* report) override; |
| 134 OperationStatus GetPendingReports(std::vector<Report>* reports) override; | 135 OperationStatus GetPendingReports(std::vector<Report>* reports) override; |
| 135 OperationStatus GetCompletedReports(std::vector<Report>* reports) override; | 136 OperationStatus GetCompletedReports(std::vector<Report>* reports) override; |
| 136 OperationStatus GetReportForUploading(const UUID& uuid, | 137 OperationStatus GetReportForUploading(const UUID& uuid, |
| 137 const Report** report) override; | 138 const Report** report) override; |
| 138 OperationStatus RecordUploadAttempt(const Report* report, | 139 OperationStatus RecordUploadAttempt(const Report* report, |
| 139 bool successful, | 140 bool successful, |
| 140 const std::string& id) override; | 141 const std::string& id) override; |
| 141 OperationStatus SkipReportUpload(const UUID& uuid) override; | 142 OperationStatus SkipReportUpload(const UUID& uuid) override; |
| 142 OperationStatus DeleteReport(const UUID& uuid) override; | 143 OperationStatus DeleteReport(const UUID& uuid) override; |
| 144 OperationStatus RequestUpload(const UUID& uuid) override; |
| 143 | 145 |
| 144 private: | 146 private: |
| 145 //! \brief A private extension of the Report class that maintains bookkeeping | 147 //! \brief A private extension of the Report class that maintains bookkeeping |
| 146 //! information of the database. | 148 //! information of the database. |
| 147 struct UploadReport : public Report { | 149 struct UploadReport : public Report { |
| 148 //! \brief Stores the flock of the file for the duration of | 150 //! \brief Stores the flock of the file for the duration of |
| 149 //! GetReportForUploading() and RecordUploadAttempt(). | 151 //! GetReportForUploading() and RecordUploadAttempt(). |
| 150 int lock_fd; | 152 int lock_fd; |
| 151 }; | 153 }; |
| 152 | 154 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 OperationStatus ReportsInDirectory(const base::FilePath& path, | 196 OperationStatus ReportsInDirectory(const base::FilePath& path, |
| 195 std::vector<Report>* reports); | 197 std::vector<Report>* reports); |
| 196 | 198 |
| 197 //! \brief Creates a database xattr name from the short constant name. | 199 //! \brief Creates a database xattr name from the short constant name. |
| 198 //! | 200 //! |
| 199 //! \param[in] name The short name of the extended attribute. | 201 //! \param[in] name The short name of the extended attribute. |
| 200 //! | 202 //! |
| 201 //! \return The long name of the extended attribute. | 203 //! \return The long name of the extended attribute. |
| 202 std::string XattrName(const base::StringPiece& name); | 204 std::string XattrName(const base::StringPiece& name); |
| 203 | 205 |
| 206 //! \brief Marks a report with a given path as completed. |
| 207 //! |
| 208 //! Assumes that the report is locked. |
| 209 //! |
| 210 //! \param[in] report_path The path of the file to mark completed. |
| 211 //! \param[out] out_path The path of the new file. This parameter is optional. |
| 212 //! |
| 213 //! \return The operation status code. |
| 214 CrashReportDatabase::OperationStatus MarkReportCompletedLocked( |
| 215 const base::FilePath& report_path, |
| 216 base::FilePath* out_path); |
| 217 |
| 204 base::FilePath base_dir_; | 218 base::FilePath base_dir_; |
| 205 Settings settings_; | 219 Settings settings_; |
| 206 bool xattr_new_names_; | 220 bool xattr_new_names_; |
| 207 InitializationStateDcheck initialized_; | 221 InitializationStateDcheck initialized_; |
| 208 | 222 |
| 209 DISALLOW_COPY_AND_ASSIGN(CrashReportDatabaseMac); | 223 DISALLOW_COPY_AND_ASSIGN(CrashReportDatabaseMac); |
| 210 }; | 224 }; |
| 211 | 225 |
| 212 CrashReportDatabaseMac::CrashReportDatabaseMac(const base::FilePath& path) | 226 CrashReportDatabaseMac::CrashReportDatabaseMac(const base::FilePath& path) |
| 213 : CrashReportDatabase(), | 227 : CrashReportDatabase(), |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 return kReportNotFound; | 456 return kReportNotFound; |
| 443 | 457 |
| 444 std::unique_ptr<const UploadReport> upload_report( | 458 std::unique_ptr<const UploadReport> upload_report( |
| 445 static_cast<const UploadReport*>(report)); | 459 static_cast<const UploadReport*>(report)); |
| 446 | 460 |
| 447 base::ScopedFD lock(upload_report->lock_fd); | 461 base::ScopedFD lock(upload_report->lock_fd); |
| 448 if (!lock.is_valid()) | 462 if (!lock.is_valid()) |
| 449 return kBusyError; | 463 return kBusyError; |
| 450 | 464 |
| 451 if (successful) { | 465 if (successful) { |
| 452 base::FilePath new_path = | 466 CrashReportDatabase::OperationStatus os = |
| 453 base_dir_.Append(kCompletedDirectory).Append(report_path.BaseName()); | 467 MarkReportCompletedLocked(report_path, &report_path); |
| 454 if (rename(report_path.value().c_str(), new_path.value().c_str()) != 0) { | 468 if (os != kNoError) |
| 455 PLOG(ERROR) << "rename " << report_path.value() << " to " | 469 return os; |
| 456 << new_path.value(); | |
| 457 return kFileSystemError; | |
| 458 } | |
| 459 report_path = new_path; | |
| 460 } | 470 } |
| 461 | 471 |
| 462 if (!WriteXattrBool(report_path, XattrName(kXattrIsUploaded), successful)) { | 472 if (!WriteXattrBool(report_path, XattrName(kXattrIsUploaded), successful)) { |
| 463 return kDatabaseError; | 473 return kDatabaseError; |
| 464 } | 474 } |
| 465 if (!WriteXattr(report_path, XattrName(kXattrCollectorID), id)) { | 475 if (!WriteXattr(report_path, XattrName(kXattrCollectorID), id)) { |
| 466 return kDatabaseError; | 476 return kDatabaseError; |
| 467 } | 477 } |
| 468 | 478 |
| 469 time_t now = time(nullptr); | 479 time_t now = time(nullptr); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 493 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 503 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 494 | 504 |
| 495 base::FilePath report_path = LocateCrashReport(uuid); | 505 base::FilePath report_path = LocateCrashReport(uuid); |
| 496 if (report_path.empty()) | 506 if (report_path.empty()) |
| 497 return kReportNotFound; | 507 return kReportNotFound; |
| 498 | 508 |
| 499 base::ScopedFD lock(ObtainReportLock(report_path)); | 509 base::ScopedFD lock(ObtainReportLock(report_path)); |
| 500 if (!lock.is_valid()) | 510 if (!lock.is_valid()) |
| 501 return kBusyError; | 511 return kBusyError; |
| 502 | 512 |
| 503 base::FilePath new_path = | 513 return MarkReportCompletedLocked(report_path, nullptr); |
| 504 base_dir_.Append(kCompletedDirectory).Append(report_path.BaseName()); | |
| 505 if (rename(report_path.value().c_str(), new_path.value().c_str()) != 0) { | |
| 506 PLOG(ERROR) << "rename " << report_path.value() << " to " | |
| 507 << new_path.value(); | |
| 508 return kFileSystemError; | |
| 509 } | |
| 510 | |
| 511 return kNoError; | |
| 512 } | 514 } |
| 513 | 515 |
| 514 CrashReportDatabase::OperationStatus CrashReportDatabaseMac::DeleteReport( | 516 CrashReportDatabase::OperationStatus CrashReportDatabaseMac::DeleteReport( |
| 515 const UUID& uuid) { | 517 const UUID& uuid) { |
| 516 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 518 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 517 | 519 |
| 518 base::FilePath report_path = LocateCrashReport(uuid); | 520 base::FilePath report_path = LocateCrashReport(uuid); |
| 519 if (report_path.empty()) | 521 if (report_path.empty()) |
| 520 return kReportNotFound; | 522 return kReportNotFound; |
| 521 | 523 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 549 if (ReadXattr(path, XattrName(kXattrUUID), | 551 if (ReadXattr(path, XattrName(kXattrUUID), |
| 550 &uuid_string) == XattrStatus::kOK && | 552 &uuid_string) == XattrStatus::kOK && |
| 551 uuid_string == target_uuid) { | 553 uuid_string == target_uuid) { |
| 552 return path; | 554 return path; |
| 553 } | 555 } |
| 554 } | 556 } |
| 555 | 557 |
| 556 return base::FilePath(); | 558 return base::FilePath(); |
| 557 } | 559 } |
| 558 | 560 |
| 561 CrashReportDatabase::OperationStatus CrashReportDatabaseMac::RequestUpload( |
| 562 const UUID& uuid) { |
| 563 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 564 |
| 565 base::FilePath report_path = LocateCrashReport(uuid); |
| 566 if (report_path.empty()) |
| 567 return kReportNotFound; |
| 568 |
| 569 base::ScopedFD lock(ObtainReportLock(report_path)); |
| 570 if (!lock.is_valid()) |
| 571 return kBusyError; |
| 572 |
| 573 // If the crash report has already been uploaded, don't request new upload. |
| 574 bool uploaded = false; |
| 575 XattrStatus status = |
| 576 ReadXattrBool(report_path, XattrName(kXattrIsUploaded), &uploaded); |
| 577 if (status == XattrStatus::kOtherError) |
| 578 return kDatabaseError; |
| 579 if (uploaded) |
| 580 return kCannotRequestUpload; |
| 581 |
| 582 // Mark the crash report as having upload explicitly requested by the user, |
| 583 // and move it to the pending state. |
| 584 if (!WriteXattrBool( |
| 585 report_path, XattrName(kXattrIsUploadExplicitlyRequested), true)) { |
| 586 return kDatabaseError; |
| 587 } |
| 588 |
| 589 base::FilePath new_path = |
| 590 base_dir_.Append(kUploadPendingDirectory).Append(report_path.BaseName()); |
| 591 if (rename(report_path.value().c_str(), new_path.value().c_str()) != 0) { |
| 592 PLOG(ERROR) << "rename " << report_path.value() << " to " |
| 593 << new_path.value(); |
| 594 return kFileSystemError; |
| 595 } |
| 596 |
| 597 return kNoError; |
| 598 } |
| 599 |
| 559 // static | 600 // static |
| 560 base::ScopedFD CrashReportDatabaseMac::ObtainReportLock( | 601 base::ScopedFD CrashReportDatabaseMac::ObtainReportLock( |
| 561 const base::FilePath& path) { | 602 const base::FilePath& path) { |
| 562 int fd = HANDLE_EINTR(open(path.value().c_str(), | 603 int fd = HANDLE_EINTR(open(path.value().c_str(), |
| 563 O_RDONLY | O_EXLOCK | O_NONBLOCK)); | 604 O_RDONLY | O_EXLOCK | O_NONBLOCK)); |
| 564 PLOG_IF(ERROR, fd < 0) << "open lock " << path.value(); | 605 PLOG_IF(ERROR, fd < 0) << "open lock " << path.value(); |
| 565 return base::ScopedFD(fd); | 606 return base::ScopedFD(fd); |
| 566 } | 607 } |
| 567 | 608 |
| 568 bool CrashReportDatabaseMac::ReadReportMetadataLocked( | 609 bool CrashReportDatabaseMac::ReadReportMetadataLocked( |
| (...skipping 28 matching lines...) Expand all Loading... |
| 597 XattrStatus::kOtherError) { | 638 XattrStatus::kOtherError) { |
| 598 return false; | 639 return false; |
| 599 } | 640 } |
| 600 | 641 |
| 601 report->upload_attempts = 0; | 642 report->upload_attempts = 0; |
| 602 if (ReadXattrInt(path, XattrName(kXattrUploadAttemptCount), | 643 if (ReadXattrInt(path, XattrName(kXattrUploadAttemptCount), |
| 603 &report->upload_attempts) == XattrStatus::kOtherError) { | 644 &report->upload_attempts) == XattrStatus::kOtherError) { |
| 604 return false; | 645 return false; |
| 605 } | 646 } |
| 606 | 647 |
| 648 report->upload_explicitly_requested = false; |
| 649 if (ReadXattrBool(path, |
| 650 XattrName(kXattrIsUploadExplicitlyRequested), |
| 651 &report->upload_explicitly_requested) == |
| 652 XattrStatus::kOtherError) { |
| 653 return false; |
| 654 } |
| 655 |
| 607 return true; | 656 return true; |
| 608 } | 657 } |
| 609 | 658 |
| 610 CrashReportDatabase::OperationStatus CrashReportDatabaseMac::ReportsInDirectory( | 659 CrashReportDatabase::OperationStatus CrashReportDatabaseMac::ReportsInDirectory( |
| 611 const base::FilePath& path, | 660 const base::FilePath& path, |
| 612 std::vector<CrashReportDatabase::Report>* reports) { | 661 std::vector<CrashReportDatabase::Report>* reports) { |
| 613 base::mac::ScopedNSAutoreleasePool pool; | 662 base::mac::ScopedNSAutoreleasePool pool; |
| 614 | 663 |
| 615 DCHECK(reports->empty()); | 664 DCHECK(reports->empty()); |
| 616 | 665 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 640 reports->push_back(report); | 689 reports->push_back(report); |
| 641 } | 690 } |
| 642 | 691 |
| 643 return kNoError; | 692 return kNoError; |
| 644 } | 693 } |
| 645 | 694 |
| 646 std::string CrashReportDatabaseMac::XattrName(const base::StringPiece& name) { | 695 std::string CrashReportDatabaseMac::XattrName(const base::StringPiece& name) { |
| 647 return XattrNameInternal(name, xattr_new_names_); | 696 return XattrNameInternal(name, xattr_new_names_); |
| 648 } | 697 } |
| 649 | 698 |
| 699 CrashReportDatabase::OperationStatus |
| 700 CrashReportDatabaseMac::MarkReportCompletedLocked( |
| 701 const base::FilePath& report_path, |
| 702 base::FilePath* out_path) { |
| 703 if (RemoveXattr(report_path, XattrName(kXattrIsUploadExplicitlyRequested)) == |
| 704 XattrStatus::kOtherError) { |
| 705 return kDatabaseError; |
| 706 } |
| 707 |
| 708 base::FilePath new_path = |
| 709 base_dir_.Append(kCompletedDirectory).Append(report_path.BaseName()); |
| 710 if (rename(report_path.value().c_str(), new_path.value().c_str()) != 0) { |
| 711 PLOG(ERROR) << "rename " << report_path.value() << " to " |
| 712 << new_path.value(); |
| 713 return kFileSystemError; |
| 714 } |
| 715 |
| 716 if (out_path) |
| 717 *out_path = new_path; |
| 718 return kNoError; |
| 719 } |
| 720 |
| 650 std::unique_ptr<CrashReportDatabase> InitializeInternal( | 721 std::unique_ptr<CrashReportDatabase> InitializeInternal( |
| 651 const base::FilePath& path, | 722 const base::FilePath& path, |
| 652 bool may_create) { | 723 bool may_create) { |
| 653 std::unique_ptr<CrashReportDatabaseMac> database_mac( | 724 std::unique_ptr<CrashReportDatabaseMac> database_mac( |
| 654 new CrashReportDatabaseMac(path)); | 725 new CrashReportDatabaseMac(path)); |
| 655 if (!database_mac->Initialize(may_create)) | 726 if (!database_mac->Initialize(may_create)) |
| 656 database_mac.reset(); | 727 database_mac.reset(); |
| 657 | 728 |
| 658 return std::unique_ptr<CrashReportDatabase>(database_mac.release()); | 729 return std::unique_ptr<CrashReportDatabase>(database_mac.release()); |
| 659 } | 730 } |
| 660 | 731 |
| 661 } // namespace | 732 } // namespace |
| 662 | 733 |
| 663 // static | 734 // static |
| 664 std::unique_ptr<CrashReportDatabase> CrashReportDatabase::Initialize( | 735 std::unique_ptr<CrashReportDatabase> CrashReportDatabase::Initialize( |
| 665 const base::FilePath& path) { | 736 const base::FilePath& path) { |
| 666 return InitializeInternal(path, true); | 737 return InitializeInternal(path, true); |
| 667 } | 738 } |
| 668 | 739 |
| 669 // static | 740 // static |
| 670 std::unique_ptr<CrashReportDatabase> | 741 std::unique_ptr<CrashReportDatabase> |
| 671 CrashReportDatabase::InitializeWithoutCreating(const base::FilePath& path) { | 742 CrashReportDatabase::InitializeWithoutCreating(const base::FilePath& path) { |
| 672 return InitializeInternal(path, false); | 743 return InitializeInternal(path, false); |
| 673 } | 744 } |
| 674 | 745 |
| 675 } // namespace crashpad | 746 } // namespace crashpad |
| OLD | NEW |