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 |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8f0dc06d547d2cf12f47638c03ea5234eb968cec |
--- /dev/null |
+++ b/src/platform/update_engine/filesystem_copier_action.h |
@@ -0,0 +1,147 @@ |
+// 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_FILESYSTEM_COPIER_ACTION_H__ |
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_FILESYSTEM_COPIER_ACTION_H__ |
+ |
+#include <sys/stat.h> |
+#include <sys/types.h> |
+#include <string> |
+#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. |
+ |
+namespace chromeos_update_engine { |
+ |
+class FilesystemCopierAction; |
+ |
+template<> |
+class ActionTraits<FilesystemCopierAction> { |
+ public: |
+ // Takes the install plan as input |
+ typedef InstallPlan InputObjectType; |
+ // Passes the install plan as output |
+ typedef InstallPlan OutputObjectType; |
+}; |
+ |
+class FilesystemCopierAction : public Action<FilesystemCopierAction> { |
+ public: |
+ FilesystemCopierAction() |
+ : thread_should_exit_(0), |
+ is_mounted_(false), |
+ copy_source_("/"), |
+ skipped_copy_(false) {} |
+ typedef ActionTraits<FilesystemCopierAction>::InputObjectType |
+ InputObjectType; |
+ typedef ActionTraits<FilesystemCopierAction>::OutputObjectType |
+ OutputObjectType; |
+ void PerformAction(); |
+ void TerminateProcessing(); |
+ |
+ // Used for testing, so we can copy from somewhere other than root |
+ void set_copy_source(const 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 string& device, const string& mountpoint); |
+ bool Unmount(const 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(); |
+ } |
+ |
+ // 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. |
+ string dest_path_; |
+ |
+ // The path to copy from. Usually left as the default "/", but tests can |
+ // change it. |
+ string copy_source_; |
+ |
+ // 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); |
+}; |
+ |
+} // namespace chromeos_update_engine |
+ |
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_FILESYSTEM_COPIER_ACTION_H__ |