local_file_sync_status.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/sync_file_system/local/local_file_sync_status.h"
6
7#include "base/logging.h"
8#include "base/stl_util.h"
9#include "webkit/common/fileapi/file_system_util.h"
10
11using storage::FileSystemURL;
12using storage::FileSystemURLSet;
13
14namespace sync_file_system {
15
16namespace {
17
18typedef LocalFileSyncStatus::OriginAndType OriginAndType;
19
20OriginAndType GetOriginAndType(const storage::FileSystemURL& url) {
21  return std::make_pair(url.origin(), url.type());
22}
23
24base::FilePath NormalizePath(const base::FilePath& path) {
25  // Ensure |path| has single trailing path-separator, so that we can use
26  // prefix-match to find descendants of |path| in an ordered container.
27  return base::FilePath(path.StripTrailingSeparators().value() +
28                        storage::VirtualPath::kSeparator);
29}
30
31struct SetKeyHelper {
32  template <typename Iterator>
33  static const base::FilePath& GetKey(Iterator itr) {
34    return *itr;
35  }
36};
37
38struct MapKeyHelper {
39  template <typename Iterator>
40  static const base::FilePath& GetKey(Iterator itr) {
41    return itr->first;
42  }
43};
44
45template <typename Container, typename GetKeyHelper>
46bool ContainsChildOrParent(const Container& paths,
47                           const base::FilePath& path,
48                           const GetKeyHelper& get_key_helper) {
49  base::FilePath normalized_path = NormalizePath(path);
50
51  // Check if |paths| has a child of |normalized_path|.
52  // Note that descendants of |normalized_path| are stored right after
53  // |normalized_path| since |normalized_path| has trailing path separator.
54  typename Container::const_iterator upper =
55      paths.upper_bound(normalized_path);
56
57  if (upper != paths.end() &&
58      normalized_path.IsParent(get_key_helper.GetKey(upper)))
59    return true;
60
61  // Check if any ancestor of |normalized_path| is in |writing_|.
62  while (true) {
63    if (ContainsKey(paths, normalized_path))
64      return true;
65
66    if (storage::VirtualPath::IsRootPath(normalized_path))
67      return false;
68
69    normalized_path =
70        NormalizePath(storage::VirtualPath::DirName(normalized_path));
71  }
72}
73
74}  // namespace
75
76LocalFileSyncStatus::LocalFileSyncStatus() {}
77
78LocalFileSyncStatus::~LocalFileSyncStatus() {}
79
80void LocalFileSyncStatus::StartWriting(const FileSystemURL& url) {
81  DCHECK(CalledOnValidThread());
82  DCHECK(!IsChildOrParentSyncing(url));
83  writing_[GetOriginAndType(url)][NormalizePath(url.path())]++;
84}
85
86void LocalFileSyncStatus::EndWriting(const FileSystemURL& url) {
87  DCHECK(CalledOnValidThread());
88  base::FilePath normalized_path = NormalizePath(url.path());
89  OriginAndType origin_and_type = GetOriginAndType(url);
90
91  int count = --writing_[origin_and_type][normalized_path];
92  if (count == 0) {
93    writing_[origin_and_type].erase(normalized_path);
94    if (writing_[origin_and_type].empty())
95      writing_.erase(origin_and_type);
96    FOR_EACH_OBSERVER(Observer, observer_list_, OnSyncEnabled(url));
97  }
98}
99
100void LocalFileSyncStatus::StartSyncing(const FileSystemURL& url) {
101  DCHECK(CalledOnValidThread());
102  DCHECK(!IsChildOrParentWriting(url));
103  DCHECK(!IsChildOrParentSyncing(url));
104  syncing_[GetOriginAndType(url)].insert(NormalizePath(url.path()));
105}
106
107void LocalFileSyncStatus::EndSyncing(const FileSystemURL& url) {
108  DCHECK(CalledOnValidThread());
109  base::FilePath normalized_path = NormalizePath(url.path());
110  OriginAndType origin_and_type = GetOriginAndType(url);
111
112  syncing_[origin_and_type].erase(normalized_path);
113  if (syncing_[origin_and_type].empty())
114    syncing_.erase(origin_and_type);
115  FOR_EACH_OBSERVER(Observer, observer_list_, OnSyncEnabled(url));
116  FOR_EACH_OBSERVER(Observer, observer_list_, OnWriteEnabled(url));
117}
118
119bool LocalFileSyncStatus::IsWriting(const FileSystemURL& url) const {
120  DCHECK(CalledOnValidThread());
121  return IsChildOrParentWriting(url);
122}
123
124bool LocalFileSyncStatus::IsWritable(const FileSystemURL& url) const {
125  DCHECK(CalledOnValidThread());
126  return !IsChildOrParentSyncing(url);
127}
128
129bool LocalFileSyncStatus::IsSyncable(const FileSystemURL& url) const {
130  DCHECK(CalledOnValidThread());
131  return !IsChildOrParentSyncing(url) && !IsChildOrParentWriting(url);
132}
133
134void LocalFileSyncStatus::AddObserver(Observer* observer) {
135  DCHECK(CalledOnValidThread());
136  observer_list_.AddObserver(observer);
137}
138
139void LocalFileSyncStatus::RemoveObserver(Observer* observer) {
140  DCHECK(CalledOnValidThread());
141  observer_list_.RemoveObserver(observer);
142}
143
144bool LocalFileSyncStatus::IsChildOrParentWriting(
145    const FileSystemURL& url) const {
146  DCHECK(CalledOnValidThread());
147
148  URLBucket::const_iterator found = writing_.find(GetOriginAndType(url));
149  if (found == writing_.end())
150    return false;
151  return ContainsChildOrParent(found->second, url.path(),
152                               MapKeyHelper());
153}
154
155bool LocalFileSyncStatus::IsChildOrParentSyncing(
156    const FileSystemURL& url) const {
157  DCHECK(CalledOnValidThread());
158  URLSet::const_iterator found = syncing_.find(GetOriginAndType(url));
159  if (found == syncing_.end())
160    return false;
161  return ContainsChildOrParent(found->second, url.path(),
162                               SetKeyHelper());
163}
164
165}  // namespace sync_file_system
166