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.
5 #include "chrome/browser/sync_file_system/local/local_file_sync_status.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "storage/common/fileapi/file_system_util.h"
11 using storage::FileSystemURL
;
12 using storage::FileSystemURLSet
;
14 namespace sync_file_system
{
18 typedef LocalFileSyncStatus::OriginAndType OriginAndType
;
20 OriginAndType
GetOriginAndType(const storage::FileSystemURL
& url
) {
21 return std::make_pair(url
.origin(), url
.type());
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 storage::VirtualPath::kSeparator
);
32 template <typename Iterator
>
33 static const base::FilePath
& GetKey(Iterator itr
) {
39 template <typename Iterator
>
40 static const base::FilePath
& GetKey(Iterator itr
) {
45 template <typename Container
, typename GetKeyHelper
>
46 bool ContainsChildOrParent(const Container
& paths
,
47 const base::FilePath
& path
,
48 const GetKeyHelper
& get_key_helper
) {
49 base::FilePath normalized_path
= NormalizePath(path
);
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
);
57 if (upper
!= paths
.end() &&
58 normalized_path
.IsParent(get_key_helper
.GetKey(upper
)))
61 // Check if any ancestor of |normalized_path| is in |writing_|.
63 if (ContainsKey(paths
, normalized_path
))
66 if (storage::VirtualPath::IsRootPath(normalized_path
))
70 NormalizePath(storage::VirtualPath::DirName(normalized_path
));
76 LocalFileSyncStatus::LocalFileSyncStatus() {}
78 LocalFileSyncStatus::~LocalFileSyncStatus() {}
80 void LocalFileSyncStatus::StartWriting(const FileSystemURL
& url
) {
81 DCHECK(CalledOnValidThread());
82 DCHECK(!IsChildOrParentSyncing(url
));
83 writing_
[GetOriginAndType(url
)][NormalizePath(url
.path())]++;
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
);
91 int count
= --writing_
[origin_and_type
][normalized_path
];
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
));
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()));
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
);
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
));
119 bool LocalFileSyncStatus::IsWriting(const FileSystemURL
& url
) const {
120 DCHECK(CalledOnValidThread());
121 return IsChildOrParentWriting(url
);
124 bool LocalFileSyncStatus::IsWritable(const FileSystemURL
& url
) const {
125 DCHECK(CalledOnValidThread());
126 return !IsChildOrParentSyncing(url
);
129 bool LocalFileSyncStatus::IsSyncable(const FileSystemURL
& url
) const {
130 DCHECK(CalledOnValidThread());
131 return !IsChildOrParentSyncing(url
) && !IsChildOrParentWriting(url
);
134 void LocalFileSyncStatus::AddObserver(Observer
* observer
) {
135 DCHECK(CalledOnValidThread());
136 observer_list_
.AddObserver(observer
);
139 void LocalFileSyncStatus::RemoveObserver(Observer
* observer
) {
140 DCHECK(CalledOnValidThread());
141 observer_list_
.RemoveObserver(observer
);
144 bool LocalFileSyncStatus::IsChildOrParentWriting(
145 const FileSystemURL
& url
) const {
146 DCHECK(CalledOnValidThread());
148 URLBucket::const_iterator found
= writing_
.find(GetOriginAndType(url
));
149 if (found
== writing_
.end())
151 return ContainsChildOrParent(found
->second
, url
.path(),
155 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())
161 return ContainsChildOrParent(found
->second
, url
.path(),
165 } // namespace sync_file_system