Missed new files in last commit

Review URL: http://codereview.chromium.org/465067


git-svn-id: svn://chrome-svn/chromeos/trunk@336 06c00378-0e64-4dae-be16-12b19f9950a1
diff --git a/filesystem_copier_action.h b/filesystem_copier_action.h
new file mode 100644
index 0000000..8f0dc06
--- /dev/null
+++ b/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__