[go: nahoru, domu]

Use StringPiece for the optional suffix in base::GetUniquePathNumber.

This removes the need to create/destroy a string when calling. This
change also adds a default value of an empty StringPiece to the suffix
so that callers who don't care about a suffix don't need to bother with
it. Finally, this change adds a unit test for the function, which it
apparently never had.

BUG=none
TBR=vasilii@chromium.org,vakh@chromium.org,eladalon@chromium.org,jamiewalch@chromium.org,carlosk@chromium.org

Change-Id: Iaf98d5237ffcc211bf9dfc2242742508f35bafac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1752302
Commit-Queue: Greg Thompson <grt@chromium.org>
Auto-Submit: Greg Thompson <grt@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#686754}
diff --git a/base/files/file_util.cc b/base/files/file_util.cc
index e6e84a2..f11f456 100644
--- a/base/files/file_util.cc
+++ b/base/files/file_util.cc
@@ -281,20 +281,34 @@
 }
 
 int GetUniquePathNumber(const FilePath& path,
-                        const FilePath::StringType& suffix) {
-  bool have_suffix = !suffix.empty();
-  if (!PathExists(path) &&
-      (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
-    return 0;
-  }
+                        FilePath::StringPieceType suffix) {
+  // Storage for use by is_unique to reduce heap churn when looping.
+  FilePath::StringType path_with_suffix;
 
-  FilePath new_path;
-  for (int count = 1; count <= kMaxUniqueFiles; ++count) {
-    new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
-    if (!PathExists(new_path) &&
-        (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
-      return count;
+  // A function that returns true if |candidate| is unique with and without an
+  // optional suffix.
+  const auto is_unique = [suffix,
+                          &path_with_suffix](const base::FilePath& candidate) {
+    if (!PathExists(candidate)) {
+      if (suffix.empty())
+        return true;
+      path_with_suffix = candidate.value();
+      suffix.AppendToString(&path_with_suffix);
+      if (!PathExists(FilePath(path_with_suffix)))
+        return true;
     }
+    return false;
+  };
+
+  if (is_unique(path))
+    return 0;
+
+  std::string number;
+  for (int count = 1; count <= kMaxUniqueFiles; ++count) {
+    StringAppendF(&number, " (%d)", count);
+    if (is_unique(path.InsertBeforeExtensionASCII(number)))
+      return count;
+    number.clear();
   }
 
   return -1;
@@ -302,7 +316,7 @@
 
 FilePath GetUniquePath(const FilePath& path) {
   FilePath unique_path = path;
-  int uniquifier = GetUniquePathNumber(path, FilePath::StringType());
+  int uniquifier = GetUniquePathNumber(path);
   if (uniquifier > 0) {
     unique_path = unique_path.InsertBeforeExtensionASCII(
         StringPrintf(" (%d)", uniquifier));
diff --git a/base/files/file_util.h b/base/files/file_util.h
index 0987b7b..fc2f443 100644
--- a/base/files/file_util.h
+++ b/base/files/file_util.h
@@ -401,8 +401,9 @@
 // unique. If |path| does not exist, 0 is returned.  If it fails to find such
 // a number, -1 is returned. If |suffix| is not empty, also checks the
 // existence of it with the given suffix.
-BASE_EXPORT int GetUniquePathNumber(const FilePath& path,
-                                    const FilePath::StringType& suffix);
+BASE_EXPORT int GetUniquePathNumber(
+    const FilePath& path,
+    FilePath::StringPieceType suffix = FilePath::StringPieceType());
 
 // If file at |path| already exists, modifies filename portion of |path| to
 // return unique path.
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index 21cefcc4..64de4d0 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/files/file_util.h"
+
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -23,7 +25,6 @@
 #include "base/files/file.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
-#include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/guid.h"
@@ -37,6 +38,7 @@
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/multiprocess_func_list.h"
@@ -3871,6 +3873,48 @@
 }
 #endif
 
+#if !defined(OS_NACL_NONSFI)
+TEST_F(FileUtilTest, GetUniquePathNumber) {
+  static constexpr FilePath::StringPieceType kSomeFile(FPL("SomeFile.txt"));
+  static constexpr FilePath::StringPieceType kSomeFileOne(
+      FPL("SomeFile (1).txt"));
+  static constexpr FilePath::StringPieceType kSomeSuffix(FPL(".SUFFIX"));
+
+  const FilePath& temp_dir = temp_dir_.GetPath();
+
+  // The dir is empty to start with.
+  EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile)), 0);
+  EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile), kSomeSuffix), 0);
+
+  // Manufacture a collision with the suffixed file.
+  FilePath::StringType path = kSomeFile.as_string();
+  kSomeSuffix.AppendToString(&path);
+  ASSERT_EQ(WriteFile(temp_dir.Append(path), "hi", 2), 2);
+  // No collision unsuffixed.
+  EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile)), 0);
+  // But there is with the suffix.
+  EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile), kSomeSuffix), 1);
+  ASSERT_TRUE(DeleteFile(temp_dir.Append(path), false));
+
+  // Manufacture a collision with the unsuffixed file.
+  ASSERT_EQ(WriteFile(temp_dir.Append(kSomeFile), "hi", 2), 2);
+  // Both collide.
+  EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile)), 1);
+  EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile), kSomeSuffix), 1);
+
+  // Now with the unsuffixed collision, manufacture a suffixed collision with
+  // the number '1'.
+  path = kSomeFileOne.as_string();
+  kSomeSuffix.AppendToString(&path);
+  ASSERT_EQ(WriteFile(temp_dir.Append(path), "hi", 2), 2);
+  EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile), kSomeSuffix), 2);
+
+  // Clean up.
+  ASSERT_TRUE(DeleteFile(temp_dir.Append(path), false));
+  ASSERT_TRUE(DeleteFile(temp_dir.Append(kSomeFile), false));
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
 // Test that temp files obtained racily are all unique (no interference between
 // threads). Mimics file operations in DoLaunchChildTestProcess() to rule out
 // thread-safety issues @ https://crbug.com/826408#c17.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc
index 4e99b80..b56953c5 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc
@@ -184,8 +184,7 @@
 
   // In the unlikely case that this filename is already taken, find a unique
   // number to append to the filename, if possible.
-  int unique_number =
-      base::GetUniquePathNumber(file_path, base::FilePath::StringType());
+  int unique_number = base::GetUniquePathNumber(file_path);
   if (unique_number < 0) {
     return;  // No available file path was found.
   } else if (unique_number != 0) {
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_database_helper.cc b/chrome/browser/safe_browsing/test_safe_browsing_database_helper.cc
index b52ff49..01ca698 100644
--- a/chrome/browser/safe_browsing/test_safe_browsing_database_helper.cc
+++ b/chrome/browser/safe_browsing/test_safe_browsing_database_helper.cc
@@ -59,8 +59,7 @@
       if (!base::Contains(*store_map, id)) {
         const base::FilePath store_path =
             base_store_path.InsertBeforeExtensionASCII(base::StringPrintf(
-                " (%d)", base::GetUniquePathNumber(
-                             base_store_path, base::FilePath::StringType())));
+                " (%d)", base::GetUniquePathNumber(base_store_path)));
         (*store_map)[id] =
             store_factory_->CreateV4Store(db_task_runner, store_path);
       }
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win.cc b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
index 21b43d9..a8fc647 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_win.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
@@ -232,8 +232,7 @@
         continue;
     }
     if (shortcut_paths[i] != web_app_path) {
-      int unique_number = base::GetUniquePathNumber(
-          shortcut_file, base::FilePath::StringType());
+      int unique_number = base::GetUniquePathNumber(shortcut_file);
       if (unique_number == -1) {
         success = false;
         continue;
diff --git a/components/offline_pages/core/model/offline_page_model_utils.cc b/components/offline_pages/core/model/offline_page_model_utils.cc
index 6785f1a..d0783e52 100644
--- a/components/offline_pages/core/model/offline_page_model_utils.cc
+++ b/components/offline_pages/core/model/offline_page_model_utils.cc
@@ -74,8 +74,7 @@
           title, url, false /* can_save_as_complete */, kMHTMLMimeType));
 
   // Find a unique name based on |suggested_path|.
-  int uniquifier =
-      base::GetUniquePathNumber(suggested_path, base::FilePath::StringType());
+  int uniquifier = base::GetUniquePathNumber(suggested_path);
   base::FilePath::StringType suffix;
   if (uniquifier > 0)
 #if defined(OS_WIN)
diff --git a/remoting/host/file_transfer/local_file_operations.cc b/remoting/host/file_transfer/local_file_operations.cc
index b09064a..ef38677 100644
--- a/remoting/host/file_transfer/local_file_operations.cc
+++ b/remoting/host/file_transfer/local_file_operations.cc
@@ -393,7 +393,7 @@
   PostTaskAndReplyWithResult(
       file_task_runner_.get(), FROM_HERE,
       base::BindOnce(&base::GetUniquePathNumber, temp_filepath,
-                     base::FilePath::StringType()),
+                     base::FilePath::StringPieceType()),
       base::BindOnce(&LocalFileWriter::CreateTempFile,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                      temp_filepath));
@@ -492,7 +492,7 @@
   base::PostTaskAndReplyWithResult(
       file_task_runner_.get(), FROM_HERE,
       base::BindOnce(&base::GetUniquePathNumber, destination_filepath_,
-                     base::FilePath::StringType()),
+                     base::FilePath::StringPieceType()),
       base::BindOnce(&LocalFileWriter::MoveToDestination,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }