// Copyright (c) 2011 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 "chrome/browser/sync/syncable/directory_manager.h"
#include <map>
#include <set>
#include <iterator>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/port.h"
#include "base/string_util.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/common/deprecated/event_sys-inl.h"
using browser_sync::Cryptographer;
namespace syncable {
static const FilePath::CharType kSyncDataDatabaseFilename[] =
FILE_PATH_LITERAL("SyncData.sqlite3");
DirectoryManagerEvent DirectoryManagerShutdownEvent() {
DirectoryManagerEvent event;
event.what_happened = DirectoryManagerEvent::SHUTDOWN;
return event;
}
// static
const FilePath DirectoryManager::GetSyncDataDatabaseFilename() {
return FilePath(kSyncDataDatabaseFilename);
}
const FilePath DirectoryManager::GetSyncDataDatabasePath() const {
return root_path_.Append(GetSyncDataDatabaseFilename());
}
DirectoryManager::DirectoryManager(const FilePath& path)
: root_path_(path),
managed_directory_(NULL),
channel_(new Channel(DirectoryManagerShutdownEvent())),
cryptographer_(new Cryptographer) {
}
DirectoryManager::~DirectoryManager() {
base::AutoLock lock(lock_);
DCHECK_EQ(managed_directory_, static_cast<Directory*>(NULL))
<< "Dir " << managed_directory_->name() << " not closed!";
delete channel_;
}
bool DirectoryManager::Open(const std::string& name) {
bool was_open = false;
const DirOpenResult result = OpenImpl(name,
GetSyncDataDatabasePath(), &was_open);
return syncable::OPENED == result;
}
// Opens a directory. Returns false on error.
DirOpenResult DirectoryManager::OpenImpl(const std::string& name,
const FilePath& path,
bool* was_open) {
bool opened = false;
{
base::AutoLock lock(lock_);
// Check to see if it's already open.
if (managed_directory_) {
DCHECK_EQ(base::strcasecmp(name.c_str(),
managed_directory_->name().c_str()), 0)
<< "Can't open more than one directory.";
opened = *was_open = true;
}
}
if (opened)
return syncable::OPENED;
// Otherwise, open it.
scoped_ptr<Directory> dir(new Directory);
const DirOpenResult result = dir->Open(path, name);
if (syncable::OPENED == result) {
base::AutoLock lock(lock_);
managed_directory_ = dir.release();
}
return result;
}
// Marks a directory as closed. It might take a while until all the file
// handles and resources are freed by other threads.
void DirectoryManager::Close(const std::string& name) {
// Erase from mounted and opened directory lists.
{
base::AutoLock lock(lock_);
if (!managed_directory_ ||
base::strcasecmp(name.c_str(),
managed_directory_->name().c_str()) != 0) {
// It wasn't open.
return;
}
}
// TODO(timsteele): No lock?!
// Notify listeners.
managed_directory_->channel()->NotifyListeners(DIRECTORY_CLOSED);
DirectoryManagerEvent event = { DirectoryManagerEvent::CLOSED, name };
channel_->NotifyListeners(event);
delete managed_directory_;
managed_directory_ = NULL;
}
void DirectoryManager::FinalSaveChangesForAll() {
base::AutoLock lock(lock_);
if (managed_directory_)
managed_directory_->SaveChanges();
}
void DirectoryManager::GetOpenDirectories(DirNames* result) {
result->clear();
base::AutoLock lock(lock_);
if (managed_directory_)
result->push_back(managed_directory_->name());
}
ScopedDirLookup::ScopedDirLookup(DirectoryManager* dirman,
const std::string& name) : dirman_(dirman) {
dir_ = dirman->managed_directory_ &&
(base::strcasecmp(name.c_str(),
dirman->managed_directory_->name().c_str()) == 0) ?
dirman->managed_directory_ : NULL;
good_ = dir_ != NULL;
good_checked_ = false;
}
ScopedDirLookup::~ScopedDirLookup() { }
Directory* ScopedDirLookup::operator -> () const {
CHECK(good_checked_);
DCHECK(good_);
return dir_;
}
ScopedDirLookup::operator Directory* () const {
CHECK(good_checked_);
DCHECK(good_);
return dir_;
}
} // namespace syncable