Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4778)

Unified Diff: chrome/browser/win/jumplist.cc

Issue 2752063002: Remove JumpListIconsOld directory and set upper limit for delete attempts (Closed)
Patch Set: Remove JumpListIconsOld related file operations. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/win/jumplist.cc
diff --git a/chrome/browser/win/jumplist.cc b/chrome/browser/win/jumplist.cc
index 680db16a6a490256bf10dd17a699b6806db5152a..dc25e7ee35b6eb02f11e3d58cf295574f16dc2a3 100644
--- a/chrome/browser/win/jumplist.cc
+++ b/chrome/browser/win/jumplist.cc
@@ -11,6 +11,7 @@
#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
+#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
@@ -63,6 +64,9 @@ namespace {
// Delay jumplist updates to allow collapsing of redundant update requests.
const int kDelayForJumplistUpdateInMS = 3500;
+// Maximum number of icon files allowed to delete per update
+const int kMaxIconFilesDeletedPerUpdate = 100;
+
// Append the common switches to each shell link.
void AppendCommonSwitches(ShellLinkItem* shell_link) {
const char* kSwitchNames[] = { switches::kUserDataDir };
@@ -229,20 +233,115 @@ bool UpdateJumpList(const wchar_t* app_id,
return true;
}
-// Renames the directory |from_dir| to |to_path|. This method fails if any
-// process has a handle open in |from_dir| or if |to_path| exists. Base::Move()
-// tries to rename a file and if this fails, it tries copy-n-delete; This
-// RenameDirectory method only does the rename part.
-bool RenameDirectory(const base::FilePath& from_path,
- const base::FilePath& to_path) {
+// This method is an exact copy of base::DeleteFileRecursive except that it has
+// an upper limit of file numbers to delete each time.
+// Deletes all files and directories in a path under the limit.
+// Returns false on the first failure it encounters, or the number of files
+// deleted exceeds the upper limit |upper_limit|.
+bool DeleteFileRecursiveWithUpperLimit(
+ const base::FilePath& path,
+ const base::FilePath::StringType& pattern,
+ bool recursive,
+ int upper_limit = INT_MAX) {
grt (UTC plus 2) 2017/03/20 09:15:36 it's confusing for a caller to invoke DeleteFileRe
chengx 2017/03/21 01:37:10 I renamed this method to DeleteFileRecursive, remo
+ base::FileEnumerator traversal(
+ path, false,
+ base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES, pattern);
+ int file_deleted = 0;
+ for (base::FilePath current = traversal.Next(); !current.empty();
+ current = traversal.Next(), file_deleted++) {
+ // Try to clear the read-only bit if we find it.
+ base::FileEnumerator::FileInfo info = traversal.GetInfo();
+ if ((info.find_data().dwFileAttributes & FILE_ATTRIBUTE_READONLY) &&
+ (recursive || !info.IsDirectory())) {
+ SetFileAttributes(
+ current.value().c_str(),
+ info.find_data().dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
+ }
+
+ if (info.IsDirectory()) {
+ if (recursive && (!DeleteFileRecursiveWithUpperLimit(current, pattern,
grt (UTC plus 2) 2017/03/20 09:15:36 |file_deleted| should not be incremented if IsDire
chengx 2017/03/21 01:37:10 I have removed the |recursive| input parameter, so
+ true, upper_limit) ||
+ !::RemoveDirectory(current.value().c_str())))
+ return false;
grt (UTC plus 2) 2017/03/20 09:15:37 nit: braces around this since the conditional span
chengx 2017/03/21 01:37:11 Done.
+ } else if (!::DeleteFile(current.value().c_str())) {
+ return false;
grt (UTC plus 2) 2017/03/20 09:15:37 why not keep going trying to delete other files in
chengx 2017/03/21 01:37:10 I think it just made sense if it returns false whe
+ }
+ if (file_deleted > upper_limit)
+ return false;
+ }
+ return true;
+}
+
+// This method deletes a file or content of a directory.
+// When deleting the content of a directory, |upper_limit| can be specified to
+// to set up the maximum number of files in this directory and any of its
+// sub-directory.
grt (UTC plus 2) 2017/03/20 09:15:36 are there ever sub-directories in JumplistIcons{,O
chengx 2017/03/21 01:37:10 There should not be sub-dir in JumplistIcos{,Old}
+bool DeleteDirectoryContentWithUpperLimit(const base::FilePath& path,
+ bool recursive,
grt (UTC plus 2) 2017/03/20 09:15:36 don't overly generalize this -- the only caller pa
chengx 2017/03/21 01:37:10 Sure, the input parameter |recursive| is gone now.
+ int upper_limit = INT_MAX) {
base::ThreadRestrictions::AssertIOAllowed();
- if (from_path.ReferencesParent() || to_path.ReferencesParent())
+
+ if (path.empty())
+ return true;
+
+ if (path.value().length() >= MAX_PATH)
return false;
- if (from_path.value().length() >= MAX_PATH ||
- to_path.value().length() >= MAX_PATH) {
+
+ // Handle any path with wildcards.
grt (UTC plus 2) 2017/03/20 09:15:36 remove wildcard support here -- it's unused
chengx 2017/03/21 01:37:10 Done.
+ if (path.BaseName().value().find_first_of(L"*?") !=
+ base::FilePath::StringType::npos) {
+ return DeleteFileRecursiveWithUpperLimit(
+ path.DirName(), path.BaseName().value(), recursive, upper_limit);
+ }
+ DWORD attr = GetFileAttributes(path.value().c_str());
+ // We're done if we can't find the path.
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ return true;
+ // We may need to clear the read-only bit.
+ if ((attr & FILE_ATTRIBUTE_READONLY) &&
+ !SetFileAttributes(path.value().c_str(),
+ attr & ~FILE_ATTRIBUTE_READONLY)) {
return false;
}
- return MoveFileEx(from_path.value().c_str(), to_path.value().c_str(), 0) != 0;
+ // If |path| is a file, simply delete it.
+ if (!(attr & FILE_ATTRIBUTE_DIRECTORY))
+ return !!::DeleteFile(path.value().c_str());
+ // If |path| is a directory and |recursive| is true, delete all its content
+ // but save the row directory. The raw directory is deleted if
grt (UTC plus 2) 2017/03/20 09:15:37 row -> raw
chengx 2017/03/21 01:37:11 Done. Sorry for the typo.
+ // |remove_directory| is true.
+ return !recursive ||
+ DeleteFileRecursiveWithUpperLimit(path, L"*", true, upper_limit);
+}
+
+// This method deletes a file or all the content of a directory depending on
+// what |path| is. There method is run in the asynchronous manner, so there is
+// return value.
+void DeleteDirectory(const base::FilePath& path, bool remove_directory = true) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ if (path.empty() || path.value().length() >= MAX_PATH)
+ return;
+
+ DWORD attr = GetFileAttributes(path.value().c_str());
+ // We're done if we can't find the path.
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ return;
+ // We may need to clear the read-only bit.
+ if ((attr & FILE_ATTRIBUTE_READONLY) &&
+ !SetFileAttributes(path.value().c_str(),
+ attr & ~FILE_ATTRIBUTE_READONLY)) {
+ return;
+ }
+ // If |path| is a file, delete it.
+ if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ ::DeleteFile(path.value().c_str());
+ return;
+ }
+ // If |path| is a directory, delete all its content. The raw directory is
+ // deleted if |remove_directory| is true.
+ if (DeleteFileRecursiveWithUpperLimit(path, L"*", true) && remove_directory)
+ ::RemoveDirectory(path.value().c_str());
+ return;
}
// Updates the jumplist, once all the data has been fetched.
@@ -267,73 +366,32 @@ void RunUpdateOnFileThread(
local_recently_closed_pages = data->recently_closed_pages_;
}
- // Delete the directory which contains old icon files, rename the current
- // icon directory, and create a new directory which contains new JumpList
- // icon files.
- base::FilePath icon_dir_old = icon_dir.DirName().Append(
- icon_dir.BaseName().value() + FILE_PATH_LITERAL("Old"));
-
- enum FolderOperationResult {
- SUCCESS = 0,
- DELETE_DEST_FAILED = 1 << 0,
- RENAME_FAILED = 1 << 1,
- DELETE_SRC_CONTENT_FAILED = 1 << 2,
- DELETE_SRC_DIR_FAILED = 1 << 3,
- CREATE_SRC_FAILED = 1 << 4,
- // This value is beyond the sum of all bit fields above and
- // should remain last (shifted by one more than the last value)
- END = 1 << 5
+ enum FolderDeleteResult {
+ SUCCEED = 0,
grt (UTC plus 2) 2017/03/20 09:15:36 SUCCEED and FAILED are very generic. do you want t
chengx 2017/03/21 01:37:11 This enum is updated. It has all the possible fail
+ FAILED,
+ // Add new items before this one, always keep this one at the end.
+ END
};
- // This variable records the status of three folder operations.
- uint32_t folder_operation_status = FolderOperationResult::SUCCESS;
+ // This variable records the delete status of folder JumpListIcons.
+ uint32_t folder_delete_status = FolderDeleteResult::SUCCEED;
grt (UTC plus 2) 2017/03/20 09:15:37 FolderDeleteResult isn't an "enum class", so no ne
chengx 2017/03/21 01:37:11 Done.
base::ScopedClosureRunner log_operation_status_when_done(base::Bind(
- [](uint32_t* folder_operation_status_ptr) {
+ [](uint32_t* folder_delete_status_ptr) {
UMA_HISTOGRAM_ENUMERATION(
"WinJumplist.DetailedFolderResultsDeleteUpdated",
- *folder_operation_status_ptr, FolderOperationResult::END);
+ *folder_delete_status_ptr, FolderDeleteResult::END);
},
- base::Unretained(&folder_operation_status)));
-
- // If deletion of |icon_dir_old| fails, do not rename |icon_dir| to
- // |icon_dir_old|, instead, delete |icon_dir| directly to avoid bloating
- // |icon_dir_old| by moving more things to it.
- if (!base::DeleteFile(icon_dir_old, true)) {
- folder_operation_status |= FolderOperationResult::DELETE_DEST_FAILED;
- // If deletion of any item in |icon_dir| fails, exit early. If deletion of
- // all the items succeeds while only deletion of the dir fails, it is okay
- // to proceed. This skips creating the same directory and updating jumplist
- // icons to avoid bloating the JumplistIcons folder.
- if (!base::DeleteFile(icon_dir, true)) {
- if (!::PathIsDirectoryEmpty(icon_dir.value().c_str())) {
- folder_operation_status |=
- FolderOperationResult::DELETE_SRC_CONTENT_FAILED;
- return;
- }
- folder_operation_status |= FolderOperationResult::DELETE_SRC_DIR_FAILED;
- }
- } else if (!RenameDirectory(icon_dir, icon_dir_old)) {
- // If RenameDirectory() fails, delete |icon_dir| to avoid file accumulation
- // in this directory, which can eventually lead the folder to be huge.
- folder_operation_status |= FolderOperationResult::RENAME_FAILED;
- // If deletion of any item in |icon_dir| fails, exit early. If deletion of
- // all the items succeeds while only deletion of the dir fails, it is okay
- // to proceed. This skips creating the same directory and updating jumplist
- // icons to avoid bloating the JumplistIcons folder.
- if (!base::DeleteFile(icon_dir, true)) {
- if (!::PathIsDirectoryEmpty(icon_dir.value().c_str())) {
- folder_operation_status |=
- FolderOperationResult::DELETE_SRC_CONTENT_FAILED;
- return;
- }
- folder_operation_status |= FolderOperationResult::DELETE_SRC_DIR_FAILED;
- }
- }
-
- // If CreateDirectory() fails, exit early.
- if (!base::CreateDirectory(icon_dir)) {
- folder_operation_status |= FolderOperationResult::CREATE_SRC_FAILED;
+ base::Unretained(&folder_delete_status)));
+
+ // If failing to delete the content in |icon_dir|, post a low-priority task
+ // to try to delete it later and exit early.
+ if (!DeleteDirectoryContentWithUpperLimit(icon_dir, true,
+ kMaxIconFilesDeletedPerUpdate)) {
+ folder_delete_status |= FolderDeleteResult::FAILED;
grt (UTC plus 2) 2017/03/20 09:15:36 is folder_delete_status a bitfield or just a varia
chengx 2017/03/21 01:37:10 In this CL, it should be changed to a variable. So
+ BrowserThread::PostAfterStartupTask(
grt (UTC plus 2) 2017/03/20 09:15:36 PostAfterStartupTask is only needed if you're post
chengx 2017/03/21 01:37:10 Thanks for the reminder. This is something that ne
+ FROM_HERE, BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE),
+ base::Bind(&DeleteDirectory, icon_dir, false));
return;
}
@@ -349,6 +407,17 @@ void RunUpdateOnFileThread(
// with it.
UpdateJumpList(app_id.c_str(), local_most_visited_pages,
local_recently_closed_pages, incognito_availability);
+
+ // Post a low-priority task to delete the content in |icon_dir_old| if there
+ // is any.
+ base::FilePath icon_dir_old = icon_dir.DirName().Append(
+ icon_dir.BaseName().value() + FILE_PATH_LITERAL("Old"));
+
+ if (::PathFileExists(icon_dir_old.value().c_str())) {
+ BrowserThread::PostAfterStartupTask(
grt (UTC plus 2) 2017/03/20 09:15:37 comments above apply here as well. does it suffice
chengx 2017/03/21 01:37:10 Thanks for pointing to these APIs and traits that
+ FROM_HERE, BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE),
+ base::Bind(&DeleteDirectory, icon_dir_old, true));
+ }
}
} // namespace
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698