diff options
author | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-12 19:36:36 +0000 |
---|---|---|
committer | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-12 19:36:36 +0000 |
commit | 37779e0d685e3e8cf948ebae2bb7dc9c04aa876f (patch) | |
tree | 42047d8e7a5a6cfba3df9ce1538be31f84fddee9 | |
parent | c7b3c63a202ab95967a51a69397dbe7b4abe423a (diff) | |
download | chromium_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.cc | 57 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util.h | 10 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util_unittest.cc | 11 | ||||
-rw-r--r-- | chrome/installer/setup/uninstall.cc | 7 |
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; } |