summaryrefslogtreecommitdiff
path: root/chromium/components/feedback/feedback_util.cc
blob: 9a295ef37624eac5c9ab75ad73f73b777bd52e11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/feedback/feedback_util.h"

#include <string>

#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "components/feedback/feedback_report.h"
#include "third_party/zlib/google/zip.h"

namespace {

constexpr char kMultilineIndicatorString[] = "<multiline>\n";
constexpr char kMultilineStartString[] = "---------- START ----------\n";
constexpr char kMultilineEndString[] = "---------- END ----------\n\n";

}  // namespace

namespace feedback_util {

bool ZipString(const base::FilePath& filename,
               const std::string& data,
               std::string* compressed_logs) {
  base::ScopedTempDir temp_dir;
  base::FilePath zip_file;

  // Create a temporary directory, put the logs into a file in it. Create
  // another temporary file to receive the zip file in.
  if (!temp_dir.CreateUniqueTempDir())
    return false;
  if (base::WriteFile(temp_dir.GetPath().Append(filename), data.c_str(),
                      data.size()) == -1) {
    return false;
  }

  bool succeed = base::CreateTemporaryFile(&zip_file) &&
                 zip::Zip(temp_dir.GetPath(), zip_file, false) &&
                 base::ReadFileToString(zip_file, compressed_logs);

  base::DeleteFile(zip_file);

  return succeed;
}

std::string LogsToString(const FeedbackCommon::SystemLogsMap& sys_info) {
  std::string syslogs_string;
  for (const auto& iter : sys_info) {
    std::string key = iter.first;
    base::TrimString(key, "\n ", &key);

    if (key == feedback::FeedbackReport::kCrashReportIdsKey ||
        key == feedback::FeedbackReport::kAllCrashReportIdsKey) {
      // Avoid adding the crash IDs to the system_logs.txt file for privacy
      // reasons. They should just be part of the product specific data.
      continue;
    }

    std::string value = iter.second;
    base::TrimString(value, "\n ", &value);
    if (value.find("\n") != std::string::npos) {
      syslogs_string.append(key + "=" + kMultilineIndicatorString +
                            kMultilineStartString + value + "\n" +
                            kMultilineEndString);
    } else {
      syslogs_string.append(key + "=" + value + "\n");
    }
  }
  return syslogs_string;
}

// Note: This function is excluded from win build because its unit tests do
// not pass on OS_WIN.
// This function is only called on ChromeOS and Lacros build.
// See https://crbug.com/1119560.
#if !BUILDFLAG(IS_WIN)
bool ReadEndOfFile(const base::FilePath& path,
                   size_t max_size,
                   std::string* contents) {
  if (!contents) {
    LOG(ERROR) << "contents buffer is null.";
    return false;
  }

  if (path.ReferencesParent()) {
    LOG(ERROR) << "ReadEndOfFile can't be called on file paths with parent "
                  "references.";
    return false;
  }

  base::ScopedFILE fp(base::OpenFile(path, "r"));
  if (!fp) {
    PLOG(ERROR) << "Failed to open file " << path.value();
    return false;
  }

  std::unique_ptr<char[]> chunk(new char[max_size]);
  std::unique_ptr<char[]> last_chunk(new char[max_size]);
  chunk[0] = '\0';
  last_chunk[0] = '\0';

  size_t total_bytes_read = 0;
  size_t bytes_read = 0;

  // Since most logs are not seekable, read until the end keeping tracking of
  // last two chunks.
  while ((bytes_read = fread(chunk.get(), 1, max_size, fp.get())) == max_size) {
    total_bytes_read += bytes_read;
    last_chunk.swap(chunk);
    chunk[0] = '\0';
  }
  total_bytes_read += bytes_read;
  if (total_bytes_read < max_size) {
    // File is smaller than max_size
    contents->assign(chunk.get(), bytes_read);
  } else if (bytes_read == 0) {
    // File is exactly max_size or a multiple of max_size
    contents->assign(last_chunk.get(), max_size);
  } else {
    // Number of bytes to keep from last_chunk
    size_t bytes_from_last = max_size - bytes_read;

    // Shift left last_chunk by size of chunk and fit it in the back of
    // last_chunk.
    memmove(last_chunk.get(), last_chunk.get() + bytes_read, bytes_from_last);
    memcpy(last_chunk.get() + bytes_from_last, chunk.get(), bytes_read);

    contents->assign(last_chunk.get(), max_size);
  }

  return true;
}
#endif  // !BUILDFLAG(IS_WIN)

}  // namespace feedback_util