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

Unified Diff: base/file.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 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 | « base/file.h ('k') | base/file_reader.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/file.cc
diff --git a/base/file.cc b/base/file.cc
deleted file mode 100644
index 8317af16d881450ff06f2e0d7a7a6468062f5bad..0000000000000000000000000000000000000000
--- a/base/file.cc
+++ /dev/null
@@ -1,1430 +0,0 @@
-// Copyright 2003-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.
-// ========================================================================
-// File handling routines
-//
-// Possible performance improvement: make a subclass or alternate class
-// that reads an entire file into memory and fulfills read/write requests
-// in memory (or equivalently, use a memory mapped file). This can greatly
-// improve performance if there are files we do a lot of read/write requests on.
-//
-// We generally are dealing with files that can be very large and want to
-// minimize memory usage, so this is not high priority
-//
-// this has the beginnings of asynchronous access support
-//
-// Unfortunately, doing asynchronous reads with FILE_FLAG_OVERLAPPED buys us
-// nothing because the system cache manager enforces serial requests.
-//
-// Hence, we need to also use FILE_FLAG_NO_BUFFERING. this has a number of
-// constraints:
-// - file read/write position must be aligned on multiples of the disk sector
-// size
-// - file read/write length must be a multiple of the sector size
-// - read/write buffer must be aligned on multiples of the disk sector size
-//
-// In particular, this means that we cannot write 8 bytes, for example, because
-// we have to write an entire sector.
-//
-// Currently, the implementation only supports enough to do some simple read
-// tests
-//
-// The general idea is code that wants to to a sequence of asynchronous actions
-// will look like the following, for an example of reading multiple event
-// records asynchronously:
-//
-// uint32 async_id = File::GetNextAsyncId()
-// while (!done) {
-// for (everything_to_do, e.g., for each event to read) {
-// call File::Read to read items needed;
-// returns TR_E_FILE_ASYNC_PENDING if queued; or returns data if done
-// process the item (e.g., event) if desired
-// }
-// call some routine to process pending completions; initiate delayed action
-// }
-// call some cleanup routine
-
-#include "omaha/base/file.h"
-#include <algorithm>
-#include "base/scoped_ptr.h"
-#include "omaha/base/app_util.h"
-#include "omaha/base/const_config.h"
-#include "omaha/base/debug.h"
-#include "omaha/base/error.h"
-#include "omaha/base/logging.h"
-#include "omaha/base/path.h"
-#include "omaha/base/reg_key.h"
-#include "omaha/base/scoped_any.h"
-#include "omaha/base/scoped_ptr_address.h"
-#include "omaha/base/string.h"
-#include "omaha/base/system.h"
-#include "omaha/base/timer.h"
-#include "omaha/base/utils.h"
-
-namespace omaha {
-
-// Constants
-const uint32 kZeroSize = 4096; // Buffer size used for clearing data in a file.
-
-// The moves-pending-reboot is a MULTISZ registry key in the HKLM part of the
-// registry.
-static const TCHAR* kSessionManagerKey =
- _T("HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager");
-static const TCHAR* kPendingFileRenameOps = _T("PendingFileRenameOperations");
-
-File::File()
- : handle_(INVALID_HANDLE_VALUE), read_only_(false), sequence_id_(0) {
-}
-
-File::~File() {
- if (handle_ != INVALID_HANDLE_VALUE) {
- VERIFY1(SUCCEEDED(Close()));
- }
-}
-
-// open for reading only if write == false, otherwise both reading and writing
-// allow asynchronous operations if async == true. Use this function when you
-// need exclusive access to the file.
-HRESULT File::Open(const TCHAR* file_name, bool write, bool async) {
- return OpenShareMode(file_name, write, async, 0);
-}
-
-// Allows specifying a sharing mode such as FILE_SHARE_READ. Otherwise,
-// this is identical to File::Open().
-HRESULT File::OpenShareMode(const TCHAR* file_name,
- bool write,
- bool async,
- DWORD share_mode) {
- ASSERT1(file_name && *file_name);
- ASSERT1(handle_ == INVALID_HANDLE_VALUE);
- VERIFY1(!async);
-
- file_name_ = file_name;
-
- // there are restrictions on what we can do if using FILE_FLAG_NO_BUFFERING
- // if (!buffer) { flags |= FILE_FLAG_NO_BUFFERING; }
- // FILE_FLAG_WRITE_THROUGH
- // how efficient is NTFS encryption? FILE_ATTRIBUTE_ENCRYPTED
- // FILE_ATTRIBUTE_TEMPORARY
- // FILE_FLAG_RANDOM_ACCESS
- // FILE_FLAG_SEQUENTIAL_SCAN
-
- handle_ = ::CreateFile(file_name,
- write ? (FILE_WRITE_DATA |
- FILE_WRITE_ATTRIBUTES |
- FILE_READ_DATA) : FILE_READ_DATA,
- share_mode,
- NULL,
- write ? OPEN_ALWAYS : OPEN_EXISTING,
- FILE_FLAG_RANDOM_ACCESS,
- NULL);
-
- if (handle_ == INVALID_HANDLE_VALUE) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR,
- (_T("[File::OpenShareMode - CreateFile failed][%s][%d][%d][0x%x]"),
- file_name, write, async, hr));
- return hr;
- }
-
- // This attribute is not supported directly by the CreateFile function.
- if (write &&
- !::SetFileAttributes(file_name, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR,
- (_T("[File::OpenShareMode - SetFileAttributes failed][0x%x]"), hr));
- return hr;
- }
-
- read_only_ = !write;
- pos_ = 0;
- return S_OK;
-}
-
-// The path must not be enclosed in quotes. This is the Windows standard.
-// ::GetFileAttributesEx() returns ERROR_INVALID_NAME for quoted paths.
-bool File::Exists(const TCHAR* file_name) {
- ASSERT1(file_name && *file_name);
- ASSERT1(lstrlen(file_name) > 0);
-
- // NOTE: This is the fastest implementation I found. The results were:
- // CreateFile 1783739 avg ticks/call
- // FindFirstFile 634148 avg ticks/call
- // GetFileAttributes 428714 avg ticks/call
- // GetFileAttributesEx 396324 avg ticks/call
- WIN32_FILE_ATTRIBUTE_DATA attrs = {0};
- return 0 != ::GetFileAttributesEx(file_name, ::GetFileExInfoStandard, &attrs);
-}
-
-bool File::IsDirectory(const TCHAR* file_name) {
- ASSERT1(file_name && *file_name);
-
- WIN32_FILE_ATTRIBUTE_DATA attrs;
- SetZero(attrs);
- if (!::GetFileAttributesEx(file_name, ::GetFileExInfoStandard, &attrs)) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[File::IsDirectory - GetFileAttributesEx failed][%s][0x%x]"),
- file_name, HRESULTFromLastError()));
- return false;
- }
-
- return (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
-}
-
-HRESULT File::GetWildcards(const TCHAR* dir,
- const TCHAR* wildcard,
- std::vector<CString>* matching_paths) {
- ASSERT1(dir && *dir);
- ASSERT1(wildcard && *wildcard);
- ASSERT1(matching_paths);
-
- matching_paths->clear();
-
- // Make sure directory name ends with "\"
- CString directory = String_MakeEndWith(dir, _T("\\"), false);
-
- WIN32_FIND_DATA find_data;
- SetZero(find_data);
- scoped_hfind hfind(::FindFirstFile(directory + wildcard, &find_data));
- if (!hfind) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(L5, (_T("[File::GetWildcards - FindFirstFile failed][0x%x]"), hr));
- return hr;
- }
- do {
- if (find_data.dwFileAttributes == FILE_ATTRIBUTE_NORMAL ||
- !(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
- CString to_file(directory + find_data.cFileName);
- matching_paths->push_back(to_file);
- }
- } while (::FindNextFile(get(hfind), &find_data));
-
- HRESULT hr = HRESULTFromLastError();
- if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[File::GetWildcards - FindNextFile failed][0x%x]"), hr));
- return hr;
- }
- return S_OK;
-}
-
-// returns error if cannot remove
-// returns success if removed or already removed
-HRESULT File::Remove(const TCHAR* file_name) {
- ASSERT1(file_name && *file_name);
-
- if (!Exists(file_name)) {
- return S_OK;
- }
-
- if (!::DeleteFile(file_name)) {
- return HRESULTFromLastError();
- }
-
- return S_OK;
-}
-
-HRESULT File::CopyWildcards(const TCHAR* from_dir,
- const TCHAR* to_dir,
- const TCHAR* wildcard,
- bool replace_existing_files) {
- ASSERT1(from_dir && *from_dir);
- ASSERT1(to_dir && *to_dir);
- ASSERT1(wildcard && *wildcard);
-
- // Make sure dir names end with a "\"
- CString from_directory = String_MakeEndWith(from_dir, _T("\\"), false);
- CString to_directory = String_MakeEndWith(to_dir, _T("\\"), false);
-
- // Get full path to source files (which is a wildcard)
- CString from_files(from_directory + wildcard);
-
- // Run over all files that match wildcard
- WIN32_FIND_DATA find_data;
- SetZero(find_data);
-
- scoped_hfind hfind(::FindFirstFile(from_files, &find_data));
- if (!hfind) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR,
- (_T("[File::CopyWildcards - FindFirstFile failed][0x%x]"), hr));
- return hr;
- }
- do {
- // Copy files
- if (find_data.dwFileAttributes == FILE_ATTRIBUTE_NORMAL ||
- !(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
- CString from_file(from_directory + find_data.cFileName);
- CString to_file(to_directory + find_data.cFileName);
-
- if (!replace_existing_files && Exists(to_file)) {
- // Continue, since the caller has explicitly asked us to not replace an
- // existing file
- continue;
- }
-
- RET_IF_FAILED(Copy(from_file, to_file, replace_existing_files));
- }
- } while (::FindNextFile(get(hfind), &find_data));
-
- HRESULT hr = HRESULTFromLastError();
- if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[File::CopyWildcards - FindNextFile failed][0x%x]"), hr));
- return hr;
- }
- return S_OK;
-}
-
-HRESULT File::CopyTree(const TCHAR* from_dir,
- const TCHAR* to_dir,
- bool replace_existing_files) {
- ASSERT1(from_dir && *from_dir);
- ASSERT1(to_dir && *to_dir);
-
- UTIL_LOG(L3, (L"[File::CopyTree][from_dir %s][to_dir %s][replace %d]",
- from_dir, to_dir, replace_existing_files));
-
- // Make sure dir names end with a "\"
- CString from_directory(String_MakeEndWith(from_dir, L"\\", false));
- CString to_directory(String_MakeEndWith(to_dir, L"\\", false));
-
- RET_IF_FAILED(CreateDir(to_directory, NULL));
- RET_IF_FAILED(CopyWildcards(from_directory,
- to_directory,
- L"*.*",
- replace_existing_files));
-
- // Run over all directories
- WIN32_FIND_DATA find_data;
- SetZero(find_data);
-
- CString from_files(from_directory);
- from_files += _T("*.*");
-
- scoped_hfind hfind(::FindFirstFile(from_files, &find_data));
- if (!hfind) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR,
- (_T("[File::CopyTree - FindFirstFile failed][0x%x]"), hr));
- return hr;
- }
- do {
- // Copy files
- if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 &&
- String_StrNCmp(find_data.cFileName, L"..", 2, false) &&
- String_StrNCmp(find_data.cFileName, L".", 2, false)) {
- CString from_subdir(from_directory + find_data.cFileName);
- CString to_subdir(to_directory + find_data.cFileName);
- RET_IF_FAILED(CopyTree(from_subdir, to_subdir, replace_existing_files));
- }
- } while (::FindNextFile(get(hfind), &find_data));
-
- HRESULT hr = HRESULTFromLastError();
- if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[File::CopyTree - FindNextFile failed][0x%x]"), hr));
- return hr;
- }
-
- return S_OK;
-}
-
-HRESULT File::Copy(const TCHAR* from,
- const TCHAR* to,
- bool replace_existing_file) {
- ASSERT1(from && *from);
- ASSERT1(to && *to);
-
- if (!replace_existing_file && Exists(to)) {
- // Return success, since the caller has explicitly asked us to not replace
- // an existing file
- return S_OK;
- }
-
- if (!::CopyFile(from, to, !replace_existing_file)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::Copy - CopyFile failed]")
- _T("[from=%s][to=%s][replace=%u][0x%x]"),
- from, to, replace_existing_file, hr));
- return hr;
- }
-
- return S_OK;
-}
-
-// TODO(omaha): Combine common code in Move/MoveAfterReboot
-HRESULT File::Move(const TCHAR* from,
- const TCHAR* to,
- bool replace_existing_file) {
- ASSERT1(from && *from);
- ASSERT1(to && *to);
-
- DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH;
- if (replace_existing_file) {
- flags |= MOVEFILE_REPLACE_EXISTING;
- }
-
- if (!::MoveFileEx(from, to, flags)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR,
- (_T("[File::Move - MoveFileEx failed]")
- _T("[from=%s][to=%s][replace=%u][0x%x]"),
- from, to, replace_existing_file, hr));
- return hr;
- }
-
- return S_OK;
-}
-
-// DeleteAfterReboot tries to delete the files by either moving them to the TEMP
-// directory and deleting them on reboot, or if that fails, by trying to delete
-// them in-place on reboot
-HRESULT File::DeleteAfterReboot(const TCHAR* from) {
- ASSERT1(from && *from);
-
- if (File::Exists(from)) {
- HRESULT hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
- CString from_temp;
-
- // No point in moving into TEMP if we're already there
- if (!String_StartsWith(from, app_util::GetTempDir(), true)) {
- // Try to move to the TEMP directory first
- CString temp_dir(String_MakeEndWith(app_util::GetTempDir(),
- _T("\\"),
- false));
- // Of the form "C:\\Windows\\Temp\\FROM.EXE1f4c0b7f"
- from_temp.Format(_T("%s%s%x"),
- temp_dir,
- GetFileFromPath(from),
- ::GetTickCount());
-
- hr = File::Move(from, from_temp, true);
- UTIL_LOG(L2, (_T("[File::DeleteAfterReboot - move %s to %s][0x%x]"),
- from, from_temp, hr));
- }
-
- if (SUCCEEDED(hr)) {
- UTIL_LOG(L2, (_T("[File::DeleteAfterReboot - delete %s after reboot]"),
- from_temp));
- // Move temp file after reboot
- if (FAILED(hr = File::MoveAfterReboot(from_temp, NULL))) {
- UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
- _T("[failed to delete after reboot %s][0x%x]"),
- from_temp, hr));
- }
- } else {
- // Move original file after reboot
- if (FAILED(hr = File::MoveAfterReboot(from, NULL))) {
- UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
- _T("[failed to delete after reboot %s][0x%x]"),
- from, hr));
- }
- }
-
- return hr;
- }
-
- return S_OK;
-}
-
-
-HRESULT File::MoveAfterReboot(const TCHAR* from, const TCHAR* to) {
- ASSERT1(from && *from);
-
- if (!File::Exists(from)) {
- // File/directory doesn't exist, should this return failure or success?
- // Decision: Failure. Because the caller can decide if it is really
- // failure or not in his specific case.
- UTIL_LOG(LEVEL_WARNING, (_T("[File::MoveAfterReboot]")
- _T("[file doesn't exist][from %s]"), from));
- return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
- }
-
- DWORD flags = MOVEFILE_DELAY_UNTIL_REBOOT;
- if (!File::IsDirectory(from)) {
- // This flag valid only for files
- flags |= MOVEFILE_REPLACE_EXISTING;
- }
-
- if (!::MoveFileEx(from, to, flags)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::MoveAfterReboot]")
- _T("[failed to MoveFileEx from '%s' to '%s'][0x%x]"),
- from, to, hr));
- return hr;
- }
-
- return S_OK;
-}
-
-// See if we have any moves pending a reboot. Return SUCCESS if we do
-// not encounter errors (not finding a move is not an error). We need to
-// also check the value of *found_ptr for whether we actually found a move.
-// On return, *value_multisz_ptr is the value within
-// "PendingFileRenameOperations", but with any moves for in_directory removed
-// from it.
-// The prefix_match boolean controls whether we do an exact match on
-// in_directory, or remove all entries with the in_directory prefix.
-// NOTE: If the only values found were our own keys, the whole
-// PendingFileRenameOperations MULTISZ needs to be deleted.
-// This is signified by a returned *value_size_chars_ptr of 0.
-HRESULT File::GetPendingRenamesValueMinusDir(const TCHAR* in_directory,
- bool prefix_match,
- TCHAR** value_multisz_ptr,
- DWORD* value_size_chars_ptr,
- bool* found_ptr) {
- ASSERT1(in_directory && *in_directory);
-
- // Convert to references for easier-to-read-code:
- TCHAR*& value_multisz = *value_multisz_ptr;
- DWORD& value_size_chars = *value_size_chars_ptr;
- bool& found = *found_ptr;
-
- // Initialize [out] parameters
- value_multisz = NULL;
- value_size_chars = 0;
- found = false;
-
- // Locals mirroring the [out] parameters.
- // We will only set the corresponding [out] parameters when we have something
- // meaningful to return to the caller
- scoped_array<TCHAR> value_multisz_local;
- DWORD value_size_chars_local = 0;
-
- DWORD value_size_bytes = 0;
- // Get the current value of the key
- // If the Key is missing, that's totally acceptable.
- RET_IF_FALSE(
- RegKey::HasValue(kSessionManagerKey, kPendingFileRenameOps) &&
- SUCCEEDED(RegKey::GetValue(kSessionManagerKey,
- kPendingFileRenameOps,
- reinterpret_cast<byte**>(&value_multisz_local),
- &value_size_bytes)),
- S_OK);
-
- ASSERT1(value_multisz_local.get() || value_size_bytes == 0);
- UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")
- _T("[read multisz %d bytes]"),
- value_size_bytes));
- RET_IF_FALSE(value_size_bytes > 0, S_OK);
-
- // The size should always be aligned to a TCHAR boundary, otherwise the key
- // is corrupted.
- ASSERT1((value_size_bytes % sizeof(TCHAR)) == 0);
- RET_IF_FALSE((value_size_bytes % sizeof(TCHAR)) == 0,
- HRESULT_FROM_WIN32(ERROR_BADKEY));
- // Valid size, so convert to TCHARs:
- value_size_chars_local = value_size_bytes / sizeof(TCHAR);
-
- // Buffer must terminate with two nulls
- ASSERT(value_size_chars_local >= 2 &&
- !value_multisz_local[value_size_chars_local - 1] &&
- !value_multisz_local[value_size_chars_local - 2],
- (_T("buffer must terminate with two nulls")));
- RET_IF_FALSE(value_size_chars_local >= 2 &&
- !value_multisz_local[value_size_chars_local - 1] &&
- !value_multisz_local[value_size_chars_local - 2],
- HRESULT_FROM_WIN32(ERROR_BADKEY));
- // Mark the end of the string.
- // multisz_end will point at the character past end of buffer:
- TCHAR* multisz_end = value_multisz_local.get() + value_size_chars_local;
-
- // We're looking for \??\C:\... The \??\ was
- // added by the OS to the directory name we specified.
- CString from_dir(_T("\\??\\"));
- from_dir += in_directory;
- DWORD from_dir_len = from_dir.GetLength();
-
- // A MULTISZ is a list of null terminated strings, terminated by a double
- // null. We keep two pointers marching along the string in parallel.
- TCHAR* str_read = value_multisz_local.get();
- TCHAR* str_write = str_read;
-
- while ((str_read < multisz_end) && *str_read) {
- size_t str_len = ::lstrlen(str_read);
- // A FALSE here indicates a corrupt PendingFileRenameOperations
- RET_IF_FALSE((str_read + str_len + 1) < multisz_end,
- HRESULT_FROM_WIN32(ERROR_BADKEY));
- if (0 == String_StrNCmp(str_read,
- from_dir,
- from_dir_len + (prefix_match ? 0 : 1),
- true)) {
- // String matches, we want to remove this string, so advance only the
- // read pointer - past this string and the replacement string.
- UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")
- _T("[skips past match '%s']"),
- str_read));
- str_read += str_len + 1;
- str_read += ::lstrlen(str_read) + 1;
- continue;
- }
- // String doesn't match, we want to keep it.
- if (str_read != str_write) {
- // Here we're not in sync in the buffer, we've got to move two
- // strings down.
- UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")
- _T("[copying some other deletion][%s][%s]"),
- str_read, str_read + ::lstrlen(str_read) + 1));
- ASSERT1(str_write < str_read);
- String_StrNCpy(str_write, str_read, str_len+1);
- str_read += str_len + 1;
- str_write += str_len + 1;
- str_len = ::lstrlen(str_read);
- String_StrNCpy(str_write, str_read, str_len+1);
- str_read += str_len + 1;
- str_write += str_len + 1;
- } else {
- // We're in sync in the buffer, advance both pointers past two strings
- UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")
- _T("[skipping past some other deletion][%s][%s]"),
- str_read, str_read + ::lstrlen(str_read) + 1));
- str_read += str_len + 1;
- str_read += ::lstrlen(str_read) + 1;
- str_write = str_read;
- }
- }
-
- // A FALSE here indicates a corrupt PendingFileRenameOperations
- RET_IF_FALSE(str_read < multisz_end,
- HRESULT_FROM_WIN32(ERROR_BADKEY));
-
- if (str_read != str_write) {
- // We found some values
- found = true;
-
- if (str_write == value_multisz_local.get()) {
- // The only values were our own keys,
- // and the whole PendingFileRenameOperations
- // value needs to be deleted. We do not populate
- // value_size_chars or value_multisz in this case.
- ASSERT1(!value_size_chars);
- ASSERT1(!value_multisz);
- } else {
- // The last string should have a NULL terminator:
- ASSERT1(str_write[-1] == '\0');
- RET_IF_FALSE(str_write[-1] == '\0',
- HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
- // a REG_MULTI_SZ needs to be terminated with an extra NULL.
- *str_write = '\0';
- ++str_write;
-
- // Populate value_size_chars and value_multisz in this case.
- value_multisz = value_multisz_local.release();
- value_size_chars = str_write - value_multisz;
- }
- }
-
- return S_OK;
-}
-
-// Remove any moves pending a reboot from the PendingFileRenameOperations
-// in the registry.
-// The prefix_match boolean controls whether we do an exact match on
-// in_directory, or remove all entries with the in_directory prefix.
-HRESULT File::RemoveFromMovesPendingReboot(const TCHAR* in_directory,
- bool prefix_match) {
- ASSERT1(in_directory && *in_directory);
-
- bool found = false;
- // scoped_array will free the value_multisz buffer on stack unwind:
- scoped_array<TCHAR> value_multisz;
- DWORD value_size_chars = 0;
- HRESULT hr = GetPendingRenamesValueMinusDir(in_directory,
- prefix_match,
- address(value_multisz),
- &value_size_chars,
- &found);
- if (SUCCEEDED(hr) && found) {
- if (value_multisz.get() == NULL) {
- // There's no point in writing an empty value_multisz.
- // Let's delete the PendingFileRenameOperations value
- UTIL_LOG(L5, (_T("[File::RemoveFromMovesPendingReboot]")
- _T("[deleting PendingFileRenameOperations value]")));
- RET_IF_FAILED(RegKey::DeleteValue(kSessionManagerKey,
- kPendingFileRenameOps));
- } else {
- // Let's write the modified value_multisz into the
- // PendingFileRenameOperations value
- UTIL_LOG(L5, (_T("[File::RemoveFromMovesPendingReboot]")
- _T("[rewriting multisz %d bytes]"),
- value_size_chars * sizeof(TCHAR)));
- RET_IF_FAILED(RegKey::SetValueMultiSZ(
- kSessionManagerKey,
- kPendingFileRenameOps,
- reinterpret_cast<byte*>(value_multisz.get()),
- value_size_chars * sizeof(TCHAR)));
- }
- }
-
- // Failure of GetPendingRenamesValueMinusDir() may indicate something
- // seriously wrong with the system. Propogate error.
- return hr;
-}
-
-// Did the user try to uninstall a previous install of the same version, and
-// we couldn't clean up without a reboot?
-// We check if there are any moves pending a reboot from the
-// PendingFileRenameOperations in the registry.
-// The prefix_match boolean controls whether we do an exact match on
-// in_directory, or check all entries with the in_directory prefix.
-bool File::AreMovesPendingReboot(const TCHAR* in_directory, bool prefix_match) {
- ASSERT1(in_directory && *in_directory);
-
- bool found = false;
- // scoped_array will free the value_multisz buffer on stack unwind:
- scoped_array<TCHAR> value_multisz;
- DWORD value_size_chars = 0;
-
- if (SUCCEEDED(GetPendingRenamesValueMinusDir(in_directory,
- prefix_match,
- address(value_multisz),
- &value_size_chars,
- &found)) && found) {
- return true;
- }
-
- return false;
-}
-
-HRESULT File::GetFileTime(const TCHAR* file_name,
- FILETIME* created,
- FILETIME* accessed,
- FILETIME* modified) {
- ASSERT1(file_name && *file_name);
-
- bool is_dir = IsDirectory(file_name);
- // To obtain a handle to a directory, call the CreateFile function with
- // the FILE_FLAG_BACKUP_SEMANTICS flag
- scoped_hfile file_handle(
- ::CreateFile(file_name,
- FILE_READ_DATA,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- is_dir ? FILE_FLAG_BACKUP_SEMANTICS : NULL,
- NULL));
- HRESULT hr = S_OK;
-
- if (!file_handle) {
- hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[File::GetFileTime]")
- _T("[failed to open file][%s][0x%x]"), file_name, hr));
- } else {
- if (!::GetFileTime(get(file_handle), created, accessed, modified)) {
- hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::GetFileTime]")
- _T("[failed to get file time][%s][0x%x]"),
- file_name, hr));
- }
- }
-
- return hr;
-}
-
-HRESULT File::SetFileTime(const TCHAR* file_name,
- const FILETIME* created,
- const FILETIME* accessed,
- const FILETIME* modified) {
- ASSERT1(file_name && *file_name);
-
- bool is_dir = IsDirectory(file_name);
- // To obtain a handle to a directory, call the CreateFile function with
- // the FILE_FLAG_BACKUP_SEMANTICS flag
- scoped_hfile file_handle(
- ::CreateFile(file_name,
- FILE_WRITE_ATTRIBUTES,
- FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- is_dir ? FILE_FLAG_BACKUP_SEMANTICS : NULL,
- NULL));
- HRESULT hr = S_OK;
-
- if (!file_handle) {
- hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::GetFileTime]")
- _T("[failed to open file][%s][0x%x]"),
- file_name, hr));
- } else {
- BOOL res = ::SetFileTime(get(file_handle), created, accessed, modified);
- if (!res) {
- hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::SetFileTime]")
- _T("[failed to set file time][%s][0x%x]"),
- file_name, hr));
- }
- }
-
- return hr;
-}
-
-HRESULT File::Sync() {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
-
- if (!::FlushFileBuffers(handle_)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::Sync]")
- _T("[FlushFileBuffers failed][%s][0x%x]"),
- file_name_, hr));
- return hr;
- }
- return S_OK;
-}
-
-HRESULT File::SeekToBegin() {
- return SeekFromBegin(0);
-}
-
-HRESULT File::SeekFromBegin(uint32 n) {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
-
- if (::SetFilePointer(handle_, n, NULL, FILE_BEGIN) ==
- INVALID_SET_FILE_POINTER) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::SeekFromBegin]")
- _T("[SetFilePointer failed][%s][0x%x]"),
- file_name_, hr));
- return hr;
- }
- pos_ = n;
- return S_OK;
-}
-
-// read nLen bytes starting at position n
-// returns number of bytes read
-//
-// async operations:
-//
-// async_id - identifier of a sequence of async operations, 0 for synchronous
-//
-// if the async operation has not been initiated, we initiate it
-// if it is in progress we do nothing
-// if it has been completed we return the data
-// does not delete async data entry
-HRESULT File::ReadAt(const uint32 offset, byte* buf, const uint32 len,
- const uint32, uint32* bytes_read) {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
- ASSERT1(buf);
- ASSERT1(len); // reading 0 bytes is not valid (differs from CRT API)
-
- RET_IF_FAILED(SeekFromBegin(offset));
-
- DWORD read = 0;
- if (!::ReadFile(handle_, buf, len, &read, NULL)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::ReadAt]")
- _T("[ReadFile failed][%s][0x%x]"), file_name_, hr));
- return hr;
- }
-
- if (bytes_read) {
- *bytes_read = read;
- }
-
- return (read == len) ? S_OK : E_FAIL;
-}
-
-
-// reads up to max_len bytes from the start of the file
-// not considered an error if there are less than max_len bytes read
-// returns number of bytes read
-HRESULT File::ReadFromStartOfFile(const uint32 max_len,
- byte* buf,
- uint32* bytes_read) {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
- ASSERT1(buf);
- ASSERT1(max_len);
-
- RET_IF_FAILED(SeekFromBegin(0));
-
- uint32 file_len = 0;
- RET_IF_FAILED(GetLength(&file_len));
-
- if (!file_len) {
- if (bytes_read) {
- *bytes_read = 0;
- }
- return S_OK;
- }
-
- uint32 len = max_len;
- if (len > file_len) {
- len = static_cast<uint32>(file_len);
- }
-
- return Read(len, buf, bytes_read);
-}
-
-// this function handles lines terminated with LF or CRLF
-// all CR characters are removed from each line, and LF is assumed
-// to be the end of line and is removed
-HRESULT File::ReadLineAnsi(uint32 max_len, char* line, uint32* len) {
- ASSERT1(line);
- ASSERT1(max_len);
-
- char c = 0;
- uint32 len_read = 0;
- uint32 total_len = 0;
-
- while (SUCCEEDED(Read(1, reinterpret_cast<byte *>(&c), &len_read)) &&
- len_read &&
- c != '\n') {
- if (total_len < max_len - 1 && c != '\r') {
- line[total_len++] = c;
- }
- }
-
- ASSERT1(total_len < max_len);
- line[total_len] = '\0';
-
- if (len) {
- *len = total_len;
- }
-
- return (len_read || total_len) ? S_OK : E_FAIL;
-}
-
-// used by ReadFromStartOfFile and ReadLineAnsi; not reading all requested bytes
-// is not considered fatal
-HRESULT File::Read(const uint32 len, byte* buf, uint32* bytes_read) {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
- ASSERT1(buf);
- ASSERT1(len);
-
- DWORD read = 0;
- if (!::ReadFile(handle_, buf, len, &read, NULL)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::ReadAt]")
- _T("[ReadFile failed][%s][0x%x]"),
- file_name_, hr));
- return hr;
- }
-
- if (bytes_read) {
- *bytes_read = read;
- }
-
- return S_OK;
-}
-
-
-// returns number of bytes written
-HRESULT File::WriteAt(const uint32 offset,
- const byte* buf,
- const uint32 len,
- uint32,
- uint32* bytes_written) {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
- ASSERT1(!read_only_);
- ASSERT1(buf);
- ASSERT1(len);
-
- RET_IF_FAILED(SeekFromBegin(offset));
-
- return Write(buf, len, bytes_written);
-}
-
-
-// write buffer n times
-HRESULT File::WriteN(const byte* buf,
- const uint32 len,
- const uint32 n,
- uint32* bytes_written) {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
- ASSERT1(!read_only_);
- ASSERT1(buf);
- ASSERT1(len);
- ASSERT1(n);
-
- HRESULT hr = S_OK;
-
- uint32 total_wrote = 0;
-
- byte* temp_buf = const_cast<byte*>(buf);
-
- scoped_array<byte> encrypt_buf;
-
- uint32 to_go = n;
- while (to_go) {
- uint32 wrote = 0;
- hr = Write(temp_buf, len, &wrote);
- if (FAILED(hr)) {
- if (bytes_written) {
- *bytes_written = total_wrote;
- }
- return hr;
- }
-
- total_wrote += wrote;
- to_go--;
- }
-
- if (bytes_written) {
- *bytes_written = total_wrote;
- }
- return hr;
-}
-
-// returns number of bytes written
-HRESULT File::Write(const byte* buf, const uint32 len, uint32* bytes_written) {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
- ASSERT1(!read_only_);
- ASSERT1(buf);
- ASSERT1(len); // writing 0 bytes is not valid (differs from CRT API)
-
- byte* b = const_cast<byte*>(buf);
-
- scoped_array<byte> encrypt_buf;
-
- DWORD wrote = 0;
- if (!::WriteFile(handle_, b, len, &wrote, NULL)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[File::Write]")
- _T("[WriteFile failed][%s][0x%x]"),
- file_name_, hr));
- return hr;
- }
-
- if (bytes_written) {
- *bytes_written = wrote;
- }
- pos_ += wrote;
-
- return (wrote == len) ? S_OK : E_FAIL;
-}
-
-HRESULT File::ClearAt(const uint32 offset,
- const uint32 len,
- uint32* bytes_written) {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
- ASSERT1(!read_only_);
- ASSERT1(len);
-
- byte zero[kZeroSize] = {0};
- uint32 to_go = len;
- uint32 written = 0;
- uint32 pos = offset;
-
- while (to_go) {
- uint32 wrote = 0;
- uint32 write_len = std::min(to_go, kZeroSize);
- RET_IF_FAILED(WriteAt(pos, zero, write_len, 0, &wrote));
-
- if (wrote != write_len) {
- return E_FAIL;
- }
- pos += wrote;
- written += wrote;
- to_go -= write_len;
- }
-
- if (bytes_written) {
- *bytes_written = written;
- }
- return S_OK;
-}
-
-// returns true on failure
-// zeros new data if zero_data == true
-HRESULT File::SetLength(const uint32 n, bool zero_data) {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
- ASSERT1(!read_only_);
- ASSERT1(n <= kMaxFileSize);
-
- HRESULT hr = S_OK;
-
- uint32 len = 0;
- VERIFY1(SUCCEEDED(GetLength(&len)));
-
- if (len == n) {
- return S_OK;
- }
-
- // according to the documentation, the
- // new space will not be initialized
- if (n > len) {
- if (zero_data) {
- uint32 bytes_written = 0;
- RET_IF_FAILED(ClearAt(len, n - len, &bytes_written));
- if (bytes_written != n - len) {
- return E_FAIL;
- }
- } else {
- byte zero = 0;
- uint32 bytes_written = 0;
- RET_IF_FAILED(WriteAt(n - 1, &zero, 1, 0, &bytes_written));
- if (bytes_written != 1) {
- return E_FAIL;
- }
- }
- } else {
- SeekFromBegin(n);
- SetEndOfFile(handle_);
- }
-
- ASSERT1(SUCCEEDED(GetLength(&len)) && len == n);
-
- return S_OK;
-}
-
-HRESULT File::ExtendInBlocks(const uint32 block_size, uint32 size_needed,
- uint32* new_size, bool clear_new_space) {
- ASSERT1(new_size);
-
- *new_size = size_needed;
-
- if (*new_size % block_size) {
- *new_size += block_size - (*new_size % block_size);
- }
-
- // is zero_data needed? may reduce fragmentation by causing the block to
- // be written
- return SetLength(*new_size, clear_new_space);
-}
-
-// returns S_OK on success
-HRESULT File::GetLength(uint32* length) {
- ASSERT1(length);
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
-
- DWORD len = GetFileSize(handle_, NULL);
- if (len == INVALID_FILE_SIZE) {
- ASSERT(false, (_T("cannot get file length")));
- return E_FAIL;
- }
- *length = len;
- return S_OK;
-}
-
-HRESULT File::Touch() {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
-
- FILETIME file_time;
- SetZero(file_time);
-
- ::GetSystemTimeAsFileTime(&file_time);
-
- if (!::SetFileTime(handle_, NULL, NULL, &file_time)) {
- return HRESULTFromLastError();
- }
- return S_OK;
-}
-
-HRESULT File::Close() {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
-
- HRESULT hr = S_OK;
- if (!::CloseHandle(handle_)) {
- hr = HRESULTFromLastError();
- }
-
- handle_ = INVALID_HANDLE_VALUE;
-
- return hr;
-}
-
-// this is just for consistency with other classes; does not do anything
-HRESULT File::Reload(uint32* number_errors) {
- ASSERT1(number_errors);
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
-
- *number_errors = 0;
- return S_OK;
-}
-
-// this is just for consistency with other classes; does not do anything
-HRESULT File::Verify(uint32* number_errors) {
- ASSERT1(number_errors);
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
-
- *number_errors = 0;
- return S_OK;
-}
-
-// this is just for consistency with other classes; does not do anything
-HRESULT File::Dump() {
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
- return S_OK;
-}
-
-// for consistency with other classes
-HRESULT File::GetSizeOnDisk(uint64* size_on_disk) {
- ASSERT1(size_on_disk);
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
-
- uint32 len = 0;
- RET_IF_FAILED(GetLength(&len));
-
- *size_on_disk = len;
- return S_OK;
-}
-
-// for consistency with other classes
-HRESULT File::GetReloadDiskSpaceNeeded(uint64* bytes_needed) {
- ASSERT1(bytes_needed);
- ASSERT1(handle_ != INVALID_HANDLE_VALUE);
-
- uint32 len = 0;
- RET_IF_FAILED(GetLength(&len));
-
- *bytes_needed = len;
- return S_OK;
-}
-
-// Get the file size
-HRESULT File::GetFileSizeUnopen(const TCHAR* filename, uint32* out_size) {
- ASSERT1(filename);
- ASSERT1(out_size);
-
- WIN32_FILE_ATTRIBUTE_DATA data;
- SetZero(data);
-
- if (!::GetFileAttributesEx(filename, ::GetFileExInfoStandard, &data)) {
- return HRESULTFromLastError();
- }
-
- *out_size = data.nFileSizeLow;
-
- return S_OK;
-}
-
-// Get the last time with a file was written to, and the size
-HRESULT File::GetLastWriteTimeAndSize(const TCHAR* file_path,
- SYSTEMTIME* out_time,
- unsigned int* out_size) {
- ASSERT1(file_path);
-
- WIN32_FIND_DATA wfd;
- SetZero(wfd);
-
- HANDLE find = ::FindFirstFile(file_path, &wfd);
- if (find == INVALID_HANDLE_VALUE) {
- return HRESULTFromLastError();
- }
-
- ::FindClose(find);
-
- if (out_size) {
- *out_size = wfd.nFileSizeLow;
- }
-
- if (out_time) {
- // If created time is newer than write time, then use that instead
- // [it tends to be more relevant when copying files around]
- FILETIME* latest_time = NULL;
- if (::CompareFileTime(&wfd.ftCreationTime, &wfd.ftLastWriteTime) > 0) {
- latest_time = &wfd.ftCreationTime;
- } else {
- latest_time = &wfd.ftLastWriteTime;
- }
-
- if (!::FileTimeToSystemTime(latest_time, out_time)) {
- return HRESULTFromLastError();
- }
- }
-
- return S_OK;
-}
-
-bool File::AreFilesIdentical(const TCHAR* filename1, const TCHAR* filename2) {
- UTIL_LOG(L4, (_T("[File::AreFilesIdentical][%s][%s]"), filename1, filename2));
-
- uint32 file_size1 = 0;
- HRESULT hr = File::GetFileSizeUnopen(filename1, &file_size1);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (_T("[GetFileSizeUnopen failed file_size1][0x%x]"), hr));
- return false;
- }
-
- uint32 file_size2 = 0;
- hr = File::GetFileSizeUnopen(filename2, &file_size2);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (_T("[GetFileSizeUnopen failed file_size2][0x%x]"), hr));
- return false;
- }
-
- if (file_size1 != file_size2) {
- UTIL_LOG(L3, (_T("[file_size1 != file_size2][%d][%d]"),
- file_size1, file_size2));
- return false;
- }
-
- File file1;
- hr = file1.OpenShareMode(filename1, false, false, FILE_SHARE_READ);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (_T("[file1.OpenShareMode failed][0x%x]"), hr));
- return false;
- }
-
- File file2;
- hr = file2.OpenShareMode(filename2, false, false, FILE_SHARE_READ);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (_T("[file2.OpenShareMode failed][0x%x]"), hr));
- return false;
- }
-
- static const uint32 kBufferSize = 0x10000;
- std::vector<uint8> buffer1(kBufferSize);
- std::vector<uint8> buffer2(kBufferSize);
- uint32 bytes_left = file_size1;
-
- while (bytes_left > 0) {
- uint32 bytes_to_read = std::min(bytes_left, kBufferSize);
- uint32 bytes_read1 = 0;
- uint32 bytes_read2 = 0;
-
- hr = file1.Read(bytes_to_read, &buffer1.front(), &bytes_read1);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (_T("[file1.Read failed][%d][%d][0x%x]"),
- bytes_left, bytes_to_read, hr));
- return false;
- }
-
- hr = file2.Read(bytes_to_read, &buffer2.front(), &bytes_read2);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (_T("[file2.Read failed][%d][%d][0x%x]"),
- bytes_left, bytes_to_read, hr));
- return false;
- }
-
- if (bytes_to_read != bytes_read1 || bytes_to_read != bytes_read2) {
- UTIL_LOG(LE,
- (_T("[bytes_to_read != bytes_read1 || bytes_to_read != bytes_read2]")
- _T("[%d][%d][%d]"), bytes_to_read, bytes_read1, bytes_read2));
- return false;
- }
-
- if (memcmp(&buffer1.front(), &buffer2.front(), bytes_read1) != 0) {
- UTIL_LOG(L3, (_T("[memcmp failed][%d][%d]"), bytes_left, bytes_read1));
- return false;
- }
-
- if (bytes_left < bytes_to_read) {
- UTIL_LOG(LE, (_T("[bytes_left < bytes_to_read][%d][%d]"),
- bytes_left, bytes_to_read));
- return false;
- }
-
- bytes_left -= bytes_to_read;
- }
-
- return true;
-}
-
-FileLock::FileLock() {
-}
-
-FileLock::~FileLock() {
- Unlock();
-}
-
-HRESULT FileLock::Lock(const TCHAR* file) {
- std::vector<CString> files;
- files.push_back(file);
- return Lock(files);
-}
-
-HRESULT FileLock::Lock(const std::vector<CString>& files) {
- ASSERT1(!files.empty());
-
- // Try to lock all files
- size_t curr_size = handles_.size();
- for (size_t i = 0; i < files.size(); ++i) {
- scoped_hfile handle(::CreateFile(files[i],
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL));
- if (!handle) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[FileLock::Lock - failed to lock file][%s][0x%x]"),
- files[i], HRESULTFromLastError()));
- break;
- }
- handles_.push_back(release(handle));
- }
-
- // Cleanup if we fail to lock all the files
- if (curr_size + files.size() < handles_.size()) {
- for (size_t i = handles_.size() - 1; i >= curr_size; --i) {
- VERIFY(::CloseHandle(handles_[i]), (_T("")));
- handles_.pop_back();
- }
- return E_FAIL;
- }
-
- return S_OK;
-}
-
-HRESULT FileLock::Unlock() {
- for (size_t i = 0; i < handles_.size(); ++i) {
- VERIFY(::CloseHandle(handles_[i]), (_T("")));
- }
- handles_.clear();
- return S_OK;
-}
-
-
-// path_name: the directory to watch
-// watch_subtree: watch all subdirectory changes or
-// only immediate child values
-// notify_filter: See the documentation for FindFirstChangeNotification
-FileWatcher::FileWatcher(const TCHAR* path_name, bool watch_subtree,
- DWORD notify_filter)
- : path_name_(path_name),
- watch_subtree_(watch_subtree),
- notify_filter_(notify_filter) {
- ASSERT1(path_name && *path_name);
- UTIL_LOG(L3, (_T("[FileWatcher::FileWatcher][%s]"), path_name));
-}
-
-// Get the event that is signaled on store changes.
-HANDLE FileWatcher::change_event() const {
- ASSERT(valid(change_event_), (_T("call FileWatcher::SetupEvent first")));
- return get(change_event_);
-}
-
-
-// Called to create/reset the event that gets signaled
-// any time the store changes. Access the created
-// event using change_event().
-HRESULT FileWatcher::EnsureEventSetup() {
- UTIL_LOG(L3, (_T("[FileWatcher::EnsureEventSetup]")));
- if (!valid(change_event_)) {
- reset(change_event_, ::FindFirstChangeNotification(path_name_,
- watch_subtree_,
- notify_filter_));
- if (!valid(change_event_)) {
- ASSERT(false, (_T("unable to get file change notification")));
- return E_FAIL;
- }
- // path name was only needed to set-up the event and now that is done....
- path_name_.Empty();
- return S_OK;
- }
-
- // if the event is set-up and no changes have occurred,
- // then there is no need to re-setup the event.
- if (valid(change_event_) && !HasChangeOccurred()) {
- return NOERROR;
- }
-
- return ::FindNextChangeNotification(get(change_event_)) ? S_OK : E_FAIL;
-}
-
-} // namespace omaha
-
« no previous file with comments | « base/file.h ('k') | base/file_reader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698