| 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
|
|
|