AU: Gut code for old updater. New protobuf for v2 updater.
Review URL: http://codereview.chromium.org/545072
diff --git a/SConstruct b/SConstruct
index 1f7ff0f..d408cb7 100644
--- a/SConstruct
+++ b/SConstruct
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import os
+
# Protobuffer compilation
""" Inputs:
target: list of targets to compile to
@@ -90,7 +92,6 @@
filesystem_iterator.cc
file_writer.cc
gzip.cc
- install_action.cc
libcurl_http_fetcher.cc
omaha_hash_calculator.cc
omaha_request_prep_action.cc
@@ -114,8 +115,6 @@
filesystem_iterator_unittest.cc
gzip_unittest.cc
http_fetcher_unittest.cc
- install_action_unittest.cc
- integration_unittest.cc
mock_http_fetcher.cc
omaha_hash_calculator_unittest.cc
omaha_request_prep_action_unittest.cc
diff --git a/delta_diff_generator.cc b/delta_diff_generator.cc
index 2dacfdf..4114c32 100644
--- a/delta_diff_generator.cc
+++ b/delta_diff_generator.cc
@@ -3,523 +3,3 @@
// found in the LICENSE file.
#include "update_engine/delta_diff_generator.h"
-#include <dirent.h>
-#include <endian.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <algorithm>
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-#include <tr1/memory>
-#include <zlib.h>
-#include "chromeos/obsolete_logging.h"
-#include "base/scoped_ptr.h"
-#include "update_engine/delta_diff_parser.h"
-#include "update_engine/gzip.h"
-#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;
-
-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
-// memory in these Node and Child structures.
-
-// Each Node struct represents a file on disk (which can be regular file,
-// directory, fifo, socket, symlink, etc). Nodes that contain children
-// (just directories) will have a vector of Child objects. Each child
-// object has a filename and a pointer to the associated Node. Thus,
-// filenames for files are stored with their parents, not as part of
-// the file itself.
-
-// These structures are easier to work with than the protobuf format
-// when adding files. When generating a delta file, we add an entry
-// for each file to a root Node object. Then, we sort each Node's
-// children vector so the children are stored alphabetically. Then,
-// we assign an index value to the idx field of each Node by a preorder
-// tree traversal. The index value assigned to a Node is the index it
-// will have in the DeltaArchiveManifest protobuf.
-// Finally, we add each Node to a DeltaArchiveManifest protobuf.
-
-struct Node;
-
-struct Child {
- Child(const string& the_name,
- Node* the_node)
- : name(the_name),
- node(the_node) {}
- string name;
- // Use shared_ptr here rather than scoped_ptr b/c this struct will be copied
- // in stl containers
- scoped_ptr<Node> node;
-};
-
-// For the C++ sort() function.
-struct ChildLessThan {
- bool operator()(const shared_ptr<Child>& a, const shared_ptr<Child>& b) {
- return a->name < b->name;
- }
-};
-
-struct Node {
- Node()
- : mode(0),
- uid(0),
- gid(0),
- nlink(0),
- inode(0),
- compressed(false),
- offset(-1),
- length(0),
- idx(0) {}
-
- mode_t mode;
- uid_t uid;
- gid_t gid;
-
- // a file may be a potential hardlink if it's not a directory
- // and it has a link count > 1.
- bool IsPotentialHardlink() const {
- return !S_ISDIR(mode) && nlink > 1;
- }
- nlink_t nlink; // number of hard links
- ino_t inode;
-
- // data
- bool compressed;
- int offset; // -1 means no data
- int length;
-
- vector<shared_ptr<Child> > children;
- int idx;
-};
-
-// This function sets *node's variables to match what's at path.
-// This includes calling this function recursively on all children. Children
-// not on the same device as the original node will not be considered.
-// Returns true on success.
-bool UpdateNodeFromPath(const string& path, Node* node) {
- // Set metadata
- struct stat stbuf;
- TEST_AND_RETURN_FALSE_ERRNO(lstat(path.c_str(), &stbuf) == 0);
- const dev_t dev = stbuf.st_dev;
- node->mode = stbuf.st_mode;
- node->uid = stbuf.st_uid;
- node->gid = stbuf.st_gid;
- node->nlink = stbuf.st_nlink;
- node->inode = stbuf.st_ino;
- if (!S_ISDIR(node->mode)) {
- return true;
- }
-
- DIR* dir = opendir(path.c_str());
- TEST_AND_RETURN_FALSE(dir);
-
- struct dirent entry;
- struct dirent* dir_entry;
-
- for (;;) {
- TEST_AND_RETURN_FALSE_ERRNO(readdir_r(dir, &entry, &dir_entry) == 0);
- if (!dir_entry) {
- // done
- break;
- }
- if (!strcmp(".", dir_entry->d_name))
- continue;
- if (!strcmp("..", dir_entry->d_name))
- continue;
-
- string child_path = path + "/" + dir_entry->d_name;
- struct stat child_stbuf;
- TEST_AND_RETURN_FALSE_ERRNO(lstat(child_path.c_str(), &child_stbuf) == 0);
- // make sure it's on the same dev
- if (child_stbuf.st_dev != dev)
- continue;
- shared_ptr<Child> child(new Child(dir_entry->d_name, new Node));
- node->children.push_back(child);
- TEST_AND_RETURN_FALSE(UpdateNodeFromPath(path + "/" + child->name,
- child->node.get()));
- }
- TEST_AND_RETURN_FALSE_ERRNO(closedir(dir) == 0);
- // Done with all subdirs. sort children.
- sort(node->children.begin(), node->children.end(), ChildLessThan());
- return true;
-}
-
-// We go through n setting the index value of each Node to
-// *next_index_value, then increment next_index_value.
-// We then recursively assign index values to children.
-// The first caller should call this with *next_index_value == 0 and
-// the root Node, thus setting the root Node's index to 0.
-void PopulateChildIndexes(Node* n, int* next_index_value) {
- n->idx = (*next_index_value)++;
- for (unsigned int i = 0; i < n->children.size(); i++) {
- PopulateChildIndexes(n->children[i]->node.get(), next_index_value);
- }
-}
-
-// This converts a Node tree rooted at n into a DeltaArchiveManifest.
-void NodeToDeltaArchiveManifest(Node* n, DeltaArchiveManifest* archive,
- map<ino_t, string>* hard_links,
- const string& path) {
- DeltaArchiveManifest_File *f = archive->add_files();
- f->set_mode(n->mode);
- f->set_uid(n->uid);
- f->set_gid(n->gid);
- if (utils::MapContainsKey(*hard_links, n->inode)) {
- // We have a hard link
- CHECK(!S_ISDIR(n->mode));
- f->set_hardlink_path((*hard_links)[n->inode]);
- } else if (n->IsPotentialHardlink()) {
- (*hard_links)[n->inode] = path;
- }
- if (!S_ISDIR(n->mode))
- return;
- for (unsigned int i = 0; i < n->children.size(); i++) {
- DeltaArchiveManifest_File_Child* child = f->add_children();
- child->set_name(n->children[i]->name);
- child->set_index(n->children[i]->node->idx);
- }
- for (unsigned int i = 0; i < n->children.size(); i++) {
- NodeToDeltaArchiveManifest(n->children[i]->node.get(), archive, hard_links,
- path + "/" + n->children[i]->name);
- }
-}
-
-} // namespace {}
-
-// For each file in archive, write a delta for it into out_file
-// and update 'file' to refer to the delta.
-// This is a recursive function. Returns true on success.
-bool DeltaDiffGenerator::WriteFileDiffsToDeltaFile(
- DeltaArchiveManifest* archive,
- DeltaArchiveManifest_File* file,
- const string& file_name,
- const string& old_path,
- const string& new_path,
- FileWriter* out_file_writer,
- int* out_file_length,
- set<string> always_full_target_paths,
- const string& force_compress_dev_path) {
- TEST_AND_RETURN_FALSE(file->has_mode());
-
- // Stat the actual file, too
- struct stat stbuf;
- TEST_AND_RETURN_FALSE_ERRNO(lstat((new_path + "/" + file_name).c_str(),
- &stbuf) == 0);
- TEST_AND_RETURN_FALSE(stbuf.st_mode == file->mode());
-
- // See if we're a directory or not
- if (S_ISDIR(file->mode())) {
- for (int i = 0; i < file->children_size(); i++) {
- 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(),
- recurse_old_path,
- recurse_new_path,
- out_file_writer,
- out_file_length,
- always_full_target_paths,
- force_compress_dev_path));
- }
- return true;
- }
-
- if (S_ISFIFO(file->mode()) || S_ISSOCK(file->mode()) ||
- file->has_hardlink_path()) {
- // These don't store any additional data
- return true;
- }
-
- vector<char> data;
- bool should_compress = true;
- bool format_set = false;
- DeltaArchiveManifest_File_DataFormat format;
- if (S_ISLNK(file->mode())) {
- TEST_AND_RETURN_FALSE(EncodeLink(new_path + "/" + file_name, &data));
- } else if (S_ISCHR(file->mode()) || S_ISBLK(file->mode())) {
- TEST_AND_RETURN_FALSE(EncodeDev(stbuf, &data, &format,
- new_path + "/" + file_name ==
- force_compress_dev_path));
- format_set = true;
- } else if (S_ISREG(file->mode())) {
- // regular file. We may use a delta here.
- 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) ||
- (format == DeltaArchiveManifest_File_DataFormat_FULL_GZ))
- TEST_AND_RETURN_FALSE(!data.empty());
- } else {
- // Should never get here; unhandled mode type.
- LOG(ERROR) << "Unhandled mode type: " << file->mode();
- return false;
- }
-
- if (!format_set) {
- // Pick a format now
- vector<char> compressed_data;
- TEST_AND_RETURN_FALSE(GzipCompress(data, &compressed_data));
- if (compressed_data.size() < data.size()) {
- format = DeltaArchiveManifest_File_DataFormat_FULL_GZ;
- data.swap(compressed_data);
- } else {
- format = DeltaArchiveManifest_File_DataFormat_FULL;
- }
- format_set = true;
- }
-
- 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 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());
- TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
- link_data.resize(rc);
- out->swap(link_data);
- return true;
-}
-
-bool DeltaDiffGenerator::EncodeDev(
- const struct stat& stbuf,
- vector<char>* out,
- DeltaArchiveManifest_File_DataFormat* format,
- bool force_compression) {
- LinuxDevice dev;
- dev.set_major(major(stbuf.st_rdev));
- dev.set_minor(minor(stbuf.st_rdev));
- out->resize(dev.ByteSize());
- TEST_AND_RETURN_FALSE(dev.SerializeToArray(&(*out)[0], out->size()));
- if (force_compression) {
- vector<char> compressed;
- TEST_AND_RETURN_FALSE(GzipCompress(*out, &compressed));
- out->swap(compressed);
- *format = DeltaArchiveManifest_File_DataFormat_FULL_GZ;
- } else {
- *format = DeltaArchiveManifest_File_DataFormat_FULL;
- }
- return true;
-}
-
-// Encode the file at new_path + "/" + file_name. It may be a binary diff
-// based on old_path + "/" + file_name. out_data_format will be set to
-// the format used. out_data_format may not be NULL.
-bool DeltaDiffGenerator::EncodeFile(
- 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,
- bool* no_change) {
- TEST_AND_RETURN_FALSE(out_data_format);
- vector<char> ret;
- vector<char> full_data;
- {
- // 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.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->swap(ret);
- return true;
- }
- // 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(kBsdiffPath);
- cmd.push_back(old_dir + "/" + file_name);
- cmd.push_back(new_dir + "/" + file_name);
- 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);
- TEST_AND_RETURN_FALSE(utils::ReadFile(&patch_file_path[0], &patch_file));
- unlink(&patch_file_path[0]);
-
- if (patch_file.size() < ret.size()) {
- *out_data_format = DeltaArchiveManifest_File_DataFormat_BSDIFF;
- ret.swap(patch_file);
- }
- out->swap(ret);
- return true;
-}
-
-DeltaArchiveManifest* DeltaDiffGenerator::EncodeMetadataToProtoBuffer(
- const char* new_path) {
- Node node;
- if (!UpdateNodeFromPath(new_path, &node))
- return NULL;
- int index = 0;
- PopulateChildIndexes(&node, &index);
- DeltaArchiveManifest *ret = new DeltaArchiveManifest;
- map<ino_t, string> hard_links; // inode -> first found path for inode
- NodeToDeltaArchiveManifest(&node, ret, &hard_links, "");
- return ret;
-}
-
-bool DeltaDiffGenerator::EncodeDataToDeltaFile(
- DeltaArchiveManifest* archive,
- 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);
- ScopedFileWriterCloser closer(&out_writer);
- TEST_AND_RETURN_FALSE(out_writer.Write(DeltaDiffParser::kFileMagic,
- strlen(DeltaDiffParser::kFileMagic))
- == static_cast<ssize_t>(
- strlen(DeltaDiffParser::kFileMagic)));
- // Write 8 null bytes. This will be filled in w/ the offset of
- // the protobuf.
- TEST_AND_RETURN_FALSE(out_writer.Write("\0\0\0\0\0\0\0\0", 8) == 8);
- // 8 more bytes will be filled w/ the protobuf length.
- TEST_AND_RETURN_FALSE(out_writer.Write("\0\0\0\0\0\0\0\0", 8) == 8);
- int out_file_length = strlen(DeltaDiffParser::kFileMagic) + 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,
- "",
- old_path,
- 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
- string encoded_archive;
- TEST_AND_RETURN_FALSE(archive->SerializeToString(&encoded_archive));
-
- // Compress the protobuf (which contains filenames)
- vector<char> compressed_encoded_archive;
- TEST_AND_RETURN_FALSE(GzipCompressString(encoded_archive,
- &compressed_encoded_archive));
-
- TEST_AND_RETURN_FALSE(out_writer.Write(compressed_encoded_archive.data(),
- compressed_encoded_archive.size()) ==
- static_cast<ssize_t>(
- compressed_encoded_archive.size()));
-
- // write offset of protobut to just after the file magic
- int64 big_endian_protobuf_offset = htobe64(out_file_length);
- TEST_AND_RETURN_FALSE(pwrite(out_writer.fd(),
- &big_endian_protobuf_offset,
- sizeof(big_endian_protobuf_offset),
- strlen(DeltaDiffParser::kFileMagic)) ==
- sizeof(big_endian_protobuf_offset));
- // Write the size just after the offset
- int64 pb_length = htobe64(compressed_encoded_archive.size());
- TEST_AND_RETURN_FALSE(pwrite(out_writer.fd(),
- &pb_length,
- sizeof(pb_length),
- strlen(DeltaDiffParser::kFileMagic) +
- sizeof(big_endian_protobuf_offset)) ==
- sizeof(pb_length));
- return true;
-}
-
-} // namespace chromeos_update_engine
diff --git a/delta_diff_generator.h b/delta_diff_generator.h
index 5d422c3..6b232da 100644
--- a/delta_diff_generator.h
+++ b/delta_diff_generator.h
@@ -5,86 +5,12 @@
#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_DELTA_DIFF_GENERATOR_H__
#define CHROMEOS_PLATFORM_UPDATE_ENGINE_DELTA_DIFF_GENERATOR_H__
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <set>
-#include <string>
-#include <vector>
#include "base/basictypes.h"
-#include "update_engine/file_writer.h"
-#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
class DeltaDiffGenerator {
- public:
- // Encodes the metadata at new_path recursively into a DeltaArchiveManifest
- // protobuf object. This will only read the filesystem. Children will
- // be recorded recursively iff they are on the same device as their
- // parent.
- // This will set all fields in the DeltaArchiveManifest except for
- // DeltaArchiveManifest_File_data_* as those are set only when writing
- // the actual delta file to disk.
- // Caller is responsible for freeing the returned value.
- // Returns NULL on failure.
- static DeltaArchiveManifest* EncodeMetadataToProtoBuffer(
- const char* new_path);
-
- // 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::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'.
- // They all return true on success.
-
- // EncodeLink stores the path the symlink points to.
- static bool EncodeLink(const std::string& path, std::vector<char>* out);
- // EncodeDev stores the major and minor device numbers.
- // Specifically it writes a LinuxDevice message.
- static bool EncodeDev(
- const struct stat& stbuf, std::vector<char>* out,
- DeltaArchiveManifest_File_DataFormat* format,
- bool force_compression);
- // EncodeFile stores the full data, gzipped data, or a binary diff from
- // the old data. out_data_format will be set to the method used.
- 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,
- 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,
- DeltaArchiveManifest_File* file,
- const std::string& file_name,
- const std::string& old_path,
- 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
DISALLOW_IMPLICIT_CONSTRUCTORS(DeltaDiffGenerator);
};
diff --git a/delta_diff_generator_unittest.cc b/delta_diff_generator_unittest.cc
index f86f0e2..a5def92 100644
--- a/delta_diff_generator_unittest.cc
+++ b/delta_diff_generator_unittest.cc
@@ -23,933 +23,6 @@
namespace chromeos_update_engine {
-using std::set;
-using std::string;
-using std::vector;
-
-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) {
- for (int i = 0; i < archive->files_size(); i++) {
- printf("Node %d\n", i);
- const DeltaArchiveManifest_File& file = archive->files(i);
- for (int j = 0; j < file.children_size(); j++) {
- const DeltaArchiveManifest_File_Child& child = file.children(j);
- printf(" %d %s\n", child.index(), child.name().c_str());
- }
- }
-}
-
-const char* const kWellCompressingFilename =
- "this_compresses_well_xxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
-// The following files are generated at the path 'base':
-// /
-// cdev (c 2 1)
-// dir/
-// bdev (b 3 1)
-// emptydir/ (owner:group = 501:503)
-// hello ("hello")
-// newempty ("")
-// subdir/
-// fifo
-// link -> /target
-// encoding/
-// long_new
-// long_small_change
-// nochange
-// onebyte
-// hi ("hi")
-void GenerateFilesAtPath(const string& base) {
- const char* base_c = base.c_str();
- EXPECT_EQ(0, System(StringPrintf("echo hi > '%s/hi'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("mkdir -p '%s/dir'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("rm -f '%s/dir/bdev'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("mknod '%s/dir/bdev' b 3 1", base_c)));
- EXPECT_EQ(0, System(StringPrintf("rm -f '%s/cdev'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("mknod '%s/cdev' c 2 1", base_c)));
- EXPECT_EQ(0, System(StringPrintf("mkdir -p '%s/dir/subdir'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("mkdir -p '%s/dir/emptydir'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("chown 501:503 '%s/dir/emptydir'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("rm -f '%s/dir/subdir/fifo'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("mkfifo '%s/dir/subdir/fifo'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("ln -f -s /target '%s/dir/subdir/link'",
- base_c)));
- EXPECT_EQ(0, System(StringPrintf("rm -f '%s/hard_link'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("ln '%s/hi' '%s/hard_link'",
- base_c, base_c)));
- EXPECT_EQ(0, System(StringPrintf(
- "ln -f -s '%s' '%s/compress_link'", kWellCompressingFilename, base_c)));
-
- // Things that will encode differently:
- EXPECT_EQ(0, System(StringPrintf("mkdir -p '%s/encoding'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("echo nochange > '%s/encoding/nochange'",
- base_c)));
- EXPECT_EQ(0, System(StringPrintf("echo -n > '%s/encoding/onebyte'", base_c)));
- EXPECT_EQ(0, System(StringPrintf("echo -n > '%s/encoding/long_new'",
- base_c)));
- // Random 1 MiB byte length file
- EXPECT_TRUE(utils::WriteFile((base +
- "/encoding/long_small_change").c_str(),
- reinterpret_cast<const char*>(kRandomString),
- sizeof(kRandomString)));
-}
-// base points to a folder that was passed to GenerateFilesAtPath().
-// This edits some, so that one can make a diff from the original data
-// and the edited data.
-void EditFilesAtPath(const string& base) {
- CHECK_EQ(0, System(string("echo hello > ") + base + "/dir/hello"));
- CHECK_EQ(0, System(string("echo -n > ") + base + "/dir/newempty"));
- CHECK_EQ(0, System(string("echo newhi > ") + base + "/hi"));
- CHECK_EQ(0, System(string("echo -n h >> ") + base +
- "/encoding/onebyte"));
- CHECK_EQ(0, System(string("echo -n h >> ") + base +
- "/encoding/long_small_change"));
- CHECK_EQ(0, System(string("echo -n This is a pice of text that should "
- "compress well since it is just ascii and it "
- "has repetition xxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxx > ") + base +
- "/encoding/long_new"));
-}
-
-} // namespace {}
-
-TEST_F(DeltaDiffGeneratorTest, FakerootEncodeMetadataToProtoBufferTest) {
- 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"));
- ASSERT_EQ(0, System(string("mkdir -p ") + cwd + "/diff-gen-test/old"));
- ASSERT_EQ(0, System(string("mkdir -p ") + cwd + "/diff-gen-test/new"));
- GenerateFilesAtPath(string(cwd) + "/diff-gen-test/old");
- GenerateFilesAtPath(string(cwd) + "/diff-gen-test/new");
- EditFilesAtPath(string(cwd) + "/diff-gen-test/new");
-
- DeltaArchiveManifest* archive =
- DeltaDiffGenerator::EncodeMetadataToProtoBuffer(
- (string(cwd) + "/diff-gen-test/new").c_str());
- EXPECT_TRUE(NULL != archive);
-
- EXPECT_EQ(18, archive->files_size());
- //DumpProto(archive);
- const DeltaArchiveManifest_File& root = archive->files(0);
- EXPECT_TRUE(S_ISDIR(root.mode()));
- EXPECT_EQ(0, root.uid());
- EXPECT_EQ(0, root.gid());
- ASSERT_EQ(6, root.children_size());
- EXPECT_EQ("cdev", root.children(0).name());
- EXPECT_EQ("compress_link", root.children(1).name());
- EXPECT_EQ("dir", root.children(2).name());
- EXPECT_EQ("encoding", root.children(3).name());
- EXPECT_EQ("hard_link", root.children(4).name());
- EXPECT_EQ("hi", root.children(5).name());
- EXPECT_FALSE(root.has_hardlink_path());
- EXPECT_FALSE(root.has_data_format());
- EXPECT_FALSE(root.has_data_offset());
- EXPECT_FALSE(root.has_data_length());
-
- const DeltaArchiveManifest_File& cdev =
- archive->files(root.children(0).index());
- EXPECT_EQ(0, cdev.children_size());
- EXPECT_TRUE(S_ISCHR(cdev.mode()));
- EXPECT_EQ(0, cdev.uid());
- EXPECT_EQ(0, cdev.gid());
- EXPECT_FALSE(cdev.has_hardlink_path());
- EXPECT_FALSE(cdev.has_data_format());
- EXPECT_FALSE(cdev.has_data_offset());
- EXPECT_FALSE(cdev.has_data_length());
-
- const DeltaArchiveManifest_File& compress_link =
- archive->files(root.children(1).index());
- EXPECT_EQ(0, compress_link.children_size());
- EXPECT_TRUE(S_ISLNK(compress_link.mode()));
- EXPECT_EQ(0, compress_link.uid());
- EXPECT_EQ(0, compress_link.gid());
- EXPECT_FALSE(compress_link.has_hardlink_path());
- EXPECT_FALSE(compress_link.has_data_format());
- EXPECT_FALSE(compress_link.has_data_offset());
- EXPECT_FALSE(compress_link.has_data_length());
-
- const DeltaArchiveManifest_File& hard_link =
- archive->files(root.children(4).index());
- EXPECT_EQ(0, hard_link.children_size());
- EXPECT_TRUE(S_ISREG(hard_link.mode()));
- EXPECT_EQ(0, hard_link.uid());
- EXPECT_EQ(0, hard_link.gid());
- EXPECT_FALSE(hard_link.has_hardlink_path());
- EXPECT_FALSE(hard_link.has_data_format());
- EXPECT_FALSE(hard_link.has_data_offset());
- EXPECT_FALSE(hard_link.has_data_length());
-
- const DeltaArchiveManifest_File& hi =
- archive->files(root.children(5).index());
- EXPECT_EQ(0, hi.children_size());
- EXPECT_TRUE(S_ISREG(hi.mode()));
- EXPECT_EQ(0, hi.uid());
- EXPECT_EQ(0, hi.gid());
- EXPECT_TRUE(hi.has_hardlink_path());
- EXPECT_EQ("/hard_link", hi.hardlink_path());
- EXPECT_FALSE(hi.has_data_format());
- EXPECT_FALSE(hi.has_data_offset());
- EXPECT_FALSE(hi.has_data_length());
-
- const DeltaArchiveManifest_File& encoding =
- archive->files(root.children(3).index());
- EXPECT_TRUE(S_ISDIR(encoding.mode()));
- EXPECT_EQ(0, encoding.uid());
- EXPECT_EQ(0, encoding.gid());
- EXPECT_EQ(4, encoding.children_size());
- EXPECT_EQ("long_new", encoding.children(0).name());
- EXPECT_EQ("long_small_change", encoding.children(1).name());
- EXPECT_EQ("nochange", encoding.children(2).name());
- EXPECT_EQ("onebyte", encoding.children(3).name());
- EXPECT_FALSE(encoding.has_hardlink_path());
- EXPECT_FALSE(encoding.has_data_format());
- EXPECT_FALSE(encoding.has_data_offset());
- EXPECT_FALSE(encoding.has_data_length());
-
- const DeltaArchiveManifest_File& long_new =
- archive->files(encoding.children(0).index());
- EXPECT_EQ(0, long_new.children_size());
- EXPECT_TRUE(S_ISREG(long_new.mode()));
- EXPECT_EQ(0, long_new.uid());
- EXPECT_EQ(0, long_new.gid());
- EXPECT_FALSE(long_new.has_hardlink_path());
- EXPECT_FALSE(long_new.has_data_format());
- EXPECT_FALSE(long_new.has_data_offset());
- EXPECT_FALSE(long_new.has_data_length());
-
- const DeltaArchiveManifest_File& long_small_change =
- archive->files(encoding.children(1).index());
- EXPECT_EQ(0, long_small_change.children_size());
- EXPECT_TRUE(S_ISREG(long_small_change.mode()));
- EXPECT_EQ(0, long_small_change.uid());
- EXPECT_EQ(0, long_small_change.gid());
- EXPECT_FALSE(long_small_change.has_hardlink_path());
- EXPECT_FALSE(long_small_change.has_data_format());
- EXPECT_FALSE(long_small_change.has_data_offset());
- EXPECT_FALSE(long_small_change.has_data_length());
-
- const DeltaArchiveManifest_File& nochange =
- archive->files(encoding.children(2).index());
- EXPECT_EQ(0, nochange.children_size());
- EXPECT_TRUE(S_ISREG(nochange.mode()));
- EXPECT_EQ(0, nochange.uid());
- EXPECT_EQ(0, nochange.gid());
- EXPECT_FALSE(nochange.has_hardlink_path());
- EXPECT_FALSE(nochange.has_data_format());
- EXPECT_FALSE(nochange.has_data_offset());
- EXPECT_FALSE(nochange.has_data_length());
-
- const DeltaArchiveManifest_File& onebyte =
- archive->files(encoding.children(3).index());
- EXPECT_EQ(0, onebyte.children_size());
- EXPECT_TRUE(S_ISREG(onebyte.mode()));
- EXPECT_EQ(0, onebyte.uid());
- EXPECT_EQ(0, onebyte.gid());
- EXPECT_FALSE(onebyte.has_hardlink_path());
- EXPECT_FALSE(onebyte.has_data_format());
- EXPECT_FALSE(onebyte.has_data_offset());
- EXPECT_FALSE(onebyte.has_data_length());
-
- const DeltaArchiveManifest_File& dir =
- archive->files(root.children(2).index());
- EXPECT_TRUE(S_ISDIR(dir.mode()));
- EXPECT_EQ(0, dir.uid());
- EXPECT_EQ(0, dir.gid());
- ASSERT_EQ(5, dir.children_size());
- EXPECT_EQ("bdev", dir.children(0).name());
- EXPECT_EQ("emptydir", dir.children(1).name());
- EXPECT_EQ("hello", dir.children(2).name());
- EXPECT_EQ("newempty", dir.children(3).name());
- EXPECT_EQ("subdir", dir.children(4).name());
- EXPECT_FALSE(dir.has_hardlink_path());
- EXPECT_FALSE(dir.has_data_format());
- EXPECT_FALSE(dir.has_data_offset());
- EXPECT_FALSE(dir.has_data_length());
-
- const DeltaArchiveManifest_File& bdev =
- archive->files(dir.children(0).index());
- EXPECT_EQ(0, bdev.children_size());
- EXPECT_TRUE(S_ISBLK(bdev.mode()));
- EXPECT_EQ(0, bdev.uid());
- EXPECT_EQ(0, bdev.gid());
- EXPECT_FALSE(bdev.has_hardlink_path());
- EXPECT_FALSE(bdev.has_data_format());
- EXPECT_FALSE(bdev.has_data_offset());
- EXPECT_FALSE(bdev.has_data_length());
-
- const DeltaArchiveManifest_File& emptydir =
- archive->files(dir.children(1).index());
- EXPECT_EQ(0, emptydir.children_size());
- EXPECT_TRUE(S_ISDIR(emptydir.mode()));
- EXPECT_EQ(501, emptydir.uid());
- EXPECT_EQ(503, emptydir.gid());
- EXPECT_FALSE(emptydir.has_hardlink_path());
- EXPECT_FALSE(emptydir.has_data_format());
- EXPECT_FALSE(emptydir.has_data_offset());
- EXPECT_FALSE(emptydir.has_data_length());
-
- const DeltaArchiveManifest_File& hello =
- archive->files(dir.children(2).index());
- EXPECT_EQ(0, hello.children_size());
- EXPECT_TRUE(S_ISREG(hello.mode()));
- EXPECT_EQ(0, hello.uid());
- EXPECT_EQ(0, hello.gid());
- EXPECT_FALSE(hello.has_hardlink_path());
- EXPECT_FALSE(hello.has_data_format());
- EXPECT_FALSE(hello.has_data_offset());
- EXPECT_FALSE(hello.has_data_length());
-
- const DeltaArchiveManifest_File& newempty =
- archive->files(dir.children(3).index());
- EXPECT_EQ(0, newempty.children_size());
- EXPECT_TRUE(S_ISREG(newempty.mode()));
- EXPECT_EQ(0, newempty.uid());
- EXPECT_EQ(0, newempty.gid());
- EXPECT_FALSE(newempty.has_hardlink_path());
- EXPECT_FALSE(newempty.has_data_format());
- EXPECT_FALSE(newempty.has_data_offset());
- EXPECT_FALSE(newempty.has_data_length());
-
- const DeltaArchiveManifest_File& subdir =
- archive->files(dir.children(4).index());
- EXPECT_EQ(2, subdir.children_size());
- EXPECT_EQ("fifo", subdir.children(0).name());
- EXPECT_EQ("link", subdir.children(1).name());
- EXPECT_TRUE(S_ISDIR(subdir.mode()));
- EXPECT_EQ(0, subdir.uid());
- EXPECT_EQ(0, subdir.gid());
- EXPECT_FALSE(subdir.has_hardlink_path());
- EXPECT_FALSE(subdir.has_data_format());
- EXPECT_FALSE(subdir.has_data_offset());
- EXPECT_FALSE(subdir.has_data_length());
-
- const DeltaArchiveManifest_File& fifo =
- archive->files(subdir.children(0).index());
- EXPECT_EQ(0, fifo.children_size());
- EXPECT_TRUE(S_ISFIFO(fifo.mode()));
- EXPECT_EQ(0, fifo.uid());
- EXPECT_EQ(0, fifo.gid());
- EXPECT_FALSE(fifo.has_hardlink_path());
- EXPECT_FALSE(fifo.has_data_format());
- EXPECT_FALSE(fifo.has_data_offset());
- EXPECT_FALSE(fifo.has_data_length());
-
- const DeltaArchiveManifest_File& link =
- archive->files(subdir.children(1).index());
- EXPECT_EQ(0, link.children_size());
- EXPECT_TRUE(S_ISLNK(link.mode()));
- EXPECT_EQ(0, link.uid());
- EXPECT_EQ(0, link.gid());
- EXPECT_FALSE(link.has_hardlink_path());
- EXPECT_FALSE(link.has_data_format());
- EXPECT_FALSE(link.has_data_offset());
- EXPECT_FALSE(link.has_data_length());
-}
-
-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"));
- ASSERT_EQ(0, System(string("mkdir -p ") + cwd + "/diff-gen-test/old"));
- ASSERT_EQ(0, System(string("mkdir -p ") + cwd + "/diff-gen-test/new"));
- GenerateFilesAtPath(string(cwd) + "/diff-gen-test/old");
- 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());
- EXPECT_TRUE(NULL != archive);
-
- EXPECT_TRUE(DeltaDiffGenerator::EncodeDataToDeltaFile(
- archive,
- 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());
-
- const DeltaArchiveManifest_File& root = archive->files(0);
- EXPECT_TRUE(S_ISDIR(root.mode()));
- EXPECT_EQ(0, root.uid());
- EXPECT_EQ(0, root.gid());
- ASSERT_EQ(6, root.children_size());
- EXPECT_EQ("cdev", root.children(0).name());
- EXPECT_EQ("compress_link", root.children(1).name());
- EXPECT_EQ("dir", root.children(2).name());
- EXPECT_EQ("encoding", root.children(3).name());
- EXPECT_EQ("hard_link", root.children(4).name());
- EXPECT_EQ("hi", root.children(5).name());
- EXPECT_FALSE(root.has_hardlink_path());
- EXPECT_FALSE(root.has_data_format());
- EXPECT_FALSE(root.has_data_offset());
- EXPECT_FALSE(root.has_data_length());
-
- const DeltaArchiveManifest_File& cdev =
- archive->files(root.children(0).index());
- EXPECT_EQ(0, cdev.children_size());
- EXPECT_TRUE(S_ISCHR(cdev.mode()));
- EXPECT_EQ(0, cdev.uid());
- EXPECT_EQ(0, cdev.gid());
- ASSERT_TRUE(cdev.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, cdev.data_format());
- EXPECT_TRUE(cdev.has_data_offset());
- ASSERT_TRUE(cdev.has_data_length());
- EXPECT_GT(cdev.data_length(), 0);
- EXPECT_FALSE(cdev.has_hardlink_path());
-
- const DeltaArchiveManifest_File& compress_link =
- archive->files(root.children(1).index());
- EXPECT_EQ(0, compress_link.children_size());
- EXPECT_TRUE(S_ISLNK(compress_link.mode()));
- EXPECT_EQ(0, compress_link.uid());
- EXPECT_EQ(0, compress_link.gid());
- ASSERT_TRUE(compress_link.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL_GZ,
- compress_link.data_format());
- EXPECT_TRUE(compress_link.has_data_offset());
- ASSERT_TRUE(compress_link.has_data_length());
- EXPECT_GT(compress_link.data_length(), 0);
- EXPECT_FALSE(compress_link.has_hardlink_path());
-
- const DeltaArchiveManifest_File& hard_link =
- archive->files(root.children(4).index());
- EXPECT_EQ(0, hard_link.children_size());
- EXPECT_TRUE(S_ISREG(hard_link.mode()));
- EXPECT_EQ(0, hard_link.uid());
- EXPECT_EQ(0, hard_link.gid());
- ASSERT_TRUE(hard_link.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, hard_link.data_format());
- EXPECT_TRUE(hard_link.has_data_offset());
- ASSERT_TRUE(hard_link.has_data_length());
- EXPECT_GT(hard_link.data_length(), 0);
- EXPECT_FALSE(hard_link.has_hardlink_path());
-
- const DeltaArchiveManifest_File& hi =
- archive->files(root.children(5).index());
- EXPECT_EQ(0, hi.children_size());
- EXPECT_TRUE(S_ISREG(hi.mode()));
- EXPECT_EQ(0, hi.uid());
- EXPECT_EQ(0, hi.gid());
- EXPECT_FALSE(hi.has_data_format());
- EXPECT_FALSE(hi.has_data_offset());
- EXPECT_FALSE(hi.has_data_length());
- EXPECT_TRUE(hi.has_hardlink_path());
- EXPECT_EQ("/hard_link", hi.hardlink_path());
-
- const DeltaArchiveManifest_File& encoding =
- archive->files(root.children(3).index());
- EXPECT_TRUE(S_ISDIR(encoding.mode()));
- EXPECT_EQ(0, encoding.uid());
- EXPECT_EQ(0, encoding.gid());
- EXPECT_EQ(4, encoding.children_size());
- EXPECT_EQ("long_new", encoding.children(0).name());
- EXPECT_EQ("long_small_change", encoding.children(1).name());
- EXPECT_EQ("nochange", encoding.children(2).name());
- EXPECT_EQ("onebyte", encoding.children(3).name());
- EXPECT_FALSE(encoding.has_data_format());
- EXPECT_FALSE(encoding.has_data_offset());
- EXPECT_FALSE(encoding.has_data_length());
- EXPECT_FALSE(encoding.has_hardlink_path());
-
- const DeltaArchiveManifest_File& long_new =
- archive->files(encoding.children(0).index());
- EXPECT_EQ(0, long_new.children_size());
- EXPECT_TRUE(S_ISREG(long_new.mode()));
- EXPECT_EQ(0, long_new.uid());
- EXPECT_EQ(0, long_new.gid());
- EXPECT_TRUE(long_new.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL_GZ,
- long_new.data_format());
- EXPECT_TRUE(long_new.has_data_offset());
- EXPECT_TRUE(long_new.has_data_length());
- EXPECT_FALSE(long_new.has_hardlink_path());
-
- const DeltaArchiveManifest_File& long_small_change =
- archive->files(encoding.children(1).index());
- EXPECT_EQ(0, long_small_change.children_size());
- EXPECT_TRUE(S_ISREG(long_small_change.mode()));
- EXPECT_EQ(0, long_small_change.uid());
- EXPECT_EQ(0, long_small_change.gid());
- EXPECT_TRUE(long_small_change.has_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());
-
- const DeltaArchiveManifest_File& nochange =
- archive->files(encoding.children(2).index());
- EXPECT_EQ(0, nochange.children_size());
- EXPECT_TRUE(S_ISREG(nochange.mode()));
- EXPECT_EQ(0, nochange.uid());
- EXPECT_EQ(0, nochange.gid());
- 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 =
- archive->files(encoding.children(3).index());
- EXPECT_EQ(0, onebyte.children_size());
- EXPECT_TRUE(S_ISREG(onebyte.mode()));
- EXPECT_EQ(0, onebyte.uid());
- EXPECT_EQ(0, onebyte.gid());
- EXPECT_TRUE(onebyte.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, onebyte.data_format());
- EXPECT_TRUE(onebyte.has_data_offset());
- EXPECT_TRUE(onebyte.has_data_length());
- EXPECT_EQ(1, onebyte.data_length());
- EXPECT_FALSE(onebyte.has_hardlink_path());
-
- const DeltaArchiveManifest_File& dir =
- archive->files(root.children(2).index());
- EXPECT_TRUE(S_ISDIR(dir.mode()));
- EXPECT_EQ(0, dir.uid());
- EXPECT_EQ(0, dir.gid());
- ASSERT_EQ(5, dir.children_size());
- EXPECT_EQ("bdev", dir.children(0).name());
- EXPECT_EQ("emptydir", dir.children(1).name());
- EXPECT_EQ("hello", dir.children(2).name());
- EXPECT_EQ("newempty", dir.children(3).name());
- EXPECT_EQ("subdir", dir.children(4).name());
- EXPECT_FALSE(dir.has_data_format());
- EXPECT_FALSE(dir.has_data_offset());
- EXPECT_FALSE(dir.has_data_length());
- EXPECT_FALSE(dir.has_hardlink_path());
-
- const DeltaArchiveManifest_File& bdev =
- archive->files(dir.children(0).index());
- EXPECT_EQ(0, bdev.children_size());
- EXPECT_TRUE(S_ISBLK(bdev.mode()));
- EXPECT_EQ(0, bdev.uid());
- EXPECT_EQ(0, bdev.gid());
- ASSERT_TRUE(bdev.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, bdev.data_format());
- EXPECT_TRUE(bdev.has_data_offset());
- ASSERT_TRUE(bdev.has_data_length());
- EXPECT_GT(bdev.data_length(), 0);
- EXPECT_FALSE(bdev.has_hardlink_path());
-
- const DeltaArchiveManifest_File& emptydir =
- archive->files(dir.children(1).index());
- EXPECT_EQ(0, emptydir.children_size());
- EXPECT_TRUE(S_ISDIR(emptydir.mode()));
- EXPECT_EQ(501, emptydir.uid());
- EXPECT_EQ(503, emptydir.gid());
- EXPECT_FALSE(emptydir.has_data_format());
- EXPECT_FALSE(emptydir.has_data_offset());
- EXPECT_FALSE(emptydir.has_data_length());
- EXPECT_FALSE(emptydir.has_hardlink_path());
-
- const DeltaArchiveManifest_File& hello =
- archive->files(dir.children(2).index());
- EXPECT_EQ(0, hello.children_size());
- EXPECT_TRUE(S_ISREG(hello.mode()));
- EXPECT_EQ(0, hello.uid());
- EXPECT_EQ(0, hello.gid());
- ASSERT_TRUE(hello.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, hello.data_format());
- EXPECT_TRUE(hello.has_data_offset());
- ASSERT_TRUE(hello.has_data_length());
- EXPECT_GT(hello.data_length(), 0);
- EXPECT_FALSE(hello.has_hardlink_path());
-
- const DeltaArchiveManifest_File& newempty =
- archive->files(dir.children(3).index());
- EXPECT_EQ(0, newempty.children_size());
- EXPECT_TRUE(S_ISREG(newempty.mode()));
- EXPECT_EQ(0, newempty.uid());
- EXPECT_EQ(0, newempty.gid());
- 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 =
- archive->files(dir.children(4).index());
- EXPECT_EQ(2, subdir.children_size());
- EXPECT_EQ("fifo", subdir.children(0).name());
- EXPECT_EQ("link", subdir.children(1).name());
- EXPECT_TRUE(S_ISDIR(subdir.mode()));
- EXPECT_EQ(0, subdir.uid());
- EXPECT_EQ(0, subdir.gid());
- EXPECT_FALSE(subdir.has_data_format());
- EXPECT_FALSE(subdir.has_data_offset());
- EXPECT_FALSE(subdir.has_data_length());
- EXPECT_FALSE(subdir.has_hardlink_path());
-
- const DeltaArchiveManifest_File& fifo =
- archive->files(subdir.children(0).index());
- EXPECT_EQ(0, fifo.children_size());
- EXPECT_TRUE(S_ISFIFO(fifo.mode()));
- EXPECT_EQ(0, fifo.uid());
- EXPECT_EQ(0, fifo.gid());
- EXPECT_FALSE(fifo.has_data_format());
- EXPECT_FALSE(fifo.has_data_offset());
- EXPECT_FALSE(fifo.has_data_length());
- EXPECT_FALSE(fifo.has_hardlink_path());
-
- const DeltaArchiveManifest_File& link =
- archive->files(subdir.children(1).index());
- EXPECT_EQ(0, link.children_size());
- EXPECT_TRUE(S_ISLNK(link.mode()));
- EXPECT_EQ(0, link.uid());
- EXPECT_EQ(0, link.gid());
- ASSERT_TRUE(link.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, link.data_format());
- EXPECT_TRUE(link.has_data_offset());
- ASSERT_TRUE(link.has_data_length());
- EXPECT_GT(link.data_length(), 0);
- EXPECT_FALSE(link.has_hardlink_path());
-}
-
-class DeltaDiffParserTest : public ::testing::Test {
- virtual void TearDown() {
- EXPECT_EQ(0, system("rm -rf diff-gen-test"));
- }
-};
-
-namespace {
-// Reads part of a file into memory
-vector<char> ReadFilePart(const string& path, off_t start, off_t size) {
- vector<char> ret;
- int fd = open(path.c_str(), O_RDONLY, 0);
- if (fd < 0)
- return ret;
- ret.resize(size);
- EXPECT_EQ(size, pread(fd, &ret[0], size, start));
- close(fd);
- return ret;
-}
-
-string ReadFilePartToString(const string& path, off_t start, off_t size) {
- vector<char> bytes = ReadFilePart(path, start, size);
- string ret;
- ret.append(&bytes[0], bytes.size());
- return ret;
-}
-
-string StringFromVectorChar(const vector<char>& in) {
- return string(&in[0], in.size());
-}
-
-string GzipDecompressToString(const vector<char>& in) {
- vector<char> out;
- EXPECT_TRUE(GzipDecompress(in, &out));
- return StringFromVectorChar(out);
-}
-
-}
-
-TEST_F(DeltaDiffParserTest, FakerootDecodeDataFromDeltaFileTest) {
- 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"));
- ASSERT_EQ(0, System(string("mkdir -p ") + cwd + "/diff-gen-test/old"));
- ASSERT_EQ(0, System(string("mkdir -p ") + cwd + "/diff-gen-test/new"));
- GenerateFilesAtPath(string(cwd) + "/diff-gen-test/old");
- GenerateFilesAtPath(string(cwd) + "/diff-gen-test/new");
- EditFilesAtPath(string(cwd) + "/diff-gen-test/new");
-
- DeltaArchiveManifest* archive =
- DeltaDiffGenerator::EncodeMetadataToProtoBuffer(
- (string(cwd) + "/diff-gen-test/new").c_str());
- EXPECT_TRUE(NULL != archive);
-
- EXPECT_TRUE(DeltaDiffGenerator::EncodeDataToDeltaFile(
- archive,
- 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");
- ASSERT_TRUE(parser.valid());
- DeltaDiffParser::Iterator it = parser.Begin();
- string expected_paths[] = {
- "",
- "/cdev",
- "/compress_link",
- "/dir",
- "/dir/bdev",
- "/dir/emptydir",
- "/dir/hello",
- "/dir/newempty",
- "/dir/subdir",
- "/dir/subdir/fifo",
- "/dir/subdir/link",
- "/encoding",
- "/encoding/long_new",
- "/encoding/long_small_change",
- "/encoding/nochange",
- "/encoding/onebyte",
- "/hard_link",
- "/hi"
- };
- for (unsigned int i = 0;
- i < (sizeof(expected_paths)/sizeof(expected_paths[0])); i++) {
- ASSERT_TRUE(it != parser.End());
- ASSERT_TRUE(parser.ContainsPath(expected_paths[i]));
- EXPECT_EQ(expected_paths[i], it.path());
- EXPECT_EQ(expected_paths[i].substr(expected_paths[i].find_last_of('/') + 1),
- it.GetName());
- DeltaArchiveManifest_File f1 = parser.GetFileAtPath(expected_paths[i]);
- DeltaArchiveManifest_File f2 = it.GetFile();
- EXPECT_EQ(f1.mode(), f2.mode()) << it.path();
- EXPECT_EQ(f1.uid(), f2.uid());
- EXPECT_EQ(f1.gid(), f2.gid());
- EXPECT_EQ(f1.has_data_format(), f2.has_data_format());
- if (f1.has_data_format()) {
- EXPECT_EQ(f1.data_format(), f2.data_format());
- EXPECT_TRUE(f1.has_data_offset());
- EXPECT_TRUE(f2.has_data_offset());
- EXPECT_EQ(f1.data_offset(), f2.data_offset());
- } else {
- EXPECT_FALSE(f2.has_data_format());
- EXPECT_FALSE(f1.has_data_offset());
- EXPECT_FALSE(f2.has_data_offset());
- }
- EXPECT_EQ(f1.children_size(), f2.children_size());
- for (int j = 0; j < f1.children_size(); j++) {
- EXPECT_EQ(f1.children(j).name(), f2.children(j).name());
- EXPECT_EQ(f1.children(j).index(), f2.children(j).index());
- }
- it.Increment();
- }
- EXPECT_TRUE(it == parser.End());
- EXPECT_FALSE(parser.ContainsPath("/cdew"));
- EXPECT_FALSE(parser.ContainsPath("/hi/hi"));
- EXPECT_FALSE(parser.ContainsPath("/dir/newempty/hi"));
- EXPECT_TRUE(parser.ContainsPath("/dir/"));
-
- // Check the data
- // root
- DeltaArchiveManifest_File file = parser.GetFileAtPath("");
- EXPECT_TRUE(S_ISDIR(file.mode()));
- EXPECT_FALSE(file.has_data_format());
-
- // cdev
- file = parser.GetFileAtPath("/cdev");
- EXPECT_TRUE(S_ISCHR(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- vector<char> data = ReadFilePart(string(cwd) + "/diff-gen-test/out.dat",
- file.data_offset(), file.data_length());
- LinuxDevice linux_device;
- linux_device.ParseFromArray(&data[0], data.size());
- EXPECT_EQ(linux_device.major(), 2);
- EXPECT_EQ(linux_device.minor(), 1);
-
- // compress_link
- file = parser.GetFileAtPath("/compress_link");
- EXPECT_TRUE(S_ISLNK(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL_GZ, file.data_format());
- EXPECT_EQ(kWellCompressingFilename,
- GzipDecompressToString(ReadFilePart(string(cwd) +
- "/diff-gen-test/out.dat",
- file.data_offset(),
- file.data_length())));
- // dir
- file = parser.GetFileAtPath("/dir");
- EXPECT_TRUE(S_ISDIR(file.mode()));
- EXPECT_FALSE(file.has_data_format());
-
- // bdev
- file = parser.GetFileAtPath("/dir/bdev");
- EXPECT_TRUE(S_ISBLK(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- data = ReadFilePart(string(cwd) + "/diff-gen-test/out.dat",
- file.data_offset(), file.data_length());
- linux_device.ParseFromArray(&data[0], data.size());
- EXPECT_EQ(linux_device.major(), 3);
- EXPECT_EQ(linux_device.minor(), 1);
-
- // emptydir
- file = parser.GetFileAtPath("/dir/emptydir");
- EXPECT_TRUE(S_ISDIR(file.mode()));
- EXPECT_FALSE(file.has_data_format());
-
- // hello
- file = parser.GetFileAtPath("/dir/hello");
- EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, file.data_format());
- EXPECT_EQ("hello\n", ReadFilePartToString(string(cwd) +
- "/diff-gen-test/out.dat",
- file.data_offset(),
- file.data_length()));
-
- // newempty
- file = parser.GetFileAtPath("/dir/newempty");
- EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, file.data_format());
-
- // subdir
- file = parser.GetFileAtPath("/dir/subdir");
- EXPECT_TRUE(S_ISDIR(file.mode()));
- EXPECT_FALSE(file.has_data_format());
-
- // fifo
- file = parser.GetFileAtPath("/dir/subdir/fifo");
- EXPECT_TRUE(S_ISFIFO(file.mode()));
- EXPECT_FALSE(file.has_data_format());
-
- // link
- file = parser.GetFileAtPath("/dir/subdir/link");
- EXPECT_TRUE(S_ISLNK(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, file.data_format());
- EXPECT_EQ("/target", ReadFilePartToString(string(cwd) +
- "/diff-gen-test/out.dat",
- file.data_offset(),
- file.data_length()));
-
- // encoding
- file = parser.GetFileAtPath("/encoding");
- EXPECT_TRUE(S_ISDIR(file.mode()));
- EXPECT_FALSE(file.has_data_format());
-
- // long_new
- file = parser.GetFileAtPath("/encoding/long_new");
- EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL_GZ, file.data_format());
- EXPECT_EQ("This is a pice of text that should "
- "compress well since it is just ascii and it "
- "has repetition xxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxx",
- GzipDecompressToString(ReadFilePart(string(cwd) +
- "/diff-gen-test/out.dat",
- file.data_offset(),
- file.data_length())));
-
- // long_small_change
- file = parser.GetFileAtPath("/encoding/long_small_change");
- EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_BSDIFF, file.data_format());
- data = ReadFilePart(string(cwd) + "/diff-gen-test/out.dat",
- file.data_offset(), file.data_length());
- WriteFileVector(string(cwd) + "/diff-gen-test/patch", data);
- int rc = 1;
- vector<string> cmd;
- cmd.push_back("/usr/bin/bspatch");
- cmd.push_back(string(cwd) + "/diff-gen-test/old/encoding/long_small_change");
- cmd.push_back(string(cwd) + "/diff-gen-test/patch_result");
- cmd.push_back(string(cwd) + "/diff-gen-test/patch");
- Subprocess::SynchronousExec(cmd, &rc);
- ASSERT_EQ(0, rc);
- vector<char> patch_result;
- EXPECT_TRUE(utils::ReadFile(string(cwd) + "/diff-gen-test/patch_result",
- &patch_result));
- vector<char> expected_data(sizeof(kRandomString) + 1);
- memcpy(&expected_data[0], kRandomString, sizeof(kRandomString));
- expected_data[expected_data.size() - 1] = 'h';
- ExpectVectorsEq(expected_data, patch_result);
-
- // nochange
- file = parser.GetFileAtPath("/encoding/nochange");
- EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_FALSE(file.has_data_format());
- EXPECT_FALSE(file.has_data_offset());
- EXPECT_FALSE(file.has_data_length());
-
- // onebyte
- file = parser.GetFileAtPath("/encoding/onebyte");
- EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, file.data_format());
- EXPECT_EQ("h", ReadFilePartToString(string(cwd) +
- "/diff-gen-test/out.dat",
- file.data_offset(),
- file.data_length()));
-
- // hard_link
- file = parser.GetFileAtPath("/hard_link");
- EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_TRUE(file.has_data_format());
- EXPECT_EQ(DeltaArchiveManifest_File_DataFormat_FULL, file.data_format());
- EXPECT_EQ("newhi\n", ReadFilePartToString(string(cwd) +
- "/diff-gen-test/out.dat",
- file.data_offset(),
- file.data_length()));
-
- // hi
- file = parser.GetFileAtPath("/hi");
- EXPECT_TRUE(S_ISREG(file.mode()));
- EXPECT_FALSE(file.has_data_format());
- EXPECT_TRUE(file.has_hardlink_path());
- EXPECT_EQ("/hard_link", file.hardlink_path());
-}
-
-TEST_F(DeltaDiffParserTest, FakerootInvalidTest) {
- ASSERT_EQ(0, mkdir("diff-gen-test", 0777));
- {
- DeltaDiffParser parser("/no/such/file");
- EXPECT_FALSE(parser.valid());
- }
- {
- vector<char> data(3);
- memcpy(&data[0], "CrA", 3);
- WriteFileVector("diff-gen-test/baddelta", data);
- DeltaDiffParser parser("diff-gen-test/baddelta");
- EXPECT_FALSE(parser.valid());
- }
- {
- vector<char> data(5);
- memcpy(&data[0], "CrAPx", 5);
- WriteFileVector("diff-gen-test/baddelta", data);
- DeltaDiffParser parser("diff-gen-test/baddelta");
- EXPECT_FALSE(parser.valid());
- }
- {
- vector<char> data(5);
- memcpy(&data[0], "CrAU\0", 5);
- WriteFileVector("diff-gen-test/baddelta", data);
- DeltaDiffParser parser("diff-gen-test/baddelta");
- EXPECT_FALSE(parser.valid());
- }
- {
- vector<char> data(14);
- memcpy(&data[0], "CrAU\0\0\0\0\0\0\0\x0cxx", 12);
- WriteFileVector("diff-gen-test/baddelta", data);
- DeltaDiffParser parser("diff-gen-test/baddelta");
- EXPECT_FALSE(parser.valid());
- }
-}
+class DeltaDiffGeneratorTest : public ::testing::Test {};
} // namespace chromeos_update_engine
diff --git a/delta_diff_parser.cc b/delta_diff_parser.cc
index 47c763f..fe7c974 100644
--- a/delta_diff_parser.cc
+++ b/delta_diff_parser.cc
@@ -3,270 +3,7 @@
// found in the LICENSE file.
#include "update_engine/delta_diff_parser.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <endian.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <algorithm>
-#include <string>
-#include <vector>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include "base/scoped_ptr.h"
-#include "update_engine/decompressing_file_writer.h"
-#include "update_engine/gzip.h"
-#include "update_engine/utils.h"
-
-using std::min;
-using std::string;
-using std::vector;
namespace chromeos_update_engine {
-namespace {
-const int kCopyFileBufferSize = 4096;
-}
-
-const char* const DeltaDiffParser::kFileMagic("CrAU");
-
-// The iterator returns a directory before returning its children.
-// Steps taken in Increment():
-// - See if the current item has children. If so, the child becomes
-// the new current item and we return.
-// - If current item has no children, we loop. Each loop iteration
-// considers an item (first the current item, then its parent,
-// then grand parent, and so on). Each loop iteration, we see if there
-// are any siblings we haven't iterated on yet. If so, we're done.
-// If not, keep looping to parents.
-void DeltaDiffParserIterator::Increment() {
- // See if we have any children.
- const DeltaArchiveManifest_File& file = GetFile();
- if (file.children_size() > 0) {
- path_indices_.push_back(file.children(0).index());
- path_ += "/";
- path_ += file.children(0).name();
- child_indices_.push_back(0);
- return;
- }
- // Look in my parent for the next child, then try grandparent, etc.
-
- path_indices_.pop_back();
- path_.resize(path_.rfind('/'));
-
- while (!child_indices_.empty()) {
- // Try to bump the last entry
- CHECK_EQ(path_indices_.size(), child_indices_.size());
- child_indices_.back()++;
- const DeltaArchiveManifest_File& parent =
- archive_->files(path_indices_.back());
- if (parent.children_size() > child_indices_.back()) {
- // we found a new child!
- path_indices_.push_back(parent.children(child_indices_.back()).index());
- path_ += "/";
- path_ += parent.children(child_indices_.back()).name();
- return;
- }
- path_indices_.pop_back();
- child_indices_.pop_back();
- if (!path_.empty())
- path_.resize(path_.rfind('/'));
- }
-}
-
-const string DeltaDiffParserIterator::GetName() const {
- if (path_.empty())
- return "";
- CHECK_NE(path_.rfind('/'), string::npos);
- return string(path_, path_.rfind('/') + 1);
-}
-
-const DeltaArchiveManifest_File& DeltaDiffParserIterator::GetFile() const {
- CHECK(!path_indices_.empty());
- return archive_->files(path_indices_.back());
-}
-
-
-DeltaDiffParser::DeltaDiffParser(const string& delta_file)
- : fd_(-1),
- valid_(false) {
- fd_ = open(delta_file.c_str(), O_RDONLY, 0);
- if (fd_ < 0) {
- LOG(ERROR) << "Unable to open delta file: " << delta_file;
- return;
- }
- ScopedFdCloser fd_closer(&fd_);
- scoped_array<char> magic(new char[strlen(kFileMagic)]);
- if (strlen(kFileMagic) != read(fd_, magic.get(), strlen(kFileMagic))) {
- LOG(ERROR) << "delta file too short";
- return;
- }
- if (strncmp(magic.get(), kFileMagic, strlen(kFileMagic))) {
- LOG(ERROR) << "Incorrect magic at beginning of delta file";
- return;
- }
-
- int64 proto_offset = 0;
- COMPILE_ASSERT(sizeof(proto_offset) == sizeof(off_t), off_t_wrong_size);
- if (sizeof(proto_offset) != read(fd_, &proto_offset, sizeof(proto_offset))) {
- LOG(ERROR) << "delta file too short";
- return;
- }
- proto_offset = be64toh(proto_offset); // switch from big-endian to host
-
- int64 proto_length = 0;
- if (sizeof(proto_length) != read(fd_, &proto_length, sizeof(proto_length))) {
- LOG(ERROR) << "delta file too short";
- return;
- }
- proto_length = be64toh(proto_length); // switch from big-endian to host
-
- vector<char> proto(proto_length);
- size_t bytes_read = 0;
- while (bytes_read < proto_length) {
- ssize_t r = pread(fd_, &proto[bytes_read], proto_length - bytes_read,
- proto_offset + bytes_read);
- TEST_AND_RETURN(r >= 0);
- bytes_read += r;
- }
- {
- vector<char> decompressed_proto;
- TEST_AND_RETURN(GzipDecompress(proto, &decompressed_proto));
- proto.swap(decompressed_proto);
- }
-
- valid_ = archive_.ParseFromArray(&proto[0], proto.size());
- if (valid_) {
- fd_closer.set_should_close(false);
- } else {
- LOG(ERROR) << "load from file failed";
- }
-}
-
-DeltaDiffParser::~DeltaDiffParser() {
- if (fd_ >= 0) {
- close(fd_);
- fd_ = -1;
- }
-}
-
-bool DeltaDiffParser::ContainsPath(const string& path) const {
- return GetIndexForPath(path) >= 0;
-}
-
-const DeltaArchiveManifest_File& DeltaDiffParser::GetFileAtPath(
- const string& path) const {
- int idx = GetIndexForPath(path);
- CHECK_GE(idx, 0) << path;
- return archive_.files(idx);
-}
-
-// Returns -1 if not found.
-int DeltaDiffParser::GetIndexOfFileChild(
- const DeltaArchiveManifest_File& file, const string& child_name) const {
- if (file.children_size() == 0)
- return -1;
- int begin = 0;
- int end = file.children_size();
- while (begin < end) {
- int middle = (begin + end) / 2;
- const string& middle_name = file.children(middle).name();
- int cmp_result = strcmp(middle_name.c_str(), child_name.c_str());
- if (cmp_result == 0)
- return file.children(middle).index();
- if (cmp_result < 0)
- begin = middle + 1;
- else
- end = middle;
- }
- return -1;
-}
-
-// Converts a path to an index in archive_. It does this by separating
-// the path components and going from root to leaf, finding the
-// File message for each component. Index values for children are
-// stored in File messages.
-int DeltaDiffParser::GetIndexForPath(const string& path) const {
- string cleaned_path = utils::NormalizePath(path, true);
- // strip leading slash
- if (cleaned_path[0] == '/')
- cleaned_path = cleaned_path.c_str() + 1;
- if (cleaned_path.empty())
- return 0;
- string::size_type begin = 0;
- string::size_type end = cleaned_path.find_first_of('/', begin + 1);
- const DeltaArchiveManifest_File* file = &archive_.files(0);
- int file_idx = -1;
- for (;;) {
- string component = cleaned_path.substr(begin, end - begin);
- if (component.empty())
- break;
- // search for component in 'file'
- file_idx = GetIndexOfFileChild(*file, component);
- if (file_idx < 0)
- return file_idx;
- file = &archive_.files(file_idx);
- if (end == string::npos)
- break;
- begin = end + 1;
- end = cleaned_path.find_first_of('/', begin + 1);
- }
- return file_idx;
-}
-
-bool DeltaDiffParser::ReadDataVector(off_t offset, off_t length,
- std::vector<char>* out) const {
- out->resize(static_cast<vector<char>::size_type>(length));
- int r = pread(fd_, &((*out)[0]), length, offset);
- TEST_AND_RETURN_FALSE_ERRNO(r >= 0);
- return true;
-}
-
-bool DeltaDiffParser::CopyDataToFile(off_t offset, off_t length,
- bool should_decompress,
- const std::string& path) const {
- DirectFileWriter direct_writer;
- GzipDecompressingFileWriter decompressing_writer(&direct_writer);
- FileWriter* writer = NULL; // will point to one of the two writers above
-
- writer = (should_decompress ?
- static_cast<FileWriter*>(&decompressing_writer) :
- static_cast<FileWriter*>(&direct_writer));
- ScopedFileWriterCloser closer(writer);
-
- int r = writer->Open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0644);
- TEST_AND_RETURN_FALSE(r == 0);
-
- off_t bytes_transferred = 0;
-
- while (bytes_transferred < length) {
- char buf[kCopyFileBufferSize];
- size_t bytes_to_read = min(length - bytes_transferred,
- static_cast<off_t>(sizeof(buf)));
- ssize_t bytes_read = pread(fd_, buf, bytes_to_read,
- offset + bytes_transferred);
- if (bytes_read == 0)
- break; // EOF
- TEST_AND_RETURN_FALSE_ERRNO(bytes_read > 0);
- int bytes_written = writer->Write(buf, bytes_read);
- TEST_AND_RETURN_FALSE(bytes_written == bytes_read);
- bytes_transferred += bytes_written;
- }
- TEST_AND_RETURN_FALSE(bytes_transferred == length);
- LOG_IF(ERROR, bytes_transferred > length) << "Wrote too many bytes(?)";
- return true;
-}
-
-
-const DeltaDiffParser::Iterator DeltaDiffParser::Begin() {
- DeltaDiffParserIterator ret(&archive_);
- ret.path_indices_.push_back(0);
- return ret;
-}
-
-const DeltaDiffParser::Iterator DeltaDiffParser::End() {
- return DeltaDiffParserIterator(&archive_);
-}
-
} // namespace chromeos_update_engine
diff --git a/delta_diff_parser.h b/delta_diff_parser.h
index 5c6d664..e6d0b1a 100644
--- a/delta_diff_parser.h
+++ b/delta_diff_parser.h
@@ -5,128 +5,10 @@
#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_DELTA_DIFF_PARSER_H__
#define CHROMEOS_PLATFORM_UPDATE_ENGINE_DELTA_DIFF_PARSER_H__
-#include <string>
-#include <vector>
-#include "chromeos/obsolete_logging.h"
#include "base/basictypes.h"
-#include "update_engine/update_metadata.pb.h"
-
-// The DeltaDiffParser class is used to parse a delta file on disk. It will
-// copy the metadata into memory, but not the file data. This class can
-// also be used to copy file data out to disk.
-
-// The DeltaDiffParserIterator class is used to iterate through the
-// metadata of a delta file. It will return directories before their
-// children.
namespace chromeos_update_engine {
-class DeltaDiffParser;
-
-class DeltaDiffParserIterator {
- friend class DeltaDiffParser;
- public:
- void Increment();
-
- // Returns the full path for the current file, e.g. "/bin/bash".
- // Returns empty string for root.
- const std::string& path() const {
- return path_;
- }
-
- // Returns the basename for the current file. If path() returns
- // "/bin/bash", then GetName() returns "bash".
- // Returns empty string for root
- const std::string GetName() const;
-
- const DeltaArchiveManifest_File& GetFile() const;
- bool operator==(const DeltaDiffParserIterator& that) const {
- return path_indices_ == that.path_indices_ &&
- child_indices_ == that.child_indices_ &&
- path_ == that.path_ &&
- archive_ == that.archive_;
- }
- bool operator!=(const DeltaDiffParserIterator& that) const {
- return !(*this == that);
- }
- private:
- // Container of all the File messages. Each File message has an index
- // in archive_. The root directory is always stored at index 0.
- const DeltaArchiveManifest* archive_;
-
- // These variables are used to implement the common recursive depth-first
- // search algorithm (which we can't use here, since we need to walk the
- // tree incrementally).
-
- // Indices into 'archive_' of the current path components. For example, if
- // the current path is "/bin/bash", 'path_stack_' will contain the archive
- // indices for "/", "/bin", and "/bin/bash", in that order. This is
- // analogous to the call stack of the recursive algorithm.
- std::vector<int> path_indices_;
-
- // For each component in 'path_stack_', the currently-selected child in its
- // child vector. In the previous example, if "/" has "abc" and "bin"
- // subdirectories and "/bin" contains only "bash", this will contain
- // [0, 1, 0], since we are using the 0th child at the root directory level
- // (there's only one child there), the first of the root dir's children
- // ("bin"), and the 0th child of /bin ("bash"). This is analogous to the
- // state of each function (in terms of which child it's currently
- // handling) in the call stack of the recursive algorithm.
- std::vector<int> child_indices_;
-
- std::string path_;
- // Instantiated by friend class DeltaDiffParser
- explicit DeltaDiffParserIterator(const DeltaArchiveManifest* archive)
- : archive_(archive) {}
- DeltaDiffParserIterator() {
- CHECK(false); // Should never be called.
- }
-};
-
-class DeltaDiffParser {
- public:
- DeltaDiffParser(const std::string& delta_file);
- ~DeltaDiffParser();
- bool valid() const { return valid_; }
- bool ContainsPath(const std::string& path) const;
- const DeltaArchiveManifest_File& GetFileAtPath(const std::string& path) const;
-
- // Reads length bytes at offset of the delta file into the out string
- // or vector. Be careful not to call this with large length values,
- // since that much memory will have to be allocated to store the output.
- // Returns true on success.
- bool ReadDataVector(off_t offset, off_t length, std::vector<char>* out) const;
-
- // Copies length bytes of data from offset into a new file at path specified.
- // If should_decompress is true, will gzip decompress while writing to the
- // file. Returns true on success.
- bool CopyDataToFile(off_t offset, off_t length, bool should_decompress,
- const std::string& path) const;
-
- typedef DeltaDiffParserIterator Iterator;
- const Iterator Begin();
- const Iterator End();
-
- // The identifier we expect at the beginning of a delta file.
- static const char* const kFileMagic;
-
- private:
- // (Binary) Searches the children of 'file' for one named child_name.
- // If found, returns the index into the archive. If not found, returns -1.
- int GetIndexOfFileChild(const DeltaArchiveManifest_File& file,
- const std::string& child_name) const;
-
- // Returns -1 if not found, 0 for root
- int GetIndexForPath(const std::string& path) const;
-
- // We keep a filedescriptor open to the delta file.
- int fd_;
-
- DeltaArchiveManifest archive_;
- bool valid_;
- DISALLOW_COPY_AND_ASSIGN(DeltaDiffParser);
-};
-
}; // namespace chromeos_update_engine
#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_DELTA_DIFF_PARSER_H__
diff --git a/download_action.cc b/download_action.cc
index 833f806..6da6719 100644
--- a/download_action.cc
+++ b/download_action.cc
@@ -31,7 +31,7 @@
should_decompress_ = install_plan.is_full_update;
url_ = install_plan.download_url;
- output_path_ = install_plan.download_path;
+ output_path_ = install_plan.install_path;
hash_ = install_plan.download_hash;
install_plan.Dump();
@@ -39,7 +39,6 @@
decompressing_file_writer_.reset(
new GzipDecompressingFileWriter(direct_file_writer_.get()));
writer_ = decompressing_file_writer_.get();
- output_path_ = install_plan.install_path;
} else {
writer_ = direct_file_writer_.get();
}
diff --git a/download_action_unittest.cc b/download_action_unittest.cc
index 57e8d7e..014d3b7 100644
--- a/download_action_unittest.cc
+++ b/download_action_unittest.cc
@@ -80,7 +80,7 @@
// takes ownership of passed in HttpFetcher
InstallPlan install_plan(compress, "",
OmahaHashCalculator::OmahaHashOfData(use_data),
- compress ? "" : path, compress ? path : "");
+ path);
ObjectFeederAction<InstallPlan> feeder_action;
feeder_action.set_obj(install_plan);
DownloadAction download_action(new MockHttpFetcher(&use_data[0],
@@ -157,7 +157,7 @@
{
// takes ownership of passed in HttpFetcher
ObjectFeederAction<InstallPlan> feeder_action;
- InstallPlan install_plan(false, "", "", path, "");
+ InstallPlan install_plan(false, "", "", path);
feeder_action.set_obj(install_plan);
DownloadAction download_action(new MockHttpFetcher(&data[0], data.size()));
TerminateEarlyTestProcessorDelegate delegate;
@@ -231,12 +231,10 @@
TEST(DownloadActionTest, PassObjectOutTest) {
GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
- const string path("/tmp/DownloadActionTest");
-
// takes ownership of passed in HttpFetcher
InstallPlan install_plan(false, "",
- OmahaHashCalculator::OmahaHashOfString("x"), path,
- "");
+ OmahaHashCalculator::OmahaHashOfString("x"),
+ "/dev/null");
ObjectFeederAction<InstallPlan> feeder_action;
feeder_action.set_obj(install_plan);
DownloadAction download_action(new MockHttpFetcher("x", 1));
@@ -267,7 +265,7 @@
const string path("/fake/path/that/cant/be/created/because/of/missing/dirs");
// takes ownership of passed in HttpFetcher
- InstallPlan install_plan(false, "", "", path, "");
+ InstallPlan install_plan(false, "", "", path);
ObjectFeederAction<InstallPlan> feeder_action;
feeder_action.set_obj(install_plan);
DownloadAction download_action(new MockHttpFetcher("x", 1));
diff --git a/filesystem_copier_action_unittest.cc b/filesystem_copier_action_unittest.cc
index 6d6f0ad..1e024f1 100644
--- a/filesystem_copier_action_unittest.cc
+++ b/filesystem_copier_action_unittest.cc
@@ -222,7 +222,7 @@
processor.set_delegate(&delegate);
ObjectFeederAction<InstallPlan> feeder_action;
- InstallPlan install_plan(true, "", "", "", "");
+ InstallPlan install_plan(true, "", "", "");
feeder_action.set_obj(install_plan);
FilesystemCopierAction copier_action;
ObjectCollectorAction<InstallPlan> collector_action;
@@ -246,7 +246,7 @@
processor.set_delegate(&delegate);
ObjectFeederAction<InstallPlan> feeder_action;
- InstallPlan install_plan(false, "", "", "", "/some/missing/file/path");
+ InstallPlan install_plan(false, "", "", "/some/missing/file/path");
feeder_action.set_obj(install_plan);
FilesystemCopierAction copier_action;
ObjectCollectorAction<InstallPlan> collector_action;
diff --git a/generate_delta_main.cc b/generate_delta_main.cc
index b64533b..551c6ef 100644
--- a/generate_delta_main.cc
+++ b/generate_delta_main.cc
@@ -25,11 +25,6 @@
namespace chromeos_update_engine {
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);
@@ -58,19 +53,8 @@
usage(argv[0]);
}
- 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,
- ""));
+ // TODO(adlr): generate delta file
+
return 0;
}
diff --git a/install_action.cc b/install_action.cc
deleted file mode 100644
index d144b7b..0000000
--- a/install_action.cc
+++ /dev/null
@@ -1,260 +0,0 @@
-// 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 <string>
-#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::string;
-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
- // Delete files that don't exist in the update, or exist but are
- // hard links.
- FilesystemIterator iter(mountpoint,
- utils::SetWithValue<string>("/lost+found"));
- for (; !iter.IsEnd(); iter.Increment()) {
- if (!parser.ContainsPath(iter.GetPartialPath()) ||
- parser.GetFileAtPath(iter.GetPartialPath()).has_hardlink_path()) {
- 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 (file.has_hardlink_path()) {
- TEST_AND_RETURN_FALSE(file.has_hardlink_path());
- TEST_AND_RETURN_FALSE_ERRNO(link(
- (mountpoint + file.hardlink_path()).c_str(),
- (mountpoint + path).c_str()) == 0);
- } else 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
- 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;
-}
-
-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(file.has_data_format());
- 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
diff --git a/install_action.h b/install_action.h
deleted file mode 100644
index 8bed632..0000000
--- a/install_action.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// 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.
-
-#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_INSTALL_ACTION_H__
-#define CHROMEOS_PLATFORM_UPDATE_ENGINE_INSTALL_ACTION_H__
-
-#include "base/scoped_ptr.h"
-#include "update_engine/action.h"
-#include "update_engine/delta_diff_parser.h"
-#include "update_engine/install_plan.h"
-#include "update_engine/update_metadata.pb.h"
-
-// The Install Action is responsible for ensuring the update that's been
-// downloaded has been installed. This may be a no-op in the case of a full
-// update, since those will be downloaded directly into the destination
-// partition. However, for a delta update some work is required.
-
-// An InstallPlan struct must be passed to this action before PerformAction()
-// is called so that this action knows if it's a delta update, and if so,
-// what the paths are.
-
-// TODO(adlr): At the moment, InstallAction is synchronous. It should be
-// updated to be asynchronous at some point.
-
-namespace chromeos_update_engine {
-
-class InstallAction;
-class NoneType;
-
-template<>
-class ActionTraits<InstallAction> {
- public:
- // Takes the InstallPlan for input
- typedef InstallPlan InputObjectType;
- // On success, puts the output device path on output
- typedef std::string OutputObjectType;
-};
-
-class InstallAction : public Action<InstallAction> {
- public:
- InstallAction() {}
- typedef ActionTraits<InstallAction>::InputObjectType InputObjectType;
- typedef ActionTraits<InstallAction>::OutputObjectType OutputObjectType;
- void PerformAction();
-
- // This action is synchronous for now.
- void TerminateProcessing() { CHECK(false); }
-
- // Debugging/logging
- static std::string StaticType() { return "InstallAction"; }
- std::string Type() const { return StaticType(); }
-
- private:
- // Installs 'file' into mountpoint. 'path' is the path that 'file'
- // should have when we reboot and mountpoint is root.
- bool InstallFile(const std::string& mountpoint,
- const DeltaArchiveManifest_File& file,
- const std::string& path,
- const DeltaDiffParser& parser) const;
- // These are helpers for InstallFile. They focus on specific file types:
- // Regular data files:
- bool InstallFileRegularFile(const std::string& mountpoint,
- const DeltaArchiveManifest_File& file,
- const std::string& path,
- const DeltaDiffParser& parser,
- const bool exists) const;
- // char/block devices, fifos, and sockets:
- bool InstallFileSpecialFile(const std::string& mountpoint,
- const DeltaArchiveManifest_File& file,
- const std::string& path,
- const DeltaDiffParser& parser,
- const bool exists) const;
- // symlinks:
- bool InstallFileSymlink(const std::string& mountpoint,
- const DeltaArchiveManifest_File& file,
- const std::string& path,
- const DeltaDiffParser& parser,
- const bool exists) const;
-
- DISALLOW_COPY_AND_ASSIGN(InstallAction);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_INSTALL_ACTION_H__
diff --git a/install_action_unittest.cc b/install_action_unittest.cc
deleted file mode 100644
index 3fd42d4..0000000
--- a/install_action_unittest.cc
+++ /dev/null
@@ -1,279 +0,0 @@
-// 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 <sys/stat.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <utime.h>
-#include <set>
-#include <string>
-#include <vector>
-#include "base/string_util.h"
-#include <gtest/gtest.h>
-#include "update_engine/delta_diff_generator.h"
-#include "update_engine/filesystem_iterator.h"
-#include "update_engine/install_action.h"
-#include "update_engine/test_utils.h"
-#include "update_engine/utils.h"
-
-using chromeos_update_engine::DeltaDiffGenerator;
-using chromeos_update_engine::kRandomString;
-using chromeos_update_engine::System;
-using chromeos_update_engine::utils::WriteFile;
-using std::set;
-using std::string;
-using std::vector;
-
-namespace {
-void GenerateFilesAtPath(const string& base) {
- EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("ln %s/hi %s/hard_link", base.c_str(),
- base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("mkdir -p %s/dir", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("echo hello > %s/dir/hello", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("echo -n > %s/dir/newempty", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("rm -f %s/dir/bdev", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("mknod %s/dir/bdev b 3 1", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("rm -f %s/cdev", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 1", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("mkdir -p %s/dir/subdir", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("mkdir -p %s/dir/emptydir", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("echo -n foo > %s/dir/bigfile",
- base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("chown 501:503 %s/dir/emptydir",
- base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("rm -f %s/dir/subdir/fifo", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("mkfifo %s/dir/subdir/fifo", base.c_str())));
- EXPECT_EQ(0, System(StringPrintf("ln -f -s /target %s/dir/subdir/link",
- base.c_str())));
- EXPECT_TRUE(WriteFile((base + "/big_file").c_str(),
- reinterpret_cast<const char*>(kRandomString),
- sizeof(kRandomString)));
-}
-
-// Returns true if files at paths a, b are equal and there are no errors.
-bool FilesEqual(const string& a, const string& b) {
- struct stat a_stbuf;
- struct stat b_stbuf;
-
- int r = lstat(a.c_str(), &a_stbuf);
- TEST_AND_RETURN_FALSE_ERRNO(r == 0);
- r = lstat(b.c_str(), &b_stbuf);
- TEST_AND_RETURN_FALSE_ERRNO(r == 0);
-
- TEST_AND_RETURN_FALSE(a_stbuf.st_mode == b_stbuf.st_mode);
- if (S_ISBLK(a_stbuf.st_mode) || S_ISCHR(a_stbuf.st_mode))
- TEST_AND_RETURN_FALSE(a_stbuf.st_rdev == b_stbuf.st_rdev);
- if (!S_ISDIR(a_stbuf.st_mode))
- TEST_AND_RETURN_FALSE(a_stbuf.st_nlink == b_stbuf.st_nlink);
- if (!S_ISREG(a_stbuf.st_mode)) {
- return true;
- }
- // Compare files
- TEST_AND_RETURN_FALSE(a_stbuf.st_size == b_stbuf.st_size);
- vector<char> a_data;
- TEST_AND_RETURN_FALSE(chromeos_update_engine::utils::ReadFile(a, &a_data));
- vector<char> b_data;
- TEST_AND_RETURN_FALSE(chromeos_update_engine::utils::ReadFile(b, &b_data));
- TEST_AND_RETURN_FALSE(a_data == b_data);
- return true;
-}
-
-class ScopedLoopDevUnmapper {
- public:
- explicit ScopedLoopDevUnmapper(const string& dev) : dev_(dev) {}
- ~ScopedLoopDevUnmapper() {
- EXPECT_EQ(0, System(string("losetup -d ") + dev_));
- }
- private:
- string dev_;
-};
-
-}
-
-namespace chromeos_update_engine {
-
-class InstallActionTest : public ::testing::Test { };
-
-TEST(InstallActionTest, RunAsRootDiffTest) {
- ASSERT_EQ(0, getuid());
- string loop_dev = GetUnusedLoopDevice();
- ScopedLoopDevUnmapper loop_dev_unmapper(loop_dev);
- LOG(INFO) << "Using loop device: " << loop_dev;
- const string original_image("orig.image");
- const string original_dir("orig");
- const string new_dir("new");
-
- ASSERT_EQ(0, System(string("dd if=/dev/zero of=") + original_image +
- " bs=5M count=1"));
- ASSERT_EQ(0, System(string("mkfs.ext3 -F ") + original_image));
- ASSERT_EQ(0, System(string("losetup ") + loop_dev + " " + original_image));
- ASSERT_EQ(0, System(string("mkdir ") + original_dir));
- ASSERT_EQ(0, System(string("mount ") + loop_dev + " " + original_dir));
- ASSERT_EQ(0, System(string("mkdir ") + new_dir));
-
- GenerateFilesAtPath(original_dir);
- GenerateFilesAtPath(new_dir);
-
- {
- // Fill bigfile w/ some data in the new folder
- vector<char> buf(100 * 1024);
- for (unsigned int i = 0; i < buf.size(); i++) {
- buf[i] = static_cast<char>(i);
- }
- EXPECT_TRUE(WriteFileVector(new_dir + "/dir/bigfile", buf));
- }
- 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 "
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
- "'%s/compress_sym'", new_dir_cstr)));
-
- // Make a device that will compress
- EXPECT_EQ(0, mknod((new_dir + "/bdev_gz").c_str(), S_IFCHR | 0644, 0));
-
- // Make a diff
- DeltaArchiveManifest* delta =
- DeltaDiffGenerator::EncodeMetadataToProtoBuffer(new_dir.c_str());
- EXPECT_TRUE(NULL != delta);
- EXPECT_TRUE(DeltaDiffGenerator::EncodeDataToDeltaFile(delta,
- original_dir,
- new_dir,
- "delta",
- set<string>(),
- new_dir + "/bdev_gz"));
-
- ASSERT_EQ(0, System(string("umount ") + original_dir));
-
- ObjectFeederAction<InstallPlan> feeder_action;
- InstallAction install_action;
- ObjectCollectorAction<string> collector_action;
-
- BondActions(&feeder_action, &install_action);
- BondActions(&install_action, &collector_action);
-
- ActionProcessor processor;
- processor.EnqueueAction(&feeder_action);
- processor.EnqueueAction(&install_action);
- processor.EnqueueAction(&collector_action);
-
- InstallPlan install_plan(false, "", "", "delta", loop_dev);
- feeder_action.set_obj(install_plan);
-
- processor.StartProcessing();
- EXPECT_FALSE(processor.IsRunning()) << "Update to handle async actions";
-
- EXPECT_EQ(loop_dev, collector_action.object());
-
- ASSERT_EQ(0, System(string("mount ") + loop_dev + " " + original_dir));
-
- // Check that original_dir and new_dir are equal
- int original_count = 0;
- LOG(INFO) << "checking old";
- {
- FilesystemIterator iter(original_dir,
- utils::SetWithValue<string>("/lost+found"));
- for (; !iter.IsEnd(); iter.Increment()) {
- original_count++;
- LOG(INFO) << "checking path: " << iter.GetPartialPath();
- EXPECT_TRUE(FilesEqual(original_dir + iter.GetPartialPath(),
- new_dir + iter.GetPartialPath()));
- }
- EXPECT_FALSE(iter.IsErr());
- }
- LOG(INFO) << "checking new";
- int new_count = 0;
- {
- FilesystemIterator iter(new_dir, set<string>());
- for (; !iter.IsEnd(); iter.Increment()) {
- new_count++;
- LOG(INFO) << "checking path: " << iter.GetPartialPath();
- EXPECT_TRUE(FilesEqual(original_dir + iter.GetPartialPath(),
- new_dir + iter.GetPartialPath()));
- }
- EXPECT_FALSE(iter.IsErr());
- }
- LOG(INFO) << "new_count = " << new_count;
- EXPECT_EQ(new_count, original_count);
- EXPECT_EQ(20, original_count);
-
- // Make sure hard-link installed properly
- {
- struct stat hard_link_stbuf;
- struct stat hi_stbuf;
- EXPECT_EQ(0, lstat((string(new_dir) + "/hard_link").c_str(),
- &hard_link_stbuf));
- EXPECT_EQ(0, lstat((string(new_dir) + "/hi").c_str(), &hi_stbuf));
- EXPECT_EQ(hard_link_stbuf.st_mode, hi_stbuf.st_mode);
- EXPECT_EQ(2, hard_link_stbuf.st_nlink);
- EXPECT_EQ(2, hi_stbuf.st_nlink);
- EXPECT_EQ(hi_stbuf.st_ino, hard_link_stbuf.st_ino);
- }
-
- EXPECT_EQ(0, System(string("umount ") + original_dir));
-
- // Cleanup generated files
- EXPECT_EQ(0, System(string("rm -rf ") + original_dir));
- EXPECT_EQ(0, System(string("rm -rf ") + new_dir));
- EXPECT_EQ(0, System(string("rm -f ") + original_image));
- EXPECT_EQ(0, system("rm -f delta"));
-}
-
-TEST(InstallActionTest, FullUpdateTest) {
- ObjectFeederAction<InstallPlan> feeder_action;
- InstallAction install_action;
- ObjectCollectorAction<string> collector_action;
-
- BondActions(&feeder_action, &install_action);
- BondActions(&install_action, &collector_action);
-
- ActionProcessor processor;
- processor.EnqueueAction(&feeder_action);
- processor.EnqueueAction(&install_action);
- processor.EnqueueAction(&collector_action);
-
- InstallPlan install_plan(true, "", "", "delta", "install_path");
- feeder_action.set_obj(install_plan);
-
- processor.StartProcessing();
- EXPECT_FALSE(processor.IsRunning()) << "Update to handle async actions";
- EXPECT_EQ("install_path", collector_action.object());
-}
-
-TEST(InstallActionTest, InvalidDeltaFileTest) {
- ObjectFeederAction<InstallPlan> feeder_action;
- InstallAction install_action;
- ObjectCollectorAction<string> collector_action;
-
- BondActions(&feeder_action, &install_action);
- BondActions(&install_action, &collector_action);
-
- ActionProcessor processor;
- processor.EnqueueAction(&feeder_action);
- processor.EnqueueAction(&install_action);
- processor.EnqueueAction(&collector_action);
-
- InstallPlan install_plan(false, "", "", "no_such_file", "install_path");
- feeder_action.set_obj(install_plan);
-
- processor.StartProcessing();
- EXPECT_FALSE(processor.IsRunning()) << "Update to handle async actions";
- EXPECT_TRUE(collector_action.object().empty());
-}
-
-} // namespace chromeos_update_engine
diff --git a/install_plan.h b/install_plan.h
index 81893d8..9151e1b 100644
--- a/install_plan.h
+++ b/install_plan.h
@@ -17,26 +17,22 @@
InstallPlan(bool is_full,
const std::string& url,
const std::string& hash,
- const std::string& d_path,
- const std::string& i_path)
+ const std::string& install_path)
: is_full_update(is_full),
download_url(url),
download_hash(hash),
- download_path(d_path),
- install_path(i_path) {}
+ install_path(install_path) {}
InstallPlan() : is_full_update(false) {}
bool is_full_update;
std::string download_url; // url to download from
std::string download_hash; // hash of the data at the url
- std::string download_path; // path to downloaded file from Omaha
std::string install_path; // path to install device
bool operator==(const InstallPlan& that) const {
return (is_full_update == that.is_full_update) &&
(download_url == that.download_url) &&
(download_hash == that.download_hash) &&
- (download_path == that.download_path) &&
(install_path == that.install_path);
}
bool operator!=(const InstallPlan& that) const {
@@ -46,7 +42,6 @@
LOG(INFO) << "InstallPlan: "
<< (is_full_update ? "full_update" : "delta_update")
<< ", url: " << download_url << ", hash: " << download_hash
- << ", path: " << download_path
<< ", install_path: " << install_path;
}
};
diff --git a/main.cc b/main.cc
index bbd9927..cbd6e44 100644
--- a/main.cc
+++ b/main.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// TODO(adlr): get rid of commented out lines or comment them back in.
+// Look for "// re-add" next to those comments.
+
#include <string>
#include <tr1/memory>
#include <vector>
@@ -11,7 +14,7 @@
#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/install_action.h" // re-add
#include "update_engine/libcurl_http_fetcher.h"
#include "update_engine/omaha_request_prep_action.h"
#include "update_engine/omaha_response_handler_action.h"
@@ -64,8 +67,8 @@
new FilesystemCopierAction);
shared_ptr<DownloadAction> download_action(
new DownloadAction(new LibcurlHttpFetcher));
- shared_ptr<InstallAction> install_action(
- new InstallAction);
+ // shared_ptr<InstallAction> install_action( // re-add
+ // new InstallAction);
shared_ptr<PostinstallRunnerAction> postinstall_runner_action(
new PostinstallRunnerAction);
shared_ptr<SetBootableFlagAction> set_bootable_flag_action(
@@ -78,7 +81,7 @@
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>(install_action)); // re-add
actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action));
actions_.push_back(shared_ptr<AbstractAction>(set_bootable_flag_action));
@@ -94,8 +97,8 @@
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(download_action.get(), install_action.get()); // re-add
+ // BondActions(install_action.get(), postinstall_runner_action.get());
BondActions(postinstall_runner_action.get(), set_bootable_flag_action.get());
processor_.StartProcessing();
diff --git a/omaha_response_handler_action.cc b/omaha_response_handler_action.cc
index 0a0a660..4bdef7d 100644
--- a/omaha_response_handler_action.cc
+++ b/omaha_response_handler_action.cc
@@ -47,9 +47,6 @@
// Very long name. Let's shorten it
filename.resize(255);
}
- // TODO(adlr): come up with a better place to download to:
- 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_unittest.cc b/omaha_response_handler_action_unittest.cc
index a76838a..4464332 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -93,9 +93,6 @@
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(string(utils::kStatefulPartition) +
- "/the_update_a.b.c.d_FULL_.tgz",
- install_plan.download_path);
EXPECT_EQ("/dev/sda2", install_plan.install_path);
}
{
@@ -113,9 +110,6 @@
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(string(utils::kStatefulPartition) +
- "/the_update_a.b.c.d_DELTA_.tgz",
- install_plan.download_path);
EXPECT_EQ("/dev/sda3", install_plan.install_path);
}
{
@@ -133,9 +127,6 @@
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(string(utils::kStatefulPartition) + "/" +
- kLongName.substr(0, 255),
- install_plan.download_path);
EXPECT_EQ("/dev/sda3", install_plan.install_path);
}
}
@@ -148,7 +139,6 @@
EXPECT_FALSE(install_plan.is_full_update);
EXPECT_EQ("", install_plan.download_url);
EXPECT_EQ("", install_plan.download_hash);
- EXPECT_EQ("", install_plan.download_path);
EXPECT_EQ("", install_plan.install_path);
}
diff --git a/test_installer_main.cc b/test_installer_main.cc
index 96e257d..435f5d4 100644
--- a/test_installer_main.cc
+++ b/test_installer_main.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// TODO(adlr): get rid of commented out lines or comment them back in.
+// Look for "// re-add" next to those comments.
+
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -17,7 +20,7 @@
#include "update_engine/delta_diff_generator.h"
#include "update_engine/delta_diff_parser.h"
#include "update_engine/filesystem_copier_action.h"
-#include "update_engine/install_action.h"
+// #include "update_engine/install_action.h" // re-add
#include "update_engine/install_plan.h"
#include "update_engine/test_utils.h"
#include "update_engine/update_metadata.pb.h"
@@ -46,7 +49,6 @@
const string& install_path)
: loop_(loop),
sys_root_(sys_root),
- delta_path_(delta_path),
install_path_(install_path) {}
void Update();
@@ -57,7 +59,6 @@
ActionProcessor processor_;
GMainLoop *loop_;
string sys_root_;
- string delta_path_;
string install_path_;
};
@@ -73,12 +74,12 @@
new ObjectFeederAction<InstallPlan>);
shared_ptr<FilesystemCopierAction> filesystem_copier_action(
new FilesystemCopierAction);
- shared_ptr<InstallAction> install_action(
- new InstallAction);
+ // shared_ptr<InstallAction> install_action( // re-add
+ // new InstallAction);
actions_.push_back(object_feeder_action);
actions_.push_back(filesystem_copier_action);
- actions_.push_back(install_action);
+ // actions_.push_back(install_action); // re-add
// Enqueue the actions
for (vector<shared_ptr<AbstractAction> >::iterator it = actions_.begin();
@@ -89,12 +90,12 @@
// Bond them together. We have to use the leaf-types when calling
// BondActions().
BondActions(object_feeder_action.get(), filesystem_copier_action.get());
- BondActions(filesystem_copier_action.get(), install_action.get());
+ // re-add
+ // BondActions(filesystem_copier_action.get(), install_action.get());
InstallPlan install_plan(false,
"",
"",
- delta_path_,
install_path_);
filesystem_copier_action->set_copy_source(sys_root_);
object_feeder_action->set_obj(install_plan);
@@ -131,50 +132,6 @@
LOG(INFO) << "starting";
- if (!FLAGS_dump_delta.empty()) {
- CHECK(FLAGS_delta.empty());
- CHECK(FLAGS_root.empty());
- CHECK(FLAGS_output_dev.empty());
-
- DeltaDiffParser parser(FLAGS_dump_delta);
- for (DeltaDiffParser::Iterator it = parser.Begin();
- it != parser.End(); it.Increment()) {
- DeltaArchiveManifest_File file = it.GetFile();
- const char* format = "---";
- ssize_t offset = -1;
- ssize_t length = -1;
- if (file.has_data_format()) {
- switch (file.data_format()) {
- case DeltaArchiveManifest_File_DataFormat_FULL:
- format = "FULL";
- break;
- case DeltaArchiveManifest_File_DataFormat_FULL_GZ:
- format = "FULL_GZ";
- break;
- case DeltaArchiveManifest_File_DataFormat_BSDIFF:
- format = "BSDIFF";
- break;
- case DeltaArchiveManifest_File_DataFormat_COURGETTE:
- format = "COURGETTE";
- break;
- default:
- format = "???";
- }
- if (file.has_data_offset())
- offset = file.data_offset();
- if (file.has_data_length())
- length = file.data_length();
- }
- printf("%s %o %s %d %d\n", it.path().c_str(), file.mode(), format, offset,
- length);
- }
- exit(0);
- }
-
- CHECK(!FLAGS_delta.empty());
- CHECK(!FLAGS_root.empty());
- CHECK(!FLAGS_output_dev.empty());
-
// Create the single GMainLoop
GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
diff --git a/update_metadata.proto b/update_metadata.proto
index 42880da..115d513 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -7,8 +7,10 @@
// version. The update format is represented by this struct pseudocode:
// struct delta_update_file {
// char magic[4] = "CrAU";
-// uint64 bom_offset; // Offset of protobuf DeltaArchiveManifest
-// uint64 bom_size; // Sise of protobuf DeltaArchiveManifest
+// uint32 file_format_version = 1;
+// uint64 manifest_size; // Size of protobuf DeltaArchiveManifest
+// // The Bzip2 compressed DeltaArchiveManifest
+// char manifest[];
//
// // Data blobs for files, no specific format. The specific offset
// // and length of each data blob is recorded in the DeltaArchiveManifest.
@@ -16,121 +18,82 @@
// char data[];
// } blobs[];
//
-// // The Gzip compressed DeltaArchiveManifest
-// char bom[];
// };
-// The DeltaArchiveManifest protobuf is an ordered list of File objects.
-// These File objects are stored in a linear array in the
-// DeltaArchiveManifest, each with a specific index. Each File object
-// can contain children in its children list. Each child in the list
-// has a name and an index. The index refers to the index within
-// DeltaArchiveManifest.files. Thus, the DeltaArchiveManifest.files
-// can be seen as a tree structure that mimicks the filesystem.
-// The root object (the object an index 0) has no name, since names
-// for children are stored in the parent.
+// The DeltaArchiveManifest protobuf is an ordered list of InstallOperation
+// objects. These objects are stored in a linear array in the
+// DeltaArchiveManifest. Each operation is applied in order by the client.
-// The DeltaArchiveManifest will contain one File entry for each
-// file that will be on the resultant filesystem. Because we have
-// a tree structure, and children are ordered alphabetically within
-// a parent, we can do log-time˜path lookup on a DeltaArchiveManifest
-// object. We can also iterate through a DeltaArchiveManifest object
-// using a preorder tree traversal to see each file in the
-// DeltaArchiveManifest, seeing each directory before any of its children;
-// this takes linear time.
+// The DeltaArchiveManifest also contains the initial and final
+// checksums for the device.
-// Here's an example from Dan Erat showing DeltaArchiveManifest
-// for a filesystem with files /bin/cat and /bin/ls.:
-
-// files[0] { // "/" directory
-// children[0] {
-// name "bin"
-// index 1
-// }
-// }
-// files[1] { // "/bin" directory
-// children[0] {
-// name "cat"
-// index 2
-// }
-// children[1] {
-// name "ls"
-// index 3
-// }
-// }
-// files[2] { // "/bin/cat"
-// }
-// files[3] { // "/bin/ls"
-// }
-
-// If a file has a data_format set, it should also have data_offset and
-// data_length set. data_offset and data_length refer to a range of bytes
-// in the delta update file itself which have the format specified by
-// data_format. FULL and FULL_GZ mean the entire file is present (FULL_GZ,
-// gzip compressed). BSDIFF means the old file with the same path should be
-// patched with 'bspatch' to produce the desired output file. COURGETTE
-// is not yet used, but it will be another binary diff format.
-
-// Directories should not have any data.
-
-// There are other types of files, too: symlinks, block and character devices,
-// fifos, and sockets. Fifos and sockets contain no data. Block and
-// character devices have data. It must be the format FULL or FULL_GZ, and
-// the contents are a serialized LinuxDevice protobuf. Symlinks must either
-// be FULL, FULL_GZ, or have no data. A symlink with no data is unchanged,
-// and with data it's set to that data.
-
-// TODO(adlr): Add support for hard links; CL is prepared already.
-// Extended attributes are unsupported at this time.
+// The client will perform each InstallOperation in order, beginning even
+// before the entire delta file is downloaded (but after at least the
+// protobuf is downloaded). The types of operations are explained:
+// - REPLACE: Replace the dst_extents on the drive with the attached data,
+// zero padding out to block size.
+// - REPLACE_BZ: bzip2-uncompress the attached data and write it into
+// dst_extents on the drive, zero padding to block size.
+// - MOVE: Copy the data in src_extents to dst_extents. Extents may overlap,
+// so it may be desirable to read all src_extents data into memory before
+// writing it out.
+// - BSDIFF: Read src_length bytes from src_extents into memory, perform
+// bspatch with attached data, write new data to dst_extents, zero padding
+// to block size.
package chromeos_update_engine;
-message DeltaArchiveManifest {
- message File {
- // This is st_mode from struct stat. It includes file type and permission
- // bits.
- optional uint32 mode = 1;
- optional uint32 uid = 2;
- optional uint32 gid = 3;
+// Data is packed into blocks on disk, always starting from the beginning
+// of the block. If a file's data is too large for one block, it overflows
+// into another block, which may or may not be the following block on the
+// physical partition. An ordered list of extents is another
+// representation of an ordered list of blocks. For example, a file stored
+// in blocks 9, 10, 11, 2, 18, 12 (in that order) would be stored in
+// extents { {9, 3}, {2, 1}, {18, 1}, {12, 1} } (in that order).
+// In general, files are stored sequentially on disk, so it's more efficient
+// to use extents to encode the block lists (this is effectively
+// run-length encoding).
+// A sentinel value (kuint64max) as the start block denotes a sparse-hole
+// in a file whose block-length is specified by num_blocks.
- // File Data, not for directories
- enum DataFormat {
- FULL = 0; // The data is the complete file
- FULL_GZ = 1; // The data is the complete file gzipped
- BSDIFF = 2; // The data is a bsdiff binary diff
- COURGETTE = 3; // The data is a courgette binary diff
- }
- // 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;
- // The length of the data in the delta file
- optional uint32 data_length = 6;
-
- // When a file is a hard link, hardlink_path exists and
- // is the path within the DeltaArchiveManifest to the "original" file.
- // When iterating through a DeltaArchiveManifest, you will be guaranteed
- // to hit a hardlink only after you've hit the path to the first file.
- // Directories can't be hardlinked.
- optional string hardlink_path = 8;
-
- message Child {
- // A File that's a directory (and only those types of File objects)
- // will have exactly one Child submessage per child.
- required string name = 1; // File name of child
-
- // Index into DeltaArchiveManifest.files for the File object of the child.
- required uint32 index = 2;
- }
- repeated Child children = 9;
- }
- repeated File files = 1;
+message Extent {
+ optional uint64 start_block = 1;
+ optional uint64 num_blocks = 2;
}
-message LinuxDevice {
- required int32 major = 1;
- required int32 minor = 2;
-}
\ No newline at end of file
+message DeltaArchiveManifest {
+ message InstallOperation {
+ enum Type {
+ REPLACE = 0; // Replace destination extents w/ attached data
+ REPLACE_BZ = 1; // Replace destination extents w/ attached bzipped data
+ MOVE = 2; // Move source extents to destination extents
+ BSDIFF = 3; // The data is a bsdiff binary diff
+ }
+ required Type type = 1;
+ // The offset into the delta file (after the protobuf)
+ // where the data (if any) is stored
+ optional uint32 data_offset = 2;
+ // The length of the data in the delta file
+ optional uint32 data_length = 3;
+
+ // Ordered list of extents that are read from (if any) and written to.
+ repeated Extent src_extents = 4;
+ // Byte length of src, not necessarily block aligned. It's only used for
+ // BSDIFF, because we need to pass that external program the number
+ // of bytes to read from the blocks we pass it.
+ optional uint64 src_length = 5;
+
+ repeated Extent dst_extents = 6;
+ // byte length of dst, not necessarily block aligned. It's only used for
+ // BSDIFF, because we need to fill in the rest of the last block
+ // that bsdiff writes with '\0' bytes.
+ optional uint64 dst_length = 7;
+ }
+ repeated InstallOperation install_operations = 1;
+ // The checksums of the install device before and after the install process.
+ optional string src_checksum = 2;
+ optional string dst_checksum = 3;
+
+ // (At time of writing) usually 4096
+ optional uint32 block_size = 5 [default = 4096];
+}