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

Unified Diff: src/platform/update_engine/install_action.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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/platform/update_engine/install_action.h ('k') | src/platform/update_engine/install_action_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/platform/update_engine/install_action.cc
diff --git a/src/platform/update_engine/install_action.cc b/src/platform/update_engine/install_action.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9c644df8ef93350581f69bb1243007c33200d23b
--- /dev/null
+++ b/src/platform/update_engine/install_action.cc
@@ -0,0 +1,249 @@
+// Copyright (c) 2009 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 "update_engine/install_action.h"
+#include <errno.h>
+#include <vector>
+#include <gflags/gflags.h>
+#include "update_engine/filesystem_iterator.h"
+#include "update_engine/gzip.h"
+#include "update_engine/subprocess.h"
+#include "update_engine/utils.h"
+
+DEFINE_string(mount_install_path, "",
+ "If set, the path to use when mounting the "
+ "destination device during install");
+
+using std::vector;
+
+namespace chromeos_update_engine {
+
+namespace {
+const string kBspatchPath = "/usr/bin/bspatch";
+}
+
+void InstallAction::PerformAction() {
+ ScopedActionCompleter completer(processor_, this);
+ // For now, do nothing other than pass what we need to to the output pipe
+ CHECK(HasInputObject());
+ const InstallPlan install_plan = GetInputObject();
+ if (HasOutputPipe())
+ SetOutputObject(install_plan.install_path);
+ if (install_plan.is_full_update) {
+ // No need to perform an install
+ completer.set_success(true);
+ return;
+ }
+ // We have a delta update.
+
+ // Open delta file
+ DeltaDiffParser parser(install_plan.download_path);
+ if (!parser.valid()) {
+ LOG(ERROR) << "Unable to open delta file";
+ return;
+ }
+
+ // Mount install fs
+ string mountpoint = FLAGS_mount_install_path;
+ if (mountpoint.empty()) {
+ // Set up dest_path_
+ char *mountpoint_temp = strdup("/tmp/install_mnt.XXXXXX");
+ CHECK(mountpoint_temp);
+ CHECK_EQ(mountpoint_temp, mkdtemp(mountpoint_temp));
+ CHECK_NE('\0', mountpoint_temp[0]);
+ mountpoint = mountpoint_temp;
+ free(mountpoint_temp);
+ }
+
+ TEST_AND_RETURN(utils::MountFilesystem(install_plan.install_path,
+ mountpoint));
+
+ // Automatically unmount the fs when this goes out of scope:
+ ScopedFilesystemUnmounter filesystem_unmounter(mountpoint);
+
+ {
+ // iterate through existing fs, deleting unneeded files
+ FilesystemIterator iter(mountpoint,
+ utils::SetWithValue<string>("/lost+found"));
+ for (; !iter.IsEnd(); iter.Increment()) {
+ if (!parser.ContainsPath(iter.GetPartialPath())) {
+ VLOG(1) << "install removing local path: " << iter.GetFullPath();
+ TEST_AND_RETURN(utils::RecursiveUnlinkDir(iter.GetFullPath()));
+ }
+ }
+ TEST_AND_RETURN(!iter.IsErr());
+ }
+
+ // iterate through delta metadata, writing files
+ DeltaDiffParserIterator iter = parser.Begin();
+ for (; iter != parser.End(); iter.Increment()) {
+ const DeltaArchiveManifest_File& file = iter.GetFile();
+ VLOG(1) << "Installing file: " << iter.path();
+ TEST_AND_RETURN(InstallFile(mountpoint, file, iter.path(), parser));
+ }
+
+ completer.set_success(true);
+}
+
+bool InstallAction::InstallFile(const std::string& mountpoint,
+ const DeltaArchiveManifest_File& file,
+ const std::string& path,
+ const DeltaDiffParser& parser) const {
+ // See what's already there
+ struct stat existing_stbuf;
+ int result = lstat((mountpoint + path).c_str(), &existing_stbuf);
+ TEST_AND_RETURN_FALSE_ERRNO((result == 0) || (errno == ENOENT));
+ bool exists = (result == 0);
+ // Create the proper file
+ if (S_ISDIR(file.mode())) {
+ if (!exists) {
+ TEST_AND_RETURN_FALSE_ERRNO(
+ (mkdir((mountpoint + path).c_str(), file.mode())) == 0);
+ }
+ } else if (S_ISLNK(file.mode())) {
+ InstallFileSymlink(mountpoint, file, path, parser, exists);
+ } else if (S_ISCHR(file.mode()) ||
+ S_ISBLK(file.mode()) ||
+ S_ISFIFO(file.mode()) ||
+ S_ISSOCK(file.mode())) {
+ InstallFileSpecialFile(mountpoint, file, path, parser, exists);
+ } else if (S_ISREG(file.mode())) {
+ InstallFileRegularFile(mountpoint, file, path, parser, exists);
+ } else {
+ // unknown mode type
+ TEST_AND_RETURN_FALSE(false);
+ }
+
+ // chmod/chown new file
+ if (!S_ISLNK(file.mode()))
+ TEST_AND_RETURN_FALSE_ERRNO(chmod((mountpoint + path).c_str(), file.mode())
+ == 0);
+ TEST_AND_RETURN_FALSE(file.has_uid() && file.has_gid());
+ TEST_AND_RETURN_FALSE_ERRNO(lchown((mountpoint + path).c_str(),
+ file.uid(), file.gid()) == 0);
+ return true;
+}
+
+bool InstallAction::InstallFileRegularFile(
+ const std::string& mountpoint,
+ const DeltaArchiveManifest_File& file,
+ const std::string& path,
+ const DeltaDiffParser& parser,
+ const bool exists) const {
+ if (!file.has_data_format())
+ return true;
+ TEST_AND_RETURN_FALSE(file.has_data_offset() && file.has_data_length());
+ if (file.data_format() == DeltaArchiveManifest_File_DataFormat_BSDIFF) {
+ // Expand with bspatch
+ string patch_path = utils::TempFilename(mountpoint + path + ".XXXXXX");
+ TEST_AND_RETURN_FALSE(file.has_data_length());
+ TEST_AND_RETURN_FALSE(parser.CopyDataToFile(
+ file.data_offset(),
+ static_cast<off_t>(file.data_length()), false,
+ patch_path));
+ string output_path = utils::TempFilename(mountpoint + path + ".XXXXXX");
+ int rc = 1;
+ vector<string> cmd;
+ cmd.push_back(kBspatchPath);
+ cmd.push_back(mountpoint + path);
+ cmd.push_back(output_path);
+ cmd.push_back(patch_path);
+ TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc));
+ TEST_AND_RETURN_FALSE(rc == 0);
+ TEST_AND_RETURN_FALSE_ERRNO(rename(output_path.c_str(),
+ (mountpoint + path).c_str()) == 0);
+ TEST_AND_RETURN_FALSE_ERRNO(unlink(patch_path.c_str()) == 0);
+ } else {
+ // Expand full data, decompressing if necessary
+ TEST_AND_RETURN_FALSE((file.data_format() ==
+ DeltaArchiveManifest_File_DataFormat_FULL) ||
+ (file.data_format() ==
+ DeltaArchiveManifest_File_DataFormat_FULL_GZ));
+ if (exists)
+ TEST_AND_RETURN_FALSE_ERRNO(unlink((mountpoint + path).c_str()) == 0);
+ TEST_AND_RETURN_FALSE(file.has_data_length());
+ const bool gzipped = file.data_format() ==
+ DeltaArchiveManifest_File_DataFormat_FULL_GZ;
+ bool success =
+ parser.CopyDataToFile(file.data_offset(), file.data_length(),
+ gzipped,
+ mountpoint + path);
+ TEST_AND_RETURN_FALSE(success);
+ }
+ return true;
+}
+
+// char/block devices, fifos, and sockets:
+bool InstallAction::InstallFileSpecialFile(
+ const std::string& mountpoint,
+ const DeltaArchiveManifest_File& file,
+ const std::string& path,
+ const DeltaDiffParser& parser,
+ const bool exists) const {
+ if (exists)
+ TEST_AND_RETURN_FALSE(unlink((mountpoint + path).c_str()) == 0);
+ dev_t dev = 0;
+ if (S_ISCHR(file.mode()) || S_ISBLK(file.mode())) {
+ vector<char> dev_proto;
+ TEST_AND_RETURN_FALSE(parser.ReadDataVector(file.data_offset(),
+ file.data_length(),
+ &dev_proto));
+ if (file.data_format() == DeltaArchiveManifest_File_DataFormat_FULL_GZ) {
+ TEST_AND_RETURN_FALSE(file.has_data_length());
+ {
+ vector<char> decompressed_dev_proto;
+ TEST_AND_RETURN_FALSE(GzipDecompress(dev_proto,
+ &decompressed_dev_proto));
+ dev_proto = decompressed_dev_proto;
+ }
+ } else {
+ TEST_AND_RETURN_FALSE(file.data_format() ==
+ DeltaArchiveManifest_File_DataFormat_FULL);
+ }
+ LinuxDevice linux_device;
+ utils::HexDumpVector(dev_proto);
+ TEST_AND_RETURN_FALSE(linux_device.ParseFromArray(&dev_proto[0],
+ dev_proto.size()));
+ dev = makedev(linux_device.major(), linux_device.minor());
+ }
+ TEST_AND_RETURN_FALSE_ERRNO(mknod((mountpoint + path).c_str(),
+ file.mode(), dev) == 0);
+ return true;
+}
+// symlinks:
+bool InstallAction::InstallFileSymlink(const std::string& mountpoint,
+ const DeltaArchiveManifest_File& file,
+ const std::string& path,
+ const DeltaDiffParser& parser,
+ const bool exists) const {
+ // If there's no data, we leave the symlink as is
+ if (!file.has_data_format())
+ return true; // No changes needed
+ TEST_AND_RETURN_FALSE((file.data_format() ==
+ DeltaArchiveManifest_File_DataFormat_FULL) ||
+ (file.data_format() ==
+ DeltaArchiveManifest_File_DataFormat_FULL_GZ));
+ TEST_AND_RETURN_FALSE(file.has_data_offset() && file.has_data_length());
+ // We have data, and thus use it to create a symlink.
+ // First delete any existing symlink:
+ if (exists)
+ TEST_AND_RETURN_FALSE_ERRNO(unlink((mountpoint + path).c_str()) == 0);
+ vector<char> symlink_data;
+ TEST_AND_RETURN_FALSE(parser.ReadDataVector(file.data_offset(),
+ file.data_length(),
+ &symlink_data));
+ if (file.data_format() == DeltaArchiveManifest_File_DataFormat_FULL_GZ) {
+ vector<char> decompressed_symlink_data;
+ TEST_AND_RETURN_FALSE(GzipDecompress(symlink_data,
+ &decompressed_symlink_data));
+ symlink_data = decompressed_symlink_data;
+ }
+ symlink_data.push_back('\0');
+ TEST_AND_RETURN_FALSE_ERRNO(symlink(&symlink_data[0],
+ (mountpoint + path).c_str()) == 0);
+ return true;
+}
+
+
+} // namespace chromeos_update_engine
« no previous file with comments | « src/platform/update_engine/install_action.h ('k') | src/platform/update_engine/install_action_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698