| 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 | 63 |
| 64 const char kXattrDatabaseInitialized[] = "initialized"; | 64 const char kXattrDatabaseInitialized[] = "initialized"; |
| 65 | 65 |
| 66 // 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 // indicating that |path| already was a directory. |
| 69 bool EnsureDirectoryExists(const base::FilePath& path) { |
| 70 struct stat st; |
| 71 if (stat(path.value().c_str(), &st) != 0) { |
| 72 PLOG(ERROR) << "stat " << path.value(); |
| 73 return false; |
| 74 } |
| 75 if (S_ISDIR(st.st_mode)) { |
| 76 return true; |
| 77 } |
| 78 LOG(ERROR) << "stat " << path.value() << ": not a directory"; |
| 79 return false; |
| 80 } |
| 81 |
| 66 // Ensures that the node at |path| is a directory, and creates it if it does | 82 // Ensures that the node at |path| is a directory, and creates it if it does |
| 67 // not exist. If the |path| points to a file, rather than a directory, or the | 83 // not exist. If the |path| refers to a file, rather than a directory, or the |
| 68 // directory could not be created, returns false. Otherwise, returns true, | 84 // directory could not be created, returns false. Otherwise, returns true, |
| 69 // indicating that |path| already was or now is a directory. | 85 // indicating that |path| already was or now is a directory. |
| 70 bool CreateOrEnsureDirectoryExists(const base::FilePath& path) { | 86 bool CreateOrEnsureDirectoryExists(const base::FilePath& path) { |
| 71 if (mkdir(path.value().c_str(), 0755) == 0) { | 87 if (mkdir(path.value().c_str(), 0755) == 0) { |
| 72 return true; | 88 return true; |
| 73 } else if (errno == EEXIST) { | 89 } |
| 74 struct stat st; | 90 if (errno != EEXIST) { |
| 75 if (stat(path.value().c_str(), &st) != 0) { | 91 PLOG(ERROR) << "mkdir " << path.value(); |
| 76 PLOG(ERROR) << "stat"; | |
| 77 return false; | |
| 78 } | |
| 79 if (S_ISDIR(st.st_mode)) { | |
| 80 return true; | |
| 81 } else { | |
| 82 LOG(ERROR) << "not a directory"; | |
| 83 return false; | |
| 84 } | |
| 85 } else { | |
| 86 PLOG(ERROR) << "mkdir"; | |
| 87 return false; | 92 return false; |
| 88 } | 93 } |
| 94 return EnsureDirectoryExists(path); |
| 89 } | 95 } |
| 90 | 96 |
| 91 //! \brief A CrashReportDatabase that uses HFS+ extended attributes to store | 97 //! \brief A CrashReportDatabase that uses HFS+ extended attributes to store |
| 92 //! report metadata. | 98 //! report metadata. |
| 93 //! | 99 //! |
| 94 //! The database maintains three directories of reports: `"new"` to hold crash | 100 //! The database maintains three directories of reports: `"new"` to hold crash |
| 95 //! reports that are in the process of being written, `"completed"` to hold | 101 //! reports that are in the process of being written, `"completed"` to hold |
| 96 //! reports that have been written and are awaiting upload, and `"uploaded"` to | 102 //! reports that have been written and are awaiting upload, and `"uploaded"` to |
| 97 //! hold reports successfully uploaded to a collection server. If the user has | 103 //! hold reports successfully uploaded to a collection server. If the user has |
| 98 //! opted out of report collection, reports will still be written and moved | 104 //! opted out of report collection, reports will still be written and moved |
| 99 //! to the completed directory, but they just will not be uploaded. | 105 //! to the completed directory, but they just will not be uploaded. |
| 100 //! | 106 //! |
| 101 //! The database stores its metadata in extended filesystem attributes. To | 107 //! The database stores its metadata in extended filesystem attributes. To |
| 102 //! ensure safe access, the report file is locked using `O_EXLOCK` during all | 108 //! ensure safe access, the report file is locked using `O_EXLOCK` during all |
| 103 //! extended attribute operations. The lock should be obtained using | 109 //! extended attribute operations. The lock should be obtained using |
| 104 //! ObtainReportLock(). | 110 //! ObtainReportLock(). |
| 105 class CrashReportDatabaseMac : public CrashReportDatabase { | 111 class CrashReportDatabaseMac : public CrashReportDatabase { |
| 106 public: | 112 public: |
| 107 explicit CrashReportDatabaseMac(const base::FilePath& path); | 113 explicit CrashReportDatabaseMac(const base::FilePath& path); |
| 108 virtual ~CrashReportDatabaseMac(); | 114 virtual ~CrashReportDatabaseMac(); |
| 109 | 115 |
| 110 bool Initialize(); | 116 bool Initialize(bool create); |
| 111 | 117 |
| 112 // CrashReportDatabase: | 118 // CrashReportDatabase: |
| 113 Settings* GetSettings() override; | 119 Settings* GetSettings() override; |
| 114 OperationStatus PrepareNewCrashReport(NewReport** report) override; | 120 OperationStatus PrepareNewCrashReport(NewReport** report) override; |
| 115 OperationStatus FinishedWritingCrashReport(NewReport* report, | 121 OperationStatus FinishedWritingCrashReport(NewReport* report, |
| 116 UUID* uuid) override; | 122 UUID* uuid) override; |
| 117 OperationStatus ErrorWritingCrashReport(NewReport* report) override; | 123 OperationStatus ErrorWritingCrashReport(NewReport* report) override; |
| 118 OperationStatus LookUpCrashReport(const UUID& uuid, | 124 OperationStatus LookUpCrashReport(const UUID& uuid, Report* report) override; |
| 119 Report* report) override; | |
| 120 OperationStatus GetPendingReports(std::vector<Report>* reports) override; | 125 OperationStatus GetPendingReports(std::vector<Report>* reports) override; |
| 121 OperationStatus GetCompletedReports(std::vector<Report>* reports) override; | 126 OperationStatus GetCompletedReports(std::vector<Report>* reports) override; |
| 122 OperationStatus GetReportForUploading(const UUID& uuid, | 127 OperationStatus GetReportForUploading(const UUID& uuid, |
| 123 const Report** report) override; | 128 const Report** report) override; |
| 124 OperationStatus RecordUploadAttempt(const Report* report, | 129 OperationStatus RecordUploadAttempt(const Report* report, |
| 125 bool successful, | 130 bool successful, |
| 126 const std::string& id) override; | 131 const std::string& id) override; |
| 127 OperationStatus SkipReportUpload(const UUID& uuid) override; | 132 OperationStatus SkipReportUpload(const UUID& uuid) override; |
| 128 | 133 |
| 129 private: | 134 private: |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 //! \brief Reads the metadata from all the reports in a database subdirectory. | 178 //! \brief Reads the metadata from all the reports in a database subdirectory. |
| 174 //! Invalid reports are skipped. | 179 //! Invalid reports are skipped. |
| 175 //! | 180 //! |
| 176 //! \param[in] path The database subdirectory path. | 181 //! \param[in] path The database subdirectory path. |
| 177 //! \param[out] reports An empty vector of reports, which will be filled. | 182 //! \param[out] reports An empty vector of reports, which will be filled. |
| 178 //! | 183 //! |
| 179 //! \return The operation status code. | 184 //! \return The operation status code. |
| 180 static OperationStatus ReportsInDirectory(const base::FilePath& path, | 185 static OperationStatus ReportsInDirectory(const base::FilePath& path, |
| 181 std::vector<Report>* reports); | 186 std::vector<Report>* reports); |
| 182 | 187 |
| 183 | |
| 184 //! \brief Creates a database xattr name from the short constant name. | 188 //! \brief Creates a database xattr name from the short constant name. |
| 185 //! | 189 //! |
| 186 //! \param[in] name The short name of the extended attribute. | 190 //! \param[in] name The short name of the extended attribute. |
| 187 //! | 191 //! |
| 188 //! \return The long name of the extended attribute. | 192 //! \return The long name of the extended attribute. |
| 189 static std::string XattrName(const base::StringPiece& name); | 193 static std::string XattrName(const base::StringPiece& name); |
| 190 | 194 |
| 191 base::FilePath base_dir_; | 195 base::FilePath base_dir_; |
| 192 Settings settings_; | 196 Settings settings_; |
| 193 InitializationStateDcheck initialized_; | 197 InitializationStateDcheck initialized_; |
| 194 | 198 |
| 195 DISALLOW_COPY_AND_ASSIGN(CrashReportDatabaseMac); | 199 DISALLOW_COPY_AND_ASSIGN(CrashReportDatabaseMac); |
| 196 }; | 200 }; |
| 197 | 201 |
| 198 CrashReportDatabaseMac::CrashReportDatabaseMac(const base::FilePath& path) | 202 CrashReportDatabaseMac::CrashReportDatabaseMac(const base::FilePath& path) |
| 199 : CrashReportDatabase(), | 203 : CrashReportDatabase(), |
| 200 base_dir_(path), | 204 base_dir_(path), |
| 201 settings_(base_dir_.Append(kSettings)), | 205 settings_(base_dir_.Append(kSettings)), |
| 202 initialized_() { | 206 initialized_() { |
| 203 } | 207 } |
| 204 | 208 |
| 205 CrashReportDatabaseMac::~CrashReportDatabaseMac() {} | 209 CrashReportDatabaseMac::~CrashReportDatabaseMac() {} |
| 206 | 210 |
| 207 bool CrashReportDatabaseMac::Initialize() { | 211 bool CrashReportDatabaseMac::Initialize(bool create) { |
| 208 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | 212 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| 209 | 213 |
| 210 // Check if the database already exists. | 214 // Check if the database already exists. |
| 211 if (!CreateOrEnsureDirectoryExists(base_dir_)) | 215 if (create) { |
| 216 if (!CreateOrEnsureDirectoryExists(base_dir_)) { |
| 217 return false; |
| 218 } |
| 219 } else if (!EnsureDirectoryExists(base_dir_)) { |
| 212 return false; | 220 return false; |
| 221 } |
| 213 | 222 |
| 214 // Create the three processing directories for the database. | 223 // Create the three processing directories for the database. |
| 215 for (size_t i = 0; i < arraysize(kReportDirectories); ++i) { | 224 for (size_t i = 0; i < arraysize(kReportDirectories); ++i) { |
| 216 if (!CreateOrEnsureDirectoryExists(base_dir_.Append(kReportDirectories[i]))) | 225 if (!CreateOrEnsureDirectoryExists(base_dir_.Append(kReportDirectories[i]))) |
| 217 return false; | 226 return false; |
| 218 } | 227 } |
| 219 | 228 |
| 220 if (!settings_.Initialize()) | 229 if (!settings_.Initialize()) |
| 221 return false; | 230 return false; |
| 222 | 231 |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 return kFileSystemError; | 482 return kFileSystemError; |
| 474 } | 483 } |
| 475 | 484 |
| 476 return kNoError; | 485 return kNoError; |
| 477 } | 486 } |
| 478 | 487 |
| 479 base::FilePath CrashReportDatabaseMac::LocateCrashReport(const UUID& uuid) { | 488 base::FilePath CrashReportDatabaseMac::LocateCrashReport(const UUID& uuid) { |
| 480 const std::string target_uuid = uuid.ToString(); | 489 const std::string target_uuid = uuid.ToString(); |
| 481 for (size_t i = 0; i < arraysize(kReportDirectories); ++i) { | 490 for (size_t i = 0; i < arraysize(kReportDirectories); ++i) { |
| 482 base::FilePath path = | 491 base::FilePath path = |
| 483 base_dir_.Append(kReportDirectories[i]) | 492 base_dir_.Append(kReportDirectories[i]) |
| 484 .Append(target_uuid + "." + kCrashReportFileExtension); | 493 .Append(target_uuid + "." + kCrashReportFileExtension); |
| 485 | 494 |
| 486 // Test if the path exists. | 495 // Test if the path exists. |
| 487 struct stat st; | 496 struct stat st; |
| 488 if (lstat(path.value().c_str(), &st)) { | 497 if (lstat(path.value().c_str(), &st)) { |
| 489 continue; | 498 continue; |
| 490 } | 499 } |
| 491 | 500 |
| 492 // Check that the UUID of the report matches. | 501 // Check that the UUID of the report matches. |
| 493 std::string uuid_string; | 502 std::string uuid_string; |
| 494 if (ReadXattr(path, XattrName(kXattrUUID), | 503 if (ReadXattr(path, XattrName(kXattrUUID), |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 | 601 |
| 593 // static | 602 // static |
| 594 std::string CrashReportDatabaseMac::XattrName(const base::StringPiece& name) { | 603 std::string CrashReportDatabaseMac::XattrName(const base::StringPiece& name) { |
| 595 return base::StringPrintf("com.googlecode.crashpad.%s", name.data()); | 604 return base::StringPrintf("com.googlecode.crashpad.%s", name.data()); |
| 596 } | 605 } |
| 597 | 606 |
| 598 } // namespace | 607 } // namespace |
| 599 | 608 |
| 600 // static | 609 // static |
| 601 scoped_ptr<CrashReportDatabase> CrashReportDatabase::Initialize( | 610 scoped_ptr<CrashReportDatabase> CrashReportDatabase::Initialize( |
| 602 const base::FilePath& path) { | 611 const base::FilePath& path, bool create) { |
| 603 scoped_ptr<CrashReportDatabaseMac> database_mac( | 612 scoped_ptr<CrashReportDatabaseMac> database_mac( |
| 604 new CrashReportDatabaseMac(path)); | 613 new CrashReportDatabaseMac(path)); |
| 605 if (!database_mac->Initialize()) | 614 if (!database_mac->Initialize(create)) |
| 606 database_mac.reset(); | 615 database_mac.reset(); |
| 607 | 616 |
| 608 return scoped_ptr<CrashReportDatabase>(database_mac.release()); | 617 return scoped_ptr<CrashReportDatabase>(database_mac.release()); |
| 609 } | 618 } |
| 610 | 619 |
| 611 } // namespace crashpad | 620 } // namespace crashpad |
| OLD | NEW |