json_pref_store.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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/common/json_pref_store.h" 6 7#include <algorithm> 8 9#include "base/file_util.h" 10#include "base/values.h" 11#include "chrome/common/json_value_serializer.h" 12 13namespace { 14 15// Some extensions we'll tack on to copies of the Preferences files. 16const FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad"); 17 18} // namespace 19 20JsonPrefStore::JsonPrefStore(const FilePath& filename, 21 base::MessageLoopProxy* file_message_loop_proxy) 22 : path_(filename), 23 prefs_(new DictionaryValue()), 24 read_only_(false), 25 writer_(filename, file_message_loop_proxy) { 26} 27 28JsonPrefStore::~JsonPrefStore() { 29 if (writer_.HasPendingWrite() && !read_only_) 30 writer_.DoScheduledWrite(); 31} 32 33PrefStore::PrefReadError JsonPrefStore::ReadPrefs() { 34 if (path_.empty()) { 35 read_only_ = true; 36 return PREF_READ_ERROR_FILE_NOT_SPECIFIED; 37 } 38 JSONFileValueSerializer serializer(path_); 39 40 int error_code = 0; 41 std::string error_msg; 42 scoped_ptr<Value> value(serializer.Deserialize(&error_code, &error_msg)); 43 if (!value.get()) { 44#if defined(GOOGLE_CHROME_BUILD) 45 // This log could be used for more detailed client-side error diagnosis, 46 // but since this triggers often with unit tests, we need to disable it 47 // in non-official builds. 48 PLOG(ERROR) << "Error reading Preferences: " << error_msg << " " << 49 path_.value(); 50#endif 51 PrefReadError error; 52 switch (error_code) { 53 case JSONFileValueSerializer::JSON_ACCESS_DENIED: 54 // If the file exists but is simply unreadable, put the file into a 55 // state where we don't try to save changes. Otherwise, we could 56 // clobber the existing prefs. 57 error = PREF_READ_ERROR_ACCESS_DENIED; 58 read_only_ = true; 59 break; 60 case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: 61 error = PREF_READ_ERROR_FILE_OTHER; 62 read_only_ = true; 63 break; 64 case JSONFileValueSerializer::JSON_FILE_LOCKED: 65 error = PREF_READ_ERROR_FILE_LOCKED; 66 read_only_ = true; 67 break; 68 case JSONFileValueSerializer::JSON_NO_SUCH_FILE: 69 // If the file just doesn't exist, maybe this is first run. In any case 70 // there's no harm in writing out default prefs in this case. 71 error = PREF_READ_ERROR_NO_FILE; 72 break; 73 default: 74 error = PREF_READ_ERROR_JSON_PARSE; 75 // JSON errors indicate file corruption of some sort. 76 // Since the file is corrupt, move it to the side and continue with 77 // empty preferences. This will result in them losing their settings. 78 // We keep the old file for possible support and debugging assistance 79 // as well as to detect if they're seeing these errors repeatedly. 80 // TODO(erikkay) Instead, use the last known good file. 81 FilePath bad = path_.ReplaceExtension(kBadExtension); 82 83 // If they've ever had a parse error before, put them in another bucket. 84 // TODO(erikkay) if we keep this error checking for very long, we may 85 // want to differentiate between recent and long ago errors. 86 if (file_util::PathExists(bad)) 87 error = PREF_READ_ERROR_JSON_REPEAT; 88 file_util::Move(path_, bad); 89 break; 90 } 91 return error; 92 } 93 94 // Preferences should always have a dictionary root. 95 if (!value->IsType(Value::TYPE_DICTIONARY)) { 96 // See comment for the default case above. 97 read_only_ = true; 98 return PREF_READ_ERROR_JSON_TYPE; 99 } 100 101 prefs_.reset(static_cast<DictionaryValue*>(value.release())); 102 103 return PREF_READ_ERROR_NONE; 104} 105 106bool JsonPrefStore::WritePrefs() { 107 std::string data; 108 if (!SerializeData(&data)) 109 return false; 110 111 // Lie about our ability to save. 112 if (read_only_) 113 return true; 114 115 writer_.WriteNow(data); 116 return true; 117} 118 119void JsonPrefStore::ScheduleWritePrefs() { 120 if (read_only_) 121 return; 122 123 writer_.ScheduleWrite(this); 124} 125 126bool JsonPrefStore::SerializeData(std::string* output) { 127 // TODO(tc): Do we want to prune webkit preferences that match the default 128 // value? 129 JSONStringValueSerializer serializer(output); 130 serializer.set_pretty_print(true); 131 scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren()); 132 return serializer.Serialize(*(copy.get())); 133} 134