Index: src/platform/update_engine/filesystem_copier_action.h |
diff --git a/src/platform/update_engine/filesystem_copier_action.h b/src/platform/update_engine/filesystem_copier_action.h |
index 3a330efd5b3ed6b065c3da5bc01a94d538bd0caa..9e7f0606796edad379f2c0faf5a6540361a1dfc9 100644 |
--- a/src/platform/update_engine/filesystem_copier_action.h |
+++ b/src/platform/update_engine/filesystem_copier_action.h |
@@ -1,4 +1,4 @@ |
-// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Copyright (c) 2010 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. |
@@ -8,30 +8,14 @@ |
#include <sys/stat.h> |
#include <sys/types.h> |
#include <string> |
+#include <vector> |
+#include <gio/gio.h> |
#include <glib.h> |
#include "update_engine/action.h" |
#include "update_engine/install_plan.h" |
// This action will only do real work if it's a delta update. It will |
-// format the install partition as ext3/4, copy the root filesystem into it, |
-// and then terminate. |
- |
-// Implementation notes: This action uses a helper thread, which seems to |
-// violate the design decision to only have a single thread and use |
-// asynchronous i/o. The issue is that (to the best of my knowledge), |
-// there are no linux APIs to crawl a filesystem's metadata asynchronously. |
-// The suggested way seems to be to open the raw device and parse the ext |
-// filesystem. That's not a good approach for a number of reasons: |
-// - ties us to ext filesystem |
-// - although this wouldn't happen at the time of writing, it may not handle |
-// changes to the source fs during the copy as gracefully. |
-// - requires us to have read-access to the source filesystem device, which |
-// may be a security issue. |
-// |
-// Having said this, using a helper thread is not ideal, but it's acceptable: |
-// we still honor the Action API. That is, all interaction between the action |
-// and other objects in the system (e.g. the ActionProcessor) happens on the |
-// main thread. The helper thread is fully encapsulated by the action. |
+// copy the root partition to install partition, and then terminate. |
namespace chromeos_update_engine { |
@@ -49,10 +33,11 @@ class ActionTraits<FilesystemCopierAction> { |
class FilesystemCopierAction : public Action<FilesystemCopierAction> { |
public: |
FilesystemCopierAction() |
- : thread_should_exit_(0), |
- is_mounted_(false), |
- copy_source_("/"), |
- skipped_copy_(false) {} |
+ : src_stream_(NULL), |
+ dst_stream_(NULL), |
+ canceller_(NULL), |
+ read_in_flight_(false), |
+ buffer_valid_size_(0) {} |
typedef ActionTraits<FilesystemCopierAction>::InputObjectType |
InputObjectType; |
typedef ActionTraits<FilesystemCopierAction>::OutputObjectType |
@@ -64,81 +49,51 @@ class FilesystemCopierAction : public Action<FilesystemCopierAction> { |
void set_copy_source(const std::string& path) { |
copy_source_ = path; |
} |
- // Returns true if we detected that a copy was unneeded and thus skipped it. |
- bool skipped_copy() { return skipped_copy_; } |
// Debugging/logging |
static std::string StaticType() { return "FilesystemCopierAction"; } |
std::string Type() const { return StaticType(); } |
private: |
- // These synchronously mount or unmount the given mountpoint |
- bool Mount(const std::string& device, const std::string& mountpoint); |
- bool Unmount(const std::string& mountpoint); |
- |
- // Performs a recursive file/directory copy from copy_source_ to dest_path_. |
- // Doesn't return until the copy has completed. Returns true on success |
- // or false on error. |
- bool CopySynchronously(); |
- |
- // There are helper functions for CopySynchronously. They handle creating |
- // various types of files. They return true on success. |
- bool CreateDirSynchronously(const std::string& new_path, |
- const struct stat& stbuf); |
- bool CopyFileSynchronously(const std::string& old_path, |
- const std::string& new_path, |
- const struct stat& stbuf); |
- bool CreateHardLinkSynchronously(const std::string& old_path, |
- const std::string& new_path); |
- // Note: Here, old_path is an existing symlink that will be copied to |
- // new_path. Thus, old_path is *not* the same as the old_path from |
- // the symlink() syscall. |
- bool CopySymlinkSynchronously(const std::string& old_path, |
- const std::string& new_path, |
- const struct stat& stbuf); |
- bool CreateNodeSynchronously(const std::string& new_path, |
- const struct stat& stbuf); |
- |
- // Returns NULL on success |
- void* HelperThreadMain(); |
- static void* HelperThreadMainStatic(void* data) { |
- FilesystemCopierAction* self = |
- reinterpret_cast<FilesystemCopierAction*>(data); |
- return self->HelperThreadMain(); |
+ // Callback from glib when the copy operation is done. |
+ void AsyncReadyCallback(GObject *source_object, GAsyncResult *res); |
+ static void StaticAsyncReadyCallback(GObject *source_object, |
+ GAsyncResult *res, |
+ gpointer user_data) { |
+ reinterpret_cast<FilesystemCopierAction*>(user_data)->AsyncReadyCallback( |
+ source_object, res); |
} |
- |
- // Joins the thread and tells the processor that we're done |
- void CollectThread(); |
- // GMainLoop callback function: |
- static gboolean CollectThreadStatic(gpointer data) { |
- FilesystemCopierAction* self = |
- reinterpret_cast<FilesystemCopierAction*>(data); |
- self->CollectThread(); |
- return FALSE; |
- } |
- |
- pthread_t helper_thread_; |
- |
- volatile gint thread_should_exit_; |
- |
- static const char* kCompleteFilesystemMarker; |
- |
- // Whether or not the destination device is currently mounted. |
- bool is_mounted_; |
- |
- // Where the destination device is mounted. |
- std::string dest_path_; |
- |
- // The path to copy from. Usually left as the default "/", but tests can |
- // change it. |
+ |
+ // Cleans up all the variables we use for async operations and tells |
+ // the ActionProcessor we're done w/ success as passed in. |
+ // was_cancelled should be true if TerminateProcessing() was called. |
+ void Cleanup(bool success, bool was_cancelled); |
+ |
+ // The path to copy from. If empty (the default), the source is from the |
+ // passed in InstallPlan. |
std::string copy_source_; |
+ // If non-NULL, these are GUnixInputStream objects for the opened |
+ // source/destination partitions. |
+ GInputStream* src_stream_; |
+ GOutputStream* dst_stream_; |
+ |
+ // If non-NULL, the cancellable object for the in-flight async call. |
+ GCancellable* canceller_; |
+ |
+ // True if we're waiting on a read to complete; false if we're |
+ // waiting on a write. |
+ bool read_in_flight_; |
+ |
+ // The buffer for storing data we read/write. |
+ std::vector<char> buffer_; |
+ |
+ // Number of valid elements in buffer_. |
+ std::vector<char>::size_type buffer_valid_size_; |
+ |
// The install plan we're passed in via the input pipe. |
InstallPlan install_plan_; |
- |
- // Set to true if we detected the copy was unneeded and thus we skipped it. |
- bool skipped_copy_; |
- |
+ |
DISALLOW_COPY_AND_ASSIGN(FilesystemCopierAction); |
}; |