Home | History | Annotate | Download | only in local
      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 
     20 OriginAndType GetOriginAndType(const fileapi::FileSystemURL& url) {
     21   return std::make_pair(url.origin(), url.type());
     22 }
     23 
     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>
     33   static const base::FilePath& GetKey(Iterator itr) {
     34     return *itr;
     35   }
     36 };
     37 
     38 struct MapKeyHelper {
     39   template <typename Iterator>
     40   static const base::FilePath& GetKey(Iterator itr) {
     41     return itr->first;
     42   }
     43 };
     44 
     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);
     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 
     76 LocalFileSyncStatus::LocalFileSyncStatus() {}
     77 
     78 LocalFileSyncStatus::~LocalFileSyncStatus() {}
     79 
     80 void LocalFileSyncStatus::StartWriting(const FileSystemURL& url) {
     81   DCHECK(CalledOnValidThread());
     82   DCHECK(!IsChildOrParentSyncing(url));
     83   writing_[GetOriginAndType(url)][NormalizePath(url.path())]++;
     84 }
     85 
     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 
    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 
    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 
    119 bool LocalFileSyncStatus::IsWriting(const FileSystemURL& url) const {
    120   DCHECK(CalledOnValidThread());
    121   return IsChildOrParentWriting(url);
    122 }
    123 
    124 bool LocalFileSyncStatus::IsWritable(const FileSystemURL& url) const {
    125   DCHECK(CalledOnValidThread());
    126   return !IsChildOrParentSyncing(url);
    127 }
    128 
    129 bool LocalFileSyncStatus::IsSyncable(const FileSystemURL& url) const {
    130   DCHECK(CalledOnValidThread());
    131   return !IsChildOrParentSyncing(url) && !IsChildOrParentWriting(url);
    132 }
    133 
    134 void LocalFileSyncStatus::AddObserver(Observer* observer) {
    135   DCHECK(CalledOnValidThread());
    136   observer_list_.AddObserver(observer);
    137 }
    138 
    139 void LocalFileSyncStatus::RemoveObserver(Observer* observer) {
    140   DCHECK(CalledOnValidThread());
    141   observer_list_.RemoveObserver(observer);
    142 }
    143 
    144 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 
    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())
    160     return false;
    161   return ContainsChildOrParent(found->second, url.path(),
    162                                SetKeyHelper());
    163 }
    164 
    165 }  // namespace sync_file_system
    166