| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 2012 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 "components/filesystem/public/cpp/prefs/filesystem_json_pref_store.h" | 
 |    6  | 
 |    7 #include <stddef.h> | 
 |    8  | 
 |    9 #include <algorithm> | 
 |   10 #include <utility> | 
 |   11  | 
 |   12 #include "base/bind.h" | 
 |   13 #include "base/callback.h" | 
 |   14 #include "base/files/file_path.h" | 
 |   15 #include "base/files/file_util.h" | 
 |   16 #include "base/json/json_string_value_serializer.h" | 
 |   17 #include "base/logging.h" | 
 |   18 #include "base/macros.h" | 
 |   19 #include "base/memory/ref_counted.h" | 
 |   20 #include "base/prefs/pref_filter.h" | 
 |   21 #include "base/strings/string_number_conversions.h" | 
 |   22 #include "base/strings/string_util.h" | 
 |   23 #include "base/task_runner_util.h" | 
 |   24 #include "base/time/default_clock.h" | 
 |   25 #include "base/values.h" | 
 |   26 #include "mojo/common/common_type_converters.h" | 
 |   27  | 
 |   28 namespace filesystem { | 
 |   29  | 
 |   30 // Result returned from internal read tasks. | 
 |   31 struct FilesystemJsonPrefStore::ReadResult { | 
 |   32  public: | 
 |   33   ReadResult(); | 
 |   34   ~ReadResult(); | 
 |   35  | 
 |   36   scoped_ptr<base::Value> value; | 
 |   37   PrefReadError error; | 
 |   38  | 
 |   39  private: | 
 |   40   DISALLOW_COPY_AND_ASSIGN(ReadResult); | 
 |   41 }; | 
 |   42  | 
 |   43 FilesystemJsonPrefStore::ReadResult::ReadResult() | 
 |   44     : error(PersistentPrefStore::PREF_READ_ERROR_NONE) {} | 
 |   45  | 
 |   46 FilesystemJsonPrefStore::ReadResult::~ReadResult() {} | 
 |   47  | 
 |   48 namespace { | 
 |   49  | 
 |   50 PersistentPrefStore::PrefReadError HandleReadErrors(const base::Value* value) { | 
 |   51   if (!value->IsType(base::Value::TYPE_DICTIONARY)) | 
 |   52     return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE; | 
 |   53   return PersistentPrefStore::PREF_READ_ERROR_NONE; | 
 |   54 } | 
 |   55  | 
 |   56 }  // namespace | 
 |   57  | 
 |   58 FilesystemJsonPrefStore::FilesystemJsonPrefStore( | 
 |   59     const std::string& pref_filename, | 
 |   60     filesystem::FileSystemPtr filesystem, | 
 |   61     scoped_ptr<PrefFilter> pref_filter) | 
 |   62     : path_(pref_filename), | 
 |   63       binding_(this), | 
 |   64       filesystem_(std::move(filesystem)), | 
 |   65       prefs_(new base::DictionaryValue()), | 
 |   66       read_only_(false), | 
 |   67       pref_filter_(std::move(pref_filter)), | 
 |   68       initialized_(false), | 
 |   69       filtering_in_progress_(false), | 
 |   70       pending_lossy_write_(false), | 
 |   71       read_error_(PREF_READ_ERROR_NONE) { | 
 |   72   DCHECK(!path_.empty()); | 
 |   73 } | 
 |   74  | 
 |   75 bool FilesystemJsonPrefStore::GetValue(const std::string& key, | 
 |   76                                        const base::Value** result) const { | 
 |   77   DCHECK(CalledOnValidThread()); | 
 |   78  | 
 |   79   base::Value* tmp = nullptr; | 
 |   80   if (!prefs_->Get(key, &tmp)) | 
 |   81     return false; | 
 |   82  | 
 |   83   if (result) | 
 |   84     *result = tmp; | 
 |   85   return true; | 
 |   86 } | 
 |   87  | 
 |   88 void FilesystemJsonPrefStore::AddObserver(PrefStore::Observer* observer) { | 
 |   89   DCHECK(CalledOnValidThread()); | 
 |   90  | 
 |   91   observers_.AddObserver(observer); | 
 |   92 } | 
 |   93  | 
 |   94 void FilesystemJsonPrefStore::RemoveObserver(PrefStore::Observer* observer) { | 
 |   95   DCHECK(CalledOnValidThread()); | 
 |   96  | 
 |   97   observers_.RemoveObserver(observer); | 
 |   98 } | 
 |   99  | 
 |  100 bool FilesystemJsonPrefStore::HasObservers() const { | 
 |  101   DCHECK(CalledOnValidThread()); | 
 |  102  | 
 |  103   return observers_.might_have_observers(); | 
 |  104 } | 
 |  105  | 
 |  106 bool FilesystemJsonPrefStore::IsInitializationComplete() const { | 
 |  107   DCHECK(CalledOnValidThread()); | 
 |  108  | 
 |  109   return initialized_; | 
 |  110 } | 
 |  111  | 
 |  112 bool FilesystemJsonPrefStore::GetMutableValue(const std::string& key, | 
 |  113                                               base::Value** result) { | 
 |  114   DCHECK(CalledOnValidThread()); | 
 |  115  | 
 |  116   return prefs_->Get(key, result); | 
 |  117 } | 
 |  118  | 
 |  119 void FilesystemJsonPrefStore::SetValue(const std::string& key, | 
 |  120                                        scoped_ptr<base::Value> value, | 
 |  121                                        uint32_t flags) { | 
 |  122   DCHECK(CalledOnValidThread()); | 
 |  123  | 
 |  124   DCHECK(value); | 
 |  125   base::Value* old_value = nullptr; | 
 |  126   prefs_->Get(key, &old_value); | 
 |  127   if (!old_value || !value->Equals(old_value)) { | 
 |  128     prefs_->Set(key, std::move(value)); | 
 |  129     ReportValueChanged(key, flags); | 
 |  130   } | 
 |  131 } | 
 |  132  | 
 |  133 void FilesystemJsonPrefStore::SetValueSilently(const std::string& key, | 
 |  134                                                scoped_ptr<base::Value> value, | 
 |  135                                                uint32_t flags) { | 
 |  136   DCHECK(CalledOnValidThread()); | 
 |  137  | 
 |  138   DCHECK(value); | 
 |  139   base::Value* old_value = nullptr; | 
 |  140   prefs_->Get(key, &old_value); | 
 |  141   if (!old_value || !value->Equals(old_value)) { | 
 |  142     prefs_->Set(key, std::move(value)); | 
 |  143     ScheduleWrite(flags); | 
 |  144   } | 
 |  145 } | 
 |  146  | 
 |  147 void FilesystemJsonPrefStore::RemoveValue(const std::string& key, | 
 |  148                                           uint32_t flags) { | 
 |  149   DCHECK(CalledOnValidThread()); | 
 |  150  | 
 |  151   if (prefs_->RemovePath(key, nullptr)) | 
 |  152     ReportValueChanged(key, flags); | 
 |  153 } | 
 |  154  | 
 |  155 void FilesystemJsonPrefStore::RemoveValueSilently(const std::string& key, | 
 |  156                                                   uint32_t flags) { | 
 |  157   DCHECK(CalledOnValidThread()); | 
 |  158  | 
 |  159   prefs_->RemovePath(key, nullptr); | 
 |  160   ScheduleWrite(flags); | 
 |  161 } | 
 |  162  | 
 |  163 bool FilesystemJsonPrefStore::ReadOnly() const { | 
 |  164   DCHECK(CalledOnValidThread()); | 
 |  165  | 
 |  166   return read_only_; | 
 |  167 } | 
 |  168  | 
 |  169 PersistentPrefStore::PrefReadError FilesystemJsonPrefStore::GetReadError() | 
 |  170     const { | 
 |  171   DCHECK(CalledOnValidThread()); | 
 |  172  | 
 |  173   return read_error_; | 
 |  174 } | 
 |  175  | 
 |  176 PersistentPrefStore::PrefReadError FilesystemJsonPrefStore::ReadPrefs() { | 
 |  177   NOTREACHED(); | 
 |  178   // TODO(erg): Synchronously reading files makes no sense in a mojo world and | 
 |  179   // should be removed from the API. | 
 |  180   return PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE; | 
 |  181 } | 
 |  182  | 
 |  183 void FilesystemJsonPrefStore::ReadPrefsAsync( | 
 |  184     ReadErrorDelegate* error_delegate) { | 
 |  185   DCHECK(CalledOnValidThread()); | 
 |  186  | 
 |  187   initialized_ = false; | 
 |  188   error_delegate_.reset(error_delegate); | 
 |  189  | 
 |  190   if (!directory_) { | 
 |  191     OpenFilesystem( | 
 |  192         Bind(&FilesystemJsonPrefStore::OnPreferencesReadStart, AsWeakPtr())); | 
 |  193   } else { | 
 |  194     OnPreferencesReadStart(); | 
 |  195   } | 
 |  196 } | 
 |  197  | 
 |  198 void FilesystemJsonPrefStore::CommitPendingWrite() { | 
 |  199   DCHECK(CalledOnValidThread()); | 
 |  200  | 
 |  201   // TODO(erg): This is another one of those cases where we have problems | 
 |  202   // because of mismatch between the models used in the pref service versus | 
 |  203   // here. Most of the time, CommitPendingWrite() is called from | 
 |  204   // PrefService. However, in JSONPrefStore, we also call this method on | 
 |  205   // shutdown and thus need to synchronously write. But in mojo:filesystem, | 
 |  206   // everything is done asynchronously. So we're sort of stuck until we can | 
 |  207   // change the interface, which we'll do in the longer term. | 
 |  208  | 
 |  209   SchedulePendingLossyWrites(); | 
 |  210 } | 
 |  211  | 
 |  212 void FilesystemJsonPrefStore::SchedulePendingLossyWrites() { | 
 |  213   // This method is misnamed for the sake of the interface. Given that writing | 
 |  214   // is already asynchronous in this new world, "sheduleing" a pending write | 
 |  215   // just starts the asynchronous process. | 
 |  216   if (pending_lossy_write_) | 
 |  217     PerformWrite(); | 
 |  218 } | 
 |  219  | 
 |  220 void FilesystemJsonPrefStore::ReportValueChanged(const std::string& key, | 
 |  221                                                  uint32_t flags) { | 
 |  222   DCHECK(CalledOnValidThread()); | 
 |  223  | 
 |  224   if (pref_filter_) | 
 |  225     pref_filter_->FilterUpdate(key); | 
 |  226  | 
 |  227   FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key)); | 
 |  228  | 
 |  229   ScheduleWrite(flags); | 
 |  230 } | 
 |  231  | 
 |  232 void FilesystemJsonPrefStore::OnFileSystemShutdown() {} | 
 |  233  | 
 |  234 void FilesystemJsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) { | 
 |  235   DCHECK(CalledOnValidThread()); | 
 |  236  | 
 |  237   DCHECK(read_result); | 
 |  238  | 
 |  239   scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue); | 
 |  240  | 
 |  241   read_error_ = read_result->error; | 
 |  242  | 
 |  243   switch (read_error_) { | 
 |  244     case PREF_READ_ERROR_ACCESS_DENIED: | 
 |  245     case PREF_READ_ERROR_FILE_OTHER: | 
 |  246     case PREF_READ_ERROR_FILE_LOCKED: | 
 |  247     case PREF_READ_ERROR_JSON_TYPE: | 
 |  248     case PREF_READ_ERROR_FILE_NOT_SPECIFIED: | 
 |  249       read_only_ = true; | 
 |  250       break; | 
 |  251     case PREF_READ_ERROR_NONE: | 
 |  252       DCHECK(read_result->value.get()); | 
 |  253       unfiltered_prefs.reset( | 
 |  254           static_cast<base::DictionaryValue*>(read_result->value.release())); | 
 |  255       break; | 
 |  256     case PREF_READ_ERROR_NO_FILE: | 
 |  257     // If the file just doesn't exist, maybe this is first run.  In any case | 
 |  258     // there's no harm in writing out default prefs in this case. | 
 |  259     case PREF_READ_ERROR_JSON_PARSE: | 
 |  260     case PREF_READ_ERROR_JSON_REPEAT: | 
 |  261       break; | 
 |  262     case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE: | 
 |  263     // This is a special error code to be returned by ReadPrefs when it | 
 |  264     // can't complete synchronously, it should never be returned by the read | 
 |  265     // operation itself. | 
 |  266     case PREF_READ_ERROR_MAX_ENUM: | 
 |  267       NOTREACHED(); | 
 |  268       break; | 
 |  269   } | 
 |  270  | 
 |  271   if (pref_filter_) { | 
 |  272     filtering_in_progress_ = true; | 
 |  273     const PrefFilter::PostFilterOnLoadCallback post_filter_on_load_callback( | 
 |  274         base::Bind(&FilesystemJsonPrefStore::FinalizeFileRead, AsWeakPtr())); | 
 |  275     pref_filter_->FilterOnLoad(post_filter_on_load_callback, | 
 |  276                                std::move(unfiltered_prefs)); | 
 |  277   } else { | 
 |  278     FinalizeFileRead(std::move(unfiltered_prefs), false); | 
 |  279   } | 
 |  280 } | 
 |  281  | 
 |  282 FilesystemJsonPrefStore::~FilesystemJsonPrefStore() { | 
 |  283   // TODO(erg): Now that writing is asynchronous, we can't really async write | 
 |  284   // prefs at shutdown. See comment in CommitPendingWrite(). | 
 |  285 } | 
 |  286  | 
 |  287 void FilesystemJsonPrefStore::FinalizeFileRead( | 
 |  288     scoped_ptr<base::DictionaryValue> prefs, | 
 |  289     bool schedule_write) { | 
 |  290   DCHECK(CalledOnValidThread()); | 
 |  291  | 
 |  292   filtering_in_progress_ = false; | 
 |  293  | 
 |  294   prefs_ = std::move(prefs); | 
 |  295  | 
 |  296   initialized_ = true; | 
 |  297  | 
 |  298   if (schedule_write) | 
 |  299     ScheduleWrite(DEFAULT_PREF_WRITE_FLAGS); | 
 |  300  | 
 |  301   if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE) | 
 |  302     error_delegate_->OnError(read_error_); | 
 |  303  | 
 |  304   FOR_EACH_OBSERVER(PrefStore::Observer, observers_, | 
 |  305                     OnInitializationCompleted(true)); | 
 |  306  | 
 |  307   return; | 
 |  308 } | 
 |  309  | 
 |  310 void FilesystemJsonPrefStore::ScheduleWrite(uint32_t flags) { | 
 |  311   if (read_only_) | 
 |  312     return; | 
 |  313  | 
 |  314   if (flags & LOSSY_PREF_WRITE_FLAG) | 
 |  315     pending_lossy_write_ = true; | 
 |  316   else | 
 |  317     PerformWrite(); | 
 |  318 } | 
 |  319  | 
 |  320 void FilesystemJsonPrefStore::PerformWrite() { | 
 |  321   if (!directory_) { | 
 |  322     OpenFilesystem( | 
 |  323         Bind(&FilesystemJsonPrefStore::OnTempFileWriteStart, AsWeakPtr())); | 
 |  324   } else { | 
 |  325     OnTempFileWriteStart(); | 
 |  326   } | 
 |  327 } | 
 |  328  | 
 |  329 void FilesystemJsonPrefStore::OpenFilesystem(base::Closure callback) { | 
 |  330   filesystem::FileSystemClientPtr client; | 
 |  331   binding_.Bind(GetProxy(&client)); | 
 |  332  | 
 |  333   filesystem_->OpenFileSystem( | 
 |  334       "origin", GetProxy(&directory_), std::move(client), | 
 |  335       base::Bind(&FilesystemJsonPrefStore::OnOpenFilesystem, AsWeakPtr(), | 
 |  336                  callback)); | 
 |  337 } | 
 |  338  | 
 |  339 void FilesystemJsonPrefStore::OnOpenFilesystem(base::Closure callback, | 
 |  340                                                FileError err) { | 
 |  341   if (err != FileError::OK) { | 
 |  342     // Do real error checking. | 
 |  343     NOTIMPLEMENTED(); | 
 |  344     return; | 
 |  345   } | 
 |  346  | 
 |  347   callback.Run(); | 
 |  348 } | 
 |  349  | 
 |  350 void FilesystemJsonPrefStore::OnTempFileWriteStart() { | 
 |  351   // Open up a temporary file and truncate it. | 
 |  352   directory_->OpenFile( | 
 |  353       "tmp", GetProxy(&temporary_file_), kFlagWrite | kFlagCreate, | 
 |  354       Bind(&FilesystemJsonPrefStore::OnTempFileOpened, AsWeakPtr())); | 
 |  355 } | 
 |  356  | 
 |  357 void FilesystemJsonPrefStore::OnTempFileOpened(FileError err) { | 
 |  358   // TODO(erg): Error handling. The JsonPrefStore code assumes that writing the | 
 |  359   // file can never fail. | 
 |  360   CHECK_EQ(FileError::OK, err); | 
 |  361  | 
 |  362   // Calculate what we want to write, and then write to the temporary file. | 
 |  363   pending_lossy_write_ = false; | 
 |  364  | 
 |  365   if (pref_filter_) | 
 |  366     pref_filter_->FilterSerializeData(prefs_.get()); | 
 |  367  | 
 |  368   std::string output; | 
 |  369   JSONStringValueSerializer serializer(&output); | 
 |  370   serializer.set_pretty_print(false); | 
 |  371   serializer.Serialize(*prefs_); | 
 |  372  | 
 |  373   temporary_file_->Write( | 
 |  374       mojo::Array<uint8_t>::From(output), 0, Whence::FROM_CURRENT, | 
 |  375       Bind(&FilesystemJsonPrefStore::OnTempFileWrite, AsWeakPtr())); | 
 |  376 } | 
 |  377  | 
 |  378 void FilesystemJsonPrefStore::OnTempFileWrite(FileError err, | 
 |  379                                               uint32_t num_bytes_written) { | 
 |  380   // TODO(erg): Error handling. The JsonPrefStore code assumes that writing the | 
 |  381   // file can never fail. | 
 |  382   CHECK_EQ(FileError::OK, err); | 
 |  383  | 
 |  384   // Now that we've written the file, close it. | 
 |  385   temporary_file_->Close( | 
 |  386       Bind(&FilesystemJsonPrefStore::OnTempFileClosed, AsWeakPtr())); | 
 |  387 } | 
 |  388  | 
 |  389 void FilesystemJsonPrefStore::OnTempFileClosed(FileError err) { | 
 |  390   // TODO(erg): Error handling. The JsonPrefStore code assumes that writing the | 
 |  391   // file can never fail. | 
 |  392   CHECK_EQ(FileError::OK, err); | 
 |  393  | 
 |  394   temporary_file_.reset(); | 
 |  395   directory_->Rename( | 
 |  396       "tmp", path_, | 
 |  397       Bind(&FilesystemJsonPrefStore::OnTempFileRenamed, AsWeakPtr())); | 
 |  398 } | 
 |  399  | 
 |  400 void FilesystemJsonPrefStore::OnTempFileRenamed(FileError err) {} | 
 |  401  | 
 |  402 void FilesystemJsonPrefStore::OnPreferencesReadStart() { | 
 |  403   // TODO(erg): implement me. | 
 |  404   directory_->OpenFile( | 
 |  405       path_, GetProxy(&preferences_file_), kFlagRead | kFlagOpen, | 
 |  406       Bind(&FilesystemJsonPrefStore::OnPreferencesFileOpened, AsWeakPtr())); | 
 |  407 } | 
 |  408  | 
 |  409 void FilesystemJsonPrefStore::OnPreferencesFileOpened(FileError err) { | 
 |  410   // TODO(erg): Error handling. | 
 |  411   if (err == FileError::OK) { | 
 |  412     preferences_file_->ReadEntireFile( | 
 |  413         Bind(&FilesystemJsonPrefStore::OnPreferencesFileRead, AsWeakPtr())); | 
 |  414   } else { | 
 |  415     OnPreferencesFileRead(err, mojo::Array<uint8_t>()); | 
 |  416   } | 
 |  417 } | 
 |  418  | 
 |  419 void FilesystemJsonPrefStore::OnPreferencesFileRead( | 
 |  420     FileError err, | 
 |  421     mojo::Array<uint8_t> contents) { | 
 |  422   scoped_ptr<FilesystemJsonPrefStore::ReadResult> read_result( | 
 |  423       new FilesystemJsonPrefStore::ReadResult); | 
 |  424   // TODO(erg): Needs even better error handling. | 
 |  425   switch (err) { | 
 |  426     case FileError::IN_USE: | 
 |  427     case FileError::ACCESS_DENIED: { | 
 |  428       read_only_ = true; | 
 |  429       break; | 
 |  430     } | 
 |  431     case FileError::NOT_FOUND: { | 
 |  432       // If the file just doesn't exist, maybe this is the first run. Just | 
 |  433       // don't pass a value. | 
 |  434       read_result->error = PREF_READ_ERROR_NO_FILE; | 
 |  435       break; | 
 |  436     } | 
 |  437     default: { | 
 |  438       int error_code; | 
 |  439       std::string error_msg; | 
 |  440       JSONStringValueDeserializer deserializer(base::StringPiece( | 
 |  441           reinterpret_cast<char*>(&contents.front()), contents.size())); | 
 |  442       read_result->value = deserializer.Deserialize(&error_code, &error_msg); | 
 |  443       read_result->error = HandleReadErrors(read_result->value.get()); | 
 |  444     } | 
 |  445   } | 
 |  446  | 
 |  447   preferences_file_.reset(); | 
 |  448  | 
 |  449   OnFileRead(std::move(read_result)); | 
 |  450 } | 
 |  451  | 
 |  452 }  // namespace filesystem | 
| OLD | NEW |