diff options
author | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-01 20:48:50 +0000 |
---|---|---|
committer | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-01 20:48:50 +0000 |
commit | 15f48de1a21230b92e4350fc4685c51c6bd4f289 (patch) | |
tree | 32d2e6dedc75acd802f2f0725eb372e0f9911c48 /base/test_file_util_win.cc | |
parent | d42369adbff8d3dc1fe878a630ce4532c3358260 (diff) | |
download | chromium_src-15f48de1a21230b92e4350fc4685c51c6bd4f289.zip chromium_src-15f48de1a21230b92e4350fc4685c51c6bd4f289.tar.gz chromium_src-15f48de1a21230b92e4350fc4685c51c6bd4f289.tar.bz2 |
Making sure that the buffer we use with ReadFile/WriteFile is page
aligned. Also restoring file attributes after evicting it from the
cache (since the function writes to the file).
Depending on hardware, file operations will fail if the buffer isn't
aligned when using the FILE_FLAG_NO_BUFFERING flag.
For more details:
http://msdn.microsoft.com/en-us/library/cc644950(VS.85).aspx
Review URL: http://codereview.chromium.org/12833
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6157 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/test_file_util_win.cc')
-rw-r--r-- | base/test_file_util_win.cc | 77 |
1 files changed, 67 insertions, 10 deletions
diff --git a/base/test_file_util_win.cc b/base/test_file_util_win.cc index 682a918a..5f6d7c7 100644 --- a/base/test_file_util_win.cc +++ b/base/test_file_util_win.cc @@ -13,31 +13,88 @@ namespace file_util { +// We could use GetSystemInfo to get the page size, but this serves +// our purpose fine since 4K is the page size on x86 as well as x64. +static const ptrdiff_t kPageSize = 4096; + bool EvictFileFromSystemCache(const wchar_t* file) { // Request exclusive access to the file and overwrite it with no buffering. - ScopedHandle hfile( + ScopedHandle file_handle( CreateFile(file, GENERIC_READ | GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, - NULL)); - if (!hfile) + OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL)); + if (!file_handle) return false; + // Get some attributes to restore later. + BY_HANDLE_FILE_INFORMATION bhi = {0}; + CHECK(::GetFileInformationByHandle(file_handle, &bhi)); + // Execute in chunks. It could be optimized. We want to do few of these since - // these opterations will be slow without the cache. - char buffer[4096]; + // these operations will be slow without the cache. + + // Non-buffered reads and writes need to be sector aligned and since sector + // sizes typically range from 512-4096 bytes, we just use the page size. + // The buffer size is twice the size of a page (minus one) since we need to + // get an aligned pointer into the buffer that we can use. + char buffer[2 * kPageSize - 1]; + // Get an aligned pointer into buffer. + char* read_write = reinterpret_cast<char*>( + reinterpret_cast<ptrdiff_t>(buffer + kPageSize - 1) & ~(kPageSize - 1)); + DCHECK((reinterpret_cast<int>(read_write) % kPageSize) == 0); + + // If the file size isn't a multiple of kPageSize, we'll need special + // processing. + bool file_is_page_aligned = true; int total_bytes = 0; - DWORD bytes_read; + DWORD bytes_read, bytes_written; for (;;) { bytes_read = 0; - ReadFile(hfile, buffer, sizeof(buffer), &bytes_read, NULL); + ReadFile(file_handle, read_write, kPageSize, &bytes_read, NULL); if (bytes_read == 0) break; - SetFilePointer(hfile, total_bytes, 0, FILE_BEGIN); - if (!WriteFile(hfile, buffer, bytes_read, &bytes_read, NULL)) + if (bytes_read < kPageSize) { + // Zero out the remaining part of the buffer. + // WriteFile will fail if we provide a buffer size that isn't a + // sector multiple, so we'll have to write the entire buffer with + // padded zeros and then use SetEndOfFile to truncate the file. + ZeroMemory(read_write + bytes_read, kPageSize - bytes_read); + file_is_page_aligned = false; + } + + // Move back to the position we just read from. + // Note that SetFilePointer will also fail if total_bytes isn't sector + // aligned, but that shouldn't happen here. + DCHECK((total_bytes % kPageSize) == 0); + SetFilePointer(file_handle, total_bytes, NULL, FILE_BEGIN); + if (!WriteFile(file_handle, read_write, kPageSize, &bytes_written, NULL) || + bytes_written != kPageSize) { + DCHECK(false); return false; + } + total_bytes += bytes_read; + + // If this is false, then we just processed the last portion of the file. + if (!file_is_page_aligned) + break; + } + + if (!file_is_page_aligned) { + // The size of the file isn't a multiple of the page size, so we'll have + // to open the file again, this time without the FILE_FLAG_NO_BUFFERING + // flag and use SetEndOfFile to mark EOF. + file_handle.Set(CreateFile(file, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + 0, NULL)); + CHECK(SetFilePointer(file_handle, total_bytes, NULL, FILE_BEGIN) != + INVALID_SET_FILE_POINTER); + CHECK(::SetEndOfFile(file_handle)); } + + // Restore the file attributes. + CHECK(::SetFileTime(file_handle, &bhi.ftCreationTime, &bhi.ftLastAccessTime, + &bhi.ftLastWriteTime)); + return true; } |