AU: Try delta updates first, then full updates
Also, some bug fixes.
Review URL: http://codereview.chromium.org/492008
diff --git a/SConstruct b/SConstruct
index 64406e4..0d124d9 100644
--- a/SConstruct
+++ b/SConstruct
@@ -123,16 +123,24 @@
unittest_main = ['testrunner.cc']
delta_generator_sources = Split("""delta_diff_generator.cc""")
+delta_generator_main = ['generate_delta_main.cc']
+
+test_installer_main = ['test_installer_main.cc']
env.Program('update_engine', sources + main)
unittest_cmd = env.Program('update_engine_unittests',
sources + delta_generator_sources +
unittest_sources + unittest_main)
+test_installer_cmd = env.Program('test_installer',
+ sources + delta_generator_sources +
+ unittest_sources + test_installer_main)
+
Clean(unittest_cmd, Glob('*.gcda') + Glob('*.gcno') + Glob('*.gcov') +
Split('html app.info'))
delta_generator_cmd = env.Program('delta_generator',
- sources + delta_generator_sources + main)
+ sources + delta_generator_sources +
+ delta_generator_main)
http_server_cmd = env.Program('test_http_server', 'test_http_server.cc')
diff --git a/action.h b/action.h
index af6deee..b45100a 100644
--- a/action.h
+++ b/action.h
@@ -62,8 +62,6 @@
// consulting ActionTraits<T>::InputObjectType (and OutputObjectType).
// This is why the ActionTraits classes are needed.
-using std::tr1::shared_ptr;
-
namespace chromeos_update_engine {
// It is handy to have a non-templated base class of all Actions.
@@ -111,7 +109,7 @@
// std::type_info for this?
// Type() returns a string of the Action type. I.e., for DownloadAction,
// Type() would return "DownloadAction".
- virtual string Type() const = 0;
+ virtual std::string Type() const = 0;
protected:
// A weak pointer to the processor that owns this Action.
@@ -138,7 +136,7 @@
void set_in_pipe(
// this type is a fancy way of saying: a shared_ptr to an
// ActionPipe<InputObjectType>.
- const shared_ptr<ActionPipe<
+ const std::tr1::shared_ptr<ActionPipe<
typename ActionTraits<SubClass>::InputObjectType> >&
in_pipe) {
in_pipe_ = in_pipe;
@@ -151,7 +149,7 @@
void set_out_pipe(
// this type is a fancy way of saying: a shared_ptr to an
// ActionPipe<OutputObjectType>.
- const shared_ptr<ActionPipe<
+ const std::tr1::shared_ptr<ActionPipe<
typename ActionTraits<SubClass>::OutputObjectType> >&
out_pipe) {
out_pipe_ = out_pipe;
@@ -194,9 +192,11 @@
// point to when the last such shared_ptr object dies. We consider the
// Actions on either end of a pipe to "own" the pipe. When the last Action
// of the two dies, the ActionPipe will die, too.
- shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType> >
+ std::tr1::shared_ptr<
+ ActionPipe<typename ActionTraits<SubClass>::InputObjectType> >
in_pipe_;
- shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType> >
+ std::tr1::shared_ptr<
+ ActionPipe<typename ActionTraits<SubClass>::OutputObjectType> >
out_pipe_;
};
diff --git a/action_pipe.h b/action_pipe.h
index 509fbee..7697043 100644
--- a/action_pipe.h
+++ b/action_pipe.h
@@ -29,10 +29,6 @@
// the two Action objects. a shared_ptr is used so that when the last Action
// pointing to an ActionPipe dies, the ActionPipe dies, too.
-using std::map;
-using std::string;
-using std::tr1::shared_ptr;
-
namespace chromeos_update_engine {
// Used by Actions an InputObjectType or OutputObjectType to specify that
@@ -62,7 +58,8 @@
// when the last Action is destroyed.
template<typename FromAction, typename ToAction>
static void Bond(FromAction* from, ToAction* to) {
- shared_ptr<ActionPipe<ObjectType> > pipe(new ActionPipe<ObjectType>);
+ std::tr1::shared_ptr<ActionPipe<ObjectType> > pipe(
+ new ActionPipe<ObjectType>);
from->set_out_pipe(pipe);
to->set_in_pipe(pipe); // If you get an error on this line, then
diff --git a/action_pipe_unittest.cc b/action_pipe_unittest.cc
index 28cf248..b0a96b7 100644
--- a/action_pipe_unittest.cc
+++ b/action_pipe_unittest.cc
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <string>
#include <gtest/gtest.h>
#include "update_engine/action.h"
#include "update_engine/action_pipe.h"
+using std::string;
+
namespace chromeos_update_engine {
using chromeos_update_engine::ActionPipe;
diff --git a/action_processor.cc b/action_processor.cc
index 21a88f1..d58b5ee 100644
--- a/action_processor.cc
+++ b/action_processor.cc
@@ -3,9 +3,12 @@
// found in the LICENSE file.
#include "update_engine/action_processor.h"
+#include <string>
#include "chromeos/obsolete_logging.h"
#include "update_engine/action.h"
+using std::string;
+
namespace chromeos_update_engine {
ActionProcessor::ActionProcessor()
@@ -70,7 +73,7 @@
LOG(INFO) << "ActionProcessor::ActionComplete: finished last action of"
" type " << old_type;
if (delegate_) {
- delegate_->ProcessingDone(this);
+ delegate_->ProcessingDone(this, success);
}
return;
}
diff --git a/action_processor.h b/action_processor.h
index 938a81d..8311b8a 100644
--- a/action_processor.h
+++ b/action_processor.h
@@ -78,8 +78,9 @@
class ActionProcessorDelegate {
public:
// Called when all processing in an ActionProcessor has completed. A pointer
- // to the ActionProcessor is passed.
- virtual void ProcessingDone(const ActionProcessor* processor) {}
+ // to the ActionProcessor is passed. success is true iff all actions
+ // completed successfully
+ virtual void ProcessingDone(const ActionProcessor* processor, bool success) {}
// Called when processing has stopped. Does not mean that all Actions have
// completed. If/when all Actions complete, ProcessingDone() will be called.
diff --git a/action_processor_unittest.cc b/action_processor_unittest.cc
index 6130585..0657207 100644
--- a/action_processor_unittest.cc
+++ b/action_processor_unittest.cc
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <string>
#include <gtest/gtest.h>
#include "update_engine/action.h"
#include "update_engine/action_processor.h"
+using std::string;
+
namespace chromeos_update_engine {
using chromeos_update_engine::ActionPipe;
@@ -60,7 +63,7 @@
explicit MyActionProcessorDelegate(const ActionProcessor* processor)
: processor_(processor), processing_done_called_(false) {}
- virtual void ProcessingDone(const ActionProcessor* processor) {
+ virtual void ProcessingDone(const ActionProcessor* processor, bool success) {
EXPECT_EQ(processor_, processor);
EXPECT_FALSE(processing_done_called_);
processing_done_called_ = true;
diff --git a/action_unittest.cc b/action_unittest.cc
index 371f84d..8dd9edd 100644
--- a/action_unittest.cc
+++ b/action_unittest.cc
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <string>
#include <gtest/gtest.h>
#include "update_engine/action.h"
#include "update_engine/action_processor.h"
+using std::string;
+
namespace chromeos_update_engine {
using chromeos_update_engine::ActionPipe;
diff --git a/delta_diff_generator.cc b/delta_diff_generator.cc
index 45872bc..2dacfdf 100644
--- a/delta_diff_generator.cc
+++ b/delta_diff_generator.cc
@@ -9,6 +9,9 @@
#include <stdio.h>
#include <unistd.h>
#include <algorithm>
+#include <map>
+#include <set>
+#include <string>
#include <vector>
#include <tr1/memory>
#include <zlib.h>
@@ -19,6 +22,9 @@
#include "update_engine/subprocess.h"
#include "update_engine/utils.h"
+using std::map;
+using std::set;
+using std::string;
using std::vector;
using std::tr1::shared_ptr;
using chromeos_update_engine::DeltaArchiveManifest;
@@ -26,6 +32,9 @@
namespace chromeos_update_engine {
namespace {
+
+const char* kBsdiffPath = "/usr/bin/bsdiff";
+
// These structs and methods are helpers for EncodeDataToDeltaFile()
// Before moving the data into a proto buffer, the data is stored in
@@ -200,12 +209,13 @@
bool DeltaDiffGenerator::WriteFileDiffsToDeltaFile(
DeltaArchiveManifest* archive,
DeltaArchiveManifest_File* file,
- const std::string& file_name,
- const std::string& old_path,
- const std::string& new_path,
+ const string& file_name,
+ const string& old_path,
+ const string& new_path,
FileWriter* out_file_writer,
int* out_file_length,
- const std::string& force_compress_dev_path) {
+ set<string> always_full_target_paths,
+ const string& force_compress_dev_path) {
TEST_AND_RETURN_FALSE(file->has_mode());
// Stat the actual file, too
@@ -220,14 +230,21 @@
DeltaArchiveManifest_File_Child* child = file->mutable_children(i);
DeltaArchiveManifest_File* child_file =
archive->mutable_files(child->index());
+ string recurse_old_path = old_path;
+ string recurse_new_path = new_path;
+ if (!file_name.empty()) {
+ recurse_new_path += "/" + file_name;
+ recurse_old_path += "/" + file_name;
+ }
TEST_AND_RETURN_FALSE(WriteFileDiffsToDeltaFile(
archive,
child_file,
child->name(),
- old_path + "/" + file_name,
- new_path + "/" + file_name,
+ recurse_old_path,
+ recurse_new_path,
out_file_writer,
out_file_length,
+ always_full_target_paths,
force_compress_dev_path));
}
return true;
@@ -252,8 +269,15 @@
format_set = true;
} else if (S_ISREG(file->mode())) {
// regular file. We may use a delta here.
- TEST_AND_RETURN_FALSE(EncodeFile(old_path, new_path, file_name, &format,
- &data));
+ const bool avoid_diff = utils::SetContainsKey(always_full_target_paths,
+ new_path + "/" + file_name);
+ bool no_change = false;
+ TEST_AND_RETURN_FALSE(EncodeFile(old_path, new_path, file_name,
+ avoid_diff, &format, &data, &no_change));
+ if (no_change) {
+ // No data change. We're done!
+ return true;
+ }
should_compress = false;
format_set = true;
if ((format == DeltaArchiveManifest_File_DataFormat_BSDIFF) ||
@@ -278,20 +302,17 @@
format_set = true;
}
- if (!data.empty()) {
- TEST_AND_RETURN_FALSE(format_set);
- file->set_data_format(format);
- file->set_data_offset(*out_file_length);
- TEST_AND_RETURN_FALSE(static_cast<ssize_t>(data.size()) ==
- out_file_writer->Write(&data[0], data.size()));
- file->set_data_length(data.size());
- *out_file_length += data.size();
- }
+ TEST_AND_RETURN_FALSE(format_set);
+ file->set_data_format(format);
+ file->set_data_offset(*out_file_length);
+ TEST_AND_RETURN_FALSE(static_cast<ssize_t>(data.size()) ==
+ out_file_writer->Write(&data[0], data.size()));
+ file->set_data_length(data.size());
+ *out_file_length += data.size();
return true;
}
-bool DeltaDiffGenerator::EncodeLink(const std::string& path,
- std::vector<char>* out) {
+bool DeltaDiffGenerator::EncodeLink(const string& path, vector<char>* out) {
// Store symlink path as file data
vector<char> link_data(4096);
int rc = readlink(path.c_str(), &link_data[0], link_data.size());
@@ -329,56 +350,85 @@
const string& old_dir,
const string& new_dir,
const string& file_name,
+ const bool avoid_diff,
DeltaArchiveManifest_File_DataFormat* out_data_format,
- vector<char>* out) {
+ vector<char>* out,
+ bool* no_change) {
TEST_AND_RETURN_FALSE(out_data_format);
- // First, see the full length:
+ vector<char> ret;
vector<char> full_data;
- TEST_AND_RETURN_FALSE(utils::ReadFile(new_dir + "/" + file_name, &full_data));
- vector<char> gz_data;
- if (!full_data.empty()) {
- TEST_AND_RETURN_FALSE(GzipCompress(full_data, &gz_data));
- }
- vector<char> *ret = NULL;
+ {
+ // First, see the full length:
+ TEST_AND_RETURN_FALSE(utils::ReadFile(new_dir + "/" + file_name,
+ &full_data));
+ vector<char> gz_data;
+ if (!full_data.empty()) {
+ TEST_AND_RETURN_FALSE(GzipCompress(full_data, &gz_data));
+ }
- if (gz_data.size() < full_data.size()) {
- *out_data_format = DeltaArchiveManifest_File_DataFormat_FULL_GZ;
- ret = &gz_data;
- } else {
- *out_data_format = DeltaArchiveManifest_File_DataFormat_FULL;
- ret = &full_data;
+ if (gz_data.size() < full_data.size()) {
+ *out_data_format = DeltaArchiveManifest_File_DataFormat_FULL_GZ;
+ ret.swap(gz_data);
+ } else {
+ *out_data_format = DeltaArchiveManifest_File_DataFormat_FULL;
+ ret = full_data;
+ }
+ }
+
+ if (avoid_diff) {
+ out->swap(ret);
+ return true;
}
struct stat old_stbuf;
if ((stat((old_dir + "/" + file_name).c_str(), &old_stbuf) < 0) ||
(!S_ISREG(old_stbuf.st_mode))) {
- // stat() failed or old file is not a regular file. Just send back the full
- // contents
- *out = *ret;
+ // stat() failed or old file is not a regular file. Just send back
+ // the full contents
+ out->swap(ret);
return true;
}
- // We have an old file. Do a binary diff. For now use bsdiff.
- const string kPatchFile = "/tmp/delta.patch";
+ // We have an old file.
+ // First see if the data is _exactly_ the same
+ {
+ vector<char> original_data;
+ TEST_AND_RETURN_FALSE(utils::ReadFile(old_dir + "/" + file_name,
+ &original_data));
+ if (original_data == full_data) {
+ // Original data unchanged in new file.
+ *no_change = true;
+ return true;
+ }
+ }
+
+ // Do a binary diff. For now use bsdiff.
+ const string kPatchFile = "/tmp/delta.patchXXXXXX";
+ vector<char> patch_file_path(kPatchFile.begin(), kPatchFile.end());
+ patch_file_path.push_back('\0');
+
+ int fd = mkstemp(&patch_file_path[0]);
+ if (fd >= 0)
+ close(fd);
+ TEST_AND_RETURN_FALSE(fd != -1);
vector<string> cmd;
- cmd.push_back("/usr/bin/bsdiff");
+ cmd.push_back(kBsdiffPath);
cmd.push_back(old_dir + "/" + file_name);
cmd.push_back(new_dir + "/" + file_name);
- cmd.push_back(kPatchFile);
+ cmd.push_back(&patch_file_path[0]);
int rc = 1;
+ vector<char> patch_file;
TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc));
TEST_AND_RETURN_FALSE(rc == 0);
- vector<char> patch_file;
- TEST_AND_RETURN_FALSE(utils::ReadFile(kPatchFile, &patch_file));
- unlink(kPatchFile.c_str());
+ TEST_AND_RETURN_FALSE(utils::ReadFile(&patch_file_path[0], &patch_file));
+ unlink(&patch_file_path[0]);
- if (patch_file.size() < ret->size()) {
+ if (patch_file.size() < ret.size()) {
*out_data_format = DeltaArchiveManifest_File_DataFormat_BSDIFF;
- ret = &patch_file;
+ ret.swap(patch_file);
}
-
- *out = *ret;
+ out->swap(ret);
return true;
}
@@ -397,10 +447,11 @@
bool DeltaDiffGenerator::EncodeDataToDeltaFile(
DeltaArchiveManifest* archive,
- const std::string& old_path,
- const std::string& new_path,
- const std::string& out_file,
- const std::string& force_compress_dev_path) {
+ const string& old_path,
+ const string& new_path,
+ const string& out_file,
+ const set<string>& nondiff_paths,
+ const string& force_compress_dev_path) {
DirectFileWriter out_writer;
int r = out_writer.Open(out_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
TEST_AND_RETURN_FALSE_ERRNO(r >= 0);
@@ -419,6 +470,16 @@
TEST_AND_RETURN_FALSE(archive->files_size() > 0);
DeltaArchiveManifest_File* file = archive->mutable_files(0);
+ // nondiff_paths is passed in w/ paths relative to the installed
+ // system (e.g. /etc/fstab), but WriteFileDiffsToDeltaFile requires them
+ // to be the entire path of the new file. We create a new set
+ // here with nondiff_paths expanded.
+ set<string> always_full_target_paths;
+ for (set<string>::const_iterator it = nondiff_paths.begin();
+ it != nondiff_paths.end(); ++it) {
+ always_full_target_paths.insert(new_path + *it);
+ }
+
TEST_AND_RETURN_FALSE(WriteFileDiffsToDeltaFile(archive,
file,
"",
@@ -426,6 +487,7 @@
new_path,
&out_writer,
&out_file_length,
+ always_full_target_paths,
force_compress_dev_path));
// Finally, write the protobuf to the end of the file
diff --git a/delta_diff_generator.h b/delta_diff_generator.h
index 2c355a4..5d422c3 100644
--- a/delta_diff_generator.h
+++ b/delta_diff_generator.h
@@ -7,6 +7,7 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <set>
#include <string>
#include <vector>
#include "base/basictypes.h"
@@ -32,14 +33,19 @@
// Takes a DeltaArchiveManifest as given from EncodeMetadataToProtoBuffer(),
// fill in the missing fields (DeltaArchiveManifest_File_data_*), and
// write the full delta out to the output file.
+ // Any paths in nondiff_paths will be included in full, rather than
+ // as a diff. This is useful for files that change during postinstall, since
+ // future updates can't depend on them having remaining unchanged.
// Returns true on success.
// If non-empty, the device at force_compress_dev_path will be compressed.
- static bool EncodeDataToDeltaFile(DeltaArchiveManifest* archive,
- const std::string& old_path,
- const std::string& new_path,
- const std::string& out_file,
- const std::string& force_compress_dev_path);
-
+ static bool EncodeDataToDeltaFile(
+ DeltaArchiveManifest* archive,
+ const std::string& old_path,
+ const std::string& new_path,
+ const std::string& out_file,
+ const std::set<std::string>& nondiff_paths,
+ const std::string& force_compress_dev_path);
+
private:
// These functions encode all the data about a file that's not already
// stored in the DeltaArchiveManifest message into the vector 'out'.
@@ -58,9 +64,15 @@
static bool EncodeFile(const std::string& old_dir,
const std::string& new_dir,
const std::string& file_name,
+ const bool avoid_diff,
DeltaArchiveManifest_File_DataFormat* out_data_format,
- std::vector<char>* out);
+ std::vector<char>* out,
+ bool* no_change);
+ // nondiff_paths is passed in to EncodeDataToDeltaFile() with
+ // paths relative to the installed system (e.g. /etc/fstab), but
+ // WriteFileDiffsToDeltaFile requires always_full_target_paths to be
+ // the entire path of the new file.
// If non-empty, the device at force_compress_dev_path will be compressed.
static bool WriteFileDiffsToDeltaFile(
DeltaArchiveManifest* archive,
@@ -70,6 +82,7 @@
const std::string& new_path,
FileWriter* out_file_writer,
int* out_file_length,
+ std::set<std::string> always_full_target_paths,
const std::string& force_compress_dev_path);
// This should never be constructed
diff --git a/delta_diff_generator_unittest.cc b/delta_diff_generator_unittest.cc
index b549041..f86f0e2 100644
--- a/delta_diff_generator_unittest.cc
+++ b/delta_diff_generator_unittest.cc
@@ -6,6 +6,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <set>
#include <string>
#include <vector>
#include "base/string_util.h"
@@ -22,10 +23,17 @@
namespace chromeos_update_engine {
+using std::set;
using std::string;
using std::vector;
-class DeltaDiffGeneratorTest : public ::testing::Test {};
+class DeltaDiffGeneratorTest : public ::testing::Test {
+ virtual void TearDown() {
+ EXPECT_EQ(0, system("rm -rf diff-gen-test"));
+ }
+protected:
+ void FakerootEncodeDataToDeltaFileTest(bool test_diff_exclusion);
+};
namespace {
void DumpProto(const DeltaArchiveManifest* archive) {
@@ -350,6 +358,14 @@
}
TEST_F(DeltaDiffGeneratorTest, FakerootEncodeDataToDeltaFileTest) {
+ FakerootEncodeDataToDeltaFileTest(false);
+}
+TEST_F(DeltaDiffGeneratorTest, FakerootDiffExclusionsTest) {
+ FakerootEncodeDataToDeltaFileTest(true);
+}
+
+void DeltaDiffGeneratorTest::FakerootEncodeDataToDeltaFileTest(
+ bool test_diff_exclusion) {
char cwd[1000];
ASSERT_EQ(cwd, getcwd(cwd, sizeof(cwd))) << "cwd buf possibly too small";
ASSERT_EQ(0, System(string("mkdir -p ") + cwd + "/diff-gen-test"));
@@ -359,6 +375,13 @@
GenerateFilesAtPath(string(cwd) + "/diff-gen-test/new");
EditFilesAtPath(string(cwd) + "/diff-gen-test/new");
+ set<string> diff_exclusions;
+ if (test_diff_exclusion) {
+ diff_exclusions.insert("/encoding/long_small_change");
+ } else {
+ diff_exclusions.insert("/hi");
+ }
+
DeltaArchiveManifest* archive =
DeltaDiffGenerator::EncodeMetadataToProtoBuffer(
(string(cwd) + "/diff-gen-test/new").c_str());
@@ -369,7 +392,7 @@
string(cwd) + "/diff-gen-test/old",
string(cwd) + "/diff-gen-test/new",
string(cwd) + "/diff-gen-test/out.dat",
- ""));
+ diff_exclusions, ""));
EXPECT_EQ(18, archive->files_size());
@@ -476,8 +499,11 @@
EXPECT_EQ(0, long_small_change.uid());
EXPECT_EQ(0, long_small_change.gid());
EXPECT_TRUE(long_small_change.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_BSDIFF,
- long_small_change.data_format());
+ DeltaArchiveManifest_File_DataFormat expected_format =
+ DeltaArchiveManifest_File_DataFormat_BSDIFF;
+ if (test_diff_exclusion)
+ expected_format = DeltaArchiveManifest_File_DataFormat_FULL;
+ EXPECT_EQ(expected_format, long_small_change.data_format());
EXPECT_TRUE(long_small_change.has_data_offset());
EXPECT_TRUE(long_small_change.has_data_length());
EXPECT_FALSE(long_small_change.has_hardlink_path());
@@ -488,10 +514,9 @@
EXPECT_TRUE(S_ISREG(nochange.mode()));
EXPECT_EQ(0, nochange.uid());
EXPECT_EQ(0, nochange.gid());
- EXPECT_TRUE(nochange.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, nochange.data_format());
- EXPECT_TRUE(nochange.has_data_offset());
- EXPECT_TRUE(nochange.has_data_length());
+ EXPECT_FALSE(nochange.has_data_format());
+ EXPECT_FALSE(nochange.has_data_offset());
+ EXPECT_FALSE(nochange.has_data_length());
EXPECT_FALSE(nochange.has_hardlink_path());
const DeltaArchiveManifest_File& onebyte =
@@ -566,9 +591,10 @@
EXPECT_TRUE(S_ISREG(newempty.mode()));
EXPECT_EQ(0, newempty.uid());
EXPECT_EQ(0, newempty.gid());
- EXPECT_FALSE(newempty.has_data_format());
- EXPECT_FALSE(newempty.has_data_offset());
- EXPECT_FALSE(newempty.has_data_length());
+ EXPECT_TRUE(newempty.has_data_format());
+ EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, newempty.data_format());
+ EXPECT_TRUE(newempty.has_data_offset());
+ EXPECT_TRUE(newempty.has_data_length());
EXPECT_FALSE(newempty.has_hardlink_path());
const DeltaArchiveManifest_File& subdir =
@@ -667,7 +693,7 @@
string(cwd) + "/diff-gen-test/old",
string(cwd) + "/diff-gen-test/new",
string(cwd) + "/diff-gen-test/out.dat",
- ""));
+ set<string>(), ""));
// parse the file
DeltaDiffParser parser(string(cwd) + "/diff-gen-test/out.dat");
@@ -789,7 +815,8 @@
// newempty
file = parser.GetFileAtPath("/dir/newempty");
EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_FALSE(file.has_data_format());
+ EXPECT_TRUE(file.has_data_format());
+ EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, file.data_format());
// subdir
file = parser.GetFileAtPath("/dir/subdir");
@@ -845,7 +872,7 @@
cmd.push_back(string(cwd) + "/diff-gen-test/patch_result");
cmd.push_back(string(cwd) + "/diff-gen-test/patch");
Subprocess::SynchronousExec(cmd, &rc);
- EXPECT_EQ(0, rc);
+ ASSERT_EQ(0, rc);
vector<char> patch_result;
EXPECT_TRUE(utils::ReadFile(string(cwd) + "/diff-gen-test/patch_result",
&patch_result));
@@ -857,12 +884,9 @@
// nochange
file = parser.GetFileAtPath("/encoding/nochange");
EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, file.data_format());
- EXPECT_EQ("nochange\n", ReadFilePartToString(string(cwd) +
- "/diff-gen-test/out.dat",
- file.data_offset(),
- file.data_length()));
+ EXPECT_FALSE(file.has_data_format());
+ EXPECT_FALSE(file.has_data_offset());
+ EXPECT_FALSE(file.has_data_length());
// onebyte
file = parser.GetFileAtPath("/encoding/onebyte");
diff --git a/download_action.h b/download_action.h
index e6939e1..d5ec026 100644
--- a/download_action.h
+++ b/download_action.h
@@ -9,7 +9,6 @@
#include <sys/stat.h>
#include <fcntl.h>
-#include <map>
#include <string>
#include <curl/curl.h>
@@ -25,9 +24,6 @@
// The Download Action downloads a requested url to a specified path on disk.
// The url and output path are determined by the InstallPlan passed in.
-using std::map;
-using std::string;
-
namespace chromeos_update_engine {
class DownloadAction;
diff --git a/download_action_unittest.cc b/download_action_unittest.cc
index 4276dc9..57e8d7e 100644
--- a/download_action_unittest.cc
+++ b/download_action_unittest.cc
@@ -28,7 +28,7 @@
virtual ~DownloadActionTestProcessorDelegate() {
EXPECT_TRUE(processing_done_called_);
}
- virtual void ProcessingDone(const ActionProcessor* processor) {
+ virtual void ProcessingDone(const ActionProcessor* processor, bool success) {
ASSERT_TRUE(loop_);
g_main_loop_quit(loop_);
vector<char> found_data;
@@ -214,7 +214,7 @@
// only by the test PassObjectOutTest.
class PassObjectOutTestProcessorDelegate : public ActionProcessorDelegate {
public:
- void ProcessingDone(const ActionProcessor* processor) {
+ void ProcessingDone(const ActionProcessor* processor, bool success) {
ASSERT_TRUE(loop_);
g_main_loop_quit(loop_);
}
diff --git a/filesystem_copier_action.cc b/filesystem_copier_action.cc
index 875df95..f9b6869 100644
--- a/filesystem_copier_action.cc
+++ b/filesystem_copier_action.cc
@@ -9,12 +9,14 @@
#include <fcntl.h>
#include <stdlib.h>
#include <algorithm>
+#include <map>
#include <string>
#include <vector>
#include "update_engine/filesystem_iterator.h"
#include "update_engine/subprocess.h"
#include "update_engine/utils.h"
+using std::map;
using std::min;
using std::string;
using std::vector;
diff --git a/filesystem_copier_action.h b/filesystem_copier_action.h
index 8f0dc06..3a330ef 100644
--- a/filesystem_copier_action.h
+++ b/filesystem_copier_action.h
@@ -61,7 +61,7 @@
void TerminateProcessing();
// Used for testing, so we can copy from somewhere other than root
- void set_copy_source(const string& path) {
+ void set_copy_source(const std::string& path) {
copy_source_ = path;
}
// Returns true if we detected that a copy was unneeded and thus skipped it.
@@ -73,8 +73,8 @@
private:
// These synchronously mount or unmount the given mountpoint
- bool Mount(const string& device, const string& mountpoint);
- bool Unmount(const string& mountpoint);
+ bool Mount(const std::string& device, const std::string& mountpoint);
+ bool Unmount(const std::string& mountpoint);
// Performs a recursive file/directory copy from copy_source_ to dest_path_.
// Doesn't return until the copy has completed. Returns true on success
@@ -127,11 +127,11 @@
bool is_mounted_;
// Where the destination device is mounted.
- string dest_path_;
+ std::string dest_path_;
// The path to copy from. Usually left as the default "/", but tests can
// change it.
- string copy_source_;
+ std::string copy_source_;
// The install plan we're passed in via the input pipe.
InstallPlan install_plan_;
diff --git a/filesystem_copier_action_unittest.cc b/filesystem_copier_action_unittest.cc
index 46c13a3..6d6f0ad 100644
--- a/filesystem_copier_action_unittest.cc
+++ b/filesystem_copier_action_unittest.cc
@@ -4,6 +4,7 @@
#include <glib.h>
#include <set>
+#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "update_engine/filesystem_copier_action.h"
@@ -13,6 +14,7 @@
#include "update_engine/utils.h"
using std::set;
+using std::string;
using std::vector;
namespace chromeos_update_engine {
@@ -32,7 +34,7 @@
class FilesystemCopierActionTestDelegate : public ActionProcessorDelegate {
public:
FilesystemCopierActionTestDelegate() : ran_(false), success_(false) {}
- void ProcessingDone(const ActionProcessor* processor) {
+ void ProcessingDone(const ActionProcessor* processor, bool success) {
g_main_loop_quit(loop_);
}
void ActionCompleted(ActionProcessor* processor,
diff --git a/gen_coverage_html.sh b/gen_coverage_html.sh
index 1d3d586..39e8c61 100755
--- a/gen_coverage_html.sh
+++ b/gen_coverage_html.sh
@@ -6,7 +6,7 @@
set -ex
-scons debug=1 -j 2
+scons debug=1 -j $(cat /proc/cpuinfo |grep '^processor' | wc -l)
lcov -d . --zerocounters
./update_engine_unittests --gtest_filter='-*.RunAsRoot*:*.Fakeroot*'
fakeroot ./update_engine_unittests --gtest_filter='*.Fakeroot*'
diff --git a/generate_delta_main.cc b/generate_delta_main.cc
index 14af193..b64533b 100644
--- a/generate_delta_main.cc
+++ b/generate_delta_main.cc
@@ -4,45 +4,80 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
+#include <errno.h>
#include <unistd.h>
-
-#include <algorithm>
+#include <set>
#include <string>
-#include <vector>
-#include <tr1/memory>
-
#include <glib.h>
-
#include "chromeos/obsolete_logging.h"
+#include "update_engine/delta_diff_generator.h"
#include "update_engine/subprocess.h"
#include "update_engine/update_metadata.pb.h"
-
-using std::sort;
-using std::string;
-using std::vector;
-using std::tr1::shared_ptr;
+#include "update_engine/utils.h"
// This file contains a simple program that takes an old path, a new path,
// and an output file as arguments and the path to an output file and
// generates a delta that can be sent to Chrome OS clients.
+using std::set;
+using std::string;
+
namespace chromeos_update_engine {
-int main(int argc, char** argv) {
+namespace {
+// These paths should never be delta diffed. They should always be transmitted
+// in full in the update.
+const char* kNonDiffPaths[] = {
+ "/boot/extlinux.conf"
+};
+
+void usage(const char* argv0) {
+ printf("usage: %s old_dir new_dir out_file\n", argv0);
+ exit(1);
+}
+
+bool IsDir(const char* path) {
+ struct stat stbuf;
+ TEST_AND_RETURN_FALSE_ERRNO(lstat(path, &stbuf) == 0);
+ return S_ISDIR(stbuf.st_mode);
+}
+
+int Main(int argc, char** argv) {
g_thread_init(NULL);
Subprocess::Init();
if (argc != 4) {
usage(argv[0]);
}
+ logging::InitLogging("",
+ logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
+ logging::DONT_LOCK_LOG_FILE,
+ logging::APPEND_TO_OLD_LOG_FILE);
const char* old_dir = argv[1];
const char* new_dir = argv[2];
if ((!IsDir(old_dir)) || (!IsDir(new_dir))) {
usage(argv[0]);
}
- // TODO(adlr): implement using DeltaDiffGenerator
+
+ set<string> non_diff_paths;
+ for (size_t i = 0; i < arraysize(kNonDiffPaths); i++)
+ non_diff_paths.insert(kNonDiffPaths[i]);
+
+ DeltaArchiveManifest* manifest =
+ DeltaDiffGenerator::EncodeMetadataToProtoBuffer(new_dir);
+ CHECK(manifest);
+ CHECK(DeltaDiffGenerator::EncodeDataToDeltaFile(manifest,
+ old_dir,
+ new_dir,
+ argv[3],
+ non_diff_paths,
+ ""));
return 0;
-}
\ No newline at end of file
+}
+
+} // namespace {}
+
+} // namespace chromeos_update_engine
+
+int main(int argc, char** argv) {
+ return chromeos_update_engine::Main(argc, argv);
+}
diff --git a/install_action.cc b/install_action.cc
index c70867e..d144b7b 100644
--- a/install_action.cc
+++ b/install_action.cc
@@ -4,6 +4,7 @@
#include "update_engine/install_action.h"
#include <errno.h>
+#include <string>
#include <vector>
#include <gflags/gflags.h>
#include "update_engine/filesystem_iterator.h"
@@ -15,6 +16,7 @@
"If set, the path to use when mounting the "
"destination device during install");
+using std::string;
using std::vector;
namespace chromeos_update_engine {
@@ -124,12 +126,12 @@
}
// 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);
+ if (!S_ISLNK(file.mode()))
+ TEST_AND_RETURN_FALSE_ERRNO(chmod((mountpoint + path).c_str(), file.mode())
+ == 0);
return true;
}
diff --git a/install_action_unittest.cc b/install_action_unittest.cc
index 68796e6..3fd42d4 100644
--- a/install_action_unittest.cc
+++ b/install_action_unittest.cc
@@ -126,11 +126,16 @@
}
const char* const new_dir_cstr = new_dir.c_str();
EXPECT_EQ(0, System(StringPrintf("mkdir -p '%s/newdir'", new_dir_cstr)));
+ EXPECT_EQ(0, System(StringPrintf("chmod 03755 '%s/newdir'", new_dir_cstr)));
EXPECT_EQ(0, System(StringPrintf("mkdir -p '%s/newdir/x'", new_dir_cstr)));
EXPECT_EQ(0, System(StringPrintf("echo -n foo > '%s/newdir/x/file'",
new_dir_cstr)));
+ EXPECT_EQ(0, System(StringPrintf("touch '%s/new_empty'", new_dir_cstr)));
+ EXPECT_EQ(0, System(StringPrintf("chmod 04644 '%s/new_empty'",
+ new_dir_cstr)));
EXPECT_EQ(0, System(StringPrintf("echo -n x >> '%s/big_file'",
new_dir_cstr)));
+ EXPECT_EQ(0, System(StringPrintf("chmod 02644 '%s/big_file'", new_dir_cstr)));
// Make a symlink that compresses well:
EXPECT_EQ(0, System(StringPrintf(
"ln -s "
@@ -150,6 +155,7 @@
original_dir,
new_dir,
"delta",
+ set<string>(),
new_dir + "/bdev_gz"));
ASSERT_EQ(0, System(string("umount ") + original_dir));
@@ -204,7 +210,7 @@
}
LOG(INFO) << "new_count = " << new_count;
EXPECT_EQ(new_count, original_count);
- EXPECT_EQ(19, original_count);
+ EXPECT_EQ(20, original_count);
// Make sure hard-link installed properly
{
diff --git a/integration_unittest.cc b/integration_unittest.cc
index e8eca56..13102da 100644
--- a/integration_unittest.cc
+++ b/integration_unittest.cc
@@ -40,7 +40,7 @@
virtual ~IntegrationTestProcessorDelegate() {
EXPECT_TRUE(processing_done_called_);
}
- virtual void ProcessingDone(const ActionProcessor* processor) {
+ virtual void ProcessingDone(const ActionProcessor* processor, bool success) {
processing_done_called_ = true;
g_main_loop_quit(loop_);
}
diff --git a/main.cc b/main.cc
index bbb6401..bbd9927 100644
--- a/main.cc
+++ b/main.cc
@@ -2,12 +2,159 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <string>
+#include <tr1/memory>
+#include <vector>
+#include <gflags/gflags.h>
#include <glib.h>
+#include "chromeos/obsolete_logging.h"
+#include "update_engine/action_processor.h"
+#include "update_engine/download_action.h"
+#include "update_engine/filesystem_copier_action.h"
+#include "update_engine/install_action.h"
+#include "update_engine/libcurl_http_fetcher.h"
+#include "update_engine/omaha_request_prep_action.h"
+#include "update_engine/omaha_response_handler_action.h"
+#include "update_engine/postinstall_runner_action.h"
+#include "update_engine/set_bootable_flag_action.h"
+#include "update_engine/update_check_action.h"
+
+using std::string;
+using std::tr1::shared_ptr;
+using std::vector;
+
+namespace chromeos_update_engine {
+
+class UpdateAttempter : public ActionProcessorDelegate {
+ public:
+ UpdateAttempter(GMainLoop *loop)
+ : full_update_(false),
+ loop_(loop) {}
+ void Update(bool force_full_update);
+
+ // Delegate method:
+ void ProcessingDone(const ActionProcessor* processor, bool success);
+ private:
+ bool full_update_;
+ vector<shared_ptr<AbstractAction> > actions_;
+ ActionProcessor processor_;
+ GMainLoop *loop_;
+
+ // pointer to the OmahaResponseHandlerAction in the actions_ vector;
+ shared_ptr<OmahaResponseHandlerAction> response_handler_action_;
+ DISALLOW_COPY_AND_ASSIGN(UpdateAttempter);
+};
+
+// Returns true on success. If there was no update available, that's still
+// success.
+// If force_full is true, try to force a full update.
+void UpdateAttempter::Update(bool force_full_update) {
+ full_update_ = force_full_update;
+ CHECK(!processor_.IsRunning());
+ processor_.set_delegate(this);
+
+ // Actions:
+ shared_ptr<OmahaRequestPrepAction> request_prep_action(
+ new OmahaRequestPrepAction(force_full_update));
+ shared_ptr<UpdateCheckAction> update_check_action(
+ new UpdateCheckAction(new LibcurlHttpFetcher));
+ shared_ptr<OmahaResponseHandlerAction> response_handler_action(
+ new OmahaResponseHandlerAction);
+ shared_ptr<FilesystemCopierAction> filesystem_copier_action(
+ new FilesystemCopierAction);
+ shared_ptr<DownloadAction> download_action(
+ new DownloadAction(new LibcurlHttpFetcher));
+ shared_ptr<InstallAction> install_action(
+ new InstallAction);
+ shared_ptr<PostinstallRunnerAction> postinstall_runner_action(
+ new PostinstallRunnerAction);
+ shared_ptr<SetBootableFlagAction> set_bootable_flag_action(
+ new SetBootableFlagAction);
+
+ response_handler_action_ = response_handler_action;
+
+ actions_.push_back(shared_ptr<AbstractAction>(request_prep_action));
+ actions_.push_back(shared_ptr<AbstractAction>(update_check_action));
+ actions_.push_back(shared_ptr<AbstractAction>(response_handler_action));
+ actions_.push_back(shared_ptr<AbstractAction>(filesystem_copier_action));
+ actions_.push_back(shared_ptr<AbstractAction>(download_action));
+ actions_.push_back(shared_ptr<AbstractAction>(install_action));
+ actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action));
+ actions_.push_back(shared_ptr<AbstractAction>(set_bootable_flag_action));
+
+ // Enqueue the actions
+ for (vector<shared_ptr<AbstractAction> >::iterator it = actions_.begin();
+ it != actions_.end(); ++it) {
+ processor_.EnqueueAction(it->get());
+ }
+
+ // Bond them together. We have to use the leaf-types when calling
+ // BondActions().
+ BondActions(request_prep_action.get(), update_check_action.get());
+ BondActions(update_check_action.get(), response_handler_action.get());
+ BondActions(response_handler_action.get(), filesystem_copier_action.get());
+ BondActions(filesystem_copier_action.get(), download_action.get());
+ BondActions(download_action.get(), install_action.get());
+ BondActions(install_action.get(), postinstall_runner_action.get());
+ BondActions(postinstall_runner_action.get(), set_bootable_flag_action.get());
+
+ processor_.StartProcessing();
+}
+
+void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
+ bool success) {
+ CHECK(response_handler_action_);
+ if (response_handler_action_->GotNoUpdateResponse()) {
+ // All done.
+ g_main_loop_quit(loop_);
+ return;
+ }
+ if (!success) {
+ if (!full_update_) {
+ LOG(ERROR) << "Update failed. Attempting full update";
+ actions_.clear();
+ response_handler_action_.reset();
+ Update(true);
+ return;
+ } else {
+ LOG(ERROR) << "Full update failed. Aborting";
+ }
+ }
+ g_main_loop_quit(loop_);
+}
+
+gboolean UpdateInMainLoop(void* arg) {
+ UpdateAttempter* update_attempter = reinterpret_cast<UpdateAttempter*>(arg);
+ update_attempter->Update(false);
+ return FALSE; // Don't call this callback function again
+}
+
+} // namespace chromeos_update_engine
#include "update_engine/subprocess.h"
int main(int argc, char** argv) {
g_thread_init(NULL);
chromeos_update_engine::Subprocess::Init();
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ // TODO(adlr): figure out log file
+ logging::InitLogging("",
+ logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
+ logging::DONT_LOCK_LOG_FILE,
+ logging::APPEND_TO_OLD_LOG_FILE);
+ LOG(INFO) << "Chrome OS Update Engine starting";
+
+ // Create the single GMainLoop
+ GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
+
+ chromeos_update_engine::UpdateAttempter update_attempter(loop);
+
+ g_timeout_add(0, &chromeos_update_engine::UpdateInMainLoop,
+ &update_attempter);
+
+ g_main_loop_run(loop);
+ g_main_loop_unref(loop);
+
+ LOG(INFO) << "Chrome OS Update Engine terminating";
return 0;
}
diff --git a/omaha_request_prep_action.cc b/omaha_request_prep_action.cc
index 8c015d8..9e144a0 100644
--- a/omaha_request_prep_action.cc
+++ b/omaha_request_prep_action.cc
@@ -16,7 +16,8 @@
namespace {
const string OmahaIdPath() {
- return chromeos_update_engine::utils::kStatefulPartition + "/etc/omaha_id";
+ return string(chromeos_update_engine::utils::kStatefulPartition) +
+ "/etc/omaha_id";
}
} // namespace {}
@@ -89,7 +90,7 @@
}
std::string OmahaRequestPrepAction::GetLsbValue(const std::string& key) const {
- string files[] = {utils::kStatefulPartition + "/etc/lsb-release",
+ string files[] = {string(utils::kStatefulPartition) + "/etc/lsb-release",
"/etc/lsb-release"};
for (unsigned int i = 0; i < arraysize(files); i++) {
string file_data;
diff --git a/omaha_response_handler_action.cc b/omaha_response_handler_action.cc
index 0a8472e..0a0a660 100644
--- a/omaha_response_handler_action.cc
+++ b/omaha_response_handler_action.cc
@@ -22,6 +22,7 @@
ScopedActionCompleter completer(processor_, this);
const UpdateCheckResponse& response = GetInputObject();
if (!response.update_exists) {
+ got_no_update_response_ = true;
LOG(INFO) << "There are no updates. Aborting.";
return;
}
@@ -47,7 +48,8 @@
filename.resize(255);
}
// TODO(adlr): come up with a better place to download to:
- install_plan.download_path = utils::kStatefulPartition + "/" + filename;
+ install_plan.download_path = string(utils::kStatefulPartition) + "/" +
+ filename;
if (HasOutputPipe())
SetOutputObject(install_plan);
LOG(INFO) << "Using this install plan:";
diff --git a/omaha_response_handler_action.h b/omaha_response_handler_action.h
index e25de28..b56d343 100644
--- a/omaha_response_handler_action.h
+++ b/omaha_response_handler_action.h
@@ -26,7 +26,7 @@
class OmahaResponseHandlerAction : public Action<OmahaResponseHandlerAction> {
public:
- OmahaResponseHandlerAction() {}
+ OmahaResponseHandlerAction() : got_no_update_response_(false) {}
typedef ActionTraits<OmahaResponseHandlerAction>::InputObjectType
InputObjectType;
typedef ActionTraits<OmahaResponseHandlerAction>::OutputObjectType
@@ -41,6 +41,8 @@
void set_boot_device(const std::string& boot_device) {
boot_device_ = boot_device;
}
+
+ bool GotNoUpdateResponse() const { return got_no_update_response_; }
// Debugging/logging
static std::string StaticType() { return "OmahaResponseHandlerAction"; }
@@ -56,6 +58,9 @@
// set to non-empty in unit tests
std::string boot_device_;
+
+ // True only if we got a response and the response said no updates
+ bool got_no_update_response_;
DISALLOW_COPY_AND_ASSIGN(OmahaResponseHandlerAction);
};
diff --git a/omaha_response_handler_action_unittest.cc b/omaha_response_handler_action_unittest.cc
index 0248daf..a76838a 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -93,7 +93,8 @@
EXPECT_TRUE(install_plan.is_full_update);
EXPECT_EQ(in.codebase, install_plan.download_url);
EXPECT_EQ(in.hash, install_plan.download_hash);
- EXPECT_EQ(utils::kStatefulPartition + "/the_update_a.b.c.d_FULL_.tgz",
+ EXPECT_EQ(string(utils::kStatefulPartition) +
+ "/the_update_a.b.c.d_FULL_.tgz",
install_plan.download_path);
EXPECT_EQ("/dev/sda2", install_plan.install_path);
}
@@ -112,7 +113,8 @@
EXPECT_FALSE(install_plan.is_full_update);
EXPECT_EQ(in.codebase, install_plan.download_url);
EXPECT_EQ(in.hash, install_plan.download_hash);
- EXPECT_EQ(utils::kStatefulPartition + "/the_update_a.b.c.d_DELTA_.tgz",
+ EXPECT_EQ(string(utils::kStatefulPartition) +
+ "/the_update_a.b.c.d_DELTA_.tgz",
install_plan.download_path);
EXPECT_EQ("/dev/sda3", install_plan.install_path);
}
@@ -131,7 +133,8 @@
EXPECT_FALSE(install_plan.is_full_update);
EXPECT_EQ(in.codebase, install_plan.download_url);
EXPECT_EQ(in.hash, install_plan.download_hash);
- EXPECT_EQ(utils::kStatefulPartition + "/" + kLongName.substr(0, 255),
+ EXPECT_EQ(string(utils::kStatefulPartition) + "/" +
+ kLongName.substr(0, 255),
install_plan.download_path);
EXPECT_EQ("/dev/sda3", install_plan.install_path);
}
diff --git a/postinstall_runner_action.cc b/postinstall_runner_action.cc
index 4122860..98de1bd 100644
--- a/postinstall_runner_action.cc
+++ b/postinstall_runner_action.cc
@@ -12,7 +12,7 @@
using std::string;
namespace {
-const string kMountPath(utils::kStatefulPartition + "/au_destination");
+const string kMountPath(string(utils::kStatefulPartition) + "/au_destination");
const string kPostinstallScript("/postinst");
}
diff --git a/postinstall_runner_action_unittest.cc b/postinstall_runner_action_unittest.cc
index c43cb8a..5bb515f 100644
--- a/postinstall_runner_action_unittest.cc
+++ b/postinstall_runner_action_unittest.cc
@@ -56,7 +56,8 @@
ASSERT_EQ(0, getuid()) << "Run me as root. Ideally don't run other tests "
<< "as root, tho.";
- const string mountpoint(utils::kStatefulPartition + "/au_destination");
+ const string mountpoint(string(utils::kStatefulPartition) +
+ "/au_destination");
string cwd;
{
diff --git a/test_utils.cc b/test_utils.cc
index d916458..f83ddf9 100644
--- a/test_utils.cc
+++ b/test_utils.cc
@@ -177,26 +177,25 @@
void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
// create 10MiB sparse file
- const char* const mount_path = kMountPath.c_str();
EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
" seek=10485759 bs=1 count=1",
path.c_str())));
EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -F %s", path.c_str())));
- EXPECT_EQ(0, System(StringPrintf("mkdir -p %s", mount_path)));
+ EXPECT_EQ(0, System(StringPrintf("mkdir -p %s", kMountPath)));
EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
- mount_path)));
- EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", mount_path)));
- EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello", mount_path)));
- EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", mount_path)));
- EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir", mount_path)));
- EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt", mount_path)));
- EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test", mount_path)));
- EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo", mount_path)));
- EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", mount_path)));
- EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym", mount_path)));
+ kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello", kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir", kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt", kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test", kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo", kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym", kMountPath)));
EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
- mount_path, mount_path)));
- EXPECT_EQ(0, System(StringPrintf("umount %s", mount_path)));
+ kMountPath, kMountPath)));
+ EXPECT_EQ(0, System(StringPrintf("umount %s", kMountPath)));
if (out_paths) {
out_paths->clear();
diff --git a/test_utils.h b/test_utils.h
index 6274a22..cd17ec1 100644
--- a/test_utils.h
+++ b/test_utils.h
@@ -88,7 +88,7 @@
0xbe, 0x9f, 0xa3, 0x5d
};
-const string kMountPath("/tmp/UpdateEngineTests_mnt");
+const char* const kMountPath = "/tmp/UpdateEngineTests_mnt";
} // namespace {}
// Creates an ext image with some files in it. The paths creates are
diff --git a/update_check_action.h b/update_check_action.h
index 402943b..5622a63 100644
--- a/update_check_action.h
+++ b/update_check_action.h
@@ -20,8 +20,6 @@
// The Update Check action makes an update check request to Omaha and
// can output the response on the output ActionPipe.
-using std::string;
-
namespace chromeos_update_engine {
// Encodes XML entities in a given string with libxml2. input must be
diff --git a/update_check_action_unittest.cc b/update_check_action_unittest.cc
index 723fc22..417a47e 100644
--- a/update_check_action_unittest.cc
+++ b/update_check_action_unittest.cc
@@ -54,7 +54,7 @@
expected_success_(true) {}
virtual ~UpdateCheckActionTestProcessorDelegate() {
}
- virtual void ProcessingDone(const ActionProcessor* processor) {
+ virtual void ProcessingDone(const ActionProcessor* processor, bool success) {
ASSERT_TRUE(loop_);
g_main_loop_quit(loop_);
}
diff --git a/update_metadata.proto b/update_metadata.proto
index 61b4965..42880da 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -102,6 +102,8 @@
}
// If present, there is data associated with this File object and
// data_offset and data_size must be set.
+ // If a file object doesn't have this set, it means the data is
+ // unchanged from the old version of the file.
optional DataFormat data_format = 4;
// The offset into the delta file where the data (if any) is stored
optional uint32 data_offset = 5;
diff --git a/utils.cc b/utils.cc
index 9fa0906..69a59cc 100644
--- a/utils.cc
+++ b/utils.cc
@@ -257,7 +257,7 @@
return true;
}
-const string kStatefulPartition = "/mnt/stateful_partition";
+const char* const kStatefulPartition = "/mnt/stateful_partition";
} // namespace utils
diff --git a/utils.h b/utils.h
index 7920f3c..de998f4 100644
--- a/utils.h
+++ b/utils.h
@@ -38,7 +38,7 @@
// of the string passed in.
// NEVER CALL THIS FUNCTION UNLESS YOU ARE SURE
// THAT YOUR PROCESS WILL BE THE ONLY THING WRITING FILES IN THIS DIRECTORY.
-std::string TempFilename(string path);
+std::string TempFilename(std::string path);
// Deletes a directory and all its contents synchronously. Returns true
// on success. This may be called with a regular file--it will just unlink it.
@@ -47,8 +47,8 @@
// Synchronously mount or unmount a filesystem. Return true on success.
// Mounts as ext3 with default options.
-bool MountFilesystem(const string& device, const string& mountpoint);
-bool UnmountFilesystem(const string& mountpoint);
+bool MountFilesystem(const std::string& device, const std::string& mountpoint);
+bool UnmountFilesystem(const std::string& mountpoint);
// Log a string in hex to LOG(INFO). Useful for debugging.
void HexDumpArray(const unsigned char* const arr, const size_t length);
@@ -59,7 +59,7 @@
HexDumpArray(reinterpret_cast<const unsigned char*>(&vect[0]), vect.size());
}
-extern const string kStatefulPartition;
+extern const char* const kStatefulPartition;
bool StringHasSuffix(const std::string& str, const std::string& suffix);
bool StringHasPrefix(const std::string& str, const std::string& prefix);
@@ -68,6 +68,10 @@
bool MapContainsKey(const std::map<KeyType, ValueType>& m, const KeyType& k) {
return m.find(k) != m.end();
}
+template<typename KeyType>
+bool SetContainsKey(const std::set<KeyType>& s, const KeyType& k) {
+ return s.find(k) != s.end();
+}
template<typename ValueType>
std::set<ValueType> SetWithValue(const ValueType& value) {
diff --git a/utils_unittest.cc b/utils_unittest.cc
index 4fee544..74f349d 100644
--- a/utils_unittest.cc
+++ b/utils_unittest.cc
@@ -5,10 +5,12 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
+#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "update_engine/utils.h"
+using std::string;
using std::vector;
namespace chromeos_update_engine {