blob: eee25ccfd241cb1f8a9447325ee060c4c259167b [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
rspangler@google.com49fdf182009-10-10 00:57:34 +00005#include "update_engine/download_action.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +00006#include <errno.h>
7#include <algorithm>
Andrew de los Reyesf9714432010-05-04 10:21:23 -07008#include <string>
9#include <vector>
adlr@google.comc98a7ed2009-12-04 18:54:03 +000010#include <glib.h>
11#include "update_engine/action_pipe.h"
Andrew de los Reyesf9714432010-05-04 10:21:23 -070012#include "update_engine/subprocess.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000013
14using std::min;
Andrew de los Reyesf9714432010-05-04 10:21:23 -070015using std::string;
16using std::vector;
rspangler@google.com49fdf182009-10-10 00:57:34 +000017
18namespace chromeos_update_engine {
19
adlr@google.comc98a7ed2009-12-04 18:54:03 +000020DownloadAction::DownloadAction(HttpFetcher* http_fetcher)
Andrew de los Reyesf9185172010-05-03 11:07:05 -070021 : writer_(NULL),
rspangler@google.com49fdf182009-10-10 00:57:34 +000022 http_fetcher_(http_fetcher) {}
23
24DownloadAction::~DownloadAction() {}
25
26void DownloadAction::PerformAction() {
27 http_fetcher_->set_delegate(this);
rspangler@google.com49fdf182009-10-10 00:57:34 +000028
adlr@google.comc98a7ed2009-12-04 18:54:03 +000029 // Get the InstallPlan and read it
30 CHECK(HasInputObject());
Andrew de los Reyesf9185172010-05-03 11:07:05 -070031 install_plan_ = GetInputObject();
adlr@google.comc98a7ed2009-12-04 18:54:03 +000032
Andrew de los Reyesf9185172010-05-03 11:07:05 -070033 install_plan_.Dump();
adlr@google.comc98a7ed2009-12-04 18:54:03 +000034
Andrew de los Reyesf9185172010-05-03 11:07:05 -070035 if (writer_) {
36 LOG(INFO) << "Using writer for test.";
rspangler@google.com49fdf182009-10-10 00:57:34 +000037 } else {
Andrew de los Reyesf9185172010-05-03 11:07:05 -070038 if (install_plan_.is_full_update) {
39 kernel_file_writer_.reset(new DirectFileWriter);
40 rootfs_file_writer_.reset(new DirectFileWriter);
41 split_file_writer_.reset(new SplitFileWriter(kernel_file_writer_.get(),
42 rootfs_file_writer_.get()));
43 split_file_writer_->SetFirstOpenArgs(
44 install_plan_.kernel_install_path.c_str(),
45 O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE,
46 0644);
47 decompressing_file_writer_.reset(
48 new GzipDecompressingFileWriter(split_file_writer_.get()));
49 writer_ = decompressing_file_writer_.get();
50 } else {
51 delta_performer_.reset(new DeltaPerformer);
52 writer_ = delta_performer_.get();
53 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000054 }
Andrew de los Reyesf9185172010-05-03 11:07:05 -070055 int rc = writer_->Open(install_plan_.install_path.c_str(),
56 O_TRUNC | O_WRONLY | O_CREAT | O_LARGEFILE,
57 0644);
rspangler@google.com49fdf182009-10-10 00:57:34 +000058 if (rc < 0) {
Andrew de los Reyesf9185172010-05-03 11:07:05 -070059 LOG(ERROR) << "Unable to open output file " << install_plan_.install_path;
rspangler@google.com49fdf182009-10-10 00:57:34 +000060 // report error to processor
61 processor_->ActionComplete(this, false);
62 return;
63 }
Andrew de los Reyesf9185172010-05-03 11:07:05 -070064 if (!install_plan_.is_full_update) {
65 if (!delta_performer_->OpenKernel(
66 install_plan_.kernel_install_path.c_str())) {
67 LOG(ERROR) << "Unable to open kernel file "
68 << install_plan_.kernel_install_path.c_str();
69 writer_->Close();
70 processor_->ActionComplete(this, false);
71 return;
72 }
73 }
74 http_fetcher_->BeginTransfer(install_plan_.download_url);
rspangler@google.com49fdf182009-10-10 00:57:34 +000075}
76
77void DownloadAction::TerminateProcessing() {
78 CHECK(writer_);
79 CHECK_EQ(writer_->Close(), 0);
80 writer_ = NULL;
81 http_fetcher_->TerminateTransfer();
82}
83
84void DownloadAction::ReceivedBytes(HttpFetcher *fetcher,
85 const char* bytes,
86 int length) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000087 int rc = writer_->Write(bytes, length);
88 TEST_AND_RETURN(rc >= 0);
rspangler@google.com49fdf182009-10-10 00:57:34 +000089 omaha_hash_calculator_.Update(bytes, length);
90}
91
Andrew de los Reyesf9714432010-05-04 10:21:23 -070092namespace {
93void FlushLinuxCaches() {
94 vector<string> command;
95 command.push_back("/bin/sync");
96 int rc;
97 LOG(INFO) << "FlushLinuxCaches/sync...";
98 Subprocess::SynchronousExec(command, &rc);
99 LOG(INFO) << "FlushLinuxCaches/drop_caches...";
100
101 const char* const drop_cmd = "3\n";
102 utils::WriteFile("/proc/sys/vm/drop_caches", drop_cmd, strlen(drop_cmd));
103
104 LOG(INFO) << "FlushLinuxCaches done.";
105}
106}
107
rspangler@google.com49fdf182009-10-10 00:57:34 +0000108void DownloadAction::TransferComplete(HttpFetcher *fetcher, bool successful) {
109 if (writer_) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000110 CHECK_EQ(writer_->Close(), 0) << errno;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000111 writer_ = NULL;
112 }
113 if (successful) {
114 // Make sure hash is correct
115 omaha_hash_calculator_.Finalize();
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700116 if (omaha_hash_calculator_.hash() != install_plan_.download_hash) {
117 LOG(ERROR) << "Download of " << install_plan_.download_url
118 << " failed. Expect hash " << install_plan_.download_hash
119 << " but got hash " << omaha_hash_calculator_.hash();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000120 successful = false;
121 }
122 }
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700123
124 FlushLinuxCaches();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000125
126 // Write the path to the output pipe if we're successful
127 if (successful && HasOutputPipe())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000128 SetOutputObject(GetInputObject());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000129 processor_->ActionComplete(this, successful);
130}
131
132}; // namespace {}