1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/profile/dirserviceprovider/src/nsProfileDirServiceProvider.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,430 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsProfileDirServiceProvider.h" 1.10 +#include "nsProfileStringTypes.h" 1.11 +#include "nsProfileLock.h" 1.12 +#include "nsIFile.h" 1.13 +#include "nsDirectoryServiceDefs.h" 1.14 +#include "nsAppDirectoryServiceDefs.h" 1.15 +#include "nsISupportsUtils.h" 1.16 +#include "nsISimpleEnumerator.h" 1.17 +#include "nsIObserverService.h" 1.18 + 1.19 +// File Name Defines 1.20 + 1.21 +#define PREFS_FILE_50_NAME NS_LITERAL_CSTRING("prefs.js") 1.22 +#define PREFS_FILE_METRO_50_NAME NS_LITERAL_CSTRING("metro-prefs.js") 1.23 +#define USER_CHROME_DIR_50_NAME NS_LITERAL_CSTRING("chrome") 1.24 +#define LOCAL_STORE_FILE_50_NAME NS_LITERAL_CSTRING("localstore.rdf") 1.25 +#define PANELS_FILE_50_NAME NS_LITERAL_CSTRING("panels.rdf") 1.26 +#define MIME_TYPES_FILE_50_NAME NS_LITERAL_CSTRING("mimeTypes.rdf") 1.27 +#define BOOKMARKS_FILE_50_NAME NS_LITERAL_CSTRING("bookmarks.html") 1.28 +#define DOWNLOADS_FILE_50_NAME NS_LITERAL_CSTRING("downloads.rdf") 1.29 +#define SEARCH_FILE_50_NAME NS_LITERAL_CSTRING("search.rdf" ) 1.30 + 1.31 +//***************************************************************************** 1.32 +// nsProfileDirServiceProvider::nsProfileDirServiceProvider 1.33 +//***************************************************************************** 1.34 + 1.35 +nsProfileDirServiceProvider::nsProfileDirServiceProvider(bool aNotifyObservers) : 1.36 +#ifdef MOZ_PROFILELOCKING 1.37 + mProfileDirLock(nullptr), 1.38 +#endif 1.39 + mNotifyObservers(aNotifyObservers), 1.40 + mSharingEnabled(false) 1.41 +{ 1.42 +} 1.43 + 1.44 + 1.45 +nsProfileDirServiceProvider::~nsProfileDirServiceProvider() 1.46 +{ 1.47 +#ifdef MOZ_PROFILELOCKING 1.48 + delete mProfileDirLock; 1.49 +#endif 1.50 +} 1.51 + 1.52 +nsresult 1.53 +nsProfileDirServiceProvider::SetProfileDir(nsIFile* aProfileDir, 1.54 + nsIFile* aLocalProfileDir) 1.55 +{ 1.56 + if (!aLocalProfileDir) 1.57 + aLocalProfileDir = aProfileDir; 1.58 + if (mProfileDir) { 1.59 + bool isEqual; 1.60 + if (aProfileDir && 1.61 + NS_SUCCEEDED(aProfileDir->Equals(mProfileDir, &isEqual)) && isEqual) { 1.62 + NS_WARNING("Setting profile dir to same as current"); 1.63 + return NS_OK; 1.64 + } 1.65 +#ifdef MOZ_PROFILELOCKING 1.66 + mProfileDirLock->Unlock(); 1.67 +#endif 1.68 + UndefineFileLocations(); 1.69 + } 1.70 + mProfileDir = aProfileDir; 1.71 + mLocalProfileDir = aLocalProfileDir; 1.72 + if (!mProfileDir) 1.73 + return NS_OK; 1.74 + 1.75 + nsresult rv = InitProfileDir(mProfileDir); 1.76 + if (NS_FAILED(rv)) 1.77 + return rv; 1.78 + 1.79 + // Make sure that the local profile dir exists 1.80 + // we just try to create it - if it exists already, that'll fail; ignore 1.81 + // errors 1.82 + mLocalProfileDir->Create(nsIFile::DIRECTORY_TYPE, 0700); 1.83 + 1.84 +#ifdef MOZ_PROFILELOCKING 1.85 + // Lock the non-shared sub-dir if we are sharing, 1.86 + // the whole profile dir if we are not. 1.87 + nsCOMPtr<nsIFile> dirToLock; 1.88 + if (mSharingEnabled) 1.89 + dirToLock = mNonSharedProfileDir; 1.90 + else 1.91 + dirToLock = mProfileDir; 1.92 + rv = mProfileDirLock->Lock(dirToLock, nullptr); 1.93 + if (NS_FAILED(rv)) 1.94 + return rv; 1.95 +#endif 1.96 + 1.97 + if (mNotifyObservers) { 1.98 + nsCOMPtr<nsIObserverService> observerService = 1.99 + do_GetService("@mozilla.org/observer-service;1"); 1.100 + if (!observerService) 1.101 + return NS_ERROR_FAILURE; 1.102 + 1.103 + NS_NAMED_LITERAL_STRING(context, "startup"); 1.104 + // Notify observers that the profile has changed - Here they respond to new profile 1.105 + observerService->NotifyObservers(nullptr, "profile-do-change", context.get()); 1.106 + // Now observers can respond to something another observer did on "profile-do-change" 1.107 + observerService->NotifyObservers(nullptr, "profile-after-change", context.get()); 1.108 + } 1.109 + 1.110 + return NS_OK; 1.111 +} 1.112 + 1.113 +nsresult 1.114 +nsProfileDirServiceProvider::Register() 1.115 +{ 1.116 + nsCOMPtr<nsIDirectoryService> directoryService = 1.117 + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); 1.118 + if (!directoryService) 1.119 + return NS_ERROR_FAILURE; 1.120 + return directoryService->RegisterProvider(this); 1.121 +} 1.122 + 1.123 +nsresult 1.124 +nsProfileDirServiceProvider::Shutdown() 1.125 +{ 1.126 + if (!mNotifyObservers) 1.127 + return NS_OK; 1.128 + 1.129 + nsCOMPtr<nsIObserverService> observerService = 1.130 + do_GetService("@mozilla.org/observer-service;1"); 1.131 + if (!observerService) 1.132 + return NS_ERROR_FAILURE; 1.133 + 1.134 + NS_NAMED_LITERAL_STRING(context, "shutdown-persist"); 1.135 + observerService->NotifyObservers(nullptr, "profile-before-change", context.get()); 1.136 + observerService->NotifyObservers(nullptr, "profile-before-change2", context.get()); 1.137 + return NS_OK; 1.138 +} 1.139 + 1.140 +//***************************************************************************** 1.141 +// nsProfileDirServiceProvider::nsISupports 1.142 +//***************************************************************************** 1.143 + 1.144 +NS_IMPL_ISUPPORTS(nsProfileDirServiceProvider, 1.145 + nsIDirectoryServiceProvider) 1.146 + 1.147 +//***************************************************************************** 1.148 +// nsProfileDirServiceProvider::nsIDirectoryServiceProvider 1.149 +//***************************************************************************** 1.150 + 1.151 +NS_IMETHODIMP 1.152 +nsProfileDirServiceProvider::GetFile(const char *prop, bool *persistant, nsIFile **_retval) 1.153 +{ 1.154 + NS_ENSURE_ARG(prop); 1.155 + NS_ENSURE_ARG_POINTER(persistant); 1.156 + NS_ENSURE_ARG_POINTER(_retval); 1.157 + 1.158 + // Don't assert - we can be called many times before SetProfileDir() has been called. 1.159 + if (!mProfileDir) 1.160 + return NS_ERROR_FAILURE; 1.161 + 1.162 + *persistant = true; 1.163 + nsIFile* domainDir = mProfileDir; 1.164 + 1.165 + nsCOMPtr<nsIFile> localFile; 1.166 + nsresult rv = NS_ERROR_FAILURE; 1.167 + 1.168 + if (strcmp(prop, NS_APP_PREFS_50_DIR) == 0) { 1.169 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.170 + } 1.171 + else if (strcmp(prop, NS_APP_PREFS_50_FILE) == 0) { 1.172 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.173 + if (NS_SUCCEEDED(rv)) 1.174 + rv = localFile->AppendNative(PREFS_FILE_50_NAME); 1.175 + } 1.176 + else if (strcmp(prop, NS_METRO_APP_PREFS_50_FILE) == 0) { 1.177 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.178 + if (NS_SUCCEEDED(rv)) 1.179 + rv = localFile->AppendNative(PREFS_FILE_METRO_50_NAME); 1.180 + } 1.181 + else if (strcmp(prop, NS_APP_USER_PROFILE_50_DIR) == 0) { 1.182 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.183 + } 1.184 + else if (strcmp(prop, NS_APP_USER_PROFILE_LOCAL_50_DIR) == 0) { 1.185 + rv = mLocalProfileDir->Clone(getter_AddRefs(localFile)); 1.186 + } 1.187 + else if (strcmp(prop, NS_APP_USER_CHROME_DIR) == 0) { 1.188 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.189 + if (NS_SUCCEEDED(rv)) 1.190 + rv = localFile->AppendNative(USER_CHROME_DIR_50_NAME); 1.191 + } 1.192 + else if (strcmp(prop, NS_APP_LOCALSTORE_50_FILE) == 0) { 1.193 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.194 + if (NS_SUCCEEDED(rv)) { 1.195 + rv = localFile->AppendNative(LOCAL_STORE_FILE_50_NAME); 1.196 + if (NS_SUCCEEDED(rv)) { 1.197 + // it's OK if we can't copy the file... it will be created 1.198 + // by client code. 1.199 + (void) EnsureProfileFileExists(localFile, domainDir); 1.200 + } 1.201 + } 1.202 + } 1.203 + else if (strcmp(prop, NS_APP_USER_PANELS_50_FILE) == 0) { 1.204 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.205 + if (NS_SUCCEEDED(rv)) { 1.206 + rv = localFile->AppendNative(PANELS_FILE_50_NAME); 1.207 + if (NS_SUCCEEDED(rv)) 1.208 + rv = EnsureProfileFileExists(localFile, domainDir); 1.209 + } 1.210 + } 1.211 + else if (strcmp(prop, NS_APP_USER_MIMETYPES_50_FILE) == 0) { 1.212 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.213 + if (NS_SUCCEEDED(rv)) { 1.214 + rv = localFile->AppendNative(MIME_TYPES_FILE_50_NAME); 1.215 + if (NS_SUCCEEDED(rv)) 1.216 + rv = EnsureProfileFileExists(localFile, domainDir); 1.217 + } 1.218 + } 1.219 + else if (strcmp(prop, NS_APP_BOOKMARKS_50_FILE) == 0) { 1.220 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.221 + if (NS_SUCCEEDED(rv)) 1.222 + rv = localFile->AppendNative(BOOKMARKS_FILE_50_NAME); 1.223 + } 1.224 + else if (strcmp(prop, NS_APP_DOWNLOADS_50_FILE) == 0) { 1.225 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.226 + if (NS_SUCCEEDED(rv)) 1.227 + rv = localFile->AppendNative(DOWNLOADS_FILE_50_NAME); 1.228 + } 1.229 + else if (strcmp(prop, NS_APP_SEARCH_50_FILE) == 0) { 1.230 + rv = domainDir->Clone(getter_AddRefs(localFile)); 1.231 + if (NS_SUCCEEDED(rv)) { 1.232 + rv = localFile->AppendNative(SEARCH_FILE_50_NAME); 1.233 + if (NS_SUCCEEDED(rv)) 1.234 + rv = EnsureProfileFileExists(localFile, domainDir); 1.235 + } 1.236 + } 1.237 + 1.238 + if (NS_FAILED(rv)) { 1.239 + return rv; 1.240 + } 1.241 + 1.242 + localFile.forget(_retval); 1.243 + return NS_OK; 1.244 +} 1.245 + 1.246 +//***************************************************************************** 1.247 +// Protected methods 1.248 +//***************************************************************************** 1.249 + 1.250 +nsresult 1.251 +nsProfileDirServiceProvider::Initialize() 1.252 +{ 1.253 +#ifdef MOZ_PROFILELOCKING 1.254 + mProfileDirLock = new nsProfileLock; 1.255 + if (!mProfileDirLock) 1.256 + return NS_ERROR_OUT_OF_MEMORY; 1.257 +#endif 1.258 + 1.259 + return NS_OK; 1.260 +} 1.261 + 1.262 +nsresult 1.263 +nsProfileDirServiceProvider::InitProfileDir(nsIFile *profileDir) 1.264 +{ 1.265 + // Make sure our "Profile" folder exists. 1.266 + // If it does not, copy the profile defaults to its location. 1.267 + 1.268 + nsresult rv; 1.269 + bool exists; 1.270 + rv = profileDir->Exists(&exists); 1.271 + if (NS_FAILED(rv)) 1.272 + return rv; 1.273 + 1.274 + if (!exists) { 1.275 + nsCOMPtr<nsIFile> profileDefaultsDir; 1.276 + nsCOMPtr<nsIFile> profileDirParent; 1.277 + nsAutoCString profileDirName; 1.278 + 1.279 + (void)profileDir->GetParent(getter_AddRefs(profileDirParent)); 1.280 + if (!profileDirParent) 1.281 + return NS_ERROR_FAILURE; 1.282 + rv = profileDir->GetNativeLeafName(profileDirName); 1.283 + if (NS_FAILED(rv)) 1.284 + return rv; 1.285 + 1.286 + rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR, getter_AddRefs(profileDefaultsDir)); 1.287 + if (NS_FAILED(rv)) { 1.288 + rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR, getter_AddRefs(profileDefaultsDir)); 1.289 + if (NS_FAILED(rv)) 1.290 + return rv; 1.291 + } 1.292 + rv = profileDefaultsDir->CopyToNative(profileDirParent, profileDirName); 1.293 + if (NS_FAILED(rv)) { 1.294 + // if copying failed, lets just ensure that the profile directory exists. 1.295 + profileDirParent->AppendNative(profileDirName); 1.296 + rv = profileDirParent->Create(nsIFile::DIRECTORY_TYPE, 0700); 1.297 + if (NS_FAILED(rv)) 1.298 + return rv; 1.299 + } 1.300 + 1.301 + rv = profileDir->SetPermissions(0700); 1.302 + if (NS_FAILED(rv)) 1.303 + return rv; 1.304 + } 1.305 + else { 1.306 + bool isDir; 1.307 + rv = profileDir->IsDirectory(&isDir); 1.308 + 1.309 + if (NS_FAILED(rv)) 1.310 + return rv; 1.311 + if (!isDir) 1.312 + return NS_ERROR_FILE_NOT_DIRECTORY; 1.313 + } 1.314 + 1.315 + if (mNonSharedDirName.Length()) 1.316 + rv = InitNonSharedProfileDir(); 1.317 + 1.318 + return rv; 1.319 +} 1.320 + 1.321 +nsresult 1.322 +nsProfileDirServiceProvider::InitNonSharedProfileDir() 1.323 +{ 1.324 + nsresult rv; 1.325 + 1.326 + NS_ENSURE_STATE(mProfileDir); 1.327 + NS_ENSURE_STATE(mNonSharedDirName.Length()); 1.328 + 1.329 + nsCOMPtr<nsIFile> localDir; 1.330 + rv = mProfileDir->Clone(getter_AddRefs(localDir)); 1.331 + if (NS_SUCCEEDED(rv)) { 1.332 + rv = localDir->Append(mNonSharedDirName); 1.333 + if (NS_SUCCEEDED(rv)) { 1.334 + bool exists; 1.335 + rv = localDir->Exists(&exists); 1.336 + if (NS_SUCCEEDED(rv)) { 1.337 + if (!exists) { 1.338 + rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700); 1.339 + } 1.340 + else { 1.341 + bool isDir; 1.342 + rv = localDir->IsDirectory(&isDir); 1.343 + if (NS_SUCCEEDED(rv)) { 1.344 + if (!isDir) 1.345 + rv = NS_ERROR_FILE_NOT_DIRECTORY; 1.346 + } 1.347 + } 1.348 + if (NS_SUCCEEDED(rv)) 1.349 + mNonSharedProfileDir = localDir; 1.350 + } 1.351 + } 1.352 + } 1.353 + return rv; 1.354 +} 1.355 + 1.356 +nsresult 1.357 +nsProfileDirServiceProvider::EnsureProfileFileExists(nsIFile *aFile, nsIFile *destDir) 1.358 +{ 1.359 + nsresult rv; 1.360 + bool exists; 1.361 + 1.362 + rv = aFile->Exists(&exists); 1.363 + if (NS_FAILED(rv)) 1.364 + return rv; 1.365 + if (exists) 1.366 + return NS_OK; 1.367 + 1.368 + nsCOMPtr<nsIFile> defaultsFile; 1.369 + 1.370 + // Attempt first to get the localized subdir of the defaults 1.371 + rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR, getter_AddRefs(defaultsFile)); 1.372 + if (NS_FAILED(rv)) { 1.373 + // If that has not been defined, use the top level of the defaults 1.374 + rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR, getter_AddRefs(defaultsFile)); 1.375 + if (NS_FAILED(rv)) 1.376 + return rv; 1.377 + } 1.378 + 1.379 + nsAutoCString leafName; 1.380 + rv = aFile->GetNativeLeafName(leafName); 1.381 + if (NS_FAILED(rv)) 1.382 + return rv; 1.383 + rv = defaultsFile->AppendNative(leafName); 1.384 + if (NS_FAILED(rv)) 1.385 + return rv; 1.386 + 1.387 + return defaultsFile->CopyTo(destDir, EmptyString()); 1.388 +} 1.389 + 1.390 +nsresult 1.391 +nsProfileDirServiceProvider::UndefineFileLocations() 1.392 +{ 1.393 + nsresult rv; 1.394 + 1.395 + nsCOMPtr<nsIProperties> directoryService = 1.396 + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); 1.397 + NS_ENSURE_TRUE(directoryService, NS_ERROR_FAILURE); 1.398 + 1.399 + (void) directoryService->Undefine(NS_APP_PREFS_50_DIR); 1.400 + (void) directoryService->Undefine(NS_APP_PREFS_50_FILE); 1.401 + (void) directoryService->Undefine(NS_APP_USER_PROFILE_50_DIR); 1.402 + (void) directoryService->Undefine(NS_APP_USER_CHROME_DIR); 1.403 + (void) directoryService->Undefine(NS_APP_LOCALSTORE_50_FILE); 1.404 + (void) directoryService->Undefine(NS_APP_USER_PANELS_50_FILE); 1.405 + (void) directoryService->Undefine(NS_APP_USER_MIMETYPES_50_FILE); 1.406 + (void) directoryService->Undefine(NS_APP_BOOKMARKS_50_FILE); 1.407 + (void) directoryService->Undefine(NS_APP_DOWNLOADS_50_FILE); 1.408 + (void) directoryService->Undefine(NS_APP_SEARCH_50_FILE); 1.409 + 1.410 + return NS_OK; 1.411 +} 1.412 + 1.413 +//***************************************************************************** 1.414 +// Global creation function 1.415 +//***************************************************************************** 1.416 + 1.417 +nsresult NS_NewProfileDirServiceProvider(bool aNotifyObservers, 1.418 + nsProfileDirServiceProvider** aProvider) 1.419 +{ 1.420 + NS_ENSURE_ARG_POINTER(aProvider); 1.421 + *aProvider = nullptr; 1.422 + 1.423 + nsProfileDirServiceProvider *prov = new nsProfileDirServiceProvider(aNotifyObservers); 1.424 + if (!prov) 1.425 + return NS_ERROR_OUT_OF_MEMORY; 1.426 + nsresult rv = prov->Initialize(); 1.427 + if (NS_FAILED(rv)) { 1.428 + delete prov; 1.429 + return rv; 1.430 + } 1.431 + NS_ADDREF(*aProvider = prov); 1.432 + return NS_OK; 1.433 +}