Match window's behavior when recursively copying directories that exist.

Unit test improvement from here (sgk): http://codereview.chromium.org/271060

BUG=none
TEST=unittests

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28838 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: abbc5739c1689384fbbdbd0ee6c9d2d9a8c2da0b
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index 4621bb3..4d9e797 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -227,9 +227,18 @@
         traverse_type | FileEnumerator::DIRECTORIES);
   FileEnumerator traversal(from_path, recursive, traverse_type);
 
-  // to_path may not exist yet, start the loop with to_path
+  // We have to mimic windows behavior here. |to_path| may not exist yet,
+  // start the loop with |to_path|.  If this is a recursive copy and
+  // the destination already exists, we have to copy the source directory
+  // as well.
   FileEnumerator::FindInfo info;
   FilePath current = from_path;
+  FilePath from_path_base = from_path;
+  if (recursive && stat(to_path.value().c_str(), &info.stat) == 0) {
+    // If the destination already exists, then the top level of source
+    // needs to be copied.
+    from_path_base = from_path.DirName();
+  }
   if (stat(from_path.value().c_str(), &info.stat) < 0) {
     LOG(ERROR) << "CopyDirectory() couldn't stat source directory: " <<
         from_path.value() << " errno = " << errno;
@@ -239,7 +248,7 @@
   while (success && !current.empty()) {
     // current is the source path, including from_path, so paste
     // the suffix after from_path onto to_path to create the target_path.
-    std::string suffix(&current.value().c_str()[from_path.value().size()]);
+    std::string suffix(&current.value().c_str()[from_path_base.value().size()]);
     // Strip the leading '/' (if any).
     if (!suffix.empty()) {
       DCHECK_EQ('/', suffix[0]);
diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc
index 073dbae..6ac55f6 100644
--- a/base/file_util_unittest.cc
+++ b/base/file_util_unittest.cc
@@ -380,7 +380,7 @@
   EXPECT_FALSE(file_util::PathExists(subdir_path));
 }
 
-TEST_F(FileUtilTest, Move) {
+TEST_F(FileUtilTest, MoveNew) {
   // Create a directory
   FilePath dir_name_from =
       test_dir_.Append(FILE_PATH_LITERAL("Move_From_Subdir"));
@@ -409,7 +409,42 @@
   EXPECT_TRUE(file_util::PathExists(file_name_to));
 }
 
-TEST_F(FileUtilTest, CopyDirectoryRecursively) {
+TEST_F(FileUtilTest, MoveExist) {
+  // Create a directory
+  FilePath dir_name_from =
+      test_dir_.Append(FILE_PATH_LITERAL("Move_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Move the directory
+  FilePath dir_name_exists =
+      test_dir_.Append(FILE_PATH_LITERAL("Destination"));
+
+  FilePath dir_name_to =
+      dir_name_exists.Append(FILE_PATH_LITERAL("Move_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+
+  // Create the destination directory.
+  file_util::CreateDirectory(dir_name_exists);
+  ASSERT_TRUE(file_util::PathExists(dir_name_exists));
+
+  EXPECT_TRUE(file_util::Move(dir_name_from, dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(file_util::PathExists(dir_name_from));
+  EXPECT_FALSE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) {
   // Create a directory.
   FilePath dir_name_from =
       test_dir_.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
@@ -459,7 +494,62 @@
   EXPECT_TRUE(file_util::PathExists(file_name2_to));
 }
 
-TEST_F(FileUtilTest, CopyDirectory) {
+TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) {
+  // Create a directory.
+  FilePath dir_name_from =
+      test_dir_.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  file_util::CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(file_util::PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name2_from));
+
+  // Copy the directory recursively.
+  FilePath dir_name_exists =
+      test_dir_.Append(FILE_PATH_LITERAL("Destination"));
+
+  FilePath dir_name_to =
+      dir_name_exists.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+  FilePath file_name2_to =
+      subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  // Create the destination directory.
+  file_util::CreateDirectory(dir_name_exists);
+  ASSERT_TRUE(file_util::PathExists(dir_name_exists));
+
+  EXPECT_TRUE(file_util::CopyDirectory(dir_name_from, dir_name_exists, true));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(file_util::PathExists(dir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(subdir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name2_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+  EXPECT_TRUE(file_util::PathExists(subdir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name2_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryNew) {
   // Create a directory.
   FilePath dir_name_from =
       test_dir_.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
@@ -506,6 +596,55 @@
   EXPECT_FALSE(file_util::PathExists(subdir_name_to));
 }
 
+TEST_F(FileUtilTest, CopyDirectoryExists) {
+  // Create a directory.
+  FilePath dir_name_from =
+      test_dir_.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  file_util::CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(file_util::PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name2_from));
+
+  // Copy the directory not recursively.
+  FilePath dir_name_to =
+      test_dir_.Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+
+  // Create the destination directory.
+  file_util::CreateDirectory(dir_name_to);
+  ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+  EXPECT_TRUE(file_util::CopyDirectory(dir_name_from, dir_name_to, false));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(file_util::PathExists(dir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(subdir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name2_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+  EXPECT_FALSE(file_util::PathExists(subdir_name_to));
+}
+
 TEST_F(FileUtilTest, CopyFile) {
   // Create a directory
   FilePath dir_name_from =