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 LOG(ERROR) << "stat " << path.value() << ": not a directory"; |
| 77 return false; |
| 78 } |
| 79 return true; |
| 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 may_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 OperationStatus DeleteReport(const UUID& uuid) override; | 133 OperationStatus DeleteReport(const UUID& uuid) override; |
129 | 134 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 //! \brief Reads the metadata from all the reports in a database subdirectory. | 179 //! \brief Reads the metadata from all the reports in a database subdirectory. |
175 //! Invalid reports are skipped. | 180 //! Invalid reports are skipped. |
176 //! | 181 //! |
177 //! \param[in] path The database subdirectory path. | 182 //! \param[in] path The database subdirectory path. |
178 //! \param[out] reports An empty vector of reports, which will be filled. | 183 //! \param[out] reports An empty vector of reports, which will be filled. |
179 //! | 184 //! |
180 //! \return The operation status code. | 185 //! \return The operation status code. |
181 static OperationStatus ReportsInDirectory(const base::FilePath& path, | 186 static OperationStatus ReportsInDirectory(const base::FilePath& path, |
182 std::vector<Report>* reports); | 187 std::vector<Report>* reports); |
183 | 188 |
184 | |
185 //! \brief Creates a database xattr name from the short constant name. | 189 //! \brief Creates a database xattr name from the short constant name. |
186 //! | 190 //! |
187 //! \param[in] name The short name of the extended attribute. | 191 //! \param[in] name The short name of the extended attribute. |
188 //! | 192 //! |
189 //! \return The long name of the extended attribute. | 193 //! \return The long name of the extended attribute. |
190 static std::string XattrName(const base::StringPiece& name); | 194 static std::string XattrName(const base::StringPiece& name); |
191 | 195 |
192 base::FilePath base_dir_; | 196 base::FilePath base_dir_; |
193 Settings settings_; | 197 Settings settings_; |
194 InitializationStateDcheck initialized_; | 198 InitializationStateDcheck initialized_; |
195 | 199 |
196 DISALLOW_COPY_AND_ASSIGN(CrashReportDatabaseMac); | 200 DISALLOW_COPY_AND_ASSIGN(CrashReportDatabaseMac); |
197 }; | 201 }; |
198 | 202 |
199 CrashReportDatabaseMac::CrashReportDatabaseMac(const base::FilePath& path) | 203 CrashReportDatabaseMac::CrashReportDatabaseMac(const base::FilePath& path) |
200 : CrashReportDatabase(), | 204 : CrashReportDatabase(), |
201 base_dir_(path), | 205 base_dir_(path), |
202 settings_(base_dir_.Append(kSettings)), | 206 settings_(base_dir_.Append(kSettings)), |
203 initialized_() { | 207 initialized_() { |
204 } | 208 } |
205 | 209 |
206 CrashReportDatabaseMac::~CrashReportDatabaseMac() {} | 210 CrashReportDatabaseMac::~CrashReportDatabaseMac() {} |
207 | 211 |
208 bool CrashReportDatabaseMac::Initialize() { | 212 bool CrashReportDatabaseMac::Initialize(bool may_create) { |
209 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | 213 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
210 | 214 |
211 // Check if the database already exists. | 215 // Check if the database already exists. |
212 if (!CreateOrEnsureDirectoryExists(base_dir_)) | 216 if (may_create) { |
| 217 if (!CreateOrEnsureDirectoryExists(base_dir_)) { |
| 218 return false; |
| 219 } |
| 220 } else if (!EnsureDirectoryExists(base_dir_)) { |
213 return false; | 221 return false; |
| 222 } |
214 | 223 |
215 // Create the three processing directories for the database. | 224 // Create the three processing directories for the database. |
216 for (size_t i = 0; i < arraysize(kReportDirectories); ++i) { | 225 for (size_t i = 0; i < arraysize(kReportDirectories); ++i) { |
217 if (!CreateOrEnsureDirectoryExists(base_dir_.Append(kReportDirectories[i]))) | 226 if (!CreateOrEnsureDirectoryExists(base_dir_.Append(kReportDirectories[i]))) |
218 return false; | 227 return false; |
219 } | 228 } |
220 | 229 |
221 if (!settings_.Initialize()) | 230 if (!settings_.Initialize()) |
222 return false; | 231 return false; |
223 | 232 |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
494 return kFileSystemError; | 503 return kFileSystemError; |
495 } | 504 } |
496 | 505 |
497 return kNoError; | 506 return kNoError; |
498 } | 507 } |
499 | 508 |
500 base::FilePath CrashReportDatabaseMac::LocateCrashReport(const UUID& uuid) { | 509 base::FilePath CrashReportDatabaseMac::LocateCrashReport(const UUID& uuid) { |
501 const std::string target_uuid = uuid.ToString(); | 510 const std::string target_uuid = uuid.ToString(); |
502 for (size_t i = 0; i < arraysize(kReportDirectories); ++i) { | 511 for (size_t i = 0; i < arraysize(kReportDirectories); ++i) { |
503 base::FilePath path = | 512 base::FilePath path = |
504 base_dir_.Append(kReportDirectories[i]) | 513 base_dir_.Append(kReportDirectories[i]) |
505 .Append(target_uuid + "." + kCrashReportFileExtension); | 514 .Append(target_uuid + "." + kCrashReportFileExtension); |
506 | 515 |
507 // Test if the path exists. | 516 // Test if the path exists. |
508 struct stat st; | 517 struct stat st; |
509 if (lstat(path.value().c_str(), &st)) { | 518 if (lstat(path.value().c_str(), &st)) { |
510 continue; | 519 continue; |
511 } | 520 } |
512 | 521 |
513 // Check that the UUID of the report matches. | 522 // Check that the UUID of the report matches. |
514 std::string uuid_string; | 523 std::string uuid_string; |
515 if (ReadXattr(path, XattrName(kXattrUUID), | 524 if (ReadXattr(path, XattrName(kXattrUUID), |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 } | 618 } |
610 | 619 |
611 return kNoError; | 620 return kNoError; |
612 } | 621 } |
613 | 622 |
614 // static | 623 // static |
615 std::string CrashReportDatabaseMac::XattrName(const base::StringPiece& name) { | 624 std::string CrashReportDatabaseMac::XattrName(const base::StringPiece& name) { |
616 return base::StringPrintf("com.googlecode.crashpad.%s", name.data()); | 625 return base::StringPrintf("com.googlecode.crashpad.%s", name.data()); |
617 } | 626 } |
618 | 627 |
| 628 scoped_ptr<CrashReportDatabase> InitializeInternal(const base::FilePath& path, |
| 629 bool may_create) { |
| 630 scoped_ptr<CrashReportDatabaseMac> database_mac( |
| 631 new CrashReportDatabaseMac(path)); |
| 632 if (!database_mac->Initialize(may_create)) |
| 633 database_mac.reset(); |
| 634 |
| 635 return scoped_ptr<CrashReportDatabase>(database_mac.release()); |
| 636 } |
| 637 |
619 } // namespace | 638 } // namespace |
620 | 639 |
621 // static | 640 // static |
622 scoped_ptr<CrashReportDatabase> CrashReportDatabase::Initialize( | 641 scoped_ptr<CrashReportDatabase> CrashReportDatabase::Initialize( |
623 const base::FilePath& path) { | 642 const base::FilePath& path) { |
624 scoped_ptr<CrashReportDatabaseMac> database_mac( | 643 return InitializeInternal(path, true); |
625 new CrashReportDatabaseMac(path)); | 644 } |
626 if (!database_mac->Initialize()) | |
627 database_mac.reset(); | |
628 | 645 |
629 return scoped_ptr<CrashReportDatabase>(database_mac.release()); | 646 // static |
| 647 scoped_ptr<CrashReportDatabase> CrashReportDatabase::InitializeWithoutCreating( |
| 648 const base::FilePath& path) { |
| 649 return InitializeInternal(path, false); |
630 } | 650 } |
631 | 651 |
632 } // namespace crashpad | 652 } // namespace crashpad |
OLD | NEW |