Index: chrome/browser/visitedlink_master.cc |
diff --git a/chrome/browser/visitedlink_master.cc b/chrome/browser/visitedlink_master.cc |
index 22a963827cd6582c7c937026db1b4efdfafa058d..85470cc40c2f4b5bf63b2fdc2fd27e5276a505c9 100644 |
--- a/chrome/browser/visitedlink_master.cc |
+++ b/chrome/browser/visitedlink_master.cc |
@@ -4,20 +4,40 @@ |
#include "chrome/browser/visitedlink_master.h" |
+#if defined(OS_WIN) |
#include <windows.h> |
+#include <io.h> |
#include <shlobj.h> |
+#endif // defined(OS_WIN) |
+#include <stdio.h> |
+ |
#include <algorithm> |
+#include "base/file_util.h" |
#include "base/logging.h" |
#include "base/message_loop.h" |
#include "base/path_service.h" |
+#include "base/process_util.h" |
#include "base/rand_util.h" |
#include "base/stack_container.h" |
#include "base/string_util.h" |
+#include "base/thread.h" |
#include "chrome/browser/browser_process.h" |
+#if defined(OS_WIN) |
#include "chrome/browser/history/history.h" |
#include "chrome/browser/profile.h" |
+#else |
+// TODO(port): We should be using history.h & profile.h, remove scaffolding |
+// when those are ported. |
+#include "chrome/common/temp_scaffolding_stubs.h" |
+#endif // !defined(OS_WIN) |
+#if defined(OS_WIN) |
#include "chrome/common/win_util.h" |
+#endif |
+ |
+using file_util::ScopedFILE; |
+using file_util::OpenFile; |
+using file_util::TruncateFile; |
const int32 VisitedLinkMaster::kFileHeaderSignatureOffset = 0; |
const int32 VisitedLinkMaster::kFileHeaderVersionOffset = 4; |
@@ -36,7 +56,7 @@ const size_t VisitedLinkMaster::kFileHeaderSize = |
// table in NewTableSizeForCount (prime number). |
const unsigned VisitedLinkMaster::kDefaultTableSize = 16381; |
-const int32 VisitedLinkMaster::kBigDeleteThreshold = 64; |
+const size_t VisitedLinkMaster::kBigDeleteThreshold = 64; |
namespace { |
@@ -48,43 +68,42 @@ void GenerateSalt(uint8 salt[LINK_SALT_LENGTH]) { |
uint64 randval = base::RandUint64(); |
memcpy(salt, &randval, 8); |
} |
+ |
// AsyncWriter ---------------------------------------------------------------- |
// This task executes on a background thread and executes a write. This |
// prevents us from blocking the UI thread doing I/O. |
class AsyncWriter : public Task { |
public: |
- AsyncWriter(HANDLE hfile, int32 offset, const void* data, int32 data_len) |
- : hfile_(hfile), |
+ AsyncWriter(FILE* file, int32 offset, const void* data, size_t data_len) |
+ : file_(file), |
offset_(offset) { |
data_->resize(data_len); |
memcpy(&*data_->begin(), data, data_len); |
} |
virtual void Run() { |
- WriteToFile(hfile_, offset_, |
+ WriteToFile(file_, offset_, |
&*data_->begin(), static_cast<int32>(data_->size())); |
} |
// Exposed as a static so it can be called directly from the Master to |
// reduce the number of platform-specific I/O sites we have. Returns true if |
// the write was complete. |
- static bool WriteToFile(HANDLE hfile, |
- int32 offset, |
+ static bool WriteToFile(FILE* file, |
+ off_t offset, |
const void* data, |
- int32 data_len) { |
- if (SetFilePointer(hfile, offset, NULL, FILE_BEGIN) == |
- INVALID_SET_FILE_POINTER) |
+ size_t data_len) { |
+ if (fseek(file, offset, SEEK_SET) != 0) |
return false; // Don't write to an invalid part of the file. |
- DWORD num_written; |
- return WriteFile(hfile, data, data_len, &num_written, NULL) && |
- (num_written == data_len); |
+ size_t num_written = fwrite(data, 1, data_len, file); |
+ return num_written == data_len; |
} |
private: |
// The data to write and where to write it. |
- HANDLE hfile_; |
+ FILE* file_; |
int32 offset_; // Offset from the beginning of the file. |
// Most writes are just a single fingerprint, so we reserve that much in this |
@@ -98,14 +117,14 @@ class AsyncWriter : public Task { |
// same thread as the writing to keep things synchronized. |
class AsyncSetEndOfFile : public Task { |
public: |
- explicit AsyncSetEndOfFile(HANDLE hfile) : hfile_(hfile) {} |
+ explicit AsyncSetEndOfFile(FILE* file) : file_(file) {} |
virtual void Run() { |
- SetEndOfFile(hfile_); |
+ TruncateFile(file_); |
} |
private: |
- HANDLE hfile_; |
+ FILE* file_; |
DISALLOW_EVIL_CONSTRUCTORS(AsyncSetEndOfFile); |
}; |
@@ -113,14 +132,14 @@ class AsyncSetEndOfFile : public Task { |
// the writing to keep things synchronized. |
class AsyncCloseHandle : public Task { |
public: |
- explicit AsyncCloseHandle(HANDLE hfile) : hfile_(hfile) {} |
+ explicit AsyncCloseHandle(FILE* file) : file_(file) {} |
virtual void Run() { |
- CloseHandle(hfile_); |
+ fclose(file_); |
} |
private: |
- HANDLE hfile_; |
+ FILE* file_; |
DISALLOW_EVIL_CONSTRUCTORS(AsyncCloseHandle); |
}; |
@@ -194,11 +213,11 @@ VisitedLinkMaster::VisitedLinkMaster(base::Thread* file_thread, |
PostNewTableEvent* poster, |
HistoryService* history_service, |
bool suppress_rebuild, |
- const std::wstring& filename, |
+ const FilePath& filename, |
int32 default_table_size) { |
InitMembers(file_thread, poster, NULL); |
- database_name_override_.assign(filename); |
+ database_name_override_ = filename; |
table_size_override_ = default_table_size; |
history_service_override_ = history_service; |
suppress_rebuild_ = suppress_rebuild; |
@@ -248,7 +267,7 @@ std::wstring VisitedLinkMaster::GetSharedMemoryName() const { |
profile_id = profile_->GetID().c_str(); |
return StringPrintf(L"GVisitedLinks_%lu_%lu_%ls", |
- GetCurrentProcessId(), shared_memory_serial_, |
+ base::GetCurrentProcId(), shared_memory_serial_, |
profile_id.c_str()); |
} |
@@ -512,19 +531,19 @@ bool VisitedLinkMaster::WriteFullTable() { |
// We should pick up the most common types of these failures when we notice |
// that the file size is different when we load it back in, and then we will |
// regenerate the table. |
- win_util::ScopedHandle hfile_closer; // Valid only when not open already. |
- HANDLE hfile; // Always valid. |
+ ScopedFILE file_closer; // Valid only when not open already. |
+ FILE* file; // Always valid. |
if (file_) { |
- hfile = file_; |
+ file = file_; |
} else { |
- std::wstring filename; |
+ FilePath filename; |
GetDatabaseFileName(&filename); |
- hfile_closer.Set( |
- CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, |
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); |
- if (!hfile_closer.IsValid()) |
+ file_closer.reset(OpenFile(filename, "wb+")); |
+ if (!file_closer.get()) { |
+ DLOG(ERROR) << "Failed to open file " << filename.value(); |
return false; |
- hfile = hfile_closer; |
+ } |
+ file = file_closer.get(); |
} |
// Write the new header. |
@@ -533,54 +552,54 @@ bool VisitedLinkMaster::WriteFullTable() { |
header[1] = kFileCurrentVersion; |
header[2] = table_length_; |
header[3] = used_items_; |
- WriteToFile(hfile, 0, header, sizeof(header)); |
- WriteToFile(hfile, sizeof(header), salt_, LINK_SALT_LENGTH); |
+ WriteToFile(file, 0, header, sizeof(header)); |
+ WriteToFile(file, sizeof(header), salt_, LINK_SALT_LENGTH); |
// Write the hash data. |
- WriteToFile(hfile, kFileHeaderSize, |
+ WriteToFile(file, kFileHeaderSize, |
hash_table_, table_length_ * sizeof(Fingerprint)); |
// The hash table may have shrunk, so make sure this is the end. |
if (file_thread_) { |
- AsyncSetEndOfFile* setter = new AsyncSetEndOfFile(hfile); |
+ AsyncSetEndOfFile* setter = new AsyncSetEndOfFile(file); |
file_thread_->PostTask(FROM_HERE, setter); |
} else { |
- SetEndOfFile(hfile); |
+ TruncateFile(file); |
} |
// Keep the file open so we can dynamically write changes to it. When the |
- // file was alrady open, the hfile_closer is NULL, and file_ is already good. |
- if (hfile_closer.IsValid()) |
- file_ = hfile_closer.Take(); |
+ // file was already open, the file_closer is NULL, and file_ is already good. |
+ if (file_closer.get()) |
+ file_ = file_closer.release(); |
return true; |
} |
bool VisitedLinkMaster::InitFromFile() { |
DCHECK(file_ == NULL); |
- std::wstring filename; |
+ FilePath filename; |
GetDatabaseFileName(&filename); |
- win_util::ScopedHandle hfile( |
- CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, |
- OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); |
- if (!hfile.IsValid()) |
+ ScopedFILE file_closer(OpenFile(filename, "rb+")); |
+ if (!file_closer.get()) { |
+ DLOG(ERROR) << "Failed to open file " << filename.value(); |
return false; |
+ } |
int32 num_entries, used_count; |
- if (!ReadFileHeader(hfile, &num_entries, &used_count, salt_)) |
+ if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt_)) |
return false; // Header isn't valid. |
// Allocate and read the table. |
if (!CreateURLTable(num_entries, false)) |
return false; |
- if (!ReadFromFile(hfile, kFileHeaderSize, |
+ if (!ReadFromFile(file_closer.get(), kFileHeaderSize, |
hash_table_, num_entries * sizeof(Fingerprint))) { |
FreeURLTable(); |
return false; |
} |
used_items_ = used_count; |
- file_ = hfile.Take(); |
+ file_ = file_closer.release(); |
return true; |
} |
@@ -609,20 +628,27 @@ bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) { |
return RebuildTableFromHistory(); |
} |
-bool VisitedLinkMaster::ReadFileHeader(HANDLE hfile, |
+bool VisitedLinkMaster::ReadFileHeader(FILE* file, |
int32* num_entries, |
int32* used_count, |
uint8 salt[LINK_SALT_LENGTH]) { |
- int32 file_size = GetFileSize(hfile, NULL); |
+ // Get file size. |
+ // Note that there is no need to seek back to the original location in the |
+ // file since ReadFromFile() [which is the next call accessing the file] |
+ // seeks before reading. |
+ if (fseek(file, 0, SEEK_END) == -1) |
+ return false; |
+ size_t file_size = ftell(file); |
+ |
if (file_size <= kFileHeaderSize) |
return false; |
uint8 header[kFileHeaderSize]; |
- if (!ReadFromFile(hfile, 0, &header, kFileHeaderSize)) |
+ if (!ReadFromFile(file, 0, &header, kFileHeaderSize)) |
return false; |
// Verify the signature. |
- uint32 signature; |
+ int32 signature; |
memcpy(&signature, &header[kFileHeaderSignatureOffset], sizeof(signature)); |
if (signature != kFileSignature) |
return false; |
@@ -652,7 +678,7 @@ bool VisitedLinkMaster::ReadFileHeader(HANDLE hfile, |
return true; |
} |
-bool VisitedLinkMaster::GetDatabaseFileName(std::wstring* filename) { |
+bool VisitedLinkMaster::GetDatabaseFileName(FilePath* filename) { |
if (!database_name_override_.empty()) { |
// use this filename, the directory must exist |
*filename = database_name_override_; |
@@ -662,8 +688,8 @@ bool VisitedLinkMaster::GetDatabaseFileName(std::wstring* filename) { |
if (!profile_ || profile_->GetPath().empty()) |
return false; |
- *filename = profile_->GetPath(); |
- filename->append(L"\\Visited Links"); |
+ FilePath profile_dir = FilePath::FromWStringHack(profile_->GetPath()); |
+ *filename = profile_dir.Append(FILE_PATH_LITERAL("Visited Links")); |
return true; |
} |
@@ -735,7 +761,7 @@ void VisitedLinkMaster::FreeURLTable() { |
AsyncCloseHandle* closer = new AsyncCloseHandle(file_); |
file_thread_->PostTask(FROM_HERE, closer); |
} else { |
- CloseHandle(file_); |
+ fclose(file_); |
} |
} |
} |
@@ -752,7 +778,8 @@ bool VisitedLinkMaster::ResizeTableIfNecessary() { |
float load = ComputeTableLoad(); |
if (load < max_table_load && |
- (table_length_ <= kDefaultTableSize || load > min_table_load)) |
+ (table_length_ <= static_cast<float>(kDefaultTableSize) || |
+ load > min_table_load)) |
return false; |
// Table needs to grow or shrink. |
@@ -823,7 +850,7 @@ uint32 VisitedLinkMaster::NewTableSizeForCount(int32 item_count) const { |
int desired = item_count * 3; |
// Find the closest prime. |
- for (int i = 0; i < arraysize(table_sizes); i ++) { |
+ for (size_t i = 0; i < arraysize(table_sizes); i ++) { |
if (table_sizes[i] > desired) |
return table_sizes[i]; |
} |
@@ -908,8 +935,8 @@ void VisitedLinkMaster::OnTableRebuildComplete( |
} |
} |
-void VisitedLinkMaster::WriteToFile(HANDLE hfile, |
- int32 offset, |
+void VisitedLinkMaster::WriteToFile(FILE* file, |
+ off_t offset, |
void* data, |
int32 data_size) { |
#ifndef NDEBUG |
@@ -918,12 +945,12 @@ void VisitedLinkMaster::WriteToFile(HANDLE hfile, |
if (file_thread_) { |
// Send the write to the other thread for execution to avoid blocking. |
- AsyncWriter* writer = new AsyncWriter(hfile, offset, data, data_size); |
+ AsyncWriter* writer = new AsyncWriter(file, offset, data, data_size); |
file_thread_->PostTask(FROM_HERE, writer); |
} else { |
// When there is no I/O thread, we are probably running in unit test mode, |
// just do the write synchronously. |
- AsyncWriter::WriteToFile(hfile, offset, data, data_size); |
+ AsyncWriter::WriteToFile(file, offset, data, data_size); |
} |
} |
@@ -949,21 +976,20 @@ void VisitedLinkMaster::WriteHashRangeToFile(Hash first_hash, Hash last_hash) { |
} |
} |
-bool VisitedLinkMaster::ReadFromFile(HANDLE hfile, |
- int32 offset, |
+bool VisitedLinkMaster::ReadFromFile(FILE* file, |
+ off_t offset, |
void* data, |
- int32 data_size) { |
+ size_t data_size) { |
#ifndef NDEBUG |
// Since this function is synchronous, we require that no asynchronous |
// operations could possibly be pending. |
DCHECK(!posted_asynchronous_operation_); |
#endif |
- SetFilePointer(hfile, offset, NULL, FILE_BEGIN); |
+ fseek(file, offset, SEEK_SET); |
- DWORD num_read; |
- return ReadFile(hfile, data, data_size, &num_read, NULL) && |
- num_read == data_size; |
+ size_t num_read = fread(data, 1, data_size, file); |
+ return num_read == data_size; |
} |
// VisitedLinkTableBuilder ---------------------------------------------------- |
@@ -972,8 +998,8 @@ VisitedLinkMaster::TableBuilder::TableBuilder( |
VisitedLinkMaster* master, |
const uint8 salt[LINK_SALT_LENGTH]) |
: master_(master), |
- success_(true), |
- main_message_loop_(MessageLoop::current()) { |
+ main_message_loop_(MessageLoop::current()), |
+ success_(true) { |
fingerprints_.reserve(4096); |
memcpy(salt_, salt, sizeof(salt)); |
} |