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

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

Issue 545072: AU: Gut code for old updater. New protobuf for v2 updater. (Closed)
Patch Set: better comments Created 10 years, 11 months 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/install_action.h"
6 #include <errno.h>
7 #include <string>
8 #include <vector>
9 #include <gflags/gflags.h>
10 #include "update_engine/filesystem_iterator.h"
11 #include "update_engine/gzip.h"
12 #include "update_engine/subprocess.h"
13 #include "update_engine/utils.h"
14
15 DEFINE_string(mount_install_path, "",
16 "If set, the path to use when mounting the "
17 "destination device during install");
18
19 using std::string;
20 using std::vector;
21
22 namespace chromeos_update_engine {
23
24 namespace {
25 const string kBspatchPath = "/usr/bin/bspatch";
26 }
27
28 void InstallAction::PerformAction() {
29 ScopedActionCompleter completer(processor_, this);
30 // For now, do nothing other than pass what we need to to the output pipe
31 CHECK(HasInputObject());
32 const InstallPlan install_plan = GetInputObject();
33 if (HasOutputPipe())
34 SetOutputObject(install_plan.install_path);
35 if (install_plan.is_full_update) {
36 // No need to perform an install
37 completer.set_success(true);
38 return;
39 }
40 // We have a delta update.
41
42 // Open delta file
43 DeltaDiffParser parser(install_plan.download_path);
44 if (!parser.valid()) {
45 LOG(ERROR) << "Unable to open delta file";
46 return;
47 }
48
49 // Mount install fs
50 string mountpoint = FLAGS_mount_install_path;
51 if (mountpoint.empty()) {
52 // Set up dest_path_
53 char *mountpoint_temp = strdup("/tmp/install_mnt.XXXXXX");
54 CHECK(mountpoint_temp);
55 CHECK_EQ(mountpoint_temp, mkdtemp(mountpoint_temp));
56 CHECK_NE('\0', mountpoint_temp[0]);
57 mountpoint = mountpoint_temp;
58 free(mountpoint_temp);
59 }
60
61 TEST_AND_RETURN(utils::MountFilesystem(install_plan.install_path,
62 mountpoint));
63
64 // Automatically unmount the fs when this goes out of scope:
65 ScopedFilesystemUnmounter filesystem_unmounter(mountpoint);
66
67 {
68 // Iterate through existing fs, deleting unneeded files
69 // Delete files that don't exist in the update, or exist but are
70 // hard links.
71 FilesystemIterator iter(mountpoint,
72 utils::SetWithValue<string>("/lost+found"));
73 for (; !iter.IsEnd(); iter.Increment()) {
74 if (!parser.ContainsPath(iter.GetPartialPath()) ||
75 parser.GetFileAtPath(iter.GetPartialPath()).has_hardlink_path()) {
76 VLOG(1) << "install removing local path: " << iter.GetFullPath();
77 TEST_AND_RETURN(utils::RecursiveUnlinkDir(iter.GetFullPath()));
78 }
79 }
80 TEST_AND_RETURN(!iter.IsErr());
81 }
82
83 // iterate through delta metadata, writing files
84 DeltaDiffParserIterator iter = parser.Begin();
85 for (; iter != parser.End(); iter.Increment()) {
86 const DeltaArchiveManifest_File& file = iter.GetFile();
87 VLOG(1) << "Installing file: " << iter.path();
88 TEST_AND_RETURN(InstallFile(mountpoint, file, iter.path(), parser));
89 }
90
91 completer.set_success(true);
92 }
93
94 bool InstallAction::InstallFile(const std::string& mountpoint,
95 const DeltaArchiveManifest_File& file,
96 const std::string& path,
97 const DeltaDiffParser& parser) const {
98 // See what's already there
99 struct stat existing_stbuf;
100 int result = lstat((mountpoint + path).c_str(), &existing_stbuf);
101 TEST_AND_RETURN_FALSE_ERRNO((result == 0) || (errno == ENOENT));
102 bool exists = (result == 0);
103 // Create the proper file
104 if (file.has_hardlink_path()) {
105 TEST_AND_RETURN_FALSE(file.has_hardlink_path());
106 TEST_AND_RETURN_FALSE_ERRNO(link(
107 (mountpoint + file.hardlink_path()).c_str(),
108 (mountpoint + path).c_str()) == 0);
109 } else if (S_ISDIR(file.mode())) {
110 if (!exists) {
111 TEST_AND_RETURN_FALSE_ERRNO(
112 (mkdir((mountpoint + path).c_str(), file.mode())) == 0);
113 }
114 } else if (S_ISLNK(file.mode())) {
115 InstallFileSymlink(mountpoint, file, path, parser, exists);
116 } else if (S_ISCHR(file.mode()) ||
117 S_ISBLK(file.mode()) ||
118 S_ISFIFO(file.mode()) ||
119 S_ISSOCK(file.mode())) {
120 InstallFileSpecialFile(mountpoint, file, path, parser, exists);
121 } else if (S_ISREG(file.mode())) {
122 InstallFileRegularFile(mountpoint, file, path, parser, exists);
123 } else {
124 // unknown mode type
125 TEST_AND_RETURN_FALSE(false);
126 }
127
128 // chmod/chown new file
129 TEST_AND_RETURN_FALSE(file.has_uid() && file.has_gid());
130 TEST_AND_RETURN_FALSE_ERRNO(lchown((mountpoint + path).c_str(),
131 file.uid(), file.gid()) == 0);
132 if (!S_ISLNK(file.mode()))
133 TEST_AND_RETURN_FALSE_ERRNO(chmod((mountpoint + path).c_str(), file.mode())
134 == 0);
135 return true;
136 }
137
138 bool InstallAction::InstallFileRegularFile(
139 const std::string& mountpoint,
140 const DeltaArchiveManifest_File& file,
141 const std::string& path,
142 const DeltaDiffParser& parser,
143 const bool exists) const {
144 if (!file.has_data_format())
145 return true;
146 TEST_AND_RETURN_FALSE(file.has_data_offset() && file.has_data_length());
147 if (file.data_format() == DeltaArchiveManifest_File_DataFormat_BSDIFF) {
148 // Expand with bspatch
149 string patch_path = utils::TempFilename(mountpoint + path + ".XXXXXX");
150 TEST_AND_RETURN_FALSE(file.has_data_length());
151 TEST_AND_RETURN_FALSE(parser.CopyDataToFile(
152 file.data_offset(),
153 static_cast<off_t>(file.data_length()), false,
154 patch_path));
155 string output_path = utils::TempFilename(mountpoint + path + ".XXXXXX");
156 int rc = 1;
157 vector<string> cmd;
158 cmd.push_back(kBspatchPath);
159 cmd.push_back(mountpoint + path);
160 cmd.push_back(output_path);
161 cmd.push_back(patch_path);
162 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc));
163 TEST_AND_RETURN_FALSE(rc == 0);
164 TEST_AND_RETURN_FALSE_ERRNO(rename(output_path.c_str(),
165 (mountpoint + path).c_str()) == 0);
166 TEST_AND_RETURN_FALSE_ERRNO(unlink(patch_path.c_str()) == 0);
167 } else {
168 // Expand full data, decompressing if necessary
169 TEST_AND_RETURN_FALSE((file.data_format() ==
170 DeltaArchiveManifest_File_DataFormat_FULL) ||
171 (file.data_format() ==
172 DeltaArchiveManifest_File_DataFormat_FULL_GZ));
173 if (exists)
174 TEST_AND_RETURN_FALSE_ERRNO(unlink((mountpoint + path).c_str()) == 0);
175 TEST_AND_RETURN_FALSE(file.has_data_length());
176 const bool gzipped = file.data_format() ==
177 DeltaArchiveManifest_File_DataFormat_FULL_GZ;
178 bool success =
179 parser.CopyDataToFile(file.data_offset(), file.data_length(),
180 gzipped,
181 mountpoint + path);
182 TEST_AND_RETURN_FALSE(success);
183 }
184 return true;
185 }
186
187 // char/block devices, fifos, and sockets:
188 bool InstallAction::InstallFileSpecialFile(
189 const std::string& mountpoint,
190 const DeltaArchiveManifest_File& file,
191 const std::string& path,
192 const DeltaDiffParser& parser,
193 const bool exists) const {
194 if (exists)
195 TEST_AND_RETURN_FALSE(unlink((mountpoint + path).c_str()) == 0);
196 dev_t dev = 0;
197 if (S_ISCHR(file.mode()) || S_ISBLK(file.mode())) {
198 vector<char> dev_proto;
199 TEST_AND_RETURN_FALSE(file.has_data_format());
200 TEST_AND_RETURN_FALSE(parser.ReadDataVector(file.data_offset(),
201 file.data_length(),
202 &dev_proto));
203 if (file.data_format() == DeltaArchiveManifest_File_DataFormat_FULL_GZ) {
204 TEST_AND_RETURN_FALSE(file.has_data_length());
205 {
206 vector<char> decompressed_dev_proto;
207 TEST_AND_RETURN_FALSE(GzipDecompress(dev_proto,
208 &decompressed_dev_proto));
209 dev_proto = decompressed_dev_proto;
210 }
211 } else {
212 TEST_AND_RETURN_FALSE(file.data_format() ==
213 DeltaArchiveManifest_File_DataFormat_FULL);
214 }
215 LinuxDevice linux_device;
216 utils::HexDumpVector(dev_proto);
217 TEST_AND_RETURN_FALSE(linux_device.ParseFromArray(&dev_proto[0],
218 dev_proto.size()));
219 dev = makedev(linux_device.major(), linux_device.minor());
220 }
221 TEST_AND_RETURN_FALSE_ERRNO(mknod((mountpoint + path).c_str(),
222 file.mode(), dev) == 0);
223 return true;
224 }
225 // symlinks:
226 bool InstallAction::InstallFileSymlink(const std::string& mountpoint,
227 const DeltaArchiveManifest_File& file,
228 const std::string& path,
229 const DeltaDiffParser& parser,
230 const bool exists) const {
231 // If there's no data, we leave the symlink as is
232 if (!file.has_data_format())
233 return true; // No changes needed
234 TEST_AND_RETURN_FALSE((file.data_format() ==
235 DeltaArchiveManifest_File_DataFormat_FULL) ||
236 (file.data_format() ==
237 DeltaArchiveManifest_File_DataFormat_FULL_GZ));
238 TEST_AND_RETURN_FALSE(file.has_data_offset() && file.has_data_length());
239 // We have data, and thus use it to create a symlink.
240 // First delete any existing symlink:
241 if (exists)
242 TEST_AND_RETURN_FALSE_ERRNO(unlink((mountpoint + path).c_str()) == 0);
243 vector<char> symlink_data;
244 TEST_AND_RETURN_FALSE(parser.ReadDataVector(file.data_offset(),
245 file.data_length(),
246 &symlink_data));
247 if (file.data_format() == DeltaArchiveManifest_File_DataFormat_FULL_GZ) {
248 vector<char> decompressed_symlink_data;
249 TEST_AND_RETURN_FALSE(GzipDecompress(symlink_data,
250 &decompressed_symlink_data));
251 symlink_data = decompressed_symlink_data;
252 }
253 symlink_data.push_back('\0');
254 TEST_AND_RETURN_FALSE_ERRNO(symlink(&symlink_data[0],
255 (mountpoint + path).c_str()) == 0);
256 return true;
257 }
258
259
260 } // namespace chromeos_update_engine
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698