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
11 using fileapi::FileSystemURL;
12 using fileapi::FileSystemURLSet;
13
14 namespace sync_file_system {
15
16 namespace {
17
18 typedef LocalFileSyncStatus::OriginAndType OriginAndType;
19
GetOriginAndType(const fileapi::FileSystemURL & url)20 OriginAndType GetOriginAndType(const fileapi::FileSystemURL& url) {
21 return std::make_pair(url.origin(), url.type());
22 }
23
NormalizePath(const base::FilePath & path)24 base::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 fileapi::VirtualPath::kSeparator);
29 }
30
31 struct SetKeyHelper {
32 template <typename Iterator>
GetKeysync_file_system::__anonae57f1950111::SetKeyHelper33 static const base::FilePath& GetKey(Iterator itr) {
34 return *itr;
35 }
36 };
37
38 struct MapKeyHelper {
39 template <typename Iterator>
GetKeysync_file_system::__anonae57f1950111::MapKeyHelper40 static const base::FilePath& GetKey(Iterator itr) {
41 return itr->first;
42 }
43 };
44
45 template <typename Container, typename GetKeyHelper>
ContainsChildOrParent(const Container & paths,const base::FilePath & path,const GetKeyHelper & get_key_helper)46 bool 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 (fileapi::VirtualPath::IsRootPath(normalized_path))
67 return false;
68
69 normalized_path =
70 NormalizePath(fileapi::VirtualPath::DirName(normalized_path));
71 }
72 }
73
74 } // namespace
75
LocalFileSyncStatus()76 LocalFileSyncStatus::LocalFileSyncStatus() {}
77
~LocalFileSyncStatus()78 LocalFileSyncStatus::~LocalFileSyncStatus() {}
79
StartWriting(const FileSystemURL & url)80 void LocalFileSyncStatus::StartWriting(const FileSystemURL& url) {
81 DCHECK(CalledOnValidThread());
82 DCHECK(!IsChildOrParentSyncing(url));
83 writing_[GetOriginAndType(url)][NormalizePath(url.path())]++;
84 }
85
EndWriting(const FileSystemURL & url)86 void 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
StartSyncing(const FileSystemURL & url)100 void 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
EndSyncing(const FileSystemURL & url)107 void 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
IsWriting(const FileSystemURL & url) const119 bool LocalFileSyncStatus::IsWriting(const FileSystemURL& url) const {
120 DCHECK(CalledOnValidThread());
121 return IsChildOrParentWriting(url);
122 }
123
IsWritable(const FileSystemURL & url) const124 bool LocalFileSyncStatus::IsWritable(const FileSystemURL& url) const {
125 DCHECK(CalledOnValidThread());
126 return !IsChildOrParentSyncing(url);
127 }
128
IsSyncable(const FileSystemURL & url) const129 bool LocalFileSyncStatus::IsSyncable(const FileSystemURL& url) const {
130 DCHECK(CalledOnValidThread());
131 return !IsChildOrParentSyncing(url) && !IsChildOrParentWriting(url);
132 }
133
AddObserver(Observer * observer)134 void LocalFileSyncStatus::AddObserver(Observer* observer) {
135 DCHECK(CalledOnValidThread());
136 observer_list_.AddObserver(observer);
137 }
138
RemoveObserver(Observer * observer)139 void LocalFileSyncStatus::RemoveObserver(Observer* observer) {
140 DCHECK(CalledOnValidThread());
141 observer_list_.RemoveObserver(observer);
142 }
143
IsChildOrParentWriting(const FileSystemURL & url) const144 bool 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
IsChildOrParentSyncing(const FileSystemURL & url) const155 bool 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