shill: Implement CreateProfile, PushProfile, PopProfile

Collateral fixes: Profiles now create a header at the beginning
of the file, and this feature is plumbed down through key_file_store
and glib.  InitStorage can be configured to fail if the profile
already exists/doesn't yet exist.

BUG=chromium-os:22221
TEST=New unit tests

Change-Id: Ie7c2d0dee97891b7850cec75b74052fce77eee8f
Reviewed-on: https://gerrit.chromium.org/gerrit/10884
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/profile.cc b/profile.cc
index 2025de1..46d979e 100644
--- a/profile.cc
+++ b/profile.cc
@@ -57,22 +57,61 @@
 
 Profile::~Profile() {}
 
-bool Profile::InitStorage(GLib *glib) {
+bool Profile::InitStorage(GLib *glib, InitStorageOption storage_option,
+                          Error *error) {
   FilePath final_path;
   if (!GetStoragePath(&final_path)) {
-    PLOG(ERROR) <<
+    const string kMessage =
         base::StringPrintf("Could not set up profile storage for %s:%s",
                            name_.user.c_str(), name_.identifier.c_str());
+    LOG(ERROR) << kMessage;
+    if (error) {
+      error->Populate(Error::kInvalidArguments, kMessage);
+    }
     return false;
   }
   scoped_ptr<KeyFileStore> storage(new KeyFileStore(glib));
   storage->set_path(final_path);
+  bool already_exists = storage->IsNonEmpty();
+  if (!already_exists && storage_option != kCreateNew &&
+      storage_option != kCreateOrOpenExisting) {
+    const string kMessage =
+        base::StringPrintf("Profile storage for %s:%s does not already exist",
+                           name_.user.c_str(), name_.identifier.c_str());
+    LOG(ERROR) << kMessage;
+    if (error) {
+      error->Populate(Error::kNotFound, kMessage);
+    }
+    return false;
+  } else if (already_exists && storage_option != kOpenExisting &&
+             storage_option != kCreateOrOpenExisting) {
+    const string kMessage =
+        base::StringPrintf("Profile storage for %s:%s already exists",
+                           name_.user.c_str(), name_.identifier.c_str());
+    LOG(ERROR) << kMessage;
+    if (error) {
+      error->Populate(Error::kAlreadyExists, kMessage);
+    }
+    return false;
+  }
   if (!storage->Open()) {
-    PLOG(ERROR) <<
+    const string kMessage =
         base::StringPrintf("Could not open profile storage for %s:%s",
                            name_.user.c_str(), name_.identifier.c_str());
+    LOG(ERROR) << kMessage;
+    if (error) {
+      error->Populate(Error::kInternalError, kMessage);
+    }
     return false;
   }
+  if (!already_exists) {
+    // Add a descriptive header to the profile so even if nothing is stored
+    // to it, it still has some content.  Completely empty keyfiles are not
+    // valid for reading.
+    storage->SetHeader(
+        base::StringPrintf("Profile %s:%s", name_.user.c_str(),
+                           name_.identifier.c_str()));
+  }
   set_storage(storage.release());
   return true;
 }
@@ -159,6 +198,10 @@
   return true;
 }
 
+bool Profile::MatchesIdentifier(const Identifier &name) const {
+  return name.user == name_.user && name.identifier == name_.identifier;
+}
+
 bool Profile::Save() {
   return storage_->Flush();
 }