Index: goopdate/package_cache.cc |
diff --git a/goopdate/package_cache.cc b/goopdate/package_cache.cc |
deleted file mode 100644 |
index 0b178b16afb31d270fba7ae4d7f5b96b8b6845d0..0000000000000000000000000000000000000000 |
--- a/goopdate/package_cache.cc |
+++ /dev/null |
@@ -1,494 +0,0 @@ |
-// Copyright 2009 Google Inc. |
-// |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
-// you may not use this file except in compliance with the License. |
-// You may obtain a copy of the License at |
-// |
-// http://www.apache.org/licenses/LICENSE-2.0 |
-// |
-// Unless required by applicable law or agreed to in writing, software |
-// distributed under the License is distributed on an "AS IS" BASIS, |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-// See the License for the specific language governing permissions and |
-// limitations under the License. |
-// ======================================================================== |
- |
-#include "omaha/goopdate/package_cache.h" |
-#include <shlwapi.h> |
-#include "omaha/base/debug.h" |
-#include "omaha/base/error.h" |
-#include "omaha/base/file.h" |
-#include "omaha/base/logging.h" |
-#include "omaha/base/path.h" |
-#include "omaha/base/string.h" |
-#include "omaha/base/signatures.h" |
-#include "omaha/base/utils.h" |
-#include "omaha/common/config_manager.h" |
-#include "omaha/goopdate/package_cache_internal.h" |
-#include "omaha/goopdate/worker_metrics.h" |
- |
-namespace omaha { |
- |
-namespace internal { |
- |
-bool PackageSortByTimePredicate(const PackageInfo& package1, |
- const PackageInfo& package2) { |
- return ::CompareFileTime(&package1.file_time, &package2.file_time) > 0; |
-} |
- |
-bool IsSpecialDirectoryFindData(const WIN32_FIND_DATA& find_data) { |
- return find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && |
- (String_StrNCmp(find_data.cFileName, _T("."), 2, false) == 0 || |
- String_StrNCmp(find_data.cFileName, _T(".."), 3, false) == 0); |
-} |
- |
-bool IsSubDirectoryFindData(const WIN32_FIND_DATA& find_data) { |
- return find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && |
- !IsSpecialDirectoryFindData(find_data); |
-} |
- |
-bool IsFileFindData(const WIN32_FIND_DATA& find_data) { |
- return ((find_data.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) || |
- !(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); |
-} |
- |
-HRESULT FindAllPackagesInfo(const CString& cache_root, |
- std::vector<PackageInfo>* packages_info) { |
- ASSERT1(packages_info); |
- ASSERT1(packages_info->empty()); |
- return FindDirectoryPackagesInfo(cache_root, |
- CACHE_DIRECTORY_ROOT, |
- packages_info); |
-} |
- |
-HRESULT FindAppPackagesInfo(const CString& app_dir, |
- std::vector<PackageInfo>* packages_info) { |
- return FindDirectoryPackagesInfo(app_dir, CACHE_DIRECTORY_APP, packages_info); |
-} |
- |
-HRESULT FindVersionPackagesInfo(const CString& version_dir, |
- std::vector<PackageInfo>* packages_info) { |
- return FindDirectoryPackagesInfo(version_dir, |
- CACHE_DIRECTORY_VERSION, |
- packages_info); |
-} |
- |
-HRESULT FindFilePackagesInfo(const CString& version_dir, |
- const WIN32_FIND_DATA& find_data, |
- std::vector<PackageInfo>* packages_info) { |
- PackageInfo package_info; |
- package_info.file_name = ConcatenatePath(version_dir, find_data.cFileName); |
- package_info.file_time = ::CompareFileTime(&find_data.ftCreationTime, |
- &find_data.ftLastWriteTime) ? |
- find_data.ftCreationTime : |
- find_data.ftLastWriteTime; |
- package_info.file_size.LowPart = find_data.nFileSizeLow; |
- package_info.file_size.HighPart = find_data.nFileSizeHigh; |
- packages_info->push_back(package_info); |
- |
- return S_OK; |
-} |
- |
-HRESULT FindDirectoryPackagesInfo(const CString& dir_path, |
- CacheDirectoryType dir_type, |
- std::vector<PackageInfo>* packages_info) { |
- CORE_LOG(L4, (_T("[FindDirectoryPackagesInfo][%s][%d]"), dir_path, dir_type)); |
- |
- WIN32_FIND_DATA find_data = {0}; |
- scoped_hfind hfind(::FindFirstFile(dir_path + _T("\\*"), &find_data)); |
- if (!hfind) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(L4, (_T("[FindDirectoryPackagesInfo failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- HRESULT hr = S_OK; |
- do { |
- switch (dir_type) { |
- case CACHE_DIRECTORY_ROOT: |
- if (IsSubDirectoryFindData(find_data)) { |
- CString app_dir = ConcatenatePath(dir_path, find_data.cFileName); |
- hr = FindAppPackagesInfo(app_dir, packages_info); |
- } |
- break; |
- case CACHE_DIRECTORY_APP: |
- if (IsSubDirectoryFindData(find_data)) { |
- CString version_dir = ConcatenatePath(dir_path, find_data.cFileName); |
- hr = FindVersionPackagesInfo(version_dir, packages_info); |
- } |
- break; |
- case CACHE_DIRECTORY_VERSION: |
- if (IsFileFindData(find_data)) { |
- hr = FindFilePackagesInfo(dir_path, find_data, packages_info); |
- } |
- break; |
- } |
- |
- if (FAILED(hr)) { |
- CORE_LOG(L4, (_T("[FindDirectoryPackagesInfo failed][0x%x]"), hr)); |
- return hr; |
- } |
- } while (::FindNextFile(get(hfind), &find_data)); |
- |
- return S_OK; |
-} |
- |
-void SortPackageInfoByTime(std::vector<PackageInfo>* packages_info) { |
- std::sort(packages_info->begin(), |
- packages_info->end(), |
- PackageSortByTimePredicate); |
-} |
- |
-} // namespace internal |
- |
-PackageCache::PackageCache() { |
- cache_time_limit_days_ = |
- ConfigManager::Instance()->GetPackageCacheExpirationTimeDays(); |
- |
- cache_size_limit_bytes_ = 1024 * 1024 * static_cast<uint64>( |
- ConfigManager::Instance()->GetPackageCacheSizeLimitMBytes()); |
-} |
- |
-PackageCache::~PackageCache() { |
-} |
- |
-HRESULT PackageCache::Initialize(const CString& cache_root) { |
- CORE_LOG(L3, (_T("[PackageCache::Initialize][%s]"), cache_root)); |
- |
- __mutexScope(cache_lock_); |
- |
- if (!IsAbsolutePath(cache_root)) { |
- return E_INVALIDARG; |
- } |
- |
- HRESULT hr = CreateDir(cache_root, NULL); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[CreateDir failed][0x%x][%s]"), hr, cache_root)); |
- return hr; |
- } |
- |
- cache_root_ = cache_root; |
- |
- return S_OK; |
-} |
- |
-bool PackageCache::IsCached(const Key& key, const CString& hash) const { |
- CORE_LOG(L3, (_T("[PackageCache::IsCached][key '%s'][hash %s]"), |
- key.ToString(), hash)); |
- |
- __mutexScope(cache_lock_); |
- |
- CString filename; |
- HRESULT hr = BuildCacheFileNameForKey(key, &filename); |
- if (FAILED(hr)) { |
- return false; |
- } |
- |
- return File::Exists(filename) && SUCCEEDED(AuthenticateFile(filename, hash)); |
-} |
- |
-HRESULT PackageCache::Put(const Key& key, |
- const CString& source_file, |
- const CString& hash) { |
- ++metric_worker_package_cache_put_total; |
- CORE_LOG(L3, (_T("[PackageCache::Put][key '%s'][source_file '%s'][hash %s]"), |
- key.ToString(), source_file, hash)); |
- |
- __mutexScope(cache_lock_); |
- |
- if (key.app_id().IsEmpty() || key.version().IsEmpty() || |
- key.package_name().IsEmpty() ) { |
- return E_INVALIDARG; |
- } |
- |
- CString destination_file; |
- HRESULT hr = BuildCacheFileNameForKey(key, &destination_file); |
- CORE_LOG(L3, (_T("[destination file '%s']"), destination_file)); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- hr = CreateDir(GetDirectoryFromPath(destination_file), NULL); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[failed to create cache directory][0x%08x][%s]"), |
- hr, destination_file)); |
- return hr; |
- } |
- |
- // TODO(omaha): consider not overwriting the file if the file is |
- // in the cache and it is valid. |
- |
- // When not impersonated, File::Copy resets the ownership of the destination |
- // file and it inherits ACEs from the new parent directory. |
- hr = File::Copy(source_file, destination_file, true); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[failed to copy file to cache][0x%08x][%s]"), |
- hr, destination_file)); |
- return hr; |
- } |
- |
- hr = AuthenticateFile(destination_file, hash); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[failed to authenticate '%s'][%s]"), |
- destination_file, hash)); |
- VERIFY1(SUCCEEDED(::DeleteFile(destination_file))); |
- return hr; |
- } |
- |
- ++metric_worker_package_cache_put_succeeded; |
- return S_OK; |
-} |
- |
-HRESULT PackageCache::Get(const Key& key, |
- const CString& destination_file, |
- const CString& hash) const { |
- CORE_LOG(L3, (_T("[PackageCache::Get][key '%s'][dest file '%s'][hash '%s']"), |
- key.ToString(), destination_file, hash)); |
- |
- __mutexScope(cache_lock_); |
- |
- if (key.app_id().IsEmpty() || key.version().IsEmpty() || |
- key.package_name().IsEmpty() ) { |
- return E_INVALIDARG; |
- } |
- |
- CString source_file; |
- HRESULT hr = BuildCacheFileNameForKey(key, &source_file); |
- CORE_LOG(L3, (_T("[source file '%s']"), source_file)); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- if (!File::Exists(source_file)) { |
- return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); |
- } |
- |
- hr = AuthenticateFile(source_file, hash); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[failed to authenticate '%s']"), source_file)); |
- return hr; |
- } |
- |
- return File::Copy(source_file, destination_file, true); |
-} |
- |
-HRESULT PackageCache::Purge(const Key& key) { |
- CORE_LOG(L3, (_T("[PackageCache::Purge][key '%s']"), key.ToString())); |
- |
- __mutexScope(cache_lock_); |
- |
- return Delete(key.app_id(), key.version(), key.package_name()); |
-} |
- |
-HRESULT PackageCache::PurgeVersion(const CString& app_id, |
- const CString& version) { |
- CORE_LOG(L3, (_T("[PackageCache::PurgeVersion][app_id '%s'][version '%s']"), |
- app_id, version)); |
- |
- __mutexScope(cache_lock_); |
- |
- return Delete(app_id, version, _T("")); |
-} |
- |
-HRESULT PackageCache::PurgeApp(const CString& app_id) { |
- CORE_LOG(L3, (_T("[PackageCache::PurgeApp][app_id '%s']"), app_id)); |
- |
- __mutexScope(cache_lock_); |
- |
- return Delete(app_id, _T(""), _T("")); |
-} |
- |
-HRESULT PackageCache::PurgeAppLowerVersions(const CString& app_id, |
- const CString& version) { |
- CORE_LOG(L3, (_T("[PackageCache::PurgeAppLowerVersions][%s][%s]"), |
- app_id, version)); |
- |
- __mutexScope(cache_lock_); |
- |
- ULONGLONG my_version = VersionFromString(version); |
- if (!my_version) { |
- return E_INVALIDARG; |
- } |
- |
- CString app_id_path; |
- HRESULT hr = BuildCacheFileName(app_id, CString(), CString(), &app_id_path); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[BuildCacheFileName fail][%s][0x%x]"), app_id_path, hr)); |
- return hr; |
- } |
- |
- WIN32_FIND_DATA find_data = {0}; |
- scoped_hfind hfind(::FindFirstFile(app_id_path + _T("\\*"), &find_data)); |
- if (!hfind) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(L4, (_T("[FindFirstFile failed][%s][0x%x]"), app_id_path, hr)); |
- return hr; |
- } |
- |
- do { |
- if (internal::IsSpecialDirectoryFindData(find_data)) { |
- continue; |
- } |
- ASSERT1(internal::IsSubDirectoryFindData(find_data)); |
- |
- ULONGLONG found_version = VersionFromString(find_data.cFileName); |
- if (!found_version || found_version >= my_version) { |
- CORE_LOG(L2, (_T("[Not purging version][%s]"), find_data.cFileName)); |
- continue; |
- } |
- |
- CString version_dir = ConcatenatePath(app_id_path, find_data.cFileName); |
- hr = DeleteBeforeOrAfterReboot(version_dir); |
- CORE_LOG(L3, (_T("[Purge version][%s][0x%x]"), version_dir, hr)); |
- } while (::FindNextFile(get(hfind), &find_data)); |
- |
- return S_OK; |
-} |
- |
-HRESULT PackageCache::PurgeAll() { |
- CORE_LOG(L3, (_T("[PackageCache::PurgeAll]"))); |
- |
- __mutexScope(cache_lock_); |
- |
- // Deletes the cache root including all the cache entries. |
- HRESULT hr = Delete(_T(""), _T(""), _T("")); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- // Recreate the cache root. |
- hr = CreateDir(cache_root_, NULL); |
- if (FAILED(hr)) { |
- CORE_LOG(LW, (_T("[CreateDir failed][0x%x][%s]"), hr, cache_root_)); |
- return hr; |
- } |
- |
- return hr; |
-} |
- |
-FILETIME PackageCache::GetCacheExpirationTime() const { |
- FILETIME current_time = {0}; |
- ::GetSystemTimeAsFileTime(¤t_time); |
- ULARGE_INTEGER now = {0}; |
- now.LowPart = current_time.dwLowDateTime; |
- now.HighPart = current_time.dwHighDateTime; |
- |
- const uint64 kNum100NanoSecondsInDay = 1000LL * 1000 * 10 * kSecondsPerDay; |
- now.QuadPart -= kNum100NanoSecondsInDay * cache_time_limit_days_; |
- |
- FILETIME expiration_time = {0}; |
- expiration_time.dwLowDateTime = now.LowPart; |
- expiration_time.dwHighDateTime = now.HighPart; |
- |
- return expiration_time; |
-} |
- |
-HRESULT PackageCache::PurgeOldPackagesIfNecessary() const { |
- __mutexScope(cache_lock_); |
- |
- std::vector<internal::PackageInfo> packages_info; |
- HRESULT hr = internal::FindAllPackagesInfo(cache_root_, &packages_info); |
- |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[internal::FindAllPackagesInfo failed][0x%x]"), hr)); |
- return hr; |
- } |
- internal::SortPackageInfoByTime(&packages_info); |
- |
- FILETIME expiration_time = GetCacheExpirationTime(); |
- |
- // Delete cached package based on the package info. |
- std::vector<internal::PackageInfo>::const_iterator it; |
- uint64 total_cache_size = 0; |
- for (it = packages_info.begin(); it != packages_info.end(); ++it) { |
- total_cache_size += it->file_size.QuadPart; |
- if (total_cache_size > cache_size_limit_bytes_) { |
- break; // Remaining packages should be deleted as size limit is reached. |
- } |
- if (::CompareFileTime(&it->file_time, &expiration_time) < 0) { |
- break; // Remaining packages should be deleted as they are expired. |
- } |
- } |
- |
- for (; it != packages_info.end(); ++it) { |
- hr = DeleteBeforeOrAfterReboot(it->file_name); |
- } |
- |
- return hr; |
-} |
- |
-HRESULT PackageCache::Delete(const CString& app_id, |
- const CString& version, |
- const CString& package_name) { |
- CString filename; |
- HRESULT hr = BuildCacheFileName(app_id, version, package_name, &filename); |
- CORE_LOG(L3, (_T("[PackageCache::Delete '%s']"), filename)); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- return DeleteBeforeOrAfterReboot(filename); |
-} |
- |
-CString PackageCache::cache_root() const { |
- __mutexScope(cache_lock_); |
- |
- ASSERT1(!cache_root_.IsEmpty()); |
- ASSERT1(File::Exists(cache_root_)); |
- |
- return cache_root_; |
-} |
- |
-uint64 PackageCache::Size() const { |
- uint64 result(0); |
- return SUCCEEDED(GetDirectorySize(cache_root_, &result)) ? result : 0; |
-} |
- |
-HRESULT PackageCache::BuildCacheFileNameForKey(const Key& key, |
- CString* filename) const { |
- ASSERT1(filename); |
- |
- return BuildCacheFileName(key.app_id(), |
- key.version(), |
- key.package_name(), |
- filename); |
-} |
- |
-HRESULT PackageCache::BuildCacheFileName(const CString& app_id, |
- const CString& version, |
- const CString& package_name, |
- CString* filename) const { |
- ASSERT1(filename); |
- |
- // Validate the package name does not contain the "..". |
- if (package_name.Find(_T("..")) != -1) { |
- return E_INVALIDARG; |
- } |
- |
- CString tmp_filename; |
- tmp_filename = ConcatenatePath(cache_root_, app_id); |
- tmp_filename = ConcatenatePath(tmp_filename, version); |
- tmp_filename = ConcatenatePath(tmp_filename, package_name); |
- |
- *filename = tmp_filename; |
- |
- return S_OK; |
-} |
- |
-HRESULT PackageCache::AuthenticateFile(const CString& filename, |
- const CString& hash) { |
- CORE_LOG(L3, (_T("[PackageCache::AuthenticateFile][%s][%s]"), |
- filename, hash)); |
- HighresTimer authentication_timer; |
- |
- std::vector<CString> files; |
- files.push_back(filename); |
- HRESULT hr = AuthenticateFiles(files, hash); |
- CORE_LOG(L3, (_T("[PackageCache::AuthenticateFile completed][0x%08x][%d ms]"), |
- hr, authentication_timer.GetElapsedMs())); |
- |
- return hr; |
-} |
- |
-} // namespace omaha |
- |