feedback_util.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/feedback/feedback_util.h"
  5. #include <string>
  6. #include "base/bind.h"
  7. #include "base/files/file_util.h"
  8. #include "base/files/scoped_temp_dir.h"
  9. #include "base/logging.h"
  10. #include "base/strings/string_util.h"
  11. #include "build/build_config.h"
  12. #include "components/feedback/feedback_report.h"
  13. #include "third_party/zlib/google/zip.h"
  14. namespace {
  15. constexpr char kMultilineIndicatorString[] = "<multiline>\n";
  16. constexpr char kMultilineStartString[] = "---------- START ----------\n";
  17. constexpr char kMultilineEndString[] = "---------- END ----------\n\n";
  18. } // namespace
  19. namespace feedback_util {
  20. bool ZipString(const base::FilePath& filename,
  21. const std::string& data,
  22. std::string* compressed_logs) {
  23. base::ScopedTempDir temp_dir;
  24. base::FilePath zip_file;
  25. // Create a temporary directory, put the logs into a file in it. Create
  26. // another temporary file to receive the zip file in.
  27. if (!temp_dir.CreateUniqueTempDir())
  28. return false;
  29. if (base::WriteFile(temp_dir.GetPath().Append(filename), data.c_str(),
  30. data.size()) == -1) {
  31. return false;
  32. }
  33. bool succeed = base::CreateTemporaryFile(&zip_file) &&
  34. zip::Zip(temp_dir.GetPath(), zip_file, false) &&
  35. base::ReadFileToString(zip_file, compressed_logs);
  36. base::DeleteFile(zip_file);
  37. return succeed;
  38. }
  39. std::string LogsToString(const FeedbackCommon::SystemLogsMap& sys_info) {
  40. std::string syslogs_string;
  41. for (const auto& iter : sys_info) {
  42. std::string key = iter.first;
  43. base::TrimString(key, "\n ", &key);
  44. if (key == feedback::FeedbackReport::kCrashReportIdsKey ||
  45. key == feedback::FeedbackReport::kAllCrashReportIdsKey) {
  46. // Avoid adding the crash IDs to the system_logs.txt file for privacy
  47. // reasons. They should just be part of the product specific data.
  48. continue;
  49. }
  50. std::string value = iter.second;
  51. base::TrimString(value, "\n ", &value);
  52. if (value.find("\n") != std::string::npos) {
  53. syslogs_string.append(key + "=" + kMultilineIndicatorString +
  54. kMultilineStartString + value + "\n" +
  55. kMultilineEndString);
  56. } else {
  57. syslogs_string.append(key + "=" + value + "\n");
  58. }
  59. }
  60. return syslogs_string;
  61. }
  62. // Note: This function is excluded from win build because its unit tests do
  63. // not pass on OS_WIN.
  64. // This function is only called on ChromeOS and Lacros build.
  65. // See https://crbug.com/1119560.
  66. #if !BUILDFLAG(IS_WIN)
  67. bool ReadEndOfFile(const base::FilePath& path,
  68. size_t max_size,
  69. std::string* contents) {
  70. if (!contents) {
  71. LOG(ERROR) << "contents buffer is null.";
  72. return false;
  73. }
  74. if (path.ReferencesParent()) {
  75. LOG(ERROR) << "ReadEndOfFile can't be called on file paths with parent "
  76. "references.";
  77. return false;
  78. }
  79. base::ScopedFILE fp(base::OpenFile(path, "r"));
  80. if (!fp) {
  81. PLOG(ERROR) << "Failed to open file " << path.value();
  82. return false;
  83. }
  84. std::unique_ptr<char[]> chunk(new char[max_size]);
  85. std::unique_ptr<char[]> last_chunk(new char[max_size]);
  86. chunk[0] = '\0';
  87. last_chunk[0] = '\0';
  88. size_t total_bytes_read = 0;
  89. size_t bytes_read = 0;
  90. // Since most logs are not seekable, read until the end keeping tracking of
  91. // last two chunks.
  92. while ((bytes_read = fread(chunk.get(), 1, max_size, fp.get())) == max_size) {
  93. total_bytes_read += bytes_read;
  94. last_chunk.swap(chunk);
  95. chunk[0] = '\0';
  96. }
  97. total_bytes_read += bytes_read;
  98. if (total_bytes_read < max_size) {
  99. // File is smaller than max_size
  100. contents->assign(chunk.get(), bytes_read);
  101. } else if (bytes_read == 0) {
  102. // File is exactly max_size or a multiple of max_size
  103. contents->assign(last_chunk.get(), max_size);
  104. } else {
  105. // Number of bytes to keep from last_chunk
  106. size_t bytes_from_last = max_size - bytes_read;
  107. // Shift left last_chunk by size of chunk and fit it in the back of
  108. // last_chunk.
  109. memmove(last_chunk.get(), last_chunk.get() + bytes_read, bytes_from_last);
  110. memcpy(last_chunk.get() + bytes_from_last, chunk.get(), bytes_read);
  111. contents->assign(last_chunk.get(), max_size);
  112. }
  113. return true;
  114. }
  115. #endif // !BUILDFLAG(IS_WIN)
  116. } // namespace feedback_util