Index: components/sessions/session_backend.cc |
diff --git a/components/sessions/session_backend.cc b/components/sessions/session_backend.cc |
deleted file mode 100644 |
index 99520b42505b527989308d3ba6b2c772b649530f..0000000000000000000000000000000000000000 |
--- a/components/sessions/session_backend.cc |
+++ /dev/null |
@@ -1,407 +0,0 @@ |
-// Copyright 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "components/sessions/session_backend.h" |
- |
-#include <limits> |
- |
-#include "base/files/file.h" |
-#include "base/files/file_util.h" |
-#include "base/memory/scoped_vector.h" |
-#include "base/metrics/histogram.h" |
-#include "base/threading/thread_restrictions.h" |
- |
-using base::TimeTicks; |
- |
-namespace sessions { |
- |
-// File version number. |
-static const int32 kFileCurrentVersion = 1; |
- |
-// The signature at the beginning of the file = SSNS (Sessions). |
-static const int32 kFileSignature = 0x53534E53; |
- |
-namespace { |
- |
-// The file header is the first bytes written to the file, |
-// and is used to identify the file as one written by us. |
-struct FileHeader { |
- int32 signature; |
- int32 version; |
-}; |
- |
-// SessionFileReader ---------------------------------------------------------- |
- |
-// SessionFileReader is responsible for reading the set of SessionCommands that |
-// describe a Session back from a file. SessionFileRead does minimal error |
-// checking on the file (pretty much only that the header is valid). |
- |
-class SessionFileReader { |
- public: |
- typedef sessions::SessionCommand::id_type id_type; |
- typedef sessions::SessionCommand::size_type size_type; |
- |
- explicit SessionFileReader(const base::FilePath& path) |
- : errored_(false), |
- buffer_(SessionBackend::kFileReadBufferSize, 0), |
- buffer_position_(0), |
- available_count_(0) { |
- file_.reset(new base::File( |
- path, base::File::FLAG_OPEN | base::File::FLAG_READ)); |
- } |
- // Reads the contents of the file specified in the constructor, returning |
- // true on success. It is up to the caller to free all SessionCommands |
- // added to commands. |
- bool Read(sessions::BaseSessionService::SessionType type, |
- ScopedVector<sessions::SessionCommand>* commands); |
- |
- private: |
- // Reads a single command, returning it. A return value of NULL indicates |
- // either there are no commands, or there was an error. Use errored_ to |
- // distinguish the two. If NULL is returned, and there is no error, it means |
- // the end of file was successfully reached. |
- sessions::SessionCommand* ReadCommand(); |
- |
- // Shifts the unused portion of buffer_ to the beginning and fills the |
- // remaining portion with data from the file. Returns false if the buffer |
- // couldn't be filled. A return value of false only signals an error if |
- // errored_ is set to true. |
- bool FillBuffer(); |
- |
- // Whether an error condition has been detected ( |
- bool errored_; |
- |
- // As we read from the file, data goes here. |
- std::string buffer_; |
- |
- // The file. |
- scoped_ptr<base::File> file_; |
- |
- // Position in buffer_ of the data. |
- size_t buffer_position_; |
- |
- // Number of available bytes; relative to buffer_position_. |
- size_t available_count_; |
- |
- DISALLOW_COPY_AND_ASSIGN(SessionFileReader); |
-}; |
- |
-bool SessionFileReader::Read(sessions::BaseSessionService::SessionType type, |
- ScopedVector<sessions::SessionCommand>* commands) { |
- if (!file_->IsValid()) |
- return false; |
- FileHeader header; |
- int read_count; |
- TimeTicks start_time = TimeTicks::Now(); |
- read_count = file_->ReadAtCurrentPos(reinterpret_cast<char*>(&header), |
- sizeof(header)); |
- if (read_count != sizeof(header) || header.signature != kFileSignature || |
- header.version != kFileCurrentVersion) |
- return false; |
- |
- ScopedVector<sessions::SessionCommand> read_commands; |
- for (sessions::SessionCommand* command = ReadCommand(); command && !errored_; |
- command = ReadCommand()) |
- read_commands.push_back(command); |
- if (!errored_) |
- read_commands.swap(*commands); |
- if (type == sessions::BaseSessionService::TAB_RESTORE) { |
- UMA_HISTOGRAM_TIMES("TabRestore.read_session_file_time", |
- TimeTicks::Now() - start_time); |
- } else { |
- UMA_HISTOGRAM_TIMES("SessionRestore.read_session_file_time", |
- TimeTicks::Now() - start_time); |
- } |
- return !errored_; |
-} |
- |
-sessions::SessionCommand* SessionFileReader::ReadCommand() { |
- // Make sure there is enough in the buffer for the size of the next command. |
- if (available_count_ < sizeof(size_type)) { |
- if (!FillBuffer()) |
- return NULL; |
- if (available_count_ < sizeof(size_type)) { |
- VLOG(1) << "SessionFileReader::ReadCommand, file incomplete"; |
- // Still couldn't read a valid size for the command, assume write was |
- // incomplete and return NULL. |
- return NULL; |
- } |
- } |
- // Get the size of the command. |
- size_type command_size; |
- memcpy(&command_size, &(buffer_[buffer_position_]), sizeof(command_size)); |
- buffer_position_ += sizeof(command_size); |
- available_count_ -= sizeof(command_size); |
- |
- if (command_size == 0) { |
- VLOG(1) << "SessionFileReader::ReadCommand, empty command"; |
- // Empty command. Shouldn't happen if write was successful, fail. |
- return NULL; |
- } |
- |
- // Make sure buffer has the complete contents of the command. |
- if (command_size > available_count_) { |
- if (command_size > buffer_.size()) |
- buffer_.resize((command_size / 1024 + 1) * 1024, 0); |
- if (!FillBuffer() || command_size > available_count_) { |
- // Again, assume the file was ok, and just the last chunk was lost. |
- VLOG(1) << "SessionFileReader::ReadCommand, last chunk lost"; |
- return NULL; |
- } |
- } |
- const id_type command_id = buffer_[buffer_position_]; |
- // NOTE: command_size includes the size of the id, which is not part of |
- // the contents of the SessionCommand. |
- sessions::SessionCommand* command = |
- new sessions::SessionCommand(command_id, command_size - sizeof(id_type)); |
- if (command_size > sizeof(id_type)) { |
- memcpy(command->contents(), |
- &(buffer_[buffer_position_ + sizeof(id_type)]), |
- command_size - sizeof(id_type)); |
- } |
- buffer_position_ += command_size; |
- available_count_ -= command_size; |
- return command; |
-} |
- |
-bool SessionFileReader::FillBuffer() { |
- if (available_count_ > 0 && buffer_position_ > 0) { |
- // Shift buffer to beginning. |
- memmove(&(buffer_[0]), &(buffer_[buffer_position_]), available_count_); |
- } |
- buffer_position_ = 0; |
- DCHECK(buffer_position_ + available_count_ < buffer_.size()); |
- int to_read = static_cast<int>(buffer_.size() - available_count_); |
- int read_count = file_->ReadAtCurrentPos(&(buffer_[available_count_]), |
- to_read); |
- if (read_count < 0) { |
- errored_ = true; |
- return false; |
- } |
- if (read_count == 0) |
- return false; |
- available_count_ += read_count; |
- return true; |
-} |
- |
-} // namespace |
- |
-// SessionBackend ------------------------------------------------------------- |
- |
-// File names (current and previous) for a type of TAB. |
-static const char* kCurrentTabSessionFileName = "Current Tabs"; |
-static const char* kLastTabSessionFileName = "Last Tabs"; |
- |
-// File names (current and previous) for a type of SESSION. |
-static const char* kCurrentSessionFileName = "Current Session"; |
-static const char* kLastSessionFileName = "Last Session"; |
- |
-// static |
-const int SessionBackend::kFileReadBufferSize = 1024; |
- |
-SessionBackend::SessionBackend(sessions::BaseSessionService::SessionType type, |
- const base::FilePath& path_to_dir) |
- : type_(type), |
- path_to_dir_(path_to_dir), |
- last_session_valid_(false), |
- inited_(false), |
- empty_file_(true) { |
- // NOTE: this is invoked on the main thread, don't do file access here. |
-} |
- |
-void SessionBackend::Init() { |
- if (inited_) |
- return; |
- |
- inited_ = true; |
- |
- // Create the directory for session info. |
- base::CreateDirectory(path_to_dir_); |
- |
- MoveCurrentSessionToLastSession(); |
-} |
- |
-void SessionBackend::AppendCommands( |
- ScopedVector<sessions::SessionCommand> commands, |
- bool reset_first) { |
- Init(); |
- // Make sure and check current_session_file_, if opening the file failed |
- // current_session_file_ will be NULL. |
- if ((reset_first && !empty_file_) || !current_session_file_.get() || |
- !current_session_file_->IsValid()) { |
- ResetFile(); |
- } |
- // Need to check current_session_file_ again, ResetFile may fail. |
- if (current_session_file_.get() && current_session_file_->IsValid() && |
- !AppendCommandsToFile(current_session_file_.get(), commands)) { |
- current_session_file_.reset(NULL); |
- } |
- empty_file_ = false; |
-} |
- |
-void SessionBackend::ReadLastSessionCommands( |
- const base::CancelableTaskTracker::IsCanceledCallback& is_canceled, |
- const sessions::BaseSessionService::GetCommandsCallback& callback) { |
- if (is_canceled.Run()) |
- return; |
- |
- Init(); |
- |
- ScopedVector<sessions::SessionCommand> commands; |
- ReadLastSessionCommandsImpl(&commands); |
- callback.Run(commands.Pass()); |
-} |
- |
-bool SessionBackend::ReadLastSessionCommandsImpl( |
- ScopedVector<sessions::SessionCommand>* commands) { |
- Init(); |
- SessionFileReader file_reader(GetLastSessionPath()); |
- return file_reader.Read(type_, commands); |
-} |
- |
-void SessionBackend::DeleteLastSession() { |
- Init(); |
- base::DeleteFile(GetLastSessionPath(), false); |
-} |
- |
-void SessionBackend::MoveCurrentSessionToLastSession() { |
- Init(); |
- current_session_file_.reset(NULL); |
- |
- const base::FilePath current_session_path = GetCurrentSessionPath(); |
- const base::FilePath last_session_path = GetLastSessionPath(); |
- if (base::PathExists(last_session_path)) |
- base::DeleteFile(last_session_path, false); |
- if (base::PathExists(current_session_path)) { |
- int64 file_size; |
- if (base::GetFileSize(current_session_path, &file_size)) { |
- if (type_ == sessions::BaseSessionService::TAB_RESTORE) { |
- UMA_HISTOGRAM_COUNTS("TabRestore.last_session_file_size", |
- static_cast<int>(file_size / 1024)); |
- } else { |
- UMA_HISTOGRAM_COUNTS("SessionRestore.last_session_file_size", |
- static_cast<int>(file_size / 1024)); |
- } |
- } |
- last_session_valid_ = base::Move(current_session_path, last_session_path); |
- } |
- |
- if (base::PathExists(current_session_path)) |
- base::DeleteFile(current_session_path, false); |
- |
- // Create and open the file for the current session. |
- ResetFile(); |
-} |
- |
-bool SessionBackend::ReadCurrentSessionCommandsImpl( |
- ScopedVector<sessions::SessionCommand>* commands) { |
- Init(); |
- SessionFileReader file_reader(GetCurrentSessionPath()); |
- return file_reader.Read(type_, commands); |
-} |
- |
-bool SessionBackend::AppendCommandsToFile(base::File* file, |
- const ScopedVector<sessions::SessionCommand>& commands) { |
- for (ScopedVector<sessions::SessionCommand>::const_iterator i = |
- commands.begin(); |
- i != commands.end(); ++i) { |
- int wrote; |
- const size_type content_size = static_cast<size_type>((*i)->size()); |
- const size_type total_size = content_size + sizeof(id_type); |
- if (type_ == sessions::BaseSessionService::TAB_RESTORE) |
- UMA_HISTOGRAM_COUNTS("TabRestore.command_size", total_size); |
- else |
- UMA_HISTOGRAM_COUNTS("SessionRestore.command_size", total_size); |
- wrote = file->WriteAtCurrentPos(reinterpret_cast<const char*>(&total_size), |
- sizeof(total_size)); |
- if (wrote != sizeof(total_size)) { |
- NOTREACHED() << "error writing"; |
- return false; |
- } |
- id_type command_id = (*i)->id(); |
- wrote = file->WriteAtCurrentPos(reinterpret_cast<char*>(&command_id), |
- sizeof(command_id)); |
- if (wrote != sizeof(command_id)) { |
- NOTREACHED() << "error writing"; |
- return false; |
- } |
- if (content_size > 0) { |
- wrote = file->WriteAtCurrentPos(reinterpret_cast<char*>((*i)->contents()), |
- content_size); |
- if (wrote != content_size) { |
- NOTREACHED() << "error writing"; |
- return false; |
- } |
- } |
- } |
-#if defined(OS_CHROMEOS) |
- file->Flush(); |
-#endif |
- return true; |
-} |
- |
-SessionBackend::~SessionBackend() { |
- if (current_session_file_.get()) { |
- // Destructor performs file IO because file is open in sync mode. |
- // crbug.com/112512. |
- base::ThreadRestrictions::ScopedAllowIO allow_io; |
- current_session_file_.reset(); |
- } |
-} |
- |
-void SessionBackend::ResetFile() { |
- DCHECK(inited_); |
- if (current_session_file_.get()) { |
- // File is already open, truncate it. We truncate instead of closing and |
- // reopening to avoid the possibility of scanners locking the file out |
- // from under us once we close it. If truncation fails, we'll try to |
- // recreate. |
- const int header_size = static_cast<int>(sizeof(FileHeader)); |
- if (current_session_file_->Seek( |
- base::File::FROM_BEGIN, header_size) != header_size || |
- !current_session_file_->SetLength(header_size)) |
- current_session_file_.reset(NULL); |
- } |
- if (!current_session_file_.get()) |
- current_session_file_.reset(OpenAndWriteHeader(GetCurrentSessionPath())); |
- empty_file_ = true; |
-} |
- |
-base::File* SessionBackend::OpenAndWriteHeader(const base::FilePath& path) { |
- DCHECK(!path.empty()); |
- scoped_ptr<base::File> file(new base::File( |
- path, |
- base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | |
- base::File::FLAG_EXCLUSIVE_WRITE | base::File::FLAG_EXCLUSIVE_READ)); |
- if (!file->IsValid()) |
- return NULL; |
- FileHeader header; |
- header.signature = kFileSignature; |
- header.version = kFileCurrentVersion; |
- int wrote = file->WriteAtCurrentPos(reinterpret_cast<char*>(&header), |
- sizeof(header)); |
- if (wrote != sizeof(header)) |
- return NULL; |
- return file.release(); |
-} |
- |
-base::FilePath SessionBackend::GetLastSessionPath() { |
- base::FilePath path = path_to_dir_; |
- if (type_ == sessions::BaseSessionService::TAB_RESTORE) |
- path = path.AppendASCII(kLastTabSessionFileName); |
- else |
- path = path.AppendASCII(kLastSessionFileName); |
- return path; |
-} |
- |
-base::FilePath SessionBackend::GetCurrentSessionPath() { |
- base::FilePath path = path_to_dir_; |
- if (type_ == sessions::BaseSessionService::TAB_RESTORE) |
- path = path.AppendASCII(kCurrentTabSessionFileName); |
- else |
- path = path.AppendASCII(kCurrentSessionFileName); |
- return path; |
-} |
- |
-} // namespace sessions |