Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Side by Side Diff: src/platform/update_engine/delta_diff_parser.cc

Issue 465067: Missed new files in last commit
Patch Set: Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2009 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 "update_engine/delta_diff_parser.h"
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <endian.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <algorithm>
14 #include <string>
15 #include <vector>
16 #include <google/protobuf/io/zero_copy_stream_impl.h>
17 #include "base/scoped_ptr.h"
18 #include "update_engine/decompressing_file_writer.h"
19 #include "update_engine/gzip.h"
20 #include "update_engine/utils.h"
21
22 using std::min;
23 using std::string;
24 using std::vector;
25
26 namespace chromeos_update_engine {
27
28 namespace {
29 const int kCopyFileBufferSize = 4096;
30 }
31
32 const char* const DeltaDiffParser::kFileMagic("CrAU");
33
34 // The iterator returns a directory before returning its children.
35 // Steps taken in Increment():
36 // - See if the current item has children. If so, the child becomes
37 // the new current item and we return.
38 // - If current item has no children, we loop. Each loop iteration
39 // considers an item (first the current item, then its parent,
40 // then grand parent, and so on). Each loop iteration, we see if there
41 // are any siblings we haven't iterated on yet. If so, we're done.
42 // If not, keep looping to parents.
43 void DeltaDiffParserIterator::Increment() {
44 // See if we have any children.
45 const DeltaArchiveManifest_File& file = GetFile();
46 if (file.children_size() > 0) {
47 path_indices_.push_back(file.children(0).index());
48 path_ += "/";
49 path_ += file.children(0).name();
50 child_indices_.push_back(0);
51 return;
52 }
53 // Look in my parent for the next child, then try grandparent, etc.
54
55 path_indices_.pop_back();
56 path_.resize(path_.rfind('/'));
57
58 while (!child_indices_.empty()) {
59 // Try to bump the last entry
60 CHECK_EQ(path_indices_.size(), child_indices_.size());
61 child_indices_.back()++;
62 const DeltaArchiveManifest_File& parent =
63 archive_->files(path_indices_.back());
64 if (parent.children_size() > child_indices_.back()) {
65 // we found a new child!
66 path_indices_.push_back(parent.children(child_indices_.back()).index());
67 path_ += "/";
68 path_ += parent.children(child_indices_.back()).name();
69 return;
70 }
71 path_indices_.pop_back();
72 child_indices_.pop_back();
73 if (!path_.empty())
74 path_.resize(path_.rfind('/'));
75 }
76 }
77
78 const string DeltaDiffParserIterator::GetName() const {
79 if (path_.empty())
80 return "";
81 CHECK_NE(path_.rfind('/'), string::npos);
82 return string(path_, path_.rfind('/') + 1);
83 }
84
85 const DeltaArchiveManifest_File& DeltaDiffParserIterator::GetFile() const {
86 CHECK(!path_indices_.empty());
87 return archive_->files(path_indices_.back());
88 }
89
90
91 DeltaDiffParser::DeltaDiffParser(const string& delta_file)
92 : fd_(-1),
93 valid_(false) {
94 fd_ = open(delta_file.c_str(), O_RDONLY, 0);
95 if (fd_ < 0) {
96 LOG(ERROR) << "Unable to open delta file: " << delta_file;
97 return;
98 }
99 ScopedFdCloser fd_closer(&fd_);
100 scoped_array<char> magic(new char[strlen(kFileMagic)]);
101 if (strlen(kFileMagic) != read(fd_, magic.get(), strlen(kFileMagic))) {
102 LOG(ERROR) << "delta file too short";
103 return;
104 }
105 if (strncmp(magic.get(), kFileMagic, strlen(kFileMagic))) {
106 LOG(ERROR) << "Incorrect magic at beginning of delta file";
107 return;
108 }
109
110 int64 proto_offset = 0;
111 COMPILE_ASSERT(sizeof(proto_offset) == sizeof(off_t), off_t_wrong_size);
112 if (sizeof(proto_offset) != read(fd_, &proto_offset, sizeof(proto_offset))) {
113 LOG(ERROR) << "delta file too short";
114 return;
115 }
116 proto_offset = be64toh(proto_offset); // switch from big-endian to host
117
118 int64 proto_length = 0;
119 if (sizeof(proto_length) != read(fd_, &proto_length, sizeof(proto_length))) {
120 LOG(ERROR) << "delta file too short";
121 return;
122 }
123 proto_length = be64toh(proto_length); // switch from big-endian to host
124
125 vector<char> proto(proto_length);
126 size_t bytes_read = 0;
127 while (bytes_read < proto_length) {
128 ssize_t r = pread(fd_, &proto[bytes_read], proto_length - bytes_read,
129 proto_offset + bytes_read);
130 TEST_AND_RETURN(r >= 0);
131 bytes_read += r;
132 }
133 {
134 vector<char> decompressed_proto;
135 TEST_AND_RETURN(GzipDecompress(proto, &decompressed_proto));
136 proto.swap(decompressed_proto);
137 }
138
139 valid_ = archive_.ParseFromArray(&proto[0], proto.size());
140 if (valid_) {
141 fd_closer.set_should_close(false);
142 } else {
143 LOG(ERROR) << "load from file failed";
144 }
145 }
146
147 DeltaDiffParser::~DeltaDiffParser() {
148 if (fd_ >= 0) {
149 close(fd_);
150 fd_ = -1;
151 }
152 }
153
154 bool DeltaDiffParser::ContainsPath(const string& path) const {
155 return GetIndexForPath(path) >= 0;
156 }
157
158 const DeltaArchiveManifest_File& DeltaDiffParser::GetFileAtPath(
159 const string& path) const {
160 int idx = GetIndexForPath(path);
161 CHECK_GE(idx, 0) << path;
162 return archive_.files(idx);
163 }
164
165 // Returns -1 if not found.
166 int DeltaDiffParser::GetIndexOfFileChild(
167 const DeltaArchiveManifest_File& file, const string& child_name) const {
168 if (file.children_size() == 0)
169 return -1;
170 int begin = 0;
171 int end = file.children_size();
172 while (begin < end) {
173 int middle = (begin + end) / 2;
174 const string& middle_name = file.children(middle).name();
175 int cmp_result = strcmp(middle_name.c_str(), child_name.c_str());
176 if (cmp_result == 0)
177 return file.children(middle).index();
178 if (cmp_result < 0)
179 begin = middle + 1;
180 else
181 end = middle;
182 }
183 return -1;
184 }
185
186 // Converts a path to an index in archive_. It does this by separating
187 // the path components and going from root to leaf, finding the
188 // File message for each component. Index values for children are
189 // stored in File messages.
190 int DeltaDiffParser::GetIndexForPath(const string& path) const {
191 string cleaned_path = utils::NormalizePath(path, true);
192 // strip leading slash
193 if (cleaned_path[0] == '/')
194 cleaned_path = cleaned_path.c_str() + 1;
195 if (cleaned_path.empty())
196 return 0;
197 string::size_type begin = 0;
198 string::size_type end = cleaned_path.find_first_of('/', begin + 1);
199 const DeltaArchiveManifest_File* file = &archive_.files(0);
200 int file_idx = -1;
201 for (;;) {
202 string component = cleaned_path.substr(begin, end - begin);
203 if (component.empty())
204 break;
205 // search for component in 'file'
206 file_idx = GetIndexOfFileChild(*file, component);
207 if (file_idx < 0)
208 return file_idx;
209 file = &archive_.files(file_idx);
210 if (end == string::npos)
211 break;
212 begin = end + 1;
213 end = cleaned_path.find_first_of('/', begin + 1);
214 }
215 return file_idx;
216 }
217
218 bool DeltaDiffParser::ReadDataVector(off_t offset, off_t length,
219 std::vector<char>* out) const {
220 out->resize(static_cast<vector<char>::size_type>(length));
221 int r = pread(fd_, &((*out)[0]), length, offset);
222 TEST_AND_RETURN_FALSE_ERRNO(r >= 0);
223 return true;
224 }
225
226 bool DeltaDiffParser::CopyDataToFile(off_t offset, off_t length,
227 bool should_decompress,
228 const std::string& path) const {
229 DirectFileWriter direct_writer;
230 GzipDecompressingFileWriter decompressing_writer(&direct_writer);
231 FileWriter* writer = NULL; // will point to one of the two writers above
232
233 writer = (should_decompress ?
234 static_cast<FileWriter*>(&decompressing_writer) :
235 static_cast<FileWriter*>(&direct_writer));
236 ScopedFileWriterCloser closer(writer);
237
238 int r = writer->Open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0644);
239 TEST_AND_RETURN_FALSE(r == 0);
240
241 off_t bytes_transferred = 0;
242
243 while (bytes_transferred < length) {
244 char buf[kCopyFileBufferSize];
245 size_t bytes_to_read = min(length - bytes_transferred,
246 static_cast<off_t>(sizeof(buf)));
247 ssize_t bytes_read = pread(fd_, buf, bytes_to_read,
248 offset + bytes_transferred);
249 if (bytes_read == 0)
250 break; // EOF
251 TEST_AND_RETURN_FALSE_ERRNO(bytes_read > 0);
252 int bytes_written = writer->Write(buf, bytes_read);
253 TEST_AND_RETURN_FALSE(bytes_written == bytes_read);
254 bytes_transferred += bytes_written;
255 }
256 TEST_AND_RETURN_FALSE(bytes_transferred == length);
257 LOG_IF(ERROR, bytes_transferred > length) << "Wrote too many bytes(?)";
258 return true;
259 }
260
261
262 const DeltaDiffParser::Iterator DeltaDiffParser::Begin() {
263 DeltaDiffParserIterator ret(&archive_);
264 ret.path_indices_.push_back(0);
265 return ret;
266 }
267
268 const DeltaDiffParser::Iterator DeltaDiffParser::End() {
269 return DeltaDiffParserIterator(&archive_);
270 }
271
272 } // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « src/platform/update_engine/delta_diff_parser.h ('k') | src/platform/update_engine/delta_diff_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698