summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-12 19:36:36 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-12 19:36:36 +0000
commit37779e0d685e3e8cf948ebae2bb7dc9c04aa876f (patch)
tree42047d8e7a5a6cfba3df9ce1538be31f84fddee9
parentc7b3c63a202ab95967a51a69397dbe7b4abe423a (diff)
downloadchromium_src-37779e0d685e3e8cf948ebae2bb7dc9c04aa876f.zip
chromium_src-37779e0d685e3e8cf948ebae2bb7dc9c04aa876f.tar.gz
chromium_src-37779e0d685e3e8cf948ebae2bb7dc9c04aa876f.tar.bz2
Delete the setup temp file on uninstall.
TEST=See repro steps in bug report. BUG=79178 Review URL: http://codereview.chromium.org/6823086 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81287 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/installer/setup/setup_util.cc57
-rw-r--r--chrome/installer/setup/setup_util.h10
-rw-r--r--chrome/installer/setup/setup_util_unittest.cc11
-rw-r--r--chrome/installer/setup/uninstall.cc7
4 files changed, 85 insertions, 0 deletions
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 19b6ce3..3fe4e16 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -81,6 +81,63 @@ Version* GetMaxVersionFromArchiveDir(const FilePath& chrome_path) {
return (version_found ? max_version.release() : NULL);
}
+bool DeleteFileFromTempProcess(const FilePath& path,
+ uint32 delay_before_delete_ms) {
+ static const wchar_t kRunDll32Path[] =
+ L"%SystemRoot%\\System32\\rundll32.exe";
+ wchar_t rundll32[MAX_PATH];
+ DWORD size = ExpandEnvironmentStrings(kRunDll32Path, rundll32,
+ arraysize(rundll32));
+ if (!size || size >= MAX_PATH)
+ return false;
+
+ STARTUPINFO startup = { sizeof(STARTUPINFO) };
+ PROCESS_INFORMATION pi = {0};
+ BOOL ok = ::CreateProcess(NULL, rundll32, NULL, NULL, FALSE, CREATE_SUSPENDED,
+ NULL, NULL, &startup, &pi);
+ if (ok) {
+ // We use the main thread of the new process to run:
+ // Sleep(delay_before_delete_ms);
+ // DeleteFile(path);
+ // ExitProcess(0);
+ // This runs before the main routine of the process runs, so it doesn't
+ // matter much which executable we choose except that we don't want to
+ // use e.g. a console app that causes a window to be created.
+ size = (path.value().length() + 1) * sizeof(path.value()[0]);
+ void* mem = ::VirtualAllocEx(pi.hProcess, NULL, size, MEM_COMMIT,
+ PAGE_READWRITE);
+ if (mem) {
+ SIZE_T written = 0;
+ ::WriteProcessMemory(pi.hProcess, mem, path.value().c_str(),
+ (path.value().size() + 1) * sizeof(path.value()[0]), &written);
+ HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll");
+ PAPCFUNC sleep = reinterpret_cast<PAPCFUNC>(
+ ::GetProcAddress(kernel32, "Sleep"));
+ PAPCFUNC delete_file = reinterpret_cast<PAPCFUNC>(
+ ::GetProcAddress(kernel32, "DeleteFileW"));
+ PAPCFUNC exit_process = reinterpret_cast<PAPCFUNC>(
+ ::GetProcAddress(kernel32, "ExitProcess"));
+ if (!sleep || !delete_file || !exit_process) {
+ NOTREACHED();
+ ok = FALSE;
+ } else {
+ ::QueueUserAPC(sleep, pi.hThread, delay_before_delete_ms);
+ ::QueueUserAPC(delete_file, pi.hThread,
+ reinterpret_cast<ULONG_PTR>(mem));
+ ::QueueUserAPC(exit_process, pi.hThread, 0);
+ ::ResumeThread(pi.hThread);
+ }
+ } else {
+ PLOG(ERROR) << "VirtualAllocEx";
+ ::TerminateProcess(pi.hProcess, ~0);
+ }
+ ::CloseHandle(pi.hThread);
+ ::CloseHandle(pi.hProcess);
+ }
+
+ return ok != FALSE;
+}
+
// Open |path| with minimal access to obtain information about it, returning
// true and populating |handle| on success.
// static
diff --git a/chrome/installer/setup/setup_util.h b/chrome/installer/setup/setup_util.h
index d9dceae..9bb0394 100644
--- a/chrome/installer/setup/setup_util.h
+++ b/chrome/installer/setup/setup_util.h
@@ -31,6 +31,16 @@ int ApplyDiffPatch(const FilePath& src,
// Returns the maximum version found or NULL if no version is found.
Version* GetMaxVersionFromArchiveDir(const FilePath& chrome_path);
+// Spawns a new process that waits for a specified amount of time before
+// attempting to delete |path|. This is useful for setup to delete the
+// currently running executable or a file that we cannot close right away but
+// estimate that it will be possible after some period of time.
+// Returns true if a new process was started, false otherwise. Note that
+// given the nature of this function, it is not possible to know if the
+// delete operation itself succeeded.
+bool DeleteFileFromTempProcess(const FilePath& path,
+ uint32 delay_before_delete_ms);
+
// A predicate that compares the program portion of a command line with a given
// file path. First, the file paths are compared directly. If they do not
// match, the filesystem is consulted to determine if the paths reference the
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index 8dacb9a..13aa7b7e 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -9,6 +9,7 @@
#include "base/memory/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/threading/platform_thread.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/installer/setup/setup_util.h"
#include "chrome/installer/util/master_preferences.h"
@@ -139,3 +140,13 @@ TEST_F(SetupUtilTest, ProgramCompare) {
ASSERT_FALSE(FilePath::CompareEqualIgnoreCase(expect.value(), short_expect));
EXPECT_TRUE(ProgramCompare(expect).Evaluate(L"\"" + short_expect + L"\""));
}
+
+TEST_F(SetupUtilTest, DeleteFileFromTempProcess) {
+ FilePath test_file;
+ file_util::CreateTemporaryFileInDir(test_dir_.path(), &test_file);
+ ASSERT_TRUE(file_util::PathExists(test_file));
+ file_util::WriteFile(test_file, "foo", 3);
+ EXPECT_TRUE(installer::DeleteFileFromTempProcess(test_file, 0));
+ base::PlatformThread::Sleep(200);
+ EXPECT_FALSE(file_util::PathExists(test_file));
+}
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index e145a8c..6aeee43 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -368,6 +368,13 @@ bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state,
VLOG(1) << "Attempting to move setup to: " << temp_file.value();
ret = file_util::Move(setup_exe, temp_file);
PLOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value();
+
+ // We cannot delete the file right away, but try to delete it some other
+ // way. Either with the help of a different process or the system.
+ if (ret && !file_util::DeleteAfterReboot(temp_file)) {
+ static const uint32 kDeleteAfterMs = 10 * 1000;
+ installer::DeleteFileFromTempProcess(temp_file, kDeleteAfterMs);
+ }
}
return ret;
}