blob: 18bab4464180f030fdcc12500f27cc9407ab4b1b [file] [log] [blame]
Andrew de los Reyesc7020782010-04-28 10:46:04 -07001// Copyright (c) 2010 The Chromium Authors. All rights reserved.
adlr@google.com3defe6a2009-12-04 20:57:17 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/filesystem_copier_action.h"
6#include <sys/stat.h>
7#include <sys/types.h>
8#include <errno.h>
9#include <fcntl.h>
10#include <stdlib.h>
11#include <algorithm>
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -080012#include <map>
adlr@google.com3defe6a2009-12-04 20:57:17 +000013#include <string>
14#include <vector>
Andrew de los Reyesc7020782010-04-28 10:46:04 -070015#include <gio/gio.h>
16#include <gio/gunixinputstream.h>
17#include <gio/gunixoutputstream.h>
18#include <glib.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000019#include "update_engine/filesystem_iterator.h"
20#include "update_engine/subprocess.h"
21#include "update_engine/utils.h"
22
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -080023using std::map;
adlr@google.com3defe6a2009-12-04 20:57:17 +000024using std::min;
25using std::string;
26using std::vector;
27
28namespace chromeos_update_engine {
29
30namespace {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070031const off_t kCopyFileBufferSize = 2 * 1024 * 1024;
adlr@google.com3defe6a2009-12-04 20:57:17 +000032} // namespace {}
33
34void FilesystemCopierAction::PerformAction() {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070035 // Will tell the ActionProcessor we've failed if we return.
36 ScopedActionCompleter abort_action_completer(processor_, this);
37
adlr@google.com3defe6a2009-12-04 20:57:17 +000038 if (!HasInputObject()) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070039 LOG(ERROR) << "FilesystemCopierAction missing input object.";
adlr@google.com3defe6a2009-12-04 20:57:17 +000040 return;
41 }
42 install_plan_ = GetInputObject();
43
44 if (install_plan_.is_full_update) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070045 // No copy needed. Done!
46 abort_action_completer.set_success(true);
adlr@google.com3defe6a2009-12-04 20:57:17 +000047 return;
48 }
49
Andrew de los Reyesc7020782010-04-28 10:46:04 -070050 const string source =
51 copy_source_.empty() ? utils::BootDevice() : copy_source_;
52 LOG(INFO) << "Copying from " << source << " to "
53 << install_plan_.install_path;
54
55 int src_fd = open(source.c_str(), O_RDONLY);
56 if (src_fd < 0) {
57 PLOG(ERROR) << "Unable to open " << source << " for reading:";
58 return;
59 }
60 int dst_fd = open(install_plan_.install_path.c_str(),
61 O_WRONLY | O_TRUNC | O_CREAT,
62 0644);
63 if (dst_fd < 0) {
64 close(src_fd);
65 PLOG(ERROR) << "Unable to open " << install_plan_.install_path
66 << " for writing:";
67 return;
adlr@google.com3defe6a2009-12-04 20:57:17 +000068 }
69
Andrew de los Reyesc7020782010-04-28 10:46:04 -070070 src_stream_ = g_unix_input_stream_new(src_fd, TRUE);
71 dst_stream_ = g_unix_output_stream_new(dst_fd, TRUE);
72
73 buffer_.resize(kCopyFileBufferSize);
74
75 // Set up the first read
76 canceller_ = g_cancellable_new();
77
78 g_input_stream_read_async(src_stream_,
79 &buffer_[0],
80 buffer_.size(),
81 G_PRIORITY_DEFAULT,
82 canceller_,
83 &FilesystemCopierAction::StaticAsyncReadyCallback,
84 this);
85 read_in_flight_ = true;
86
87 abort_action_completer.set_should_complete(false);
adlr@google.com3defe6a2009-12-04 20:57:17 +000088}
89
90void FilesystemCopierAction::TerminateProcessing() {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070091 if (canceller_) {
92 g_cancellable_cancel(canceller_);
adlr@google.com3defe6a2009-12-04 20:57:17 +000093 }
94}
95
Andrew de los Reyesc7020782010-04-28 10:46:04 -070096void FilesystemCopierAction::Cleanup(bool success, bool was_cancelled) {
97 g_object_unref(src_stream_);
98 src_stream_ = NULL;
99 g_object_unref(dst_stream_);
100 dst_stream_ = NULL;
101 if (was_cancelled)
102 return;
103 if (success && HasOutputPipe())
adlr@google.com3defe6a2009-12-04 20:57:17 +0000104 SetOutputObject(install_plan_);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000105 processor_->ActionComplete(this, success);
106}
107
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700108void FilesystemCopierAction::AsyncReadyCallback(GObject *source_object,
109 GAsyncResult *res) {
110 GError* error = NULL;
111 CHECK(canceller_);
112 bool was_cancelled = g_cancellable_is_cancelled(canceller_) == TRUE;
113 g_object_unref(canceller_);
114 canceller_ = NULL;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000115
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700116 if (read_in_flight_) {
117 ssize_t bytes_read = g_input_stream_read_finish(src_stream_, res, &error);
118 if (bytes_read < 0) {
119 LOG(ERROR) << "Read failed:" << utils::GetGErrorMessage(error);
120 Cleanup(false, was_cancelled);
121 return;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000122 }
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700123
124 if (bytes_read == 0) {
125 // We're done!
126 Cleanup(true, was_cancelled);
127 return;
128 }
129 // Kick off a write
130 read_in_flight_ = false;
131 buffer_valid_size_ = bytes_read;
132 canceller_ = g_cancellable_new();
133 g_output_stream_write_async(
134 dst_stream_,
135 &buffer_[0],
136 bytes_read,
137 G_PRIORITY_DEFAULT,
138 canceller_,
139 &FilesystemCopierAction::StaticAsyncReadyCallback,
140 this);
141 return;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000142 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000143
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700144 ssize_t bytes_written = g_output_stream_write_finish(dst_stream_,
145 res,
146 &error);
147 if (bytes_written < static_cast<ssize_t>(buffer_valid_size_)) {
148 if (bytes_written < 0) {
149 LOG(ERROR) << "Write failed:" << utils::GetGErrorMessage(error);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000150 } else {
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700151 LOG(ERROR) << "Write was short: wrote " << bytes_written
152 << " but expected to write " << buffer_valid_size_;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000153 }
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700154 Cleanup(false, was_cancelled);
155 return;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000156 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000157
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700158 // Kick off a read
159 read_in_flight_ = true;
160 canceller_ = g_cancellable_new();
161 g_input_stream_read_async(
162 src_stream_,
163 &buffer_[0],
164 buffer_.size(),
165 G_PRIORITY_DEFAULT,
166 canceller_,
167 &FilesystemCopierAction::StaticAsyncReadyCallback,
168 this);
169}
adlr@google.com3defe6a2009-12-04 20:57:17 +0000170
171} // namespace chromeos_update_engine