Order posix file listings by type as well as name.

http://crbug.com/12812
TEST=go to /, see that directories are sorted before other files.

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

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


CrOS-Libchrome-Original-Commit: 172c55057003795131ecb2ad5dd012b0c1785171
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index aca0ff9..26f4b8f 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -28,6 +28,23 @@
 #include "base/string_util.h"
 #include "base/time.h"
 
+namespace {
+
+bool IsDirectory(const FTSENT* file) {
+  switch (file->fts_info) {
+    case FTS_D:
+    case FTS_DC:
+    case FTS_DNR:
+    case FTS_DOT:
+    case FTS_DP:
+      return true;
+    default:
+      return false;
+  }
+}
+
+}  // namespace
+
 namespace file_util {
 
 #if defined(GOOGLE_CHROME_BUILD)
@@ -560,10 +577,14 @@
 }
 
 int CompareFiles(const FTSENT** a, const FTSENT** b) {
-  // Order lexicographically, ignoring case and whether they are files or
-  // directories.
-  // TODO(yuzo): make this case-sensitive, directories-then-files, and
-  // internationalized.
+  // Order lexicographically with directories before other files.
+  const bool a_is_dir = IsDirectory(*a);
+  const bool b_is_dir = IsDirectory(*b);
+  if (a_is_dir != b_is_dir)
+    return a_is_dir ? -1 : 1;
+
+  // TODO(yuzo): make this internationalized when encoding detection function
+  // becomes available.
   return base::strcasecmp((*a)->fts_name, (*b)->fts_name);
 }
 
diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc
index 3ecd1cf..e0884f7 100644
--- a/base/file_util_unittest.cc
+++ b/base/file_util_unittest.cc
@@ -1035,10 +1035,12 @@
   EXPECT_TRUE(file_util::CreateDirectory(dirC));
   EXPECT_TRUE(file_util::CreateDirectory(dirD));
 
-  // Files and directories are enumerated in the lexicographical order,
-  // ignoring case and whether they are files or directories.
+  // On Windows, files and directories are enumerated in the lexicographical
+  // order, ignoring case and whether they are files or directories. On posix,
+  // we order directories before files.
   file_util::FileEnumerator enumerator(test_dir_, false, FILES_AND_DIRECTORIES);
   FilePath cur_file = enumerator.Next();
+#if defined(OS_WIN)
   EXPECT_EQ(fileA.value(), cur_file.value());
   cur_file = enumerator.Next();
   EXPECT_EQ(fileB.value(), cur_file.value());
@@ -1051,6 +1053,21 @@
   cur_file = enumerator.Next();
   EXPECT_EQ(fileF.value(), cur_file.value());
   cur_file = enumerator.Next();
+#elif defined(OS_POSIX)
+  EXPECT_EQ(dirC.value(), cur_file.value());
+  cur_file = enumerator.Next();
+  EXPECT_EQ(dirD.value(), cur_file.value());
+  cur_file = enumerator.Next();
+  EXPECT_EQ(dirE.value(), cur_file.value());
+  cur_file = enumerator.Next();
+  EXPECT_EQ(fileA.value(), cur_file.value());
+  cur_file = enumerator.Next();
+  EXPECT_EQ(fileB.value(), cur_file.value());
+  cur_file = enumerator.Next();
+  EXPECT_EQ(fileF.value(), cur_file.value());
+  cur_file = enumerator.Next();
+#endif
+
   EXPECT_EQ(FILE_PATH_LITERAL(""), cur_file.value());
 }