OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "update_engine/delta_diff_generator.h" | 5 #include "update_engine/delta_diff_generator.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <inttypes.h> | 9 #include <inttypes.h> |
10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 using std::vector; | 48 using std::vector; |
49 | 49 |
50 namespace chromeos_update_engine { | 50 namespace chromeos_update_engine { |
51 | 51 |
52 typedef DeltaDiffGenerator::Block Block; | 52 typedef DeltaDiffGenerator::Block Block; |
53 typedef map<const DeltaArchiveManifest_InstallOperation*, | 53 typedef map<const DeltaArchiveManifest_InstallOperation*, |
54 const string*> OperationNameMap; | 54 const string*> OperationNameMap; |
55 | 55 |
56 namespace { | 56 namespace { |
57 const size_t kBlockSize = 4096; // bytes | 57 const size_t kBlockSize = 4096; // bytes |
| 58 const string kNonexistentPath = ""; |
58 | 59 |
59 // TODO(adlr): switch from 1GiB to 2GiB when we no longer care about old | 60 // TODO(adlr): switch from 1GiB to 2GiB when we no longer care about old |
60 // clients: | 61 // clients: |
61 const size_t kRootFSPartitionSize = 1 * 1024 * 1024 * 1024; // bytes | 62 const size_t kRootFSPartitionSize = 1 * 1024 * 1024 * 1024; // bytes |
62 const uint64_t kVersionNumber = 1; | 63 const uint64_t kVersionNumber = 1; |
63 const uint64_t kFullUpdateChunkSize = 1024 * 1024; // bytes | 64 const uint64_t kFullUpdateChunkSize = 1024 * 1024; // bytes |
64 | 65 |
65 static const char* kInstallOperationTypes[] = { | 66 static const char* kInstallOperationTypes[] = { |
66 "REPLACE", | 67 "REPLACE", |
67 "REPLACE_BZ", | 68 "REPLACE_BZ", |
(...skipping 22 matching lines...) Expand all Loading... |
90 Vertex::Index existing_vertex, | 91 Vertex::Index existing_vertex, |
91 vector<Block>* blocks, | 92 vector<Block>* blocks, |
92 const string& old_root, | 93 const string& old_root, |
93 const string& new_root, | 94 const string& new_root, |
94 const string& path, // within new_root | 95 const string& path, // within new_root |
95 int data_fd, | 96 int data_fd, |
96 off_t* data_file_size) { | 97 off_t* data_file_size) { |
97 vector<char> data; | 98 vector<char> data; |
98 DeltaArchiveManifest_InstallOperation operation; | 99 DeltaArchiveManifest_InstallOperation operation; |
99 | 100 |
100 TEST_AND_RETURN_FALSE(DeltaDiffGenerator::ReadFileToDiff(old_root + path, | 101 string old_path = (old_root == kNonexistentPath) ? kNonexistentPath : |
| 102 old_root + path; |
| 103 |
| 104 TEST_AND_RETURN_FALSE(DeltaDiffGenerator::ReadFileToDiff(old_path, |
101 new_root + path, | 105 new_root + path, |
102 &data, | 106 &data, |
103 &operation, | 107 &operation, |
104 true)); | 108 true)); |
105 | 109 |
106 // Write the data | 110 // Write the data |
107 if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_MOVE) { | 111 if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_MOVE) { |
108 operation.set_data_offset(*data_file_size); | 112 operation.set_data_offset(*data_file_size); |
109 operation.set_data_length(data.size()); | 113 operation.set_data_length(data.size()); |
110 } | 114 } |
(...skipping 23 matching lines...) Expand all Loading... |
134 // For each regular file within new_root, creates a node in the graph, | 138 // For each regular file within new_root, creates a node in the graph, |
135 // determines the best way to compress it (REPLACE, REPLACE_BZ, COPY, BSDIFF), | 139 // determines the best way to compress it (REPLACE, REPLACE_BZ, COPY, BSDIFF), |
136 // and writes any necessary data to the end of data_fd. | 140 // and writes any necessary data to the end of data_fd. |
137 bool DeltaReadFiles(Graph* graph, | 141 bool DeltaReadFiles(Graph* graph, |
138 vector<Block>* blocks, | 142 vector<Block>* blocks, |
139 const string& old_root, | 143 const string& old_root, |
140 const string& new_root, | 144 const string& new_root, |
141 int data_fd, | 145 int data_fd, |
142 off_t* data_file_size) { | 146 off_t* data_file_size) { |
143 set<ino_t> visited_inodes; | 147 set<ino_t> visited_inodes; |
| 148 set<ino_t> visited_src_inodes; |
144 for (FilesystemIterator fs_iter(new_root, | 149 for (FilesystemIterator fs_iter(new_root, |
145 utils::SetWithValue<string>("/lost+found")); | 150 utils::SetWithValue<string>("/lost+found")); |
146 !fs_iter.IsEnd(); fs_iter.Increment()) { | 151 !fs_iter.IsEnd(); fs_iter.Increment()) { |
147 if (!S_ISREG(fs_iter.GetStat().st_mode)) | 152 if (!S_ISREG(fs_iter.GetStat().st_mode)) |
148 continue; | 153 continue; |
149 | 154 |
150 // Make sure we visit each inode only once. | 155 // Make sure we visit each inode only once. |
151 if (utils::SetContainsKey(visited_inodes, fs_iter.GetStat().st_ino)) | 156 if (utils::SetContainsKey(visited_inodes, fs_iter.GetStat().st_ino)) |
152 continue; | 157 continue; |
153 visited_inodes.insert(fs_iter.GetStat().st_ino); | 158 visited_inodes.insert(fs_iter.GetStat().st_ino); |
154 if (fs_iter.GetStat().st_size == 0) | 159 if (fs_iter.GetStat().st_size == 0) |
155 continue; | 160 continue; |
156 | 161 |
157 LOG(INFO) << "Encoding file " << fs_iter.GetPartialPath(); | 162 LOG(INFO) << "Encoding file " << fs_iter.GetPartialPath(); |
158 | 163 |
| 164 // We can't visit each dst image inode more than once, as that would |
| 165 // duplicate work. Here, we avoid visiting each source image inode |
| 166 // more than once. Technically, we could have multiple operations |
| 167 // that read the same blocks from the source image for diffing, but |
| 168 // we choose not to to avoid complexity. Eventually we will move away |
| 169 // from using a graph/cycle detection/etc to generate diffs, and at that |
| 170 // time, it will be easy (non-complex) to have many operations read |
| 171 // from the same source blocks. At that time, this code can die. -adlr |
| 172 bool should_diff_from_source = true; |
| 173 string src_path = old_root + fs_iter.GetPartialPath(); |
| 174 if (utils::FileExists(src_path.c_str())) { |
| 175 struct stat src_stbuf; |
| 176 TEST_AND_RETURN_FALSE_ERRNO(0 == stat(src_path.c_str(), &src_stbuf)); |
| 177 should_diff_from_source = !utils::SetContainsKey(visited_src_inodes, |
| 178 src_stbuf.st_ino); |
| 179 visited_src_inodes.insert(src_stbuf.st_ino); |
| 180 } |
| 181 |
159 TEST_AND_RETURN_FALSE(DeltaReadFile(graph, | 182 TEST_AND_RETURN_FALSE(DeltaReadFile(graph, |
160 Vertex::kInvalidIndex, | 183 Vertex::kInvalidIndex, |
161 blocks, | 184 blocks, |
162 old_root, | 185 (should_diff_from_source ? |
| 186 old_root : |
| 187 kNonexistentPath), |
163 new_root, | 188 new_root, |
164 fs_iter.GetPartialPath(), | 189 fs_iter.GetPartialPath(), |
165 data_fd, | 190 data_fd, |
166 data_file_size)); | 191 data_file_size)); |
167 } | 192 } |
168 return true; | 193 return true; |
169 } | 194 } |
170 | 195 |
171 // This class allocates non-existent temp blocks, starting from | 196 // This class allocates non-existent temp blocks, starting from |
172 // kTempBlockStart. Other code is responsible for converting these | 197 // kTempBlockStart. Other code is responsible for converting these |
(...skipping 980 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1153 if ((*graph)[cut.old_dst].op.type() != | 1178 if ((*graph)[cut.old_dst].op.type() != |
1154 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ && | 1179 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ && |
1155 (*graph)[cut.old_dst].op.type() != | 1180 (*graph)[cut.old_dst].op.type() != |
1156 DeltaArchiveManifest_InstallOperation_Type_REPLACE) { | 1181 DeltaArchiveManifest_InstallOperation_Type_REPLACE) { |
1157 Vertex::EdgeMap out_edges = (*graph)[cut.old_dst].out_edges; | 1182 Vertex::EdgeMap out_edges = (*graph)[cut.old_dst].out_edges; |
1158 graph_utils::DropWriteBeforeDeps(&out_edges); | 1183 graph_utils::DropWriteBeforeDeps(&out_edges); |
1159 | 1184 |
1160 TEST_AND_RETURN_FALSE(DeltaReadFile(graph, | 1185 TEST_AND_RETURN_FALSE(DeltaReadFile(graph, |
1161 cut.old_dst, | 1186 cut.old_dst, |
1162 NULL, | 1187 NULL, |
1163 "/-!@:&*nonexistent_path", | 1188 kNonexistentPath, |
1164 new_root, | 1189 new_root, |
1165 (*graph)[cut.old_dst].file_name, | 1190 (*graph)[cut.old_dst].file_name, |
1166 data_fd, | 1191 data_fd, |
1167 data_file_size)); | 1192 data_file_size)); |
1168 | 1193 |
1169 (*graph)[cut.old_dst].out_edges = out_edges; | 1194 (*graph)[cut.old_dst].out_edges = out_edges; |
1170 | 1195 |
1171 // Right now we don't have doubly-linked edges, so we have to scan | 1196 // Right now we don't have doubly-linked edges, so we have to scan |
1172 // the whole graph. | 1197 // the whole graph. |
1173 graph_utils::DropIncomingEdgesTo(graph, cut.old_dst); | 1198 graph_utils::DropIncomingEdgesTo(graph, cut.old_dst); |
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1601 dummy_extent->set_start_block(kSparseHole); | 1626 dummy_extent->set_start_block(kSparseHole); |
1602 dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) / | 1627 dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) / |
1603 kBlockSize); | 1628 kBlockSize); |
1604 } | 1629 } |
1605 | 1630 |
1606 const char* const kBsdiffPath = "bsdiff"; | 1631 const char* const kBsdiffPath = "bsdiff"; |
1607 const char* const kBspatchPath = "bspatch"; | 1632 const char* const kBspatchPath = "bspatch"; |
1608 const char* const kDeltaMagic = "CrAU"; | 1633 const char* const kDeltaMagic = "CrAU"; |
1609 | 1634 |
1610 }; // namespace chromeos_update_engine | 1635 }; // namespace chromeos_update_engine |
OLD | NEW |