diff options
Diffstat (limited to 'chrome/browser/visitedlink_master.cc')
-rw-r--r-- | chrome/browser/visitedlink_master.cc | 166 |
1 files changed, 96 insertions, 70 deletions
diff --git a/chrome/browser/visitedlink_master.cc b/chrome/browser/visitedlink_master.cc index 22a9638..85470cc 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)); } |