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
5 #include "extensions/browser/computed_hashes.h"
6
7 #include "base/base64.h"
8 #include "base/file_util.h"
9 #include "base/files/file_path.h"
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12
13 namespace {
14 const char kPathKey[] = "path";
15 const char kBlockSizeKey[] = "block_size";
16 const char kBlockHashesKey[] = "block_hashes";
17 }
18
19 namespace extensions {
20
Reader()21 ComputedHashes::Reader::Reader() {
22 }
~Reader()23 ComputedHashes::Reader::~Reader() {
24 }
25
InitFromFile(const base::FilePath & path)26 bool ComputedHashes::Reader::InitFromFile(const base::FilePath& path) {
27 std::string contents;
28 if (!base::ReadFileToString(path, &contents))
29 return false;
30
31 base::ListValue* all_hashes = NULL;
32 scoped_ptr<base::Value> value(base::JSONReader::Read(contents));
33 if (!value.get() || !value->GetAsList(&all_hashes))
34 return false;
35
36 for (size_t i = 0; i < all_hashes->GetSize(); i++) {
37 base::DictionaryValue* dictionary = NULL;
38 if (!all_hashes->GetDictionary(i, &dictionary))
39 return false;
40
41 std::string relative_path_utf8;
42 if (!dictionary->GetString(kPathKey, &relative_path_utf8))
43 return false;
44
45 int block_size;
46 if (!dictionary->GetInteger(kBlockSizeKey, &block_size))
47 return false;
48 if (block_size <= 0 || ((block_size % 1024) != 0)) {
49 LOG(ERROR) << "Invalid block size: " << block_size;
50 block_size = 0;
51 return false;
52 }
53
54 base::ListValue* hashes_list = NULL;
55 if (!dictionary->GetList(kBlockHashesKey, &hashes_list))
56 return false;
57
58 base::FilePath relative_path =
59 base::FilePath::FromUTF8Unsafe(relative_path_utf8);
60
61 data_[relative_path] = HashInfo(block_size, std::vector<std::string>());
62 std::vector<std::string>* hashes = &(data_[relative_path].second);
63
64 for (size_t j = 0; j < hashes_list->GetSize(); j++) {
65 std::string encoded;
66 if (!hashes_list->GetString(j, &encoded))
67 return false;
68
69 hashes->push_back(std::string());
70 std::string* decoded = &hashes->back();
71 if (!base::Base64Decode(encoded, decoded)) {
72 hashes->clear();
73 return false;
74 }
75 }
76 }
77 return true;
78 }
79
GetHashes(const base::FilePath & relative_path,int * block_size,std::vector<std::string> * hashes)80 bool ComputedHashes::Reader::GetHashes(const base::FilePath& relative_path,
81 int* block_size,
82 std::vector<std::string>* hashes) {
83 std::map<base::FilePath, HashInfo>::iterator i = data_.find(relative_path);
84 if (i == data_.end())
85 return false;
86 HashInfo& info = i->second;
87 *block_size = info.first;
88 *hashes = info.second;
89 return true;
90 }
91
Writer()92 ComputedHashes::Writer::Writer() {
93 }
~Writer()94 ComputedHashes::Writer::~Writer() {
95 }
96
AddHashes(const base::FilePath & relative_path,int block_size,const std::vector<std::string> & hashes)97 void ComputedHashes::Writer::AddHashes(const base::FilePath& relative_path,
98 int block_size,
99 const std::vector<std::string>& hashes) {
100 base::DictionaryValue* dict = new base::DictionaryValue();
101 base::ListValue* block_hashes = new base::ListValue();
102 file_list_.Append(dict);
103 dict->SetString(kPathKey, relative_path.AsUTF8Unsafe());
104 dict->SetInteger(kBlockSizeKey, block_size);
105 dict->Set(kBlockHashesKey, block_hashes);
106
107 for (std::vector<std::string>::const_iterator i = hashes.begin();
108 i != hashes.end();
109 ++i) {
110 std::string encoded;
111 base::Base64Encode(*i, &encoded);
112 block_hashes->AppendString(encoded);
113 }
114 }
115
WriteToFile(const base::FilePath & path)116 bool ComputedHashes::Writer::WriteToFile(const base::FilePath& path) {
117 std::string json;
118 if (!base::JSONWriter::Write(&file_list_, &json))
119 return false;
120 int written = base::WriteFile(path, json.data(), json.size());
121 if (static_cast<unsigned>(written) != json.size()) {
122 LOG(ERROR) << "Error writing " << path.MaybeAsASCII()
123 << " ; write result:" << written << " expected:" << json.size();
124 return false;
125 }
126 return true;
127 }
128
129 } // namespace extensions
130