1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/devicestorage/nsDeviceStorage.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,4370 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsDeviceStorage.h" 1.11 + 1.12 +#include "mozilla/Attributes.h" 1.13 +#include "mozilla/ClearOnShutdown.h" 1.14 +#include "mozilla/DebugOnly.h" 1.15 +#include "mozilla/dom/ContentChild.h" 1.16 +#include "mozilla/dom/DeviceStorageBinding.h" 1.17 +#include "mozilla/dom/DeviceStorageFileSystem.h" 1.18 +#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h" 1.19 +#include "mozilla/dom/Directory.h" 1.20 +#include "mozilla/dom/FileSystemUtils.h" 1.21 +#include "mozilla/dom/ipc/Blob.h" 1.22 +#include "mozilla/dom/PBrowserChild.h" 1.23 +#include "mozilla/dom/PContentPermissionRequestChild.h" 1.24 +#include "mozilla/dom/PermissionMessageUtils.h" 1.25 +#include "mozilla/dom/Promise.h" 1.26 +#include "mozilla/EventDispatcher.h" 1.27 +#include "mozilla/EventListenerManager.h" 1.28 +#include "mozilla/LazyIdleThread.h" 1.29 +#include "mozilla/Preferences.h" 1.30 +#include "mozilla/Scoped.h" 1.31 +#include "mozilla/Services.h" 1.32 + 1.33 +#include "nsAutoPtr.h" 1.34 +#include "nsServiceManagerUtils.h" 1.35 +#include "nsIFile.h" 1.36 +#include "nsIDirectoryEnumerator.h" 1.37 +#include "nsAppDirectoryServiceDefs.h" 1.38 +#include "nsDirectoryServiceDefs.h" 1.39 +#include "nsIDOMFile.h" 1.40 +#include "nsDOMBlobBuilder.h" 1.41 +#include "nsNetUtil.h" 1.42 +#include "nsCycleCollectionParticipant.h" 1.43 +#include "nsIPrincipal.h" 1.44 +#include "nsJSUtils.h" 1.45 +#include "nsContentUtils.h" 1.46 +#include "nsCxPusher.h" 1.47 +#include "nsXULAppAPI.h" 1.48 +#include "TabChild.h" 1.49 +#include "DeviceStorageFileDescriptor.h" 1.50 +#include "DeviceStorageRequestChild.h" 1.51 +#include "nsIDOMDeviceStorageChangeEvent.h" 1.52 +#include "nsCRT.h" 1.53 +#include "nsIObserverService.h" 1.54 +#include "GeneratedEvents.h" 1.55 +#include "nsIMIMEService.h" 1.56 +#include "nsCExternalHandlerService.h" 1.57 +#include "nsIPermissionManager.h" 1.58 +#include "nsIStringBundle.h" 1.59 +#include "nsIDocument.h" 1.60 +#include "nsPrintfCString.h" 1.61 +#include <algorithm> 1.62 +#include "private/pprio.h" 1.63 +#include "nsContentPermissionHelper.h" 1.64 + 1.65 +#include "mozilla/dom/DeviceStorageBinding.h" 1.66 + 1.67 +// Microsoft's API Name hackery sucks 1.68 +#undef CreateEvent 1.69 + 1.70 +#ifdef MOZ_WIDGET_GONK 1.71 +#include "nsIVolume.h" 1.72 +#include "nsIVolumeService.h" 1.73 +#endif 1.74 + 1.75 +#define DEVICESTORAGE_PROPERTIES \ 1.76 + "chrome://global/content/devicestorage.properties" 1.77 +#define DEFAULT_THREAD_TIMEOUT_MS 30000 1.78 + 1.79 +using namespace mozilla; 1.80 +using namespace mozilla::dom; 1.81 +using namespace mozilla::dom::devicestorage; 1.82 +using namespace mozilla::ipc; 1.83 + 1.84 +#include "nsDirectoryServiceDefs.h" 1.85 + 1.86 +namespace mozilla { 1.87 + MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, PR_Close); 1.88 +} 1.89 + 1.90 +StaticAutoPtr<DeviceStorageUsedSpaceCache> 1.91 + DeviceStorageUsedSpaceCache::sDeviceStorageUsedSpaceCache; 1.92 + 1.93 +DeviceStorageUsedSpaceCache::DeviceStorageUsedSpaceCache() 1.94 +{ 1.95 + MOZ_ASSERT(NS_IsMainThread()); 1.96 + 1.97 + mIOThread = new LazyIdleThread( 1.98 + DEFAULT_THREAD_TIMEOUT_MS, 1.99 + NS_LITERAL_CSTRING("DeviceStorageUsedSpaceCache I/O")); 1.100 + 1.101 +} 1.102 + 1.103 +DeviceStorageUsedSpaceCache::~DeviceStorageUsedSpaceCache() 1.104 +{ 1.105 +} 1.106 + 1.107 +DeviceStorageUsedSpaceCache* 1.108 +DeviceStorageUsedSpaceCache::CreateOrGet() 1.109 +{ 1.110 + if (sDeviceStorageUsedSpaceCache) { 1.111 + return sDeviceStorageUsedSpaceCache; 1.112 + } 1.113 + 1.114 + MOZ_ASSERT(NS_IsMainThread()); 1.115 + 1.116 + sDeviceStorageUsedSpaceCache = new DeviceStorageUsedSpaceCache(); 1.117 + ClearOnShutdown(&sDeviceStorageUsedSpaceCache); 1.118 + return sDeviceStorageUsedSpaceCache; 1.119 +} 1.120 + 1.121 +already_AddRefed<DeviceStorageUsedSpaceCache::CacheEntry> 1.122 +DeviceStorageUsedSpaceCache::GetCacheEntry(const nsAString& aStorageName) 1.123 +{ 1.124 + nsTArray<nsRefPtr<CacheEntry>>::size_type numEntries = mCacheEntries.Length(); 1.125 + nsTArray<nsRefPtr<CacheEntry>>::index_type i; 1.126 + for (i = 0; i < numEntries; i++) { 1.127 + nsRefPtr<CacheEntry>& cacheEntry = mCacheEntries[i]; 1.128 + if (cacheEntry->mStorageName.Equals(aStorageName)) { 1.129 + nsRefPtr<CacheEntry> addRefedCacheEntry = cacheEntry; 1.130 + return addRefedCacheEntry.forget(); 1.131 + } 1.132 + } 1.133 + return nullptr; 1.134 +} 1.135 + 1.136 +static int64_t 1.137 +GetFreeBytes(const nsAString& aStorageName) 1.138 +{ 1.139 + // This function makes the assumption that the various types 1.140 + // are all stored on the same filesystem. So we use pictures. 1.141 + 1.142 + DeviceStorageFile dsf(NS_LITERAL_STRING(DEVICESTORAGE_PICTURES), 1.143 + aStorageName); 1.144 + int64_t freeBytes = 0; 1.145 + dsf.GetDiskFreeSpace(&freeBytes); 1.146 + return freeBytes; 1.147 +} 1.148 + 1.149 +nsresult 1.150 +DeviceStorageUsedSpaceCache::AccumUsedSizes(const nsAString& aStorageName, 1.151 + uint64_t* aPicturesSoFar, 1.152 + uint64_t* aVideosSoFar, 1.153 + uint64_t* aMusicSoFar, 1.154 + uint64_t* aTotalSoFar) 1.155 +{ 1.156 + nsRefPtr<CacheEntry> cacheEntry = GetCacheEntry(aStorageName); 1.157 + if (!cacheEntry || cacheEntry->mDirty) { 1.158 + return NS_ERROR_NOT_AVAILABLE; 1.159 + } 1.160 + int64_t freeBytes = GetFreeBytes(cacheEntry->mStorageName); 1.161 + if (freeBytes != cacheEntry->mFreeBytes) { 1.162 + // Free space changed, so our cached results are no longer valid. 1.163 + return NS_ERROR_NOT_AVAILABLE; 1.164 + } 1.165 + 1.166 + *aPicturesSoFar += cacheEntry->mPicturesUsedSize; 1.167 + *aVideosSoFar += cacheEntry->mVideosUsedSize; 1.168 + *aMusicSoFar += cacheEntry->mMusicUsedSize; 1.169 + *aTotalSoFar += cacheEntry->mTotalUsedSize; 1.170 + 1.171 + return NS_OK; 1.172 +} 1.173 + 1.174 +void 1.175 +DeviceStorageUsedSpaceCache::SetUsedSizes(const nsAString& aStorageName, 1.176 + uint64_t aPictureSize, 1.177 + uint64_t aVideosSize, 1.178 + uint64_t aMusicSize, 1.179 + uint64_t aTotalUsedSize) 1.180 +{ 1.181 + nsRefPtr<CacheEntry> cacheEntry = GetCacheEntry(aStorageName); 1.182 + if (!cacheEntry) { 1.183 + cacheEntry = new CacheEntry; 1.184 + cacheEntry->mStorageName = aStorageName; 1.185 + mCacheEntries.AppendElement(cacheEntry); 1.186 + } 1.187 + cacheEntry->mFreeBytes = GetFreeBytes(cacheEntry->mStorageName); 1.188 + 1.189 + cacheEntry->mPicturesUsedSize = aPictureSize; 1.190 + cacheEntry->mVideosUsedSize = aVideosSize; 1.191 + cacheEntry->mMusicUsedSize = aMusicSize; 1.192 + cacheEntry->mTotalUsedSize = aTotalUsedSize; 1.193 + cacheEntry->mDirty = false; 1.194 +} 1.195 + 1.196 +class GlobalDirs 1.197 +{ 1.198 +public: 1.199 + NS_INLINE_DECL_REFCOUNTING(GlobalDirs) 1.200 +#if !defined(MOZ_WIDGET_GONK) 1.201 + nsCOMPtr<nsIFile> pictures; 1.202 + nsCOMPtr<nsIFile> videos; 1.203 + nsCOMPtr<nsIFile> music; 1.204 + nsCOMPtr<nsIFile> sdcard; 1.205 +#endif 1.206 + nsCOMPtr<nsIFile> apps; 1.207 + nsCOMPtr<nsIFile> crashes; 1.208 + nsCOMPtr<nsIFile> overrideRootDir; 1.209 +}; 1.210 + 1.211 +static StaticRefPtr<GlobalDirs> sDirs; 1.212 + 1.213 +StaticAutoPtr<DeviceStorageTypeChecker> 1.214 + DeviceStorageTypeChecker::sDeviceStorageTypeChecker; 1.215 + 1.216 +DeviceStorageTypeChecker::DeviceStorageTypeChecker() 1.217 +{ 1.218 +} 1.219 + 1.220 +DeviceStorageTypeChecker::~DeviceStorageTypeChecker() 1.221 +{ 1.222 +} 1.223 + 1.224 +DeviceStorageTypeChecker* 1.225 +DeviceStorageTypeChecker::CreateOrGet() 1.226 +{ 1.227 + if (sDeviceStorageTypeChecker) { 1.228 + return sDeviceStorageTypeChecker; 1.229 + } 1.230 + 1.231 + MOZ_ASSERT(NS_IsMainThread()); 1.232 + 1.233 + nsCOMPtr<nsIStringBundleService> stringService 1.234 + = mozilla::services::GetStringBundleService(); 1.235 + if (!stringService) { 1.236 + return nullptr; 1.237 + } 1.238 + 1.239 + nsCOMPtr<nsIStringBundle> filterBundle; 1.240 + if (NS_FAILED(stringService->CreateBundle(DEVICESTORAGE_PROPERTIES, 1.241 + getter_AddRefs(filterBundle)))) { 1.242 + return nullptr; 1.243 + } 1.244 + 1.245 + DeviceStorageTypeChecker* result = new DeviceStorageTypeChecker(); 1.246 + result->InitFromBundle(filterBundle); 1.247 + 1.248 + sDeviceStorageTypeChecker = result; 1.249 + ClearOnShutdown(&sDeviceStorageTypeChecker); 1.250 + return result; 1.251 +} 1.252 + 1.253 +void 1.254 +DeviceStorageTypeChecker::InitFromBundle(nsIStringBundle* aBundle) 1.255 +{ 1.256 + aBundle->GetStringFromName( 1.257 + NS_ConvertASCIItoUTF16(DEVICESTORAGE_PICTURES).get(), 1.258 + getter_Copies(mPicturesExtensions)); 1.259 + aBundle->GetStringFromName( 1.260 + NS_ConvertASCIItoUTF16(DEVICESTORAGE_MUSIC).get(), 1.261 + getter_Copies(mMusicExtensions)); 1.262 + aBundle->GetStringFromName( 1.263 + NS_ConvertASCIItoUTF16(DEVICESTORAGE_VIDEOS).get(), 1.264 + getter_Copies(mVideosExtensions)); 1.265 +} 1.266 + 1.267 + 1.268 +bool 1.269 +DeviceStorageTypeChecker::Check(const nsAString& aType, nsIDOMBlob* aBlob) 1.270 +{ 1.271 + MOZ_ASSERT(aBlob); 1.272 + 1.273 + nsString mimeType; 1.274 + if (NS_FAILED(aBlob->GetType(mimeType))) { 1.275 + return false; 1.276 + } 1.277 + 1.278 + if (aType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { 1.279 + return StringBeginsWith(mimeType, NS_LITERAL_STRING("image/")); 1.280 + } 1.281 + 1.282 + if (aType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { 1.283 + return StringBeginsWith(mimeType, NS_LITERAL_STRING("video/")); 1.284 + } 1.285 + 1.286 + if (aType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { 1.287 + return StringBeginsWith(mimeType, NS_LITERAL_STRING("audio/")); 1.288 + } 1.289 + 1.290 + if (aType.EqualsLiteral(DEVICESTORAGE_APPS) || 1.291 + aType.EqualsLiteral(DEVICESTORAGE_SDCARD) || 1.292 + aType.EqualsLiteral(DEVICESTORAGE_CRASHES)) { 1.293 + // Apps, crashes and sdcard have no restriction on mime types 1.294 + return true; 1.295 + } 1.296 + 1.297 + return false; 1.298 +} 1.299 + 1.300 +bool 1.301 +DeviceStorageTypeChecker::Check(const nsAString& aType, nsIFile* aFile) 1.302 +{ 1.303 + MOZ_ASSERT(aFile); 1.304 + 1.305 + if (aType.EqualsLiteral(DEVICESTORAGE_APPS) || 1.306 + aType.EqualsLiteral(DEVICESTORAGE_SDCARD) || 1.307 + aType.EqualsLiteral(DEVICESTORAGE_CRASHES)) { 1.308 + // Apps, crashes and sdcard have no restrictions on what file extensions used. 1.309 + return true; 1.310 + } 1.311 + 1.312 + nsString path; 1.313 + aFile->GetPath(path); 1.314 + 1.315 + int32_t dotIdx = path.RFindChar(char16_t('.')); 1.316 + if (dotIdx == kNotFound) { 1.317 + return false; 1.318 + } 1.319 + 1.320 + nsAutoString extensionMatch; 1.321 + extensionMatch.AssignLiteral("*"); 1.322 + extensionMatch.Append(Substring(path, dotIdx)); 1.323 + extensionMatch.AppendLiteral(";"); 1.324 + 1.325 + if (aType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { 1.326 + return CaseInsensitiveFindInReadable(extensionMatch, mPicturesExtensions); 1.327 + } 1.328 + 1.329 + if (aType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { 1.330 + return CaseInsensitiveFindInReadable(extensionMatch, mVideosExtensions); 1.331 + } 1.332 + 1.333 + if (aType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { 1.334 + return CaseInsensitiveFindInReadable(extensionMatch, mMusicExtensions); 1.335 + } 1.336 + 1.337 + return false; 1.338 +} 1.339 + 1.340 +void 1.341 +DeviceStorageTypeChecker::GetTypeFromFile(nsIFile* aFile, nsAString& aType) 1.342 +{ 1.343 + MOZ_ASSERT(aFile); 1.344 + 1.345 + nsString path; 1.346 + aFile->GetPath(path); 1.347 + 1.348 + GetTypeFromFileName(path, aType); 1.349 +} 1.350 + 1.351 +void 1.352 +DeviceStorageTypeChecker::GetTypeFromFileName(const nsAString& aFileName, 1.353 + nsAString& aType) 1.354 +{ 1.355 + aType.AssignLiteral(DEVICESTORAGE_SDCARD); 1.356 + 1.357 + nsString fileName(aFileName); 1.358 + int32_t dotIdx = fileName.RFindChar(char16_t('.')); 1.359 + if (dotIdx == kNotFound) { 1.360 + return; 1.361 + } 1.362 + 1.363 + nsAutoString extensionMatch; 1.364 + extensionMatch.AssignLiteral("*"); 1.365 + extensionMatch.Append(Substring(aFileName, dotIdx)); 1.366 + extensionMatch.AppendLiteral(";"); 1.367 + 1.368 + if (CaseInsensitiveFindInReadable(extensionMatch, mPicturesExtensions)) { 1.369 + aType.AssignLiteral(DEVICESTORAGE_PICTURES); 1.370 + } 1.371 + else if (CaseInsensitiveFindInReadable(extensionMatch, mVideosExtensions)) { 1.372 + aType.AssignLiteral(DEVICESTORAGE_VIDEOS); 1.373 + } 1.374 + else if (CaseInsensitiveFindInReadable(extensionMatch, mMusicExtensions)) { 1.375 + aType.AssignLiteral(DEVICESTORAGE_MUSIC); 1.376 + } 1.377 +} 1.378 + 1.379 +nsresult 1.380 +DeviceStorageTypeChecker::GetPermissionForType(const nsAString& aType, 1.381 + nsACString& aPermissionResult) 1.382 +{ 1.383 + if (!aType.EqualsLiteral(DEVICESTORAGE_PICTURES) && 1.384 + !aType.EqualsLiteral(DEVICESTORAGE_VIDEOS) && 1.385 + !aType.EqualsLiteral(DEVICESTORAGE_MUSIC) && 1.386 + !aType.EqualsLiteral(DEVICESTORAGE_APPS) && 1.387 + !aType.EqualsLiteral(DEVICESTORAGE_SDCARD) && 1.388 + !aType.EqualsLiteral(DEVICESTORAGE_CRASHES)) { 1.389 + // unknown type 1.390 + return NS_ERROR_FAILURE; 1.391 + } 1.392 + 1.393 + aPermissionResult.AssignLiteral("device-storage:"); 1.394 + aPermissionResult.Append(NS_ConvertUTF16toUTF8(aType)); 1.395 + return NS_OK; 1.396 +} 1.397 + 1.398 +nsresult 1.399 +DeviceStorageTypeChecker::GetAccessForRequest( 1.400 + const DeviceStorageRequestType aRequestType, nsACString& aAccessResult) 1.401 +{ 1.402 + switch(aRequestType) { 1.403 + case DEVICE_STORAGE_REQUEST_READ: 1.404 + case DEVICE_STORAGE_REQUEST_WATCH: 1.405 + case DEVICE_STORAGE_REQUEST_FREE_SPACE: 1.406 + case DEVICE_STORAGE_REQUEST_USED_SPACE: 1.407 + case DEVICE_STORAGE_REQUEST_AVAILABLE: 1.408 + case DEVICE_STORAGE_REQUEST_STATUS: 1.409 + aAccessResult.AssignLiteral("read"); 1.410 + break; 1.411 + case DEVICE_STORAGE_REQUEST_WRITE: 1.412 + case DEVICE_STORAGE_REQUEST_DELETE: 1.413 + case DEVICE_STORAGE_REQUEST_FORMAT: 1.414 + case DEVICE_STORAGE_REQUEST_MOUNT: 1.415 + case DEVICE_STORAGE_REQUEST_UNMOUNT: 1.416 + aAccessResult.AssignLiteral("write"); 1.417 + break; 1.418 + case DEVICE_STORAGE_REQUEST_CREATE: 1.419 + case DEVICE_STORAGE_REQUEST_CREATEFD: 1.420 + aAccessResult.AssignLiteral("create"); 1.421 + break; 1.422 + default: 1.423 + aAccessResult.AssignLiteral("undefined"); 1.424 + } 1.425 + return NS_OK; 1.426 +} 1.427 + 1.428 +//static 1.429 +bool 1.430 +DeviceStorageTypeChecker::IsVolumeBased(const nsAString& aType) 1.431 +{ 1.432 +#ifdef MOZ_WIDGET_GONK 1.433 + // The apps and crashes aren't stored in the same place as the media, so 1.434 + // we only ever return a single apps object, and not an array 1.435 + // with one per volume (as is the case for the remaining 1.436 + // storage types). 1.437 + return !aType.EqualsLiteral(DEVICESTORAGE_APPS) && 1.438 + !aType.EqualsLiteral(DEVICESTORAGE_CRASHES); 1.439 +#else 1.440 + return false; 1.441 +#endif 1.442 +} 1.443 + 1.444 +NS_IMPL_ISUPPORTS(FileUpdateDispatcher, nsIObserver) 1.445 + 1.446 +mozilla::StaticRefPtr<FileUpdateDispatcher> FileUpdateDispatcher::sSingleton; 1.447 + 1.448 +FileUpdateDispatcher* 1.449 +FileUpdateDispatcher::GetSingleton() 1.450 +{ 1.451 + if (sSingleton) { 1.452 + return sSingleton; 1.453 + } 1.454 + 1.455 + sSingleton = new FileUpdateDispatcher(); 1.456 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.457 + obs->AddObserver(sSingleton, "file-watcher-notify", false); 1.458 + ClearOnShutdown(&sSingleton); 1.459 + 1.460 + return sSingleton; 1.461 +} 1.462 + 1.463 +NS_IMETHODIMP 1.464 +FileUpdateDispatcher::Observe(nsISupports *aSubject, 1.465 + const char *aTopic, 1.466 + const char16_t *aData) 1.467 +{ 1.468 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.469 + 1.470 + DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject); 1.471 + if (!file || !file->mFile) { 1.472 + NS_WARNING("Device storage file looks invalid!"); 1.473 + return NS_OK; 1.474 + } 1.475 + ContentChild::GetSingleton() 1.476 + ->SendFilePathUpdateNotify(file->mStorageType, 1.477 + file->mStorageName, 1.478 + file->mPath, 1.479 + NS_ConvertUTF16toUTF8(aData)); 1.480 + } else { 1.481 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.482 + obs->NotifyObservers(aSubject, "file-watcher-update", aData); 1.483 + } 1.484 + return NS_OK; 1.485 +} 1.486 + 1.487 +class IOEventComplete : public nsRunnable 1.488 +{ 1.489 +public: 1.490 + IOEventComplete(DeviceStorageFile *aFile, const char *aType) 1.491 + : mFile(aFile) 1.492 + , mType(aType) 1.493 + { 1.494 + } 1.495 + 1.496 + ~IOEventComplete() {} 1.497 + 1.498 + NS_IMETHOD Run() 1.499 + { 1.500 + MOZ_ASSERT(NS_IsMainThread()); 1.501 + nsString data; 1.502 + CopyASCIItoUTF16(mType, data); 1.503 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.504 + 1.505 + obs->NotifyObservers(mFile, "file-watcher-notify", data.get()); 1.506 + 1.507 + DeviceStorageUsedSpaceCache* usedSpaceCache 1.508 + = DeviceStorageUsedSpaceCache::CreateOrGet(); 1.509 + MOZ_ASSERT(usedSpaceCache); 1.510 + usedSpaceCache->Invalidate(mFile->mStorageName); 1.511 + return NS_OK; 1.512 + } 1.513 + 1.514 +private: 1.515 + nsRefPtr<DeviceStorageFile> mFile; 1.516 + nsCString mType; 1.517 +}; 1.518 + 1.519 +DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, 1.520 + const nsAString& aStorageName, 1.521 + const nsAString& aRootDir, 1.522 + const nsAString& aPath) 1.523 + : mStorageType(aStorageType) 1.524 + , mStorageName(aStorageName) 1.525 + , mRootDir(aRootDir) 1.526 + , mPath(aPath) 1.527 + , mEditable(false) 1.528 + , mLength(UINT64_MAX) 1.529 + , mLastModifiedDate(UINT64_MAX) 1.530 +{ 1.531 + Init(); 1.532 + AppendRelativePath(mRootDir); 1.533 + if (!mPath.EqualsLiteral("")) { 1.534 + AppendRelativePath(mPath); 1.535 + } 1.536 + NormalizeFilePath(); 1.537 +} 1.538 + 1.539 +DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, 1.540 + const nsAString& aStorageName, 1.541 + const nsAString& aPath) 1.542 + : mStorageType(aStorageType) 1.543 + , mStorageName(aStorageName) 1.544 + , mPath(aPath) 1.545 + , mEditable(false) 1.546 + , mLength(UINT64_MAX) 1.547 + , mLastModifiedDate(UINT64_MAX) 1.548 +{ 1.549 + Init(); 1.550 + AppendRelativePath(aPath); 1.551 + NormalizeFilePath(); 1.552 +} 1.553 + 1.554 +DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, 1.555 + const nsAString& aStorageName) 1.556 + : mStorageType(aStorageType) 1.557 + , mStorageName(aStorageName) 1.558 + , mEditable(false) 1.559 + , mLength(UINT64_MAX) 1.560 + , mLastModifiedDate(UINT64_MAX) 1.561 +{ 1.562 + Init(); 1.563 +} 1.564 + 1.565 +void 1.566 +DeviceStorageFile::Dump(const char* label) 1.567 +{ 1.568 + nsString path; 1.569 + if (mFile) { 1.570 + mFile->GetPath(path); 1.571 + } else { 1.572 + path = NS_LITERAL_STRING("(null)"); 1.573 + } 1.574 + const char* ptStr; 1.575 + if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.576 + ptStr = "parent"; 1.577 + } else { 1.578 + ptStr = "child"; 1.579 + } 1.580 + 1.581 + printf_stderr("DSF (%s) %s: mStorageType '%s' mStorageName '%s' " 1.582 + "mRootDir '%s' mPath '%s' mFile->GetPath '%s'\n", 1.583 + ptStr, label, 1.584 + NS_LossyConvertUTF16toASCII(mStorageType).get(), 1.585 + NS_LossyConvertUTF16toASCII(mStorageName).get(), 1.586 + NS_LossyConvertUTF16toASCII(mRootDir).get(), 1.587 + NS_LossyConvertUTF16toASCII(mPath).get(), 1.588 + NS_LossyConvertUTF16toASCII(path).get()); 1.589 +} 1.590 + 1.591 +void 1.592 +DeviceStorageFile::Init() 1.593 +{ 1.594 + DeviceStorageFile::GetRootDirectoryForType(mStorageType, 1.595 + mStorageName, 1.596 + getter_AddRefs(mFile)); 1.597 + 1.598 + DebugOnly<DeviceStorageTypeChecker*> typeChecker 1.599 + = DeviceStorageTypeChecker::CreateOrGet(); 1.600 + MOZ_ASSERT(typeChecker); 1.601 +} 1.602 + 1.603 +// The OverrideRootDir is needed to facilitate testing of the 1.604 +// device.storage.overrideRootDir preference. The preference is normally 1.605 +// only read once during initialization, but since the test environment has 1.606 +// no convenient way to restart, we use a pref watcher instead. 1.607 +class OverrideRootDir MOZ_FINAL : public nsIObserver 1.608 +{ 1.609 +public: 1.610 + NS_DECL_ISUPPORTS 1.611 + NS_DECL_NSIOBSERVER 1.612 + 1.613 + static OverrideRootDir* GetSingleton(); 1.614 + ~OverrideRootDir(); 1.615 + void Init(); 1.616 +private: 1.617 + static mozilla::StaticRefPtr<OverrideRootDir> sSingleton; 1.618 +}; 1.619 + 1.620 +NS_IMPL_ISUPPORTS(OverrideRootDir, nsIObserver) 1.621 + 1.622 +mozilla::StaticRefPtr<OverrideRootDir> 1.623 + OverrideRootDir::sSingleton; 1.624 + 1.625 +OverrideRootDir* 1.626 +OverrideRootDir::GetSingleton() 1.627 +{ 1.628 + if (sSingleton) { 1.629 + return sSingleton; 1.630 + } 1.631 + // Preference changes are automatically forwarded from parent to child 1.632 + // in ContentParent::Observe, so we'll see the change in both the parent 1.633 + // and the child process. 1.634 + 1.635 + sSingleton = new OverrideRootDir(); 1.636 + Preferences::AddStrongObserver(sSingleton, "device.storage.overrideRootDir"); 1.637 + ClearOnShutdown(&sSingleton); 1.638 + 1.639 + return sSingleton; 1.640 +} 1.641 + 1.642 +OverrideRootDir::~OverrideRootDir() 1.643 +{ 1.644 + Preferences::RemoveObserver(this, "device.storage.overrideRootDir"); 1.645 +} 1.646 + 1.647 +NS_IMETHODIMP 1.648 +OverrideRootDir::Observe(nsISupports *aSubject, 1.649 + const char *aTopic, 1.650 + const char16_t *aData) 1.651 +{ 1.652 + MOZ_ASSERT(NS_IsMainThread()); 1.653 + 1.654 + if (sSingleton) { 1.655 + sSingleton->Init(); 1.656 + } 1.657 + return NS_OK; 1.658 +} 1.659 + 1.660 +void 1.661 +OverrideRootDir::Init() 1.662 +{ 1.663 + MOZ_ASSERT(NS_IsMainThread()); 1.664 + 1.665 + if (!sDirs) { 1.666 + return; 1.667 + } 1.668 + 1.669 + if (mozilla::Preferences::GetBool("device.storage.testing", false)) { 1.670 + nsCOMPtr<nsIProperties> dirService 1.671 + = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); 1.672 + MOZ_ASSERT(dirService); 1.673 + dirService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile), 1.674 + getter_AddRefs(sDirs->overrideRootDir)); 1.675 + if (sDirs->overrideRootDir) { 1.676 + sDirs->overrideRootDir->AppendRelativeNativePath( 1.677 + NS_LITERAL_CSTRING("device-storage-testing")); 1.678 + } 1.679 + } else { 1.680 + // For users running on desktop, it's convenient to be able to override 1.681 + // all of the directories to point to a single tree, much like what happens 1.682 + // on a real device. 1.683 + const nsAdoptingString& overrideRootDir = 1.684 + mozilla::Preferences::GetString("device.storage.overrideRootDir"); 1.685 + if (overrideRootDir && overrideRootDir.Length() > 0) { 1.686 + NS_NewLocalFile(overrideRootDir, false, 1.687 + getter_AddRefs(sDirs->overrideRootDir)); 1.688 + } else { 1.689 + sDirs->overrideRootDir = nullptr; 1.690 + } 1.691 + } 1.692 + 1.693 + if (sDirs->overrideRootDir) { 1.694 + if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.695 + // Only the parent process can create directories. In testing, because 1.696 + // the preference is updated after startup, its entirely possible that 1.697 + // the preference updated notification will be received by a child 1.698 + // prior to the parent. 1.699 + nsresult rv 1.700 + = sDirs->overrideRootDir->Create(nsIFile::DIRECTORY_TYPE, 0777); 1.701 + nsString path; 1.702 + sDirs->overrideRootDir->GetPath(path); 1.703 + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) { 1.704 + nsPrintfCString msg("DeviceStorage: Unable to create directory '%s'", 1.705 + NS_LossyConvertUTF16toASCII(path).get()); 1.706 + NS_WARNING(msg.get()); 1.707 + } 1.708 + } 1.709 + sDirs->overrideRootDir->Normalize(); 1.710 + } 1.711 +} 1.712 + 1.713 +// Directories which don't depend on a volume should be calculated once 1.714 +// here. Directories which depend on the root directory of a volume 1.715 +// should be calculated in DeviceStorageFile::GetRootDirectoryForType. 1.716 +static void 1.717 +InitDirs() 1.718 +{ 1.719 + if (sDirs) { 1.720 + return; 1.721 + } 1.722 + MOZ_ASSERT(NS_IsMainThread()); 1.723 + sDirs = new GlobalDirs; 1.724 + ClearOnShutdown(&sDirs); 1.725 + 1.726 + nsCOMPtr<nsIProperties> dirService 1.727 + = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); 1.728 + MOZ_ASSERT(dirService); 1.729 + 1.730 +#if !defined(MOZ_WIDGET_GONK) 1.731 + 1.732 +#if defined (MOZ_WIDGET_COCOA) 1.733 + dirService->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, 1.734 + NS_GET_IID(nsIFile), 1.735 + getter_AddRefs(sDirs->pictures)); 1.736 + dirService->Get(NS_OSX_MOVIE_DOCUMENTS_DIR, 1.737 + NS_GET_IID(nsIFile), 1.738 + getter_AddRefs(sDirs->videos)); 1.739 + dirService->Get(NS_OSX_MUSIC_DOCUMENTS_DIR, 1.740 + NS_GET_IID(nsIFile), 1.741 + getter_AddRefs(sDirs->music)); 1.742 +#elif defined (XP_UNIX) 1.743 + dirService->Get(NS_UNIX_XDG_PICTURES_DIR, 1.744 + NS_GET_IID(nsIFile), 1.745 + getter_AddRefs(sDirs->pictures)); 1.746 + dirService->Get(NS_UNIX_XDG_VIDEOS_DIR, 1.747 + NS_GET_IID(nsIFile), 1.748 + getter_AddRefs(sDirs->videos)); 1.749 + dirService->Get(NS_UNIX_XDG_MUSIC_DIR, 1.750 + NS_GET_IID(nsIFile), 1.751 + getter_AddRefs(sDirs->music)); 1.752 +#elif defined (XP_WIN) 1.753 + dirService->Get(NS_WIN_PICTURES_DIR, 1.754 + NS_GET_IID(nsIFile), 1.755 + getter_AddRefs(sDirs->pictures)); 1.756 + dirService->Get(NS_WIN_VIDEOS_DIR, 1.757 + NS_GET_IID(nsIFile), 1.758 + getter_AddRefs(sDirs->videos)); 1.759 + dirService->Get(NS_WIN_MUSIC_DIR, 1.760 + NS_GET_IID(nsIFile), 1.761 + getter_AddRefs(sDirs->music)); 1.762 +#endif 1.763 + 1.764 + // Eventually, on desktop, we want to do something smarter -- for example, 1.765 + // detect when an sdcard is inserted, and use that instead of this. 1.766 + dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile), 1.767 + getter_AddRefs(sDirs->sdcard)); 1.768 + if (sDirs->sdcard) { 1.769 + sDirs->sdcard->AppendRelativeNativePath(NS_LITERAL_CSTRING("fake-sdcard")); 1.770 + } 1.771 +#endif // !MOZ_WIDGET_GONK 1.772 + 1.773 +#ifdef MOZ_WIDGET_GONK 1.774 + NS_NewLocalFile(NS_LITERAL_STRING("/data"), 1.775 + false, 1.776 + getter_AddRefs(sDirs->apps)); 1.777 +#else 1.778 + dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile), 1.779 + getter_AddRefs(sDirs->apps)); 1.780 + if (sDirs->apps) { 1.781 + sDirs->apps->AppendRelativeNativePath(NS_LITERAL_CSTRING("webapps")); 1.782 + } 1.783 +#endif 1.784 + 1.785 + if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.786 + NS_GetSpecialDirectory("UAppData", getter_AddRefs(sDirs->crashes)); 1.787 + if (sDirs->crashes) { 1.788 + sDirs->crashes->Append(NS_LITERAL_STRING("Crash Reports")); 1.789 + } 1.790 + } else { 1.791 + // NS_GetSpecialDirectory("UAppData") fails in content processes because 1.792 + // gAppData from toolkit/xre/nsAppRunner.cpp is not initialized. 1.793 +#ifdef MOZ_WIDGET_GONK 1.794 + NS_NewLocalFile(NS_LITERAL_STRING("/data/b2g/mozilla/Crash Reports"), 1.795 + false, 1.796 + getter_AddRefs(sDirs->crashes)); 1.797 +#endif 1.798 + } 1.799 + 1.800 + OverrideRootDir::GetSingleton()->Init(); 1.801 +} 1.802 + 1.803 +void 1.804 +DeviceStorageFile::GetFullPath(nsAString &aFullPath) 1.805 +{ 1.806 + aFullPath.Truncate(); 1.807 + if (!mStorageName.EqualsLiteral("")) { 1.808 + aFullPath.AppendLiteral("/"); 1.809 + aFullPath.Append(mStorageName); 1.810 + aFullPath.AppendLiteral("/"); 1.811 + } 1.812 + if (!mRootDir.EqualsLiteral("")) { 1.813 + aFullPath.Append(mRootDir); 1.814 + aFullPath.AppendLiteral("/"); 1.815 + } 1.816 + aFullPath.Append(mPath); 1.817 +} 1.818 + 1.819 + 1.820 +// Directories which don't depend on a volume should be calculated once 1.821 +// in InitDirs. Directories which depend on the root directory of a volume 1.822 +// should be calculated in this method. 1.823 +void 1.824 +DeviceStorageFile::GetRootDirectoryForType(const nsAString& aStorageType, 1.825 + const nsAString& aStorageName, 1.826 + nsIFile** aFile) 1.827 +{ 1.828 + nsCOMPtr<nsIFile> f; 1.829 + *aFile = nullptr; 1.830 + bool allowOverride = true; 1.831 + 1.832 + InitDirs(); 1.833 + 1.834 +#ifdef MOZ_WIDGET_GONK 1.835 + nsString volMountPoint; 1.836 + if (DeviceStorageTypeChecker::IsVolumeBased(aStorageType)) { 1.837 + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); 1.838 + NS_ENSURE_TRUE_VOID(vs); 1.839 + nsresult rv; 1.840 + nsCOMPtr<nsIVolume> vol; 1.841 + rv = vs->GetVolumeByName(aStorageName, getter_AddRefs(vol)); 1.842 + NS_ENSURE_SUCCESS_VOID(rv); 1.843 + vol->GetMountPoint(volMountPoint); 1.844 + } 1.845 +#endif 1.846 + 1.847 + // Picture directory 1.848 + if (aStorageType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { 1.849 +#ifdef MOZ_WIDGET_GONK 1.850 + NS_NewLocalFile(volMountPoint, false, getter_AddRefs(f)); 1.851 +#else 1.852 + f = sDirs->pictures; 1.853 +#endif 1.854 + } 1.855 + 1.856 + // Video directory 1.857 + else if (aStorageType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { 1.858 +#ifdef MOZ_WIDGET_GONK 1.859 + NS_NewLocalFile(volMountPoint, false, getter_AddRefs(f)); 1.860 +#else 1.861 + f = sDirs->videos; 1.862 +#endif 1.863 + } 1.864 + 1.865 + // Music directory 1.866 + else if (aStorageType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { 1.867 +#ifdef MOZ_WIDGET_GONK 1.868 + NS_NewLocalFile(volMountPoint, false, getter_AddRefs(f)); 1.869 +#else 1.870 + f = sDirs->music; 1.871 +#endif 1.872 + } 1.873 + 1.874 + // Apps directory 1.875 + else if (aStorageType.EqualsLiteral(DEVICESTORAGE_APPS)) { 1.876 + f = sDirs->apps; 1.877 + allowOverride = false; 1.878 + } 1.879 + 1.880 + // default SDCard 1.881 + else if (aStorageType.EqualsLiteral(DEVICESTORAGE_SDCARD)) { 1.882 +#ifdef MOZ_WIDGET_GONK 1.883 + NS_NewLocalFile(volMountPoint, false, getter_AddRefs(f)); 1.884 +#else 1.885 + f = sDirs->sdcard; 1.886 +#endif 1.887 + } 1.888 + 1.889 + // crash reports directory. 1.890 + else if (aStorageType.EqualsLiteral(DEVICESTORAGE_CRASHES)) { 1.891 + f = sDirs->crashes; 1.892 + allowOverride = false; 1.893 + } else { 1.894 + // Not a storage type that we recognize. Return null 1.895 + return; 1.896 + } 1.897 + 1.898 + // In testing, we default all device storage types to a temp directory. 1.899 + // sDirs->overrideRootDir will only have been initialized (in InitDirs) 1.900 + // if the preference device.storage.testing was set to true, or if 1.901 + // device.storage.overrideRootDir is set. We can't test the preferences 1.902 + // directly here, since we may not be on the main thread. 1.903 + if (allowOverride && sDirs->overrideRootDir) { 1.904 + f = sDirs->overrideRootDir; 1.905 + } 1.906 + 1.907 + if (f) { 1.908 + f->Clone(aFile); 1.909 + } 1.910 +} 1.911 + 1.912 +//static 1.913 +already_AddRefed<DeviceStorageFile> 1.914 +DeviceStorageFile::CreateUnique(nsAString& aFileName, 1.915 + uint32_t aFileType, 1.916 + uint32_t aFileAttributes) 1.917 +{ 1.918 + DeviceStorageTypeChecker* typeChecker 1.919 + = DeviceStorageTypeChecker::CreateOrGet(); 1.920 + MOZ_ASSERT(typeChecker); 1.921 + 1.922 + nsString storageType; 1.923 + typeChecker->GetTypeFromFileName(aFileName, storageType); 1.924 + 1.925 + nsString storageName; 1.926 + nsString storagePath; 1.927 + if (!nsDOMDeviceStorage::ParseFullPath(aFileName, storageName, storagePath)) { 1.928 + return nullptr; 1.929 + } 1.930 + if (storageName.IsEmpty()) { 1.931 + nsDOMDeviceStorage::GetDefaultStorageName(storageType, storageName); 1.932 + } 1.933 + nsRefPtr<DeviceStorageFile> dsf = 1.934 + new DeviceStorageFile(storageType, storageName, storagePath); 1.935 + if (!dsf->mFile) { 1.936 + return nullptr; 1.937 + } 1.938 + 1.939 + nsresult rv = dsf->mFile->CreateUnique(aFileType, aFileAttributes); 1.940 + NS_ENSURE_SUCCESS(rv, nullptr); 1.941 + 1.942 + // CreateUnique may cause the filename to change. So we need to update mPath 1.943 + // to reflect that. 1.944 + nsString leafName; 1.945 + dsf->mFile->GetLeafName(leafName); 1.946 + 1.947 + int32_t lastSlashIndex = dsf->mPath.RFindChar('/'); 1.948 + if (lastSlashIndex == kNotFound) { 1.949 + dsf->mPath.Assign(leafName); 1.950 + } else { 1.951 + // Include the last '/' 1.952 + dsf->mPath = Substring(dsf->mPath, 0, lastSlashIndex + 1); 1.953 + dsf->mPath.Append(leafName); 1.954 + } 1.955 + 1.956 + return dsf.forget(); 1.957 +} 1.958 + 1.959 +void 1.960 +DeviceStorageFile::SetPath(const nsAString& aPath) { 1.961 + mPath.Assign(aPath); 1.962 + NormalizeFilePath(); 1.963 +} 1.964 + 1.965 +void 1.966 +DeviceStorageFile::SetEditable(bool aEditable) { 1.967 + mEditable = aEditable; 1.968 +} 1.969 + 1.970 +// we want to make sure that the names of file can't reach 1.971 +// outside of the type of storage the user asked for. 1.972 +bool 1.973 +DeviceStorageFile::IsSafePath() 1.974 +{ 1.975 + return IsSafePath(mRootDir) && IsSafePath(mPath); 1.976 +} 1.977 + 1.978 +bool 1.979 +DeviceStorageFile::IsSafePath(const nsAString& aPath) 1.980 +{ 1.981 + nsAString::const_iterator start, end; 1.982 + aPath.BeginReading(start); 1.983 + aPath.EndReading(end); 1.984 + 1.985 + // if the path is a '~' or starts with '~/', return false. 1.986 + NS_NAMED_LITERAL_STRING(tilde, "~"); 1.987 + NS_NAMED_LITERAL_STRING(tildeSlash, "~/"); 1.988 + if (aPath.Equals(tilde) || 1.989 + StringBeginsWith(aPath, tildeSlash)) { 1.990 + NS_WARNING("Path name starts with tilde!"); 1.991 + return false; 1.992 + } 1.993 + // split on /. if any token is "", ., or .., return false. 1.994 + NS_ConvertUTF16toUTF8 cname(aPath); 1.995 + char* buffer = cname.BeginWriting(); 1.996 + const char* token; 1.997 + 1.998 + while ((token = nsCRT::strtok(buffer, "/", &buffer))) { 1.999 + if (PL_strcmp(token, "") == 0 || 1.1000 + PL_strcmp(token, ".") == 0 || 1.1001 + PL_strcmp(token, "..") == 0 ) { 1.1002 + return false; 1.1003 + } 1.1004 + } 1.1005 + return true; 1.1006 +} 1.1007 + 1.1008 +void 1.1009 +DeviceStorageFile::NormalizeFilePath() { 1.1010 + FileSystemUtils::LocalPathToNormalizedPath(mPath, mPath); 1.1011 +} 1.1012 + 1.1013 +void 1.1014 +DeviceStorageFile::AppendRelativePath(const nsAString& aPath) { 1.1015 + if (!mFile) { 1.1016 + return; 1.1017 + } 1.1018 + if (!IsSafePath(aPath)) { 1.1019 + // All of the APIs (in the child) do checks to verify that the path is 1.1020 + // valid and return PERMISSION_DENIED if a non-safe path is entered. 1.1021 + // This check is done in the parent and prevents a compromised 1.1022 + // child from bypassing the check. It shouldn't be possible for this 1.1023 + // code path to be taken with a non-compromised child. 1.1024 + NS_WARNING("Unsafe path detected - ignoring"); 1.1025 + NS_WARNING(NS_LossyConvertUTF16toASCII(aPath).get()); 1.1026 + return; 1.1027 + } 1.1028 + nsString localPath; 1.1029 + FileSystemUtils::NormalizedPathToLocalPath(aPath, localPath); 1.1030 + mFile->AppendRelativePath(localPath); 1.1031 +} 1.1032 + 1.1033 +nsresult 1.1034 +DeviceStorageFile::CreateFileDescriptor(FileDescriptor& aFileDescriptor) 1.1035 +{ 1.1036 + ScopedPRFileDesc fd; 1.1037 + nsresult rv = mFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE, 1.1038 + 0660, &fd.rwget()); 1.1039 + NS_ENSURE_SUCCESS(rv, rv); 1.1040 + 1.1041 + // NOTE: The FileDescriptor::PlatformHandleType constructor returns a dup of 1.1042 + // the file descriptor, so we don't need the original fd after this. 1.1043 + // Our scoped file descriptor will automatically close fd. 1.1044 + aFileDescriptor = 1.1045 + FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd)); 1.1046 + return NS_OK; 1.1047 +} 1.1048 + 1.1049 +nsresult 1.1050 +DeviceStorageFile::Write(nsIInputStream* aInputStream) 1.1051 +{ 1.1052 + if (!aInputStream || !mFile) { 1.1053 + return NS_ERROR_FAILURE; 1.1054 + } 1.1055 + 1.1056 + nsresult rv = mFile->Create(nsIFile::NORMAL_FILE_TYPE, 00600); 1.1057 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.1058 + return rv; 1.1059 + } 1.1060 + 1.1061 + nsCOMPtr<nsIRunnable> iocomplete = new IOEventComplete(this, "created"); 1.1062 + rv = NS_DispatchToMainThread(iocomplete); 1.1063 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.1064 + return rv; 1.1065 + } 1.1066 + 1.1067 + uint64_t bufSize = 0; 1.1068 + aInputStream->Available(&bufSize); 1.1069 + 1.1070 + nsCOMPtr<nsIOutputStream> outputStream; 1.1071 + NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile); 1.1072 + 1.1073 + if (!outputStream) { 1.1074 + return NS_ERROR_FAILURE; 1.1075 + } 1.1076 + 1.1077 + nsCOMPtr<nsIOutputStream> bufferedOutputStream; 1.1078 + rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), 1.1079 + outputStream, 1.1080 + 4096*4); 1.1081 + NS_ENSURE_SUCCESS(rv, rv); 1.1082 + 1.1083 + while (bufSize) { 1.1084 + uint32_t wrote; 1.1085 + rv = bufferedOutputStream->WriteFrom( 1.1086 + aInputStream, 1.1087 + static_cast<uint32_t>(std::min<uint64_t>(bufSize, UINT32_MAX)), 1.1088 + &wrote); 1.1089 + if (NS_FAILED(rv)) { 1.1090 + break; 1.1091 + } 1.1092 + bufSize -= wrote; 1.1093 + } 1.1094 + 1.1095 + iocomplete = new IOEventComplete(this, "modified"); 1.1096 + rv = NS_DispatchToMainThread(iocomplete); 1.1097 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.1098 + return rv; 1.1099 + } 1.1100 + 1.1101 + bufferedOutputStream->Close(); 1.1102 + outputStream->Close(); 1.1103 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.1104 + return rv; 1.1105 + } 1.1106 + return NS_OK; 1.1107 +} 1.1108 + 1.1109 +nsresult 1.1110 +DeviceStorageFile::Write(InfallibleTArray<uint8_t>& aBits) 1.1111 +{ 1.1112 + if (!mFile) { 1.1113 + return NS_ERROR_FAILURE; 1.1114 + } 1.1115 + 1.1116 + nsresult rv = mFile->Create(nsIFile::NORMAL_FILE_TYPE, 00600); 1.1117 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.1118 + return rv; 1.1119 + } 1.1120 + 1.1121 + nsCOMPtr<nsIRunnable> iocomplete = new IOEventComplete(this, "created"); 1.1122 + rv = NS_DispatchToMainThread(iocomplete); 1.1123 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.1124 + return rv; 1.1125 + } 1.1126 + 1.1127 + nsCOMPtr<nsIOutputStream> outputStream; 1.1128 + NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile); 1.1129 + 1.1130 + if (!outputStream) { 1.1131 + return NS_ERROR_FAILURE; 1.1132 + } 1.1133 + 1.1134 + uint32_t wrote; 1.1135 + outputStream->Write((char*) aBits.Elements(), aBits.Length(), &wrote); 1.1136 + outputStream->Close(); 1.1137 + 1.1138 + iocomplete = new IOEventComplete(this, "modified"); 1.1139 + rv = NS_DispatchToMainThread(iocomplete); 1.1140 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.1141 + return rv; 1.1142 + } 1.1143 + 1.1144 + if (aBits.Length() != wrote) { 1.1145 + return NS_ERROR_FAILURE; 1.1146 + } 1.1147 + return NS_OK; 1.1148 +} 1.1149 + 1.1150 +nsresult 1.1151 +DeviceStorageFile::Remove() 1.1152 +{ 1.1153 + MOZ_ASSERT(!NS_IsMainThread()); 1.1154 + 1.1155 + if (!mFile) { 1.1156 + return NS_ERROR_FAILURE; 1.1157 + } 1.1158 + 1.1159 + bool check; 1.1160 + nsresult rv = mFile->Exists(&check); 1.1161 + if (NS_FAILED(rv)) { 1.1162 + return rv; 1.1163 + } 1.1164 + 1.1165 + if (!check) { 1.1166 + return NS_OK; 1.1167 + } 1.1168 + 1.1169 + rv = mFile->Remove(true); 1.1170 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.1171 + return rv; 1.1172 + } 1.1173 + 1.1174 + nsCOMPtr<nsIRunnable> iocomplete = new IOEventComplete(this, "deleted"); 1.1175 + return NS_DispatchToMainThread(iocomplete); 1.1176 +} 1.1177 + 1.1178 +nsresult 1.1179 +DeviceStorageFile::CalculateMimeType() 1.1180 +{ 1.1181 + MOZ_ASSERT(NS_IsMainThread()); 1.1182 + 1.1183 + nsAutoCString mimeType; 1.1184 + nsCOMPtr<nsIMIMEService> mimeService = 1.1185 + do_GetService(NS_MIMESERVICE_CONTRACTID); 1.1186 + if (mimeService) { 1.1187 + nsresult rv = mimeService->GetTypeFromFile(mFile, mimeType); 1.1188 + if (NS_FAILED(rv)) { 1.1189 + mimeType.Truncate(); 1.1190 + return rv; 1.1191 + } 1.1192 + } 1.1193 + 1.1194 + mMimeType = NS_ConvertUTF8toUTF16(mimeType); 1.1195 + return NS_OK; 1.1196 +} 1.1197 + 1.1198 +nsresult 1.1199 +DeviceStorageFile::CalculateSizeAndModifiedDate() 1.1200 +{ 1.1201 + MOZ_ASSERT(!NS_IsMainThread()); 1.1202 + 1.1203 + int64_t fileSize; 1.1204 + nsresult rv = mFile->GetFileSize(&fileSize); 1.1205 + NS_ENSURE_SUCCESS(rv, rv); 1.1206 + 1.1207 + mLength = fileSize; 1.1208 + 1.1209 + PRTime modDate; 1.1210 + rv = mFile->GetLastModifiedTime(&modDate); 1.1211 + NS_ENSURE_SUCCESS(rv, rv); 1.1212 + 1.1213 + mLastModifiedDate = modDate; 1.1214 + return NS_OK; 1.1215 +} 1.1216 + 1.1217 +void 1.1218 +DeviceStorageFile::CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, 1.1219 + PRTime aSince) 1.1220 +{ 1.1221 + nsString fullRootPath; 1.1222 + mFile->GetPath(fullRootPath); 1.1223 + collectFilesInternal(aFiles, aSince, fullRootPath); 1.1224 +} 1.1225 + 1.1226 +void 1.1227 +DeviceStorageFile::collectFilesInternal( 1.1228 + nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, 1.1229 + PRTime aSince, 1.1230 + nsAString& aRootPath) 1.1231 +{ 1.1232 + if (!mFile || !IsAvailable()) { 1.1233 + return; 1.1234 + } 1.1235 + 1.1236 + nsCOMPtr<nsISimpleEnumerator> e; 1.1237 + mFile->GetDirectoryEntries(getter_AddRefs(e)); 1.1238 + 1.1239 + if (!e) { 1.1240 + return; 1.1241 + } 1.1242 + 1.1243 + nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e); 1.1244 + nsCOMPtr<nsIFile> f; 1.1245 + 1.1246 + while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(f))) && f) { 1.1247 + 1.1248 + PRTime msecs; 1.1249 + f->GetLastModifiedTime(&msecs); 1.1250 + 1.1251 + if (msecs < aSince) { 1.1252 + continue; 1.1253 + } 1.1254 + 1.1255 + bool isDir; 1.1256 + f->IsDirectory(&isDir); 1.1257 + 1.1258 + bool isFile; 1.1259 + f->IsFile(&isFile); 1.1260 + 1.1261 + nsString fullpath; 1.1262 + nsresult rv = f->GetPath(fullpath); 1.1263 + if (NS_FAILED(rv)) { 1.1264 + continue; 1.1265 + } 1.1266 + 1.1267 + if (!StringBeginsWith(fullpath, aRootPath)) { 1.1268 + NS_ERROR("collectFiles returned a path that does not belong!"); 1.1269 + continue; 1.1270 + } 1.1271 + 1.1272 + nsAString::size_type len = aRootPath.Length() + 1; // +1 for the trailing / 1.1273 + nsDependentSubstring newPath = Substring(fullpath, len); 1.1274 + 1.1275 + if (isDir) { 1.1276 + DeviceStorageFile dsf(mStorageType, mStorageName, mRootDir, newPath); 1.1277 + dsf.collectFilesInternal(aFiles, aSince, aRootPath); 1.1278 + } else if (isFile) { 1.1279 + nsRefPtr<DeviceStorageFile> dsf = 1.1280 + new DeviceStorageFile(mStorageType, mStorageName, mRootDir, newPath); 1.1281 + dsf->CalculateSizeAndModifiedDate(); 1.1282 + aFiles.AppendElement(dsf); 1.1283 + } 1.1284 + } 1.1285 +} 1.1286 + 1.1287 +void 1.1288 +DeviceStorageFile::AccumDiskUsage(uint64_t* aPicturesSoFar, 1.1289 + uint64_t* aVideosSoFar, 1.1290 + uint64_t* aMusicSoFar, 1.1291 + uint64_t* aTotalSoFar) 1.1292 +{ 1.1293 + if (!IsAvailable()) { 1.1294 + return; 1.1295 + } 1.1296 + 1.1297 + uint64_t pictureUsage = 0, videoUsage = 0, musicUsage = 0, totalUsage = 0; 1.1298 + 1.1299 + if (DeviceStorageTypeChecker::IsVolumeBased(mStorageType)) { 1.1300 + DeviceStorageUsedSpaceCache* usedSpaceCache = 1.1301 + DeviceStorageUsedSpaceCache::CreateOrGet(); 1.1302 + MOZ_ASSERT(usedSpaceCache); 1.1303 + nsresult rv = usedSpaceCache->AccumUsedSizes(mStorageName, 1.1304 + aPicturesSoFar, aVideosSoFar, 1.1305 + aMusicSoFar, aTotalSoFar); 1.1306 + if (NS_SUCCEEDED(rv)) { 1.1307 + return; 1.1308 + } 1.1309 + AccumDirectoryUsage(mFile, &pictureUsage, &videoUsage, 1.1310 + &musicUsage, &totalUsage); 1.1311 + usedSpaceCache->SetUsedSizes(mStorageName, pictureUsage, videoUsage, 1.1312 + musicUsage, totalUsage); 1.1313 + } else { 1.1314 + AccumDirectoryUsage(mFile, &pictureUsage, &videoUsage, 1.1315 + &musicUsage, &totalUsage); 1.1316 + } 1.1317 + 1.1318 + *aPicturesSoFar += pictureUsage; 1.1319 + *aVideosSoFar += videoUsage; 1.1320 + *aMusicSoFar += musicUsage; 1.1321 + *aTotalSoFar += totalUsage; 1.1322 +} 1.1323 + 1.1324 +void 1.1325 +DeviceStorageFile::AccumDirectoryUsage(nsIFile* aFile, 1.1326 + uint64_t* aPicturesSoFar, 1.1327 + uint64_t* aVideosSoFar, 1.1328 + uint64_t* aMusicSoFar, 1.1329 + uint64_t* aTotalSoFar) 1.1330 +{ 1.1331 + if (!aFile) { 1.1332 + return; 1.1333 + } 1.1334 + 1.1335 + nsresult rv; 1.1336 + nsCOMPtr<nsISimpleEnumerator> e; 1.1337 + rv = aFile->GetDirectoryEntries(getter_AddRefs(e)); 1.1338 + 1.1339 + if (NS_FAILED(rv) || !e) { 1.1340 + return; 1.1341 + } 1.1342 + 1.1343 + nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e); 1.1344 + MOZ_ASSERT(files); 1.1345 + 1.1346 + nsCOMPtr<nsIFile> f; 1.1347 + while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(f))) && f) { 1.1348 + bool isDir; 1.1349 + rv = f->IsDirectory(&isDir); 1.1350 + if (NS_FAILED(rv)) { 1.1351 + continue; 1.1352 + } 1.1353 + 1.1354 + bool isFile; 1.1355 + rv = f->IsFile(&isFile); 1.1356 + if (NS_FAILED(rv)) { 1.1357 + continue; 1.1358 + } 1.1359 + 1.1360 + bool isLink; 1.1361 + rv = f->IsSymlink(&isLink); 1.1362 + if (NS_FAILED(rv)) { 1.1363 + continue; 1.1364 + } 1.1365 + 1.1366 + if (isLink) { 1.1367 + // for now, lets just totally ignore symlinks. 1.1368 + NS_WARNING("DirectoryDiskUsage ignores symlinks"); 1.1369 + } else if (isDir) { 1.1370 + AccumDirectoryUsage(f, aPicturesSoFar, aVideosSoFar, 1.1371 + aMusicSoFar, aTotalSoFar); 1.1372 + } else if (isFile) { 1.1373 + 1.1374 + int64_t size; 1.1375 + rv = f->GetFileSize(&size); 1.1376 + if (NS_FAILED(rv)) { 1.1377 + continue; 1.1378 + } 1.1379 + DeviceStorageTypeChecker* typeChecker 1.1380 + = DeviceStorageTypeChecker::CreateOrGet(); 1.1381 + MOZ_ASSERT(typeChecker); 1.1382 + nsString type; 1.1383 + typeChecker->GetTypeFromFile(f, type); 1.1384 + 1.1385 + if (type.EqualsLiteral(DEVICESTORAGE_PICTURES)) { 1.1386 + *aPicturesSoFar += size; 1.1387 + } 1.1388 + else if (type.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { 1.1389 + *aVideosSoFar += size; 1.1390 + } 1.1391 + else if (type.EqualsLiteral(DEVICESTORAGE_MUSIC)) { 1.1392 + *aMusicSoFar += size; 1.1393 + } 1.1394 + *aTotalSoFar += size; 1.1395 + } 1.1396 + } 1.1397 +} 1.1398 + 1.1399 +void 1.1400 +DeviceStorageFile::GetDiskFreeSpace(int64_t* aSoFar) 1.1401 +{ 1.1402 + DeviceStorageTypeChecker* typeChecker 1.1403 + = DeviceStorageTypeChecker::CreateOrGet(); 1.1404 + if (!typeChecker) { 1.1405 + return; 1.1406 + } 1.1407 + if (!mFile || !IsAvailable()) { 1.1408 + return; 1.1409 + } 1.1410 + 1.1411 + int64_t storageAvail = 0; 1.1412 + nsresult rv = mFile->GetDiskSpaceAvailable(&storageAvail); 1.1413 + if (NS_SUCCEEDED(rv)) { 1.1414 + *aSoFar += storageAvail; 1.1415 + } 1.1416 +} 1.1417 + 1.1418 +bool 1.1419 +DeviceStorageFile::IsAvailable() 1.1420 +{ 1.1421 + nsString status; 1.1422 + GetStatus(status); 1.1423 + return status.EqualsLiteral("available"); 1.1424 +} 1.1425 + 1.1426 +void 1.1427 +DeviceStorageFile::DoFormat(nsAString& aStatus) 1.1428 +{ 1.1429 + DeviceStorageTypeChecker* typeChecker 1.1430 + = DeviceStorageTypeChecker::CreateOrGet(); 1.1431 + if (!typeChecker) { 1.1432 + return; 1.1433 + } 1.1434 + if (!typeChecker->IsVolumeBased(mStorageType)) { 1.1435 + aStatus.AssignLiteral("notVolume"); 1.1436 + return; 1.1437 + } 1.1438 +#ifdef MOZ_WIDGET_GONK 1.1439 + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); 1.1440 + NS_ENSURE_TRUE_VOID(vs); 1.1441 + 1.1442 + nsCOMPtr<nsIVolume> vol; 1.1443 + nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); 1.1444 + NS_ENSURE_SUCCESS_VOID(rv); 1.1445 + if (!vol) { 1.1446 + return; 1.1447 + } 1.1448 + 1.1449 + vol->Format(); 1.1450 + 1.1451 + aStatus.AssignLiteral("formatting"); 1.1452 +#endif 1.1453 + return; 1.1454 +} 1.1455 + 1.1456 +void 1.1457 +DeviceStorageFile::DoMount(nsAString& aStatus) 1.1458 +{ 1.1459 + DeviceStorageTypeChecker* typeChecker 1.1460 + = DeviceStorageTypeChecker::CreateOrGet(); 1.1461 + if (!typeChecker) { 1.1462 + return; 1.1463 + } 1.1464 + if (!typeChecker->IsVolumeBased(mStorageType)) { 1.1465 + aStatus.AssignLiteral("notVolume"); 1.1466 + return; 1.1467 + } 1.1468 +#ifdef MOZ_WIDGET_GONK 1.1469 + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); 1.1470 + NS_ENSURE_TRUE_VOID(vs); 1.1471 + 1.1472 + nsCOMPtr<nsIVolume> vol; 1.1473 + nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); 1.1474 + NS_ENSURE_SUCCESS_VOID(rv); 1.1475 + if (!vol) { 1.1476 + return; 1.1477 + } 1.1478 + 1.1479 + vol->Mount(); 1.1480 + 1.1481 + aStatus.AssignLiteral("mounting"); 1.1482 +#endif 1.1483 + return; 1.1484 +} 1.1485 + 1.1486 +void 1.1487 +DeviceStorageFile::DoUnmount(nsAString& aStatus) 1.1488 +{ 1.1489 + DeviceStorageTypeChecker* typeChecker 1.1490 + = DeviceStorageTypeChecker::CreateOrGet(); 1.1491 + if (!typeChecker) { 1.1492 + return; 1.1493 + } 1.1494 + if (!typeChecker->IsVolumeBased(mStorageType)) { 1.1495 + aStatus.AssignLiteral("notVolume"); 1.1496 + return; 1.1497 + } 1.1498 +#ifdef MOZ_WIDGET_GONK 1.1499 + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); 1.1500 + NS_ENSURE_TRUE_VOID(vs); 1.1501 + 1.1502 + nsCOMPtr<nsIVolume> vol; 1.1503 + nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); 1.1504 + NS_ENSURE_SUCCESS_VOID(rv); 1.1505 + if (!vol) { 1.1506 + return; 1.1507 + } 1.1508 + 1.1509 + vol->Unmount(); 1.1510 + 1.1511 + aStatus.AssignLiteral("unmounting"); 1.1512 +#endif 1.1513 + return; 1.1514 +} 1.1515 + 1.1516 +void 1.1517 +DeviceStorageFile::GetStatus(nsAString& aStatus) 1.1518 +{ 1.1519 + aStatus.AssignLiteral("unavailable"); 1.1520 + 1.1521 + DeviceStorageTypeChecker* typeChecker 1.1522 + = DeviceStorageTypeChecker::CreateOrGet(); 1.1523 + if (!typeChecker) { 1.1524 + return; 1.1525 + } 1.1526 + if (!typeChecker->IsVolumeBased(mStorageType)) { 1.1527 + aStatus.AssignLiteral("available"); 1.1528 + return; 1.1529 + } 1.1530 + 1.1531 +#ifdef MOZ_WIDGET_GONK 1.1532 + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); 1.1533 + NS_ENSURE_TRUE_VOID(vs); 1.1534 + 1.1535 + nsCOMPtr<nsIVolume> vol; 1.1536 + nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); 1.1537 + NS_ENSURE_SUCCESS_VOID(rv); 1.1538 + if (!vol) { 1.1539 + return; 1.1540 + } 1.1541 + bool isMediaPresent; 1.1542 + rv = vol->GetIsMediaPresent(&isMediaPresent); 1.1543 + NS_ENSURE_SUCCESS_VOID(rv); 1.1544 + if (!isMediaPresent) { 1.1545 + return; 1.1546 + } 1.1547 + bool isSharing; 1.1548 + rv = vol->GetIsSharing(&isSharing); 1.1549 + NS_ENSURE_SUCCESS_VOID(rv); 1.1550 + if (isSharing) { 1.1551 + aStatus.AssignLiteral("shared"); 1.1552 + return; 1.1553 + } 1.1554 + bool isFormatting; 1.1555 + rv = vol->GetIsFormatting(&isFormatting); 1.1556 + NS_ENSURE_SUCCESS_VOID(rv); 1.1557 + if (isFormatting) { 1.1558 + aStatus.AssignLiteral("unavailable"); 1.1559 + return; 1.1560 + } 1.1561 + int32_t volState; 1.1562 + rv = vol->GetState(&volState); 1.1563 + NS_ENSURE_SUCCESS_VOID(rv); 1.1564 + if (volState == nsIVolume::STATE_MOUNTED) { 1.1565 + aStatus.AssignLiteral("available"); 1.1566 + } 1.1567 +#endif 1.1568 +} 1.1569 + 1.1570 +void 1.1571 +DeviceStorageFile::GetStorageStatus(nsAString& aStatus) 1.1572 +{ 1.1573 + aStatus.AssignLiteral("undefined"); 1.1574 + 1.1575 + DeviceStorageTypeChecker* typeChecker 1.1576 + = DeviceStorageTypeChecker::CreateOrGet(); 1.1577 + if (!typeChecker) { 1.1578 + return; 1.1579 + } 1.1580 + if (!typeChecker->IsVolumeBased(mStorageType)) { 1.1581 + aStatus.AssignLiteral("available"); 1.1582 + return; 1.1583 + } 1.1584 + 1.1585 +#ifdef MOZ_WIDGET_GONK 1.1586 + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); 1.1587 + NS_ENSURE_TRUE_VOID(vs); 1.1588 + 1.1589 + nsCOMPtr<nsIVolume> vol; 1.1590 + nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); 1.1591 + NS_ENSURE_SUCCESS_VOID(rv); 1.1592 + if (!vol) { 1.1593 + return; 1.1594 + } 1.1595 + 1.1596 + int32_t volState; 1.1597 + rv = vol->GetState(&volState); 1.1598 + NS_ENSURE_SUCCESS_VOID(rv); 1.1599 + aStatus.AssignASCII(mozilla::system::NS_VolumeStateStr(volState)); 1.1600 +#endif 1.1601 +} 1.1602 + 1.1603 +NS_IMPL_ISUPPORTS0(DeviceStorageFile) 1.1604 + 1.1605 +static void 1.1606 +RegisterForSDCardChanges(nsIObserver* aObserver) 1.1607 +{ 1.1608 +#ifdef MOZ_WIDGET_GONK 1.1609 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.1610 + obs->AddObserver(aObserver, NS_VOLUME_STATE_CHANGED, false); 1.1611 +#endif 1.1612 +} 1.1613 + 1.1614 +static void 1.1615 +UnregisterForSDCardChanges(nsIObserver* aObserver) 1.1616 +{ 1.1617 +#ifdef MOZ_WIDGET_GONK 1.1618 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.1619 + obs->RemoveObserver(aObserver, NS_VOLUME_STATE_CHANGED); 1.1620 +#endif 1.1621 +} 1.1622 + 1.1623 +void 1.1624 +nsDOMDeviceStorage::SetRootDirectoryForType(const nsAString& aStorageType, 1.1625 + const nsAString& aStorageName) 1.1626 +{ 1.1627 + MOZ_ASSERT(NS_IsMainThread()); 1.1628 + 1.1629 + nsCOMPtr<nsIFile> f; 1.1630 + DeviceStorageFile::GetRootDirectoryForType(aStorageType, 1.1631 + aStorageName, 1.1632 + getter_AddRefs(f)); 1.1633 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.1634 + obs->AddObserver(this, "file-watcher-update", false); 1.1635 + obs->AddObserver(this, "disk-space-watcher", false); 1.1636 + mRootDirectory = f; 1.1637 + mStorageType = aStorageType; 1.1638 + mStorageName = aStorageName; 1.1639 +} 1.1640 + 1.1641 +JS::Value 1.1642 +InterfaceToJsval(nsPIDOMWindow* aWindow, 1.1643 + nsISupports* aObject, 1.1644 + const nsIID* aIID) 1.1645 +{ 1.1646 + nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow); 1.1647 + if (!sgo) { 1.1648 + return JS::NullValue(); 1.1649 + } 1.1650 + 1.1651 + JSObject *unrootedScopeObj = sgo->GetGlobalJSObject(); 1.1652 + NS_ENSURE_TRUE(unrootedScopeObj, JS::NullValue()); 1.1653 + JSRuntime *runtime = JS_GetObjectRuntime(unrootedScopeObj); 1.1654 + JS::Rooted<JS::Value> someJsVal(runtime); 1.1655 + nsresult rv; 1.1656 + 1.1657 + { // Protect someJsVal from moving GC in ~JSAutoCompartment 1.1658 + AutoJSContext cx; 1.1659 + 1.1660 + JS::Rooted<JSObject*> scopeObj(cx, unrootedScopeObj); 1.1661 + JSAutoCompartment ac(cx, scopeObj); 1.1662 + 1.1663 + rv = nsContentUtils::WrapNative(cx, aObject, aIID, &someJsVal); 1.1664 + } 1.1665 + if (NS_FAILED(rv)) { 1.1666 + return JS::NullValue(); 1.1667 + } 1.1668 + 1.1669 + return someJsVal; 1.1670 +} 1.1671 + 1.1672 +JS::Value 1.1673 +nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile) 1.1674 +{ 1.1675 + MOZ_ASSERT(NS_IsMainThread()); 1.1676 + MOZ_ASSERT(aWindow); 1.1677 + 1.1678 + if (!aFile) { 1.1679 + return JSVAL_NULL; 1.1680 + } 1.1681 + 1.1682 + if (aFile->mEditable) { 1.1683 + // TODO - needs janv's file handle support. 1.1684 + return JSVAL_NULL; 1.1685 + } 1.1686 + 1.1687 + nsString fullPath; 1.1688 + aFile->GetFullPath(fullPath); 1.1689 + 1.1690 + // This check is useful to know if somewhere the DeviceStorageFile 1.1691 + // has not been properly set. Mimetype is not checked because it can be 1.1692 + // empty. 1.1693 + MOZ_ASSERT(aFile->mLength != UINT64_MAX); 1.1694 + MOZ_ASSERT(aFile->mLastModifiedDate != UINT64_MAX); 1.1695 + 1.1696 + nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(fullPath, aFile->mMimeType, 1.1697 + aFile->mLength, aFile->mFile, 1.1698 + aFile->mLastModifiedDate); 1.1699 + return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob)); 1.1700 +} 1.1701 + 1.1702 +JS::Value StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString) 1.1703 +{ 1.1704 + MOZ_ASSERT(NS_IsMainThread()); 1.1705 + MOZ_ASSERT(aWindow); 1.1706 + 1.1707 + nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow); 1.1708 + if (!sgo) { 1.1709 + return JSVAL_NULL; 1.1710 + } 1.1711 + 1.1712 + nsIScriptContext *scriptContext = sgo->GetScriptContext(); 1.1713 + if (!scriptContext) { 1.1714 + return JSVAL_NULL; 1.1715 + } 1.1716 + 1.1717 + AutoPushJSContext cx(scriptContext->GetNativeContext()); 1.1718 + if (!cx) { 1.1719 + return JSVAL_NULL; 1.1720 + } 1.1721 + 1.1722 + JS::Rooted<JS::Value> result(cx); 1.1723 + if (!xpc::StringToJsval(cx, aString, &result)) { 1.1724 + return JSVAL_NULL; 1.1725 + } 1.1726 + 1.1727 + return result; 1.1728 +} 1.1729 + 1.1730 +class DeviceStorageCursorRequest MOZ_FINAL 1.1731 + : public nsIContentPermissionRequest 1.1732 + , public PCOMContentPermissionRequestChild 1.1733 +{ 1.1734 +public: 1.1735 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.1736 + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageCursorRequest, 1.1737 + nsIContentPermissionRequest) 1.1738 + 1.1739 + NS_FORWARD_NSICONTENTPERMISSIONREQUEST(mCursor->); 1.1740 + 1.1741 + DeviceStorageCursorRequest(nsDOMDeviceStorageCursor* aCursor) 1.1742 + : mCursor(aCursor) { } 1.1743 + 1.1744 + ~DeviceStorageCursorRequest() {} 1.1745 + 1.1746 + bool Recv__delete__(const bool& allow, 1.1747 + const InfallibleTArray<PermissionChoice>& choices) 1.1748 + { 1.1749 + MOZ_ASSERT(choices.IsEmpty(), "DeviceStorageCursor doesn't support permission choice"); 1.1750 + if (allow) { 1.1751 + Allow(JS::UndefinedHandleValue); 1.1752 + } 1.1753 + else { 1.1754 + Cancel(); 1.1755 + } 1.1756 + return true; 1.1757 + } 1.1758 + 1.1759 + void IPDLRelease() 1.1760 + { 1.1761 + Release(); 1.1762 + } 1.1763 + 1.1764 +private: 1.1765 + nsRefPtr<nsDOMDeviceStorageCursor> mCursor; 1.1766 +}; 1.1767 + 1.1768 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageCursorRequest) 1.1769 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest) 1.1770 + NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest) 1.1771 +NS_INTERFACE_MAP_END 1.1772 + 1.1773 +NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageCursorRequest) 1.1774 +NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageCursorRequest) 1.1775 + 1.1776 +NS_IMPL_CYCLE_COLLECTION(DeviceStorageCursorRequest, 1.1777 + mCursor) 1.1778 + 1.1779 + 1.1780 +class PostErrorEvent : public nsRunnable 1.1781 +{ 1.1782 +public: 1.1783 + PostErrorEvent(already_AddRefed<DOMRequest> aRequest, const char* aMessage) 1.1784 + : mRequest(aRequest) 1.1785 + { 1.1786 + CopyASCIItoUTF16(aMessage, mError); 1.1787 + } 1.1788 + 1.1789 + PostErrorEvent(DOMRequest* aRequest, const char* aMessage) 1.1790 + : mRequest(aRequest) 1.1791 + { 1.1792 + CopyASCIItoUTF16(aMessage, mError); 1.1793 + } 1.1794 + 1.1795 + ~PostErrorEvent() {} 1.1796 + 1.1797 + NS_IMETHOD Run() 1.1798 + { 1.1799 + MOZ_ASSERT(NS_IsMainThread()); 1.1800 + if (!mRequest->GetOwner()) { 1.1801 + return NS_OK; 1.1802 + } 1.1803 + mRequest->FireError(mError); 1.1804 + mRequest = nullptr; 1.1805 + return NS_OK; 1.1806 + } 1.1807 + 1.1808 +private: 1.1809 + nsRefPtr<DOMRequest> mRequest; 1.1810 + nsString mError; 1.1811 +}; 1.1812 + 1.1813 +ContinueCursorEvent::ContinueCursorEvent(already_AddRefed<DOMRequest> aRequest) 1.1814 + : mRequest(aRequest) 1.1815 +{ 1.1816 +} 1.1817 + 1.1818 +ContinueCursorEvent::ContinueCursorEvent(DOMRequest* aRequest) 1.1819 + : mRequest(aRequest) 1.1820 +{ 1.1821 +} 1.1822 + 1.1823 +already_AddRefed<DeviceStorageFile> 1.1824 +ContinueCursorEvent::GetNextFile() 1.1825 +{ 1.1826 + MOZ_ASSERT(NS_IsMainThread()); 1.1827 + 1.1828 + nsDOMDeviceStorageCursor* cursor 1.1829 + = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); 1.1830 + nsString cursorStorageType; 1.1831 + cursor->GetStorageType(cursorStorageType); 1.1832 + 1.1833 + DeviceStorageTypeChecker* typeChecker 1.1834 + = DeviceStorageTypeChecker::CreateOrGet(); 1.1835 + if (!typeChecker) { 1.1836 + return nullptr; 1.1837 + } 1.1838 + 1.1839 + while (cursor->mFiles.Length() > 0) { 1.1840 + nsRefPtr<DeviceStorageFile> file = cursor->mFiles[0]; 1.1841 + cursor->mFiles.RemoveElementAt(0); 1.1842 + if (!typeChecker->Check(cursorStorageType, file->mFile)) { 1.1843 + continue; 1.1844 + } 1.1845 + 1.1846 + file->CalculateMimeType(); 1.1847 + return file.forget(); 1.1848 + } 1.1849 + 1.1850 + return nullptr; 1.1851 +} 1.1852 + 1.1853 +ContinueCursorEvent::~ContinueCursorEvent() {} 1.1854 + 1.1855 +void 1.1856 +ContinueCursorEvent::Continue() 1.1857 +{ 1.1858 + if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.1859 + DebugOnly<nsresult> rv = NS_DispatchToMainThread(this); 1.1860 + MOZ_ASSERT(NS_SUCCEEDED(rv)); 1.1861 + return; 1.1862 + } 1.1863 + 1.1864 + nsRefPtr<DeviceStorageFile> file = GetNextFile(); 1.1865 + 1.1866 + if (!file) { 1.1867 + // done with enumeration. 1.1868 + DebugOnly<nsresult> rv = NS_DispatchToMainThread(this); 1.1869 + MOZ_ASSERT(NS_SUCCEEDED(rv)); 1.1870 + return; 1.1871 + } 1.1872 + 1.1873 + nsDOMDeviceStorageCursor* cursor 1.1874 + = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); 1.1875 + nsString cursorStorageType; 1.1876 + cursor->GetStorageType(cursorStorageType); 1.1877 + 1.1878 + DeviceStorageRequestChild* child 1.1879 + = new DeviceStorageRequestChild(mRequest, file); 1.1880 + child->SetCallback(cursor); 1.1881 + DeviceStorageGetParams params(cursorStorageType, 1.1882 + file->mStorageName, 1.1883 + file->mRootDir, 1.1884 + file->mPath); 1.1885 + ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, 1.1886 + params); 1.1887 + mRequest = nullptr; 1.1888 +} 1.1889 + 1.1890 +NS_IMETHODIMP 1.1891 +ContinueCursorEvent::Run() 1.1892 +{ 1.1893 + nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); 1.1894 + if (!window) { 1.1895 + return NS_OK; 1.1896 + } 1.1897 + 1.1898 + nsRefPtr<DeviceStorageFile> file = GetNextFile(); 1.1899 + 1.1900 + nsDOMDeviceStorageCursor* cursor 1.1901 + = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); 1.1902 + 1.1903 + AutoJSContext cx; 1.1904 + JS::Rooted<JS::Value> val(cx, nsIFileToJsval(window, file)); 1.1905 + 1.1906 + if (file) { 1.1907 + cursor->mOkToCallContinue = true; 1.1908 + cursor->FireSuccess(val); 1.1909 + } else { 1.1910 + cursor->FireDone(); 1.1911 + } 1.1912 + mRequest = nullptr; 1.1913 + return NS_OK; 1.1914 +} 1.1915 + 1.1916 +class InitCursorEvent : public nsRunnable 1.1917 +{ 1.1918 +public: 1.1919 + InitCursorEvent(DOMRequest* aRequest, DeviceStorageFile* aFile) 1.1920 + : mFile(aFile) 1.1921 + , mRequest(aRequest) 1.1922 + { 1.1923 + } 1.1924 + 1.1925 + ~InitCursorEvent() {} 1.1926 + 1.1927 + NS_IMETHOD Run() { 1.1928 + MOZ_ASSERT(!NS_IsMainThread()); 1.1929 + 1.1930 + if (mFile->mFile) { 1.1931 + bool check; 1.1932 + mFile->mFile->IsDirectory(&check); 1.1933 + if (!check) { 1.1934 + nsCOMPtr<nsIRunnable> event = 1.1935 + new PostErrorEvent(mRequest.forget(), 1.1936 + POST_ERROR_EVENT_FILE_NOT_ENUMERABLE); 1.1937 + return NS_DispatchToMainThread(event); 1.1938 + } 1.1939 + } 1.1940 + 1.1941 + nsDOMDeviceStorageCursor* cursor 1.1942 + = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); 1.1943 + mFile->CollectFiles(cursor->mFiles, cursor->mSince); 1.1944 + 1.1945 + nsRefPtr<ContinueCursorEvent> event 1.1946 + = new ContinueCursorEvent(mRequest.forget()); 1.1947 + event->Continue(); 1.1948 + 1.1949 + return NS_OK; 1.1950 + } 1.1951 + 1.1952 + 1.1953 +private: 1.1954 + nsRefPtr<DeviceStorageFile> mFile; 1.1955 + nsRefPtr<DOMRequest> mRequest; 1.1956 +}; 1.1957 + 1.1958 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDeviceStorageCursor) 1.1959 + NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest) 1.1960 +NS_INTERFACE_MAP_END_INHERITING(DOMCursor) 1.1961 + 1.1962 +NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageCursor, DOMCursor) 1.1963 +NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageCursor, DOMCursor) 1.1964 + 1.1965 +nsDOMDeviceStorageCursor::nsDOMDeviceStorageCursor(nsPIDOMWindow* aWindow, 1.1966 + nsIPrincipal* aPrincipal, 1.1967 + DeviceStorageFile* aFile, 1.1968 + PRTime aSince) 1.1969 + : DOMCursor(aWindow, nullptr) 1.1970 + , mOkToCallContinue(false) 1.1971 + , mSince(aSince) 1.1972 + , mFile(aFile) 1.1973 + , mPrincipal(aPrincipal) 1.1974 +{ 1.1975 +} 1.1976 + 1.1977 +nsDOMDeviceStorageCursor::~nsDOMDeviceStorageCursor() 1.1978 +{ 1.1979 +} 1.1980 + 1.1981 +void 1.1982 +nsDOMDeviceStorageCursor::GetStorageType(nsAString & aType) 1.1983 +{ 1.1984 + aType = mFile->mStorageType; 1.1985 +} 1.1986 + 1.1987 +NS_IMETHODIMP 1.1988 +nsDOMDeviceStorageCursor::GetTypes(nsIArray** aTypes) 1.1989 +{ 1.1990 + nsCString type; 1.1991 + nsresult rv = 1.1992 + DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type); 1.1993 + NS_ENSURE_SUCCESS(rv, rv); 1.1994 + 1.1995 + nsTArray<nsString> emptyOptions; 1.1996 + return CreatePermissionArray(type, 1.1997 + NS_LITERAL_CSTRING("read"), 1.1998 + emptyOptions, 1.1999 + aTypes); 1.2000 +} 1.2001 + 1.2002 +NS_IMETHODIMP 1.2003 +nsDOMDeviceStorageCursor::GetPrincipal(nsIPrincipal * *aRequestingPrincipal) 1.2004 +{ 1.2005 + NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal); 1.2006 + return NS_OK; 1.2007 +} 1.2008 + 1.2009 +NS_IMETHODIMP 1.2010 +nsDOMDeviceStorageCursor::GetWindow(nsIDOMWindow * *aRequestingWindow) 1.2011 +{ 1.2012 + NS_IF_ADDREF(*aRequestingWindow = GetOwner()); 1.2013 + return NS_OK; 1.2014 +} 1.2015 + 1.2016 +NS_IMETHODIMP 1.2017 +nsDOMDeviceStorageCursor::GetElement(nsIDOMElement * *aRequestingElement) 1.2018 +{ 1.2019 + *aRequestingElement = nullptr; 1.2020 + return NS_OK; 1.2021 +} 1.2022 + 1.2023 +NS_IMETHODIMP 1.2024 +nsDOMDeviceStorageCursor::Cancel() 1.2025 +{ 1.2026 + nsCOMPtr<nsIRunnable> event 1.2027 + = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED); 1.2028 + return NS_DispatchToMainThread(event); 1.2029 +} 1.2030 + 1.2031 +NS_IMETHODIMP 1.2032 +nsDOMDeviceStorageCursor::Allow(JS::HandleValue aChoices) 1.2033 +{ 1.2034 + MOZ_ASSERT(aChoices.isUndefined()); 1.2035 + 1.2036 + if (!mFile->IsSafePath()) { 1.2037 + nsCOMPtr<nsIRunnable> r 1.2038 + = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED); 1.2039 + return NS_DispatchToMainThread(r); 1.2040 + } 1.2041 + 1.2042 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.2043 + PDeviceStorageRequestChild* child 1.2044 + = new DeviceStorageRequestChild(this, mFile); 1.2045 + DeviceStorageEnumerationParams params(mFile->mStorageType, 1.2046 + mFile->mStorageName, 1.2047 + mFile->mRootDir, 1.2048 + mSince); 1.2049 + ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, 1.2050 + params); 1.2051 + return NS_OK; 1.2052 + } 1.2053 + 1.2054 + nsCOMPtr<nsIEventTarget> target 1.2055 + = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); 1.2056 + MOZ_ASSERT(target); 1.2057 + 1.2058 + nsCOMPtr<nsIRunnable> event = new InitCursorEvent(this, mFile); 1.2059 + target->Dispatch(event, NS_DISPATCH_NORMAL); 1.2060 + return NS_OK; 1.2061 +} 1.2062 + 1.2063 +void 1.2064 +nsDOMDeviceStorageCursor::Continue(ErrorResult& aRv) 1.2065 +{ 1.2066 + if (!mOkToCallContinue) { 1.2067 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.2068 + return; 1.2069 + } 1.2070 + 1.2071 + if (mResult != JSVAL_VOID) { 1.2072 + // We call onsuccess multiple times. Clear the last 1.2073 + // result. 1.2074 + mResult = JSVAL_VOID; 1.2075 + mDone = false; 1.2076 + } 1.2077 + 1.2078 + nsRefPtr<ContinueCursorEvent> event = new ContinueCursorEvent(this); 1.2079 + event->Continue(); 1.2080 + 1.2081 + mOkToCallContinue = false; 1.2082 +} 1.2083 + 1.2084 +bool 1.2085 +nsDOMDeviceStorageCursor::Recv__delete__(const bool& allow, 1.2086 + const InfallibleTArray<PermissionChoice>& choices) 1.2087 +{ 1.2088 + MOZ_ASSERT(choices.IsEmpty(), "DeviceStorageCursor doesn't support permission choice"); 1.2089 + 1.2090 + if (allow) { 1.2091 + Allow(JS::UndefinedHandleValue); 1.2092 + } 1.2093 + else { 1.2094 + Cancel(); 1.2095 + } 1.2096 + return true; 1.2097 +} 1.2098 + 1.2099 +void 1.2100 +nsDOMDeviceStorageCursor::IPDLRelease() 1.2101 +{ 1.2102 + Release(); 1.2103 +} 1.2104 + 1.2105 +void 1.2106 +nsDOMDeviceStorageCursor::RequestComplete() 1.2107 +{ 1.2108 + MOZ_ASSERT(!mOkToCallContinue); 1.2109 + mOkToCallContinue = true; 1.2110 +} 1.2111 + 1.2112 +class PostAvailableResultEvent : public nsRunnable 1.2113 +{ 1.2114 +public: 1.2115 + PostAvailableResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) 1.2116 + : mFile(aFile) 1.2117 + , mRequest(aRequest) 1.2118 + { 1.2119 + MOZ_ASSERT(mRequest); 1.2120 + } 1.2121 + 1.2122 + ~PostAvailableResultEvent() {} 1.2123 + 1.2124 + NS_IMETHOD Run() 1.2125 + { 1.2126 + MOZ_ASSERT(NS_IsMainThread()); 1.2127 + nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); 1.2128 + if (!window) { 1.2129 + return NS_OK; 1.2130 + } 1.2131 + 1.2132 + nsString state = NS_LITERAL_STRING("unavailable"); 1.2133 + if (mFile) { 1.2134 + mFile->GetStatus(state); 1.2135 + } 1.2136 + 1.2137 + AutoJSContext cx; 1.2138 + JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); 1.2139 + mRequest->FireSuccess(result); 1.2140 + mRequest = nullptr; 1.2141 + return NS_OK; 1.2142 + } 1.2143 + 1.2144 +private: 1.2145 + nsRefPtr<DeviceStorageFile> mFile; 1.2146 + nsRefPtr<DOMRequest> mRequest; 1.2147 +}; 1.2148 + 1.2149 +class PostStatusResultEvent : public nsRunnable 1.2150 +{ 1.2151 +public: 1.2152 + PostStatusResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) 1.2153 + : mFile(aFile) 1.2154 + , mRequest(aRequest) 1.2155 + { 1.2156 + MOZ_ASSERT(mRequest); 1.2157 + } 1.2158 + 1.2159 + ~PostStatusResultEvent() {} 1.2160 + 1.2161 + NS_IMETHOD Run() 1.2162 + { 1.2163 + MOZ_ASSERT(NS_IsMainThread()); 1.2164 + nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); 1.2165 + if (!window) { 1.2166 + return NS_OK; 1.2167 + } 1.2168 + 1.2169 + nsString state = NS_LITERAL_STRING("undefined"); 1.2170 + if (mFile) { 1.2171 + mFile->GetStorageStatus(state); 1.2172 + } 1.2173 + 1.2174 + AutoJSContext cx; 1.2175 + JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); 1.2176 + mRequest->FireSuccess(result); 1.2177 + mRequest = nullptr; 1.2178 + return NS_OK; 1.2179 + } 1.2180 + 1.2181 +private: 1.2182 + nsRefPtr<DeviceStorageFile> mFile; 1.2183 + nsRefPtr<DOMRequest> mRequest; 1.2184 +}; 1.2185 + 1.2186 +class PostFormatResultEvent : public nsRunnable 1.2187 +{ 1.2188 +public: 1.2189 + PostFormatResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) 1.2190 + : mFile(aFile) 1.2191 + , mRequest(aRequest) 1.2192 + { 1.2193 + MOZ_ASSERT(mRequest); 1.2194 + } 1.2195 + 1.2196 + ~PostFormatResultEvent() {} 1.2197 + 1.2198 + NS_IMETHOD Run() 1.2199 + { 1.2200 + MOZ_ASSERT(NS_IsMainThread()); 1.2201 + nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); 1.2202 + if (!window) { 1.2203 + return NS_OK; 1.2204 + } 1.2205 + 1.2206 + nsString state = NS_LITERAL_STRING("unavailable"); 1.2207 + if (mFile) { 1.2208 + mFile->DoFormat(state); 1.2209 + } 1.2210 + 1.2211 + AutoJSContext cx; 1.2212 + JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); 1.2213 + mRequest->FireSuccess(result); 1.2214 + mRequest = nullptr; 1.2215 + return NS_OK; 1.2216 + } 1.2217 + 1.2218 +private: 1.2219 + nsRefPtr<DeviceStorageFile> mFile; 1.2220 + nsRefPtr<DOMRequest> mRequest; 1.2221 +}; 1.2222 + 1.2223 +class PostMountResultEvent : public nsRunnable 1.2224 +{ 1.2225 +public: 1.2226 + PostMountResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) 1.2227 + : mFile(aFile) 1.2228 + , mRequest(aRequest) 1.2229 + { 1.2230 + MOZ_ASSERT(mRequest); 1.2231 + } 1.2232 + 1.2233 + ~PostMountResultEvent() {} 1.2234 + 1.2235 + NS_IMETHOD Run() 1.2236 + { 1.2237 + MOZ_ASSERT(NS_IsMainThread()); 1.2238 + nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); 1.2239 + if (!window) { 1.2240 + return NS_OK; 1.2241 + } 1.2242 + 1.2243 + nsString state = NS_LITERAL_STRING("unavailable"); 1.2244 + if (mFile) { 1.2245 + mFile->DoMount(state); 1.2246 + } 1.2247 + 1.2248 + AutoJSContext cx; 1.2249 + JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); 1.2250 + mRequest->FireSuccess(result); 1.2251 + mRequest = nullptr; 1.2252 + return NS_OK; 1.2253 + } 1.2254 + 1.2255 +private: 1.2256 + nsRefPtr<DeviceStorageFile> mFile; 1.2257 + nsRefPtr<DOMRequest> mRequest; 1.2258 +}; 1.2259 + 1.2260 +class PostUnmountResultEvent : public nsRunnable 1.2261 +{ 1.2262 +public: 1.2263 + PostUnmountResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) 1.2264 + : mFile(aFile) 1.2265 + , mRequest(aRequest) 1.2266 + { 1.2267 + MOZ_ASSERT(mRequest); 1.2268 + } 1.2269 + 1.2270 + ~PostUnmountResultEvent() {} 1.2271 + 1.2272 + NS_IMETHOD Run() 1.2273 + { 1.2274 + MOZ_ASSERT(NS_IsMainThread()); 1.2275 + nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); 1.2276 + if (!window) { 1.2277 + return NS_OK; 1.2278 + } 1.2279 + 1.2280 + nsString state = NS_LITERAL_STRING("unavailable"); 1.2281 + if (mFile) { 1.2282 + mFile->DoUnmount(state); 1.2283 + } 1.2284 + 1.2285 + AutoJSContext cx; 1.2286 + JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); 1.2287 + mRequest->FireSuccess(result); 1.2288 + mRequest = nullptr; 1.2289 + return NS_OK; 1.2290 + } 1.2291 + 1.2292 +private: 1.2293 + nsRefPtr<DeviceStorageFile> mFile; 1.2294 + nsRefPtr<DOMRequest> mRequest; 1.2295 +}; 1.2296 + 1.2297 +class PostResultEvent : public nsRunnable 1.2298 +{ 1.2299 +public: 1.2300 + PostResultEvent(already_AddRefed<DOMRequest> aRequest, 1.2301 + DeviceStorageFile* aFile) 1.2302 + : mFile(aFile) 1.2303 + , mRequest(aRequest) 1.2304 + { 1.2305 + MOZ_ASSERT(mRequest); 1.2306 + } 1.2307 + 1.2308 + PostResultEvent(already_AddRefed<DOMRequest> aRequest, 1.2309 + const nsAString & aPath) 1.2310 + : mPath(aPath) 1.2311 + , mRequest(aRequest) 1.2312 + { 1.2313 + MOZ_ASSERT(mRequest); 1.2314 + } 1.2315 + 1.2316 + PostResultEvent(already_AddRefed<DOMRequest> aRequest, 1.2317 + const uint64_t aValue) 1.2318 + : mValue(aValue) 1.2319 + , mRequest(aRequest) 1.2320 + { 1.2321 + MOZ_ASSERT(mRequest); 1.2322 + } 1.2323 + 1.2324 + ~PostResultEvent() {} 1.2325 + 1.2326 + NS_IMETHOD Run() 1.2327 + { 1.2328 + MOZ_ASSERT(NS_IsMainThread()); 1.2329 + nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); 1.2330 + if (!window) { 1.2331 + return NS_OK; 1.2332 + } 1.2333 + 1.2334 + AutoJSContext cx; 1.2335 + JS::Rooted<JS::Value> result(cx, JSVAL_NULL); 1.2336 + 1.2337 + if (mFile) { 1.2338 + result = nsIFileToJsval(window, mFile); 1.2339 + } else if (mPath.Length()) { 1.2340 + result = StringToJsval(window, mPath); 1.2341 + } 1.2342 + else { 1.2343 + result = JS_NumberValue(double(mValue)); 1.2344 + } 1.2345 + 1.2346 + mRequest->FireSuccess(result); 1.2347 + mRequest = nullptr; 1.2348 + return NS_OK; 1.2349 + } 1.2350 + 1.2351 +private: 1.2352 + nsRefPtr<DeviceStorageFile> mFile; 1.2353 + nsString mPath; 1.2354 + uint64_t mValue; 1.2355 + nsRefPtr<DOMRequest> mRequest; 1.2356 +}; 1.2357 + 1.2358 +class CreateFdEvent : public nsRunnable 1.2359 +{ 1.2360 +public: 1.2361 + CreateFdEvent(DeviceStorageFileDescriptor* aDSFileDescriptor, 1.2362 + already_AddRefed<DOMRequest> aRequest) 1.2363 + : mDSFileDescriptor(aDSFileDescriptor) 1.2364 + , mRequest(aRequest) 1.2365 + { 1.2366 + MOZ_ASSERT(mDSFileDescriptor); 1.2367 + MOZ_ASSERT(mRequest); 1.2368 + } 1.2369 + 1.2370 + NS_IMETHOD Run() 1.2371 + { 1.2372 + MOZ_ASSERT(!NS_IsMainThread()); 1.2373 + 1.2374 + DeviceStorageFile* dsFile = mDSFileDescriptor->mDSFile; 1.2375 + MOZ_ASSERT(dsFile); 1.2376 + 1.2377 + nsString fullPath; 1.2378 + dsFile->GetFullPath(fullPath); 1.2379 + MOZ_ASSERT(!fullPath.IsEmpty()); 1.2380 + 1.2381 + bool check = false; 1.2382 + dsFile->mFile->Exists(&check); 1.2383 + if (check) { 1.2384 + nsCOMPtr<nsIRunnable> event = 1.2385 + new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_EXISTS); 1.2386 + return NS_DispatchToMainThread(event); 1.2387 + } 1.2388 + 1.2389 + nsresult rv = dsFile->CreateFileDescriptor(mDSFileDescriptor->mFileDescriptor); 1.2390 + 1.2391 + if (NS_FAILED(rv)) { 1.2392 + dsFile->mFile->Remove(false); 1.2393 + 1.2394 + nsCOMPtr<nsIRunnable> event = 1.2395 + new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN); 1.2396 + return NS_DispatchToMainThread(event); 1.2397 + } 1.2398 + 1.2399 + nsCOMPtr<nsIRunnable> event = 1.2400 + new PostResultEvent(mRequest.forget(), fullPath); 1.2401 + return NS_DispatchToMainThread(event); 1.2402 + } 1.2403 + 1.2404 +private: 1.2405 + nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor; 1.2406 + nsRefPtr<DOMRequest> mRequest; 1.2407 +}; 1.2408 + 1.2409 +class WriteFileEvent : public nsRunnable 1.2410 +{ 1.2411 +public: 1.2412 + WriteFileEvent(nsIDOMBlob* aBlob, 1.2413 + DeviceStorageFile *aFile, 1.2414 + already_AddRefed<DOMRequest> aRequest) 1.2415 + : mBlob(aBlob) 1.2416 + , mFile(aFile) 1.2417 + , mRequest(aRequest) 1.2418 + { 1.2419 + MOZ_ASSERT(mFile); 1.2420 + MOZ_ASSERT(mRequest); 1.2421 + } 1.2422 + 1.2423 + ~WriteFileEvent() {} 1.2424 + 1.2425 + NS_IMETHOD Run() 1.2426 + { 1.2427 + MOZ_ASSERT(!NS_IsMainThread()); 1.2428 + 1.2429 + nsCOMPtr<nsIInputStream> stream; 1.2430 + mBlob->GetInternalStream(getter_AddRefs(stream)); 1.2431 + 1.2432 + bool check = false; 1.2433 + mFile->mFile->Exists(&check); 1.2434 + if (check) { 1.2435 + nsCOMPtr<nsIRunnable> event = 1.2436 + new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_EXISTS); 1.2437 + return NS_DispatchToMainThread(event); 1.2438 + } 1.2439 + 1.2440 + nsresult rv = mFile->Write(stream); 1.2441 + 1.2442 + if (NS_FAILED(rv)) { 1.2443 + mFile->mFile->Remove(false); 1.2444 + 1.2445 + nsCOMPtr<nsIRunnable> event = 1.2446 + new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN); 1.2447 + return NS_DispatchToMainThread(event); 1.2448 + } 1.2449 + 1.2450 + nsString fullPath; 1.2451 + mFile->GetFullPath(fullPath); 1.2452 + nsCOMPtr<nsIRunnable> event = 1.2453 + new PostResultEvent(mRequest.forget(), fullPath); 1.2454 + return NS_DispatchToMainThread(event); 1.2455 + } 1.2456 + 1.2457 +private: 1.2458 + nsCOMPtr<nsIDOMBlob> mBlob; 1.2459 + nsRefPtr<DeviceStorageFile> mFile; 1.2460 + nsRefPtr<DOMRequest> mRequest; 1.2461 +}; 1.2462 + 1.2463 +class ReadFileEvent : public nsRunnable 1.2464 +{ 1.2465 +public: 1.2466 + ReadFileEvent(DeviceStorageFile* aFile, 1.2467 + already_AddRefed<DOMRequest> aRequest) 1.2468 + : mFile(aFile) 1.2469 + , mRequest(aRequest) 1.2470 + { 1.2471 + MOZ_ASSERT(mFile); 1.2472 + MOZ_ASSERT(mRequest); 1.2473 + mFile->CalculateMimeType(); 1.2474 + } 1.2475 + 1.2476 + ~ReadFileEvent() {} 1.2477 + 1.2478 + NS_IMETHOD Run() 1.2479 + { 1.2480 + MOZ_ASSERT(!NS_IsMainThread()); 1.2481 + 1.2482 + nsCOMPtr<nsIRunnable> r; 1.2483 + if (!mFile->mEditable) { 1.2484 + bool check = false; 1.2485 + mFile->mFile->Exists(&check); 1.2486 + if (!check) { 1.2487 + r = new PostErrorEvent(mRequest.forget(), 1.2488 + POST_ERROR_EVENT_FILE_DOES_NOT_EXIST); 1.2489 + } 1.2490 + } 1.2491 + 1.2492 + if (!r) { 1.2493 + nsresult rv = mFile->CalculateSizeAndModifiedDate(); 1.2494 + if (NS_FAILED(rv)) { 1.2495 + r = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN); 1.2496 + } 1.2497 + } 1.2498 + 1.2499 + if (!r) { 1.2500 + r = new PostResultEvent(mRequest.forget(), mFile); 1.2501 + } 1.2502 + return NS_DispatchToMainThread(r); 1.2503 + } 1.2504 + 1.2505 +private: 1.2506 + nsRefPtr<DeviceStorageFile> mFile; 1.2507 + nsRefPtr<DOMRequest> mRequest; 1.2508 +}; 1.2509 + 1.2510 +class DeleteFileEvent : public nsRunnable 1.2511 +{ 1.2512 +public: 1.2513 + DeleteFileEvent(DeviceStorageFile* aFile, 1.2514 + already_AddRefed<DOMRequest> aRequest) 1.2515 + : mFile(aFile) 1.2516 + , mRequest(aRequest) 1.2517 + { 1.2518 + MOZ_ASSERT(mFile); 1.2519 + MOZ_ASSERT(mRequest); 1.2520 + } 1.2521 + 1.2522 + ~DeleteFileEvent() {} 1.2523 + 1.2524 + NS_IMETHOD Run() 1.2525 + { 1.2526 + MOZ_ASSERT(!NS_IsMainThread()); 1.2527 + mFile->Remove(); 1.2528 + 1.2529 + nsCOMPtr<nsIRunnable> r; 1.2530 + bool check = false; 1.2531 + mFile->mFile->Exists(&check); 1.2532 + if (check) { 1.2533 + r = new PostErrorEvent(mRequest.forget(), 1.2534 + POST_ERROR_EVENT_FILE_DOES_NOT_EXIST); 1.2535 + } 1.2536 + else { 1.2537 + nsString fullPath; 1.2538 + mFile->GetFullPath(fullPath); 1.2539 + r = new PostResultEvent(mRequest.forget(), fullPath); 1.2540 + } 1.2541 + return NS_DispatchToMainThread(r); 1.2542 + } 1.2543 + 1.2544 +private: 1.2545 + nsRefPtr<DeviceStorageFile> mFile; 1.2546 + nsRefPtr<DOMRequest> mRequest; 1.2547 +}; 1.2548 + 1.2549 +class UsedSpaceFileEvent : public nsRunnable 1.2550 +{ 1.2551 +public: 1.2552 + UsedSpaceFileEvent(DeviceStorageFile* aFile, 1.2553 + already_AddRefed<DOMRequest> aRequest) 1.2554 + : mFile(aFile) 1.2555 + , mRequest(aRequest) 1.2556 + { 1.2557 + MOZ_ASSERT(mFile); 1.2558 + MOZ_ASSERT(mRequest); 1.2559 + } 1.2560 + 1.2561 + ~UsedSpaceFileEvent() {} 1.2562 + 1.2563 + NS_IMETHOD Run() 1.2564 + { 1.2565 + MOZ_ASSERT(!NS_IsMainThread()); 1.2566 + 1.2567 + uint64_t picturesUsage = 0, videosUsage = 0, musicUsage = 0, totalUsage = 0; 1.2568 + mFile->AccumDiskUsage(&picturesUsage, &videosUsage, 1.2569 + &musicUsage, &totalUsage); 1.2570 + nsCOMPtr<nsIRunnable> r; 1.2571 + if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { 1.2572 + r = new PostResultEvent(mRequest.forget(), picturesUsage); 1.2573 + } 1.2574 + else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { 1.2575 + r = new PostResultEvent(mRequest.forget(), videosUsage); 1.2576 + } 1.2577 + else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { 1.2578 + r = new PostResultEvent(mRequest.forget(), musicUsage); 1.2579 + } else { 1.2580 + r = new PostResultEvent(mRequest.forget(), totalUsage); 1.2581 + } 1.2582 + return NS_DispatchToMainThread(r); 1.2583 + } 1.2584 + 1.2585 +private: 1.2586 + nsRefPtr<DeviceStorageFile> mFile; 1.2587 + nsRefPtr<DOMRequest> mRequest; 1.2588 +}; 1.2589 + 1.2590 +class FreeSpaceFileEvent : public nsRunnable 1.2591 +{ 1.2592 +public: 1.2593 + FreeSpaceFileEvent(DeviceStorageFile* aFile, 1.2594 + already_AddRefed<DOMRequest> aRequest) 1.2595 + : mFile(aFile) 1.2596 + , mRequest(aRequest) 1.2597 + { 1.2598 + MOZ_ASSERT(mFile); 1.2599 + MOZ_ASSERT(mRequest); 1.2600 + } 1.2601 + 1.2602 + ~FreeSpaceFileEvent() {} 1.2603 + 1.2604 + NS_IMETHOD Run() 1.2605 + { 1.2606 + MOZ_ASSERT(!NS_IsMainThread()); 1.2607 + 1.2608 + int64_t freeSpace = 0; 1.2609 + if (mFile) { 1.2610 + mFile->GetDiskFreeSpace(&freeSpace); 1.2611 + } 1.2612 + 1.2613 + nsCOMPtr<nsIRunnable> r; 1.2614 + r = new PostResultEvent(mRequest.forget(), 1.2615 + static_cast<uint64_t>(freeSpace)); 1.2616 + return NS_DispatchToMainThread(r); 1.2617 + } 1.2618 + 1.2619 +private: 1.2620 + nsRefPtr<DeviceStorageFile> mFile; 1.2621 + nsRefPtr<DOMRequest> mRequest; 1.2622 +}; 1.2623 + 1.2624 +class DeviceStorageRequest MOZ_FINAL 1.2625 + : public nsIContentPermissionRequest 1.2626 + , public nsIRunnable 1.2627 + , public PCOMContentPermissionRequestChild 1.2628 +{ 1.2629 +public: 1.2630 + 1.2631 + DeviceStorageRequest(const DeviceStorageRequestType aRequestType, 1.2632 + nsPIDOMWindow* aWindow, 1.2633 + nsIPrincipal* aPrincipal, 1.2634 + DeviceStorageFile* aFile, 1.2635 + DOMRequest* aRequest, 1.2636 + nsDOMDeviceStorage* aDeviceStorage) 1.2637 + : mRequestType(aRequestType) 1.2638 + , mWindow(aWindow) 1.2639 + , mPrincipal(aPrincipal) 1.2640 + , mFile(aFile) 1.2641 + , mRequest(aRequest) 1.2642 + , mDeviceStorage(aDeviceStorage) 1.2643 + { 1.2644 + MOZ_ASSERT(mWindow); 1.2645 + MOZ_ASSERT(mPrincipal); 1.2646 + MOZ_ASSERT(mFile); 1.2647 + MOZ_ASSERT(mRequest); 1.2648 + MOZ_ASSERT(mDeviceStorage); 1.2649 + } 1.2650 + 1.2651 + DeviceStorageRequest(const DeviceStorageRequestType aRequestType, 1.2652 + nsPIDOMWindow* aWindow, 1.2653 + nsIPrincipal* aPrincipal, 1.2654 + DeviceStorageFile* aFile, 1.2655 + DOMRequest* aRequest, 1.2656 + nsIDOMBlob* aBlob = nullptr) 1.2657 + : mRequestType(aRequestType) 1.2658 + , mWindow(aWindow) 1.2659 + , mPrincipal(aPrincipal) 1.2660 + , mFile(aFile) 1.2661 + , mRequest(aRequest) 1.2662 + , mBlob(aBlob) 1.2663 + { 1.2664 + MOZ_ASSERT(mWindow); 1.2665 + MOZ_ASSERT(mPrincipal); 1.2666 + MOZ_ASSERT(mFile); 1.2667 + MOZ_ASSERT(mRequest); 1.2668 + } 1.2669 + 1.2670 + DeviceStorageRequest(const DeviceStorageRequestType aRequestType, 1.2671 + nsPIDOMWindow* aWindow, 1.2672 + nsIPrincipal* aPrincipal, 1.2673 + DeviceStorageFile* aFile, 1.2674 + DOMRequest* aRequest, 1.2675 + DeviceStorageFileDescriptor* aDSFileDescriptor) 1.2676 + : mRequestType(aRequestType) 1.2677 + , mWindow(aWindow) 1.2678 + , mPrincipal(aPrincipal) 1.2679 + , mFile(aFile) 1.2680 + , mRequest(aRequest) 1.2681 + , mDSFileDescriptor(aDSFileDescriptor) 1.2682 + { 1.2683 + MOZ_ASSERT(mRequestType == DEVICE_STORAGE_REQUEST_CREATEFD); 1.2684 + MOZ_ASSERT(mWindow); 1.2685 + MOZ_ASSERT(mPrincipal); 1.2686 + MOZ_ASSERT(mFile); 1.2687 + MOZ_ASSERT(mRequest); 1.2688 + MOZ_ASSERT(mDSFileDescriptor); 1.2689 + } 1.2690 + 1.2691 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.2692 + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageRequest, 1.2693 + nsIContentPermissionRequest) 1.2694 + 1.2695 + NS_IMETHOD Run() { 1.2696 + MOZ_ASSERT(NS_IsMainThread()); 1.2697 + 1.2698 + if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) { 1.2699 + Allow(JS::UndefinedHandleValue); 1.2700 + return NS_OK; 1.2701 + } 1.2702 + 1.2703 + if (XRE_GetProcessType() == GeckoProcessType_Content) { 1.2704 + 1.2705 + // because owner implements nsITabChild, we can assume that it is 1.2706 + // the one and only TabChild. 1.2707 + TabChild* child = TabChild::GetFrom(mWindow->GetDocShell()); 1.2708 + if (!child) { 1.2709 + return NS_OK; 1.2710 + } 1.2711 + 1.2712 + // Retain a reference so the object isn't deleted without IPDL's 1.2713 + // knowledge. Corresponding release occurs in 1.2714 + // DeallocPContentPermissionRequest. 1.2715 + AddRef(); 1.2716 + 1.2717 + nsCString type; 1.2718 + nsresult rv = DeviceStorageTypeChecker::GetPermissionForType( 1.2719 + mFile->mStorageType, type); 1.2720 + if (NS_FAILED(rv)) { 1.2721 + return rv; 1.2722 + } 1.2723 + nsCString access; 1.2724 + rv = DeviceStorageTypeChecker::GetAccessForRequest( 1.2725 + DeviceStorageRequestType(mRequestType), access); 1.2726 + if (NS_FAILED(rv)) { 1.2727 + return rv; 1.2728 + } 1.2729 + nsTArray<PermissionRequest> permArray; 1.2730 + nsTArray<nsString> emptyOptions; 1.2731 + permArray.AppendElement(PermissionRequest(type, access, emptyOptions)); 1.2732 + child->SendPContentPermissionRequestConstructor( 1.2733 + this, permArray, IPC::Principal(mPrincipal)); 1.2734 + 1.2735 + Sendprompt(); 1.2736 + return NS_OK; 1.2737 + } 1.2738 + 1.2739 + nsCOMPtr<nsIContentPermissionPrompt> prompt 1.2740 + = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); 1.2741 + if (prompt) { 1.2742 + prompt->Prompt(this); 1.2743 + } 1.2744 + return NS_OK; 1.2745 + } 1.2746 + 1.2747 + NS_IMETHODIMP GetTypes(nsIArray** aTypes) 1.2748 + { 1.2749 + nsCString type; 1.2750 + nsresult rv = 1.2751 + DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type); 1.2752 + if (NS_FAILED(rv)) { 1.2753 + return rv; 1.2754 + } 1.2755 + 1.2756 + nsCString access; 1.2757 + rv = DeviceStorageTypeChecker::GetAccessForRequest( 1.2758 + DeviceStorageRequestType(mRequestType), access); 1.2759 + if (NS_FAILED(rv)) { 1.2760 + return rv; 1.2761 + } 1.2762 + 1.2763 + nsTArray<nsString> emptyOptions; 1.2764 + return CreatePermissionArray(type, access, emptyOptions, aTypes); 1.2765 + } 1.2766 + 1.2767 + NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal) 1.2768 + { 1.2769 + NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal); 1.2770 + return NS_OK; 1.2771 + } 1.2772 + 1.2773 + NS_IMETHOD GetWindow(nsIDOMWindow * *aRequestingWindow) 1.2774 + { 1.2775 + NS_IF_ADDREF(*aRequestingWindow = mWindow); 1.2776 + return NS_OK; 1.2777 + } 1.2778 + 1.2779 + NS_IMETHOD GetElement(nsIDOMElement * *aRequestingElement) 1.2780 + { 1.2781 + *aRequestingElement = nullptr; 1.2782 + return NS_OK; 1.2783 + } 1.2784 + 1.2785 + NS_IMETHOD Cancel() 1.2786 + { 1.2787 + nsCOMPtr<nsIRunnable> event 1.2788 + = new PostErrorEvent(mRequest.forget(), 1.2789 + POST_ERROR_EVENT_PERMISSION_DENIED); 1.2790 + return NS_DispatchToMainThread(event); 1.2791 + } 1.2792 + 1.2793 + NS_IMETHOD Allow(JS::HandleValue aChoices) 1.2794 + { 1.2795 + MOZ_ASSERT(NS_IsMainThread()); 1.2796 + MOZ_ASSERT(aChoices.isUndefined()); 1.2797 + 1.2798 + if (!mRequest) { 1.2799 + return NS_ERROR_FAILURE; 1.2800 + } 1.2801 + 1.2802 + nsCOMPtr<nsIRunnable> r; 1.2803 + 1.2804 + switch(mRequestType) { 1.2805 + case DEVICE_STORAGE_REQUEST_CREATEFD: 1.2806 + { 1.2807 + if (!mFile->mFile) { 1.2808 + return NS_ERROR_FAILURE; 1.2809 + } 1.2810 + 1.2811 + DeviceStorageTypeChecker* typeChecker 1.2812 + = DeviceStorageTypeChecker::CreateOrGet(); 1.2813 + if (!typeChecker) { 1.2814 + return NS_OK; 1.2815 + } 1.2816 + 1.2817 + if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) { 1.2818 + r = new PostErrorEvent(mRequest.forget(), 1.2819 + POST_ERROR_EVENT_ILLEGAL_TYPE); 1.2820 + return NS_DispatchToCurrentThread(r); 1.2821 + } 1.2822 + 1.2823 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.2824 + 1.2825 + DeviceStorageCreateFdParams params; 1.2826 + params.type() = mFile->mStorageType; 1.2827 + params.storageName() = mFile->mStorageName; 1.2828 + params.relpath() = mFile->mPath; 1.2829 + 1.2830 + mFile->Dump("DeviceStorageCreateFdParams"); 1.2831 + 1.2832 + PDeviceStorageRequestChild* child 1.2833 + = new DeviceStorageRequestChild(mRequest, mFile, 1.2834 + mDSFileDescriptor.get()); 1.2835 + ContentChild::GetSingleton() 1.2836 + ->SendPDeviceStorageRequestConstructor(child, params); 1.2837 + return NS_OK; 1.2838 + } 1.2839 + mDSFileDescriptor->mDSFile = mFile; 1.2840 + r = new CreateFdEvent(mDSFileDescriptor.get(), mRequest.forget()); 1.2841 + break; 1.2842 + } 1.2843 + 1.2844 + case DEVICE_STORAGE_REQUEST_CREATE: 1.2845 + { 1.2846 + if (!mBlob || !mFile->mFile) { 1.2847 + return NS_ERROR_FAILURE; 1.2848 + } 1.2849 + 1.2850 + DeviceStorageTypeChecker* typeChecker 1.2851 + = DeviceStorageTypeChecker::CreateOrGet(); 1.2852 + if (!typeChecker) { 1.2853 + return NS_OK; 1.2854 + } 1.2855 + 1.2856 + if (!typeChecker->Check(mFile->mStorageType, mFile->mFile) || 1.2857 + !typeChecker->Check(mFile->mStorageType, mBlob)) { 1.2858 + r = new PostErrorEvent(mRequest.forget(), 1.2859 + POST_ERROR_EVENT_ILLEGAL_TYPE); 1.2860 + return NS_DispatchToCurrentThread(r); 1.2861 + } 1.2862 + 1.2863 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.2864 + BlobChild* actor 1.2865 + = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob); 1.2866 + if (!actor) { 1.2867 + return NS_ERROR_FAILURE; 1.2868 + } 1.2869 + 1.2870 + DeviceStorageAddParams params; 1.2871 + params.blobChild() = actor; 1.2872 + params.type() = mFile->mStorageType; 1.2873 + params.storageName() = mFile->mStorageName; 1.2874 + params.relpath() = mFile->mPath; 1.2875 + 1.2876 + PDeviceStorageRequestChild* child 1.2877 + = new DeviceStorageRequestChild(mRequest, mFile); 1.2878 + ContentChild::GetSingleton() 1.2879 + ->SendPDeviceStorageRequestConstructor(child, params); 1.2880 + return NS_OK; 1.2881 + } 1.2882 + r = new WriteFileEvent(mBlob, mFile, mRequest.forget()); 1.2883 + break; 1.2884 + } 1.2885 + 1.2886 + case DEVICE_STORAGE_REQUEST_READ: 1.2887 + case DEVICE_STORAGE_REQUEST_WRITE: 1.2888 + { 1.2889 + if (!mFile->mFile) { 1.2890 + return NS_ERROR_FAILURE; 1.2891 + } 1.2892 + 1.2893 + DeviceStorageTypeChecker* typeChecker 1.2894 + = DeviceStorageTypeChecker::CreateOrGet(); 1.2895 + if (!typeChecker) { 1.2896 + return NS_OK; 1.2897 + } 1.2898 + 1.2899 + if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) { 1.2900 + r = new PostErrorEvent(mRequest.forget(), 1.2901 + POST_ERROR_EVENT_ILLEGAL_TYPE); 1.2902 + return NS_DispatchToCurrentThread(r); 1.2903 + } 1.2904 + 1.2905 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.2906 + PDeviceStorageRequestChild* child 1.2907 + = new DeviceStorageRequestChild(mRequest, mFile); 1.2908 + DeviceStorageGetParams params(mFile->mStorageType, 1.2909 + mFile->mStorageName, 1.2910 + mFile->mRootDir, 1.2911 + mFile->mPath); 1.2912 + ContentChild::GetSingleton() 1.2913 + ->SendPDeviceStorageRequestConstructor(child, params); 1.2914 + return NS_OK; 1.2915 + } 1.2916 + 1.2917 + r = new ReadFileEvent(mFile, mRequest.forget()); 1.2918 + break; 1.2919 + } 1.2920 + 1.2921 + case DEVICE_STORAGE_REQUEST_DELETE: 1.2922 + { 1.2923 + if (!mFile->mFile) { 1.2924 + return NS_ERROR_FAILURE; 1.2925 + } 1.2926 + 1.2927 + DeviceStorageTypeChecker* typeChecker 1.2928 + = DeviceStorageTypeChecker::CreateOrGet(); 1.2929 + if (!typeChecker) { 1.2930 + return NS_OK; 1.2931 + } 1.2932 + 1.2933 + if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) { 1.2934 + r = new PostErrorEvent(mRequest.forget(), 1.2935 + POST_ERROR_EVENT_ILLEGAL_TYPE); 1.2936 + return NS_DispatchToCurrentThread(r); 1.2937 + } 1.2938 + 1.2939 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.2940 + PDeviceStorageRequestChild* child 1.2941 + = new DeviceStorageRequestChild(mRequest, mFile); 1.2942 + DeviceStorageDeleteParams params(mFile->mStorageType, 1.2943 + mFile->mStorageName, 1.2944 + mFile->mPath); 1.2945 + ContentChild::GetSingleton() 1.2946 + ->SendPDeviceStorageRequestConstructor(child, params); 1.2947 + return NS_OK; 1.2948 + } 1.2949 + r = new DeleteFileEvent(mFile, mRequest.forget()); 1.2950 + break; 1.2951 + } 1.2952 + 1.2953 + case DEVICE_STORAGE_REQUEST_FREE_SPACE: 1.2954 + { 1.2955 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.2956 + PDeviceStorageRequestChild* child 1.2957 + = new DeviceStorageRequestChild(mRequest, mFile); 1.2958 + DeviceStorageFreeSpaceParams params(mFile->mStorageType, 1.2959 + mFile->mStorageName); 1.2960 + ContentChild::GetSingleton() 1.2961 + ->SendPDeviceStorageRequestConstructor(child, params); 1.2962 + return NS_OK; 1.2963 + } 1.2964 + r = new FreeSpaceFileEvent(mFile, mRequest.forget()); 1.2965 + break; 1.2966 + } 1.2967 + 1.2968 + case DEVICE_STORAGE_REQUEST_USED_SPACE: 1.2969 + { 1.2970 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.2971 + PDeviceStorageRequestChild* child 1.2972 + = new DeviceStorageRequestChild(mRequest, mFile); 1.2973 + DeviceStorageUsedSpaceParams params(mFile->mStorageType, 1.2974 + mFile->mStorageName); 1.2975 + ContentChild::GetSingleton() 1.2976 + ->SendPDeviceStorageRequestConstructor(child, params); 1.2977 + return NS_OK; 1.2978 + } 1.2979 + // this needs to be dispatched to only one (1) 1.2980 + // thread or we will do more work than required. 1.2981 + DeviceStorageUsedSpaceCache* usedSpaceCache 1.2982 + = DeviceStorageUsedSpaceCache::CreateOrGet(); 1.2983 + MOZ_ASSERT(usedSpaceCache); 1.2984 + r = new UsedSpaceFileEvent(mFile, mRequest.forget()); 1.2985 + usedSpaceCache->Dispatch(r); 1.2986 + return NS_OK; 1.2987 + } 1.2988 + 1.2989 + case DEVICE_STORAGE_REQUEST_AVAILABLE: 1.2990 + { 1.2991 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.2992 + PDeviceStorageRequestChild* child 1.2993 + = new DeviceStorageRequestChild(mRequest, mFile); 1.2994 + DeviceStorageAvailableParams params(mFile->mStorageType, 1.2995 + mFile->mStorageName); 1.2996 + ContentChild::GetSingleton() 1.2997 + ->SendPDeviceStorageRequestConstructor(child, params); 1.2998 + return NS_OK; 1.2999 + } 1.3000 + r = new PostAvailableResultEvent(mFile, mRequest); 1.3001 + return NS_DispatchToCurrentThread(r); 1.3002 + } 1.3003 + 1.3004 + case DEVICE_STORAGE_REQUEST_STATUS: 1.3005 + { 1.3006 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.3007 + PDeviceStorageRequestChild* child 1.3008 + = new DeviceStorageRequestChild(mRequest, mFile); 1.3009 + DeviceStorageStatusParams params(mFile->mStorageType, 1.3010 + mFile->mStorageName); 1.3011 + ContentChild::GetSingleton() 1.3012 + ->SendPDeviceStorageRequestConstructor(child, params); 1.3013 + return NS_OK; 1.3014 + } 1.3015 + r = new PostStatusResultEvent(mFile, mRequest); 1.3016 + return NS_DispatchToCurrentThread(r); 1.3017 + } 1.3018 + 1.3019 + case DEVICE_STORAGE_REQUEST_WATCH: 1.3020 + { 1.3021 + mDeviceStorage->mAllowedToWatchFile = true; 1.3022 + return NS_OK; 1.3023 + } 1.3024 + 1.3025 + case DEVICE_STORAGE_REQUEST_FORMAT: 1.3026 + { 1.3027 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.3028 + PDeviceStorageRequestChild* child 1.3029 + = new DeviceStorageRequestChild(mRequest, mFile); 1.3030 + DeviceStorageFormatParams params(mFile->mStorageType, 1.3031 + mFile->mStorageName); 1.3032 + ContentChild::GetSingleton() 1.3033 + ->SendPDeviceStorageRequestConstructor(child, params); 1.3034 + return NS_OK; 1.3035 + } 1.3036 + r = new PostFormatResultEvent(mFile, mRequest); 1.3037 + return NS_DispatchToCurrentThread(r); 1.3038 + } 1.3039 + 1.3040 + case DEVICE_STORAGE_REQUEST_MOUNT: 1.3041 + { 1.3042 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.3043 + PDeviceStorageRequestChild* child 1.3044 + = new DeviceStorageRequestChild(mRequest, mFile); 1.3045 + DeviceStorageMountParams params(mFile->mStorageType, 1.3046 + mFile->mStorageName); 1.3047 + ContentChild::GetSingleton() 1.3048 + ->SendPDeviceStorageRequestConstructor(child, params); 1.3049 + return NS_OK; 1.3050 + } 1.3051 + r = new PostMountResultEvent(mFile, mRequest); 1.3052 + return NS_DispatchToCurrentThread(r); 1.3053 + } 1.3054 + 1.3055 + case DEVICE_STORAGE_REQUEST_UNMOUNT: 1.3056 + { 1.3057 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.3058 + PDeviceStorageRequestChild* child 1.3059 + = new DeviceStorageRequestChild(mRequest, mFile); 1.3060 + DeviceStorageUnmountParams params(mFile->mStorageType, 1.3061 + mFile->mStorageName); 1.3062 + ContentChild::GetSingleton() 1.3063 + ->SendPDeviceStorageRequestConstructor(child, params); 1.3064 + return NS_OK; 1.3065 + } 1.3066 + r = new PostUnmountResultEvent(mFile, mRequest); 1.3067 + return NS_DispatchToCurrentThread(r); 1.3068 + } 1.3069 + } 1.3070 + 1.3071 + if (r) { 1.3072 + nsCOMPtr<nsIEventTarget> target 1.3073 + = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); 1.3074 + MOZ_ASSERT(target); 1.3075 + target->Dispatch(r, NS_DISPATCH_NORMAL); 1.3076 + } 1.3077 + 1.3078 + return NS_OK; 1.3079 + } 1.3080 + 1.3081 + bool Recv__delete__(const bool& allow, 1.3082 + const InfallibleTArray<PermissionChoice>& choices) 1.3083 + { 1.3084 + MOZ_ASSERT(choices.IsEmpty(), "DeviceStorage doesn't support permission choice"); 1.3085 + 1.3086 + if (allow) { 1.3087 + Allow(JS::UndefinedHandleValue); 1.3088 + } 1.3089 + else { 1.3090 + Cancel(); 1.3091 + } 1.3092 + return true; 1.3093 + } 1.3094 + 1.3095 + void IPDLRelease() 1.3096 + { 1.3097 + Release(); 1.3098 + } 1.3099 + 1.3100 +private: 1.3101 + int32_t mRequestType; 1.3102 + nsCOMPtr<nsPIDOMWindow> mWindow; 1.3103 + nsCOMPtr<nsIPrincipal> mPrincipal; 1.3104 + nsRefPtr<DeviceStorageFile> mFile; 1.3105 + 1.3106 + nsRefPtr<DOMRequest> mRequest; 1.3107 + nsCOMPtr<nsIDOMBlob> mBlob; 1.3108 + nsRefPtr<nsDOMDeviceStorage> mDeviceStorage; 1.3109 + nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor; 1.3110 +}; 1.3111 + 1.3112 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest) 1.3113 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest) 1.3114 + NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest) 1.3115 + NS_INTERFACE_MAP_ENTRY(nsIRunnable) 1.3116 +NS_INTERFACE_MAP_END 1.3117 + 1.3118 +NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageRequest) 1.3119 +NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageRequest) 1.3120 + 1.3121 +NS_IMPL_CYCLE_COLLECTION(DeviceStorageRequest, 1.3122 + mRequest, 1.3123 + mWindow, 1.3124 + mBlob, 1.3125 + mDeviceStorage) 1.3126 + 1.3127 + 1.3128 +NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorage) 1.3129 + NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorage) 1.3130 + NS_INTERFACE_MAP_ENTRY(nsIObserver) 1.3131 +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 1.3132 + 1.3133 +NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorage, DOMEventTargetHelper) 1.3134 +NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorage, DOMEventTargetHelper) 1.3135 + 1.3136 +nsDOMDeviceStorage::nsDOMDeviceStorage(nsPIDOMWindow* aWindow) 1.3137 + : DOMEventTargetHelper(aWindow) 1.3138 + , mIsWatchingFile(false) 1.3139 + , mAllowedToWatchFile(false) 1.3140 +{ 1.3141 +} 1.3142 + 1.3143 +/* virtual */ JSObject* 1.3144 +nsDOMDeviceStorage::WrapObject(JSContext* aCx) 1.3145 +{ 1.3146 + return DeviceStorageBinding::Wrap(aCx, this); 1.3147 +} 1.3148 + 1.3149 +nsresult 1.3150 +nsDOMDeviceStorage::Init(nsPIDOMWindow* aWindow, const nsAString &aType, 1.3151 + const nsAString &aVolName) 1.3152 +{ 1.3153 + DebugOnly<FileUpdateDispatcher*> observer 1.3154 + = FileUpdateDispatcher::GetSingleton(); 1.3155 + MOZ_ASSERT(observer); 1.3156 + 1.3157 + MOZ_ASSERT(aWindow); 1.3158 + 1.3159 + SetRootDirectoryForType(aType, aVolName); 1.3160 + if (!mRootDirectory) { 1.3161 + return NS_ERROR_NOT_AVAILABLE; 1.3162 + } 1.3163 + if (!mStorageName.IsEmpty()) { 1.3164 + RegisterForSDCardChanges(this); 1.3165 + } 1.3166 + 1.3167 + // Grab the principal of the document 1.3168 + nsCOMPtr<nsIDocument> doc = aWindow->GetDoc(); 1.3169 + if (!doc) { 1.3170 + return NS_ERROR_FAILURE; 1.3171 + } 1.3172 + mPrincipal = doc->NodePrincipal(); 1.3173 + 1.3174 + // the 'apps' type is special. We only want this exposed 1.3175 + // if the caller has the "webapps-manage" permission. 1.3176 + if (aType.EqualsLiteral(DEVICESTORAGE_APPS)) { 1.3177 + nsCOMPtr<nsIPermissionManager> permissionManager 1.3178 + = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); 1.3179 + NS_ENSURE_TRUE(permissionManager, NS_ERROR_FAILURE); 1.3180 + 1.3181 + uint32_t permission; 1.3182 + nsresult rv 1.3183 + = permissionManager->TestPermissionFromPrincipal(mPrincipal, 1.3184 + "webapps-manage", 1.3185 + &permission); 1.3186 + 1.3187 + if (NS_FAILED(rv) || permission != nsIPermissionManager::ALLOW_ACTION) { 1.3188 + return NS_ERROR_NOT_AVAILABLE; 1.3189 + } 1.3190 + } 1.3191 + 1.3192 + return NS_OK; 1.3193 +} 1.3194 + 1.3195 +nsDOMDeviceStorage::~nsDOMDeviceStorage() 1.3196 +{ 1.3197 +} 1.3198 + 1.3199 +void 1.3200 +nsDOMDeviceStorage::Shutdown() 1.3201 +{ 1.3202 + MOZ_ASSERT(NS_IsMainThread()); 1.3203 + 1.3204 + if (mFileSystem) { 1.3205 + mFileSystem->Shutdown(); 1.3206 + mFileSystem = nullptr; 1.3207 + } 1.3208 + 1.3209 + if (!mStorageName.IsEmpty()) { 1.3210 + UnregisterForSDCardChanges(this); 1.3211 + } 1.3212 + 1.3213 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.3214 + obs->RemoveObserver(this, "file-watcher-update"); 1.3215 + obs->RemoveObserver(this, "disk-space-watcher"); 1.3216 +} 1.3217 + 1.3218 +StaticAutoPtr<nsTArray<nsString>> nsDOMDeviceStorage::sVolumeNameCache; 1.3219 + 1.3220 +// static 1.3221 +void 1.3222 +nsDOMDeviceStorage::GetOrderedVolumeNames( 1.3223 + nsDOMDeviceStorage::VolumeNameArray &aVolumeNames) 1.3224 +{ 1.3225 + if (sVolumeNameCache && sVolumeNameCache->Length() > 0) { 1.3226 + aVolumeNames.AppendElements(*sVolumeNameCache); 1.3227 + return; 1.3228 + } 1.3229 +#ifdef MOZ_WIDGET_GONK 1.3230 + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); 1.3231 + if (vs) { 1.3232 + vs->GetVolumeNames(aVolumeNames); 1.3233 + 1.3234 + // If the volume sdcard exists, then we want it to be first. 1.3235 + 1.3236 + VolumeNameArray::index_type sdcardIndex; 1.3237 + sdcardIndex = aVolumeNames.IndexOf(NS_LITERAL_STRING("sdcard")); 1.3238 + if (sdcardIndex != VolumeNameArray::NoIndex && sdcardIndex > 0) { 1.3239 + aVolumeNames.RemoveElementAt(sdcardIndex); 1.3240 + aVolumeNames.InsertElementAt(0, NS_LITERAL_STRING("sdcard")); 1.3241 + } 1.3242 + } 1.3243 +#endif 1.3244 + if (aVolumeNames.IsEmpty()) { 1.3245 + aVolumeNames.AppendElement(EmptyString()); 1.3246 + } 1.3247 + sVolumeNameCache = new nsTArray<nsString>; 1.3248 + sVolumeNameCache->AppendElements(aVolumeNames); 1.3249 +} 1.3250 + 1.3251 +// static 1.3252 +void 1.3253 +nsDOMDeviceStorage::CreateDeviceStorageFor(nsPIDOMWindow* aWin, 1.3254 + const nsAString &aType, 1.3255 + nsDOMDeviceStorage** aStore) 1.3256 +{ 1.3257 + nsString storageName; 1.3258 + if (!DeviceStorageTypeChecker::IsVolumeBased(aType)) { 1.3259 + // The storage name will be the empty string 1.3260 + storageName.Truncate(); 1.3261 + } else { 1.3262 + GetDefaultStorageName(aType, storageName); 1.3263 + } 1.3264 + 1.3265 + nsRefPtr<nsDOMDeviceStorage> ds = new nsDOMDeviceStorage(aWin); 1.3266 + if (NS_FAILED(ds->Init(aWin, aType, storageName))) { 1.3267 + *aStore = nullptr; 1.3268 + return; 1.3269 + } 1.3270 + NS_ADDREF(*aStore = ds.get()); 1.3271 +} 1.3272 + 1.3273 +// static 1.3274 +void 1.3275 +nsDOMDeviceStorage::CreateDeviceStoragesFor( 1.3276 + nsPIDOMWindow* aWin, 1.3277 + const nsAString &aType, 1.3278 + nsTArray<nsRefPtr<nsDOMDeviceStorage> > &aStores) 1.3279 +{ 1.3280 + nsresult rv; 1.3281 + 1.3282 + if (!DeviceStorageTypeChecker::IsVolumeBased(aType)) { 1.3283 + nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage(aWin); 1.3284 + rv = storage->Init(aWin, aType, EmptyString()); 1.3285 + if (NS_SUCCEEDED(rv)) { 1.3286 + aStores.AppendElement(storage); 1.3287 + } 1.3288 + return; 1.3289 + } 1.3290 + VolumeNameArray volNames; 1.3291 + GetOrderedVolumeNames(volNames); 1.3292 + 1.3293 + VolumeNameArray::size_type numVolumeNames = volNames.Length(); 1.3294 + for (VolumeNameArray::index_type i = 0; i < numVolumeNames; i++) { 1.3295 + nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage(aWin); 1.3296 + rv = storage->Init(aWin, aType, volNames[i]); 1.3297 + if (NS_FAILED(rv)) { 1.3298 + break; 1.3299 + } 1.3300 + aStores.AppendElement(storage); 1.3301 + } 1.3302 +} 1.3303 + 1.3304 +// static 1.3305 +bool 1.3306 +nsDOMDeviceStorage::ParseFullPath(const nsAString& aFullPath, 1.3307 + nsAString& aOutStorageName, 1.3308 + nsAString& aOutStoragePath) 1.3309 +{ 1.3310 + aOutStorageName.Truncate(); 1.3311 + aOutStoragePath.Truncate(); 1.3312 + 1.3313 + NS_NAMED_LITERAL_STRING(slash, "/"); 1.3314 + 1.3315 + nsDependentSubstring storageName; 1.3316 + 1.3317 + if (StringBeginsWith(aFullPath, slash)) { 1.3318 + int32_t slashIndex = aFullPath.FindChar('/', 1); 1.3319 + if (slashIndex == kNotFound) { 1.3320 + // names of the form /filename are illegal 1.3321 + return false; 1.3322 + } 1.3323 + storageName.Rebind(aFullPath, 1, slashIndex - 1); 1.3324 + aOutStoragePath = Substring(aFullPath, slashIndex + 1); 1.3325 + } else { 1.3326 + aOutStoragePath = aFullPath; 1.3327 + } 1.3328 + // If no volume name was specified in aFullPath, then aOutStorageName 1.3329 + // will wind up being the empty string. It's up to the caller to figure 1.3330 + // out which storage name to actually use. 1.3331 + aOutStorageName = storageName; 1.3332 + return true; 1.3333 +} 1.3334 + 1.3335 +already_AddRefed<nsDOMDeviceStorage> 1.3336 +nsDOMDeviceStorage::GetStorage(const nsAString& aFullPath, 1.3337 + nsAString& aOutStoragePath) 1.3338 +{ 1.3339 + nsString storageName; 1.3340 + if (!ParseFullPath(aFullPath, storageName, aOutStoragePath)) { 1.3341 + return nullptr; 1.3342 + } 1.3343 + nsRefPtr<nsDOMDeviceStorage> ds; 1.3344 + if (storageName.IsEmpty()) { 1.3345 + ds = this; 1.3346 + } else { 1.3347 + ds = GetStorageByName(storageName); 1.3348 + } 1.3349 + return ds.forget(); 1.3350 +} 1.3351 + 1.3352 +already_AddRefed<nsDOMDeviceStorage> 1.3353 +nsDOMDeviceStorage::GetStorageByName(const nsAString& aStorageName) 1.3354 +{ 1.3355 + MOZ_ASSERT(NS_IsMainThread()); 1.3356 + 1.3357 + nsRefPtr<nsDOMDeviceStorage> ds; 1.3358 + 1.3359 + if (mStorageName.Equals(aStorageName)) { 1.3360 + ds = this; 1.3361 + return ds.forget(); 1.3362 + } 1.3363 + VolumeNameArray volNames; 1.3364 + GetOrderedVolumeNames(volNames); 1.3365 + VolumeNameArray::size_type numVolumes = volNames.Length(); 1.3366 + VolumeNameArray::index_type i; 1.3367 + for (i = 0; i < numVolumes; i++) { 1.3368 + if (volNames[i].Equals(aStorageName)) { 1.3369 + ds = new nsDOMDeviceStorage(GetOwner()); 1.3370 + nsresult rv = ds->Init(GetOwner(), mStorageType, aStorageName); 1.3371 + if (NS_FAILED(rv)) { 1.3372 + return nullptr; 1.3373 + } 1.3374 + return ds.forget(); 1.3375 + } 1.3376 + } 1.3377 + return nullptr; 1.3378 +} 1.3379 + 1.3380 +// static 1.3381 +void 1.3382 +nsDOMDeviceStorage::GetDefaultStorageName(const nsAString& aStorageType, 1.3383 + nsAString& aStorageName) 1.3384 +{ 1.3385 + // See if the preferred volume is available. 1.3386 + nsRefPtr<nsDOMDeviceStorage> ds; 1.3387 + nsAdoptingString prefStorageName = 1.3388 + mozilla::Preferences::GetString("device.storage.writable.name"); 1.3389 + if (prefStorageName) { 1.3390 + aStorageName = prefStorageName; 1.3391 + return; 1.3392 + } 1.3393 + 1.3394 + // No preferred storage, we'll use the first one (which should be sdcard). 1.3395 + 1.3396 + VolumeNameArray volNames; 1.3397 + GetOrderedVolumeNames(volNames); 1.3398 + if (volNames.Length() > 0) { 1.3399 + aStorageName = volNames[0]; 1.3400 + return; 1.3401 + } 1.3402 + 1.3403 + // No volumes available, return the empty string. This is normal for 1.3404 + // b2g-desktop. 1.3405 + aStorageName.Truncate(); 1.3406 +} 1.3407 + 1.3408 +bool 1.3409 +nsDOMDeviceStorage::IsAvailable() 1.3410 +{ 1.3411 + DeviceStorageFile dsf(mStorageType, mStorageName); 1.3412 + return dsf.IsAvailable(); 1.3413 +} 1.3414 + 1.3415 +NS_IMETHODIMP 1.3416 +nsDOMDeviceStorage::Add(nsIDOMBlob *aBlob, nsIDOMDOMRequest * *_retval) 1.3417 +{ 1.3418 + ErrorResult rv; 1.3419 + nsRefPtr<DOMRequest> request = Add(aBlob, rv); 1.3420 + request.forget(_retval); 1.3421 + return rv.ErrorCode(); 1.3422 +} 1.3423 + 1.3424 +already_AddRefed<DOMRequest> 1.3425 +nsDOMDeviceStorage::Add(nsIDOMBlob* aBlob, ErrorResult& aRv) 1.3426 +{ 1.3427 + if (!aBlob) { 1.3428 + return nullptr; 1.3429 + } 1.3430 + 1.3431 + nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID); 1.3432 + if (!mimeSvc) { 1.3433 + aRv.Throw(NS_ERROR_FAILURE); 1.3434 + return nullptr; 1.3435 + } 1.3436 + 1.3437 + // if mimeType isn't set, we will not get a correct 1.3438 + // extension, and AddNamed() will fail. This will post an 1.3439 + // onerror to the requestee. 1.3440 + nsString mimeType; 1.3441 + aBlob->GetType(mimeType); 1.3442 + 1.3443 + nsCString extension; 1.3444 + mimeSvc->GetPrimaryExtension(NS_LossyConvertUTF16toASCII(mimeType), 1.3445 + EmptyCString(), extension); 1.3446 + // if extension is null here, we will ignore it for now. 1.3447 + // AddNamed() will check the file path and fail. This 1.3448 + // will post an onerror to the requestee. 1.3449 + 1.3450 + // possible race here w/ unique filename 1.3451 + char buffer[32]; 1.3452 + NS_MakeRandomString(buffer, ArrayLength(buffer) - 1); 1.3453 + 1.3454 + nsAutoCString path; 1.3455 + path.Assign(nsDependentCString(buffer)); 1.3456 + path.Append("."); 1.3457 + path.Append(extension); 1.3458 + 1.3459 + return AddNamed(aBlob, NS_ConvertASCIItoUTF16(path), aRv); 1.3460 +} 1.3461 + 1.3462 +NS_IMETHODIMP 1.3463 +nsDOMDeviceStorage::AddNamed(nsIDOMBlob *aBlob, 1.3464 + const nsAString & aPath, 1.3465 + nsIDOMDOMRequest * *_retval) 1.3466 +{ 1.3467 + ErrorResult rv; 1.3468 + nsRefPtr<DOMRequest> request = AddNamed(aBlob, aPath, rv); 1.3469 + request.forget(_retval); 1.3470 + return rv.ErrorCode(); 1.3471 +} 1.3472 + 1.3473 +already_AddRefed<DOMRequest> 1.3474 +nsDOMDeviceStorage::AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath, 1.3475 + ErrorResult& aRv) 1.3476 +{ 1.3477 + MOZ_ASSERT(NS_IsMainThread()); 1.3478 + 1.3479 + // if the blob is null here, bail 1.3480 + if (!aBlob) { 1.3481 + return nullptr; 1.3482 + } 1.3483 + 1.3484 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3485 + if (!win) { 1.3486 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3487 + return nullptr; 1.3488 + } 1.3489 + 1.3490 + DeviceStorageTypeChecker* typeChecker 1.3491 + = DeviceStorageTypeChecker::CreateOrGet(); 1.3492 + if (!typeChecker) { 1.3493 + aRv.Throw(NS_ERROR_FAILURE); 1.3494 + return nullptr; 1.3495 + } 1.3496 + 1.3497 + nsCOMPtr<nsIRunnable> r; 1.3498 + nsresult rv; 1.3499 + 1.3500 + if (IsFullPath(aPath)) { 1.3501 + nsString storagePath; 1.3502 + nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); 1.3503 + if (!ds) { 1.3504 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3505 + r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); 1.3506 + rv = NS_DispatchToCurrentThread(r); 1.3507 + if (NS_FAILED(rv)) { 1.3508 + aRv.Throw(rv); 1.3509 + } 1.3510 + return request.forget(); 1.3511 + } 1.3512 + return ds->AddNamed(aBlob, storagePath, aRv); 1.3513 + } 1.3514 + 1.3515 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3516 + 1.3517 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3518 + mStorageName, 1.3519 + aPath); 1.3520 + if (!dsf->IsSafePath()) { 1.3521 + r = new PostErrorEvent(request, POST_ERROR_EVENT_PERMISSION_DENIED); 1.3522 + } else if (!typeChecker->Check(mStorageType, dsf->mFile) || 1.3523 + !typeChecker->Check(mStorageType, aBlob)) { 1.3524 + r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE); 1.3525 + } else { 1.3526 + r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_CREATE, 1.3527 + win, mPrincipal, dsf, request, aBlob); 1.3528 + } 1.3529 + 1.3530 + rv = NS_DispatchToCurrentThread(r); 1.3531 + if (NS_FAILED(rv)) { 1.3532 + aRv.Throw(rv); 1.3533 + } 1.3534 + return request.forget(); 1.3535 +} 1.3536 + 1.3537 +NS_IMETHODIMP 1.3538 +nsDOMDeviceStorage::Get(const nsAString& aPath, nsIDOMDOMRequest** aRetval) 1.3539 +{ 1.3540 + ErrorResult rv; 1.3541 + nsRefPtr<DOMRequest> request = Get(aPath, rv); 1.3542 + request.forget(aRetval); 1.3543 + return rv.ErrorCode(); 1.3544 +} 1.3545 + 1.3546 +NS_IMETHODIMP 1.3547 +nsDOMDeviceStorage::GetEditable(const nsAString& aPath, 1.3548 + nsIDOMDOMRequest** aRetval) 1.3549 +{ 1.3550 + ErrorResult rv; 1.3551 + nsRefPtr<DOMRequest> request = GetEditable(aPath, rv); 1.3552 + request.forget(aRetval); 1.3553 + return rv.ErrorCode(); 1.3554 +} 1.3555 + 1.3556 +already_AddRefed<DOMRequest> 1.3557 +nsDOMDeviceStorage::GetInternal(const nsAString& aPath, bool aEditable, 1.3558 + ErrorResult& aRv) 1.3559 +{ 1.3560 + MOZ_ASSERT(NS_IsMainThread()); 1.3561 + 1.3562 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3563 + if (!win) { 1.3564 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3565 + return nullptr; 1.3566 + } 1.3567 + 1.3568 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3569 + 1.3570 + if (IsFullPath(aPath)) { 1.3571 + nsString storagePath; 1.3572 + nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); 1.3573 + if (!ds) { 1.3574 + nsCOMPtr<nsIRunnable> r = 1.3575 + new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); 1.3576 + nsresult rv = NS_DispatchToCurrentThread(r); 1.3577 + if (NS_FAILED(rv)) { 1.3578 + aRv.Throw(rv); 1.3579 + } 1.3580 + return request.forget(); 1.3581 + } 1.3582 + ds->GetInternal(win, storagePath, request, aEditable); 1.3583 + return request.forget(); 1.3584 + } 1.3585 + GetInternal(win, aPath, request, aEditable); 1.3586 + return request.forget(); 1.3587 +} 1.3588 + 1.3589 +void 1.3590 +nsDOMDeviceStorage::GetInternal(nsPIDOMWindow *aWin, 1.3591 + const nsAString& aPath, 1.3592 + DOMRequest* aRequest, 1.3593 + bool aEditable) 1.3594 +{ 1.3595 + MOZ_ASSERT(NS_IsMainThread()); 1.3596 + 1.3597 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3598 + mStorageName, 1.3599 + aPath); 1.3600 + dsf->SetEditable(aEditable); 1.3601 + 1.3602 + nsCOMPtr<nsIRunnable> r; 1.3603 + if (!dsf->IsSafePath()) { 1.3604 + r = new PostErrorEvent(aRequest, POST_ERROR_EVENT_PERMISSION_DENIED); 1.3605 + } else { 1.3606 + r = new DeviceStorageRequest(aEditable ? DEVICE_STORAGE_REQUEST_WRITE 1.3607 + : DEVICE_STORAGE_REQUEST_READ, 1.3608 + aWin, mPrincipal, dsf, aRequest); 1.3609 + } 1.3610 + DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(r); 1.3611 + MOZ_ASSERT(NS_SUCCEEDED(rv)); 1.3612 +} 1.3613 + 1.3614 +NS_IMETHODIMP 1.3615 +nsDOMDeviceStorage::Delete(const nsAString& aPath, nsIDOMDOMRequest** aRetval) 1.3616 +{ 1.3617 + ErrorResult rv; 1.3618 + nsRefPtr<DOMRequest> request = Delete(aPath, rv); 1.3619 + request.forget(aRetval); 1.3620 + return rv.ErrorCode(); 1.3621 +} 1.3622 + 1.3623 +already_AddRefed<DOMRequest> 1.3624 +nsDOMDeviceStorage::Delete(const nsAString& aPath, ErrorResult& aRv) 1.3625 +{ 1.3626 + MOZ_ASSERT(NS_IsMainThread()); 1.3627 + 1.3628 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3629 + if (!win) { 1.3630 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3631 + return nullptr; 1.3632 + } 1.3633 + 1.3634 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3635 + 1.3636 + if (IsFullPath(aPath)) { 1.3637 + nsString storagePath; 1.3638 + nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); 1.3639 + if (!ds) { 1.3640 + nsCOMPtr<nsIRunnable> r = 1.3641 + new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); 1.3642 + nsresult rv = NS_DispatchToCurrentThread(r); 1.3643 + if (NS_FAILED(rv)) { 1.3644 + aRv.Throw(rv); 1.3645 + } 1.3646 + return request.forget(); 1.3647 + } 1.3648 + ds->DeleteInternal(win, storagePath, request); 1.3649 + return request.forget(); 1.3650 + } 1.3651 + DeleteInternal(win, aPath, request); 1.3652 + return request.forget(); 1.3653 +} 1.3654 + 1.3655 +void 1.3656 +nsDOMDeviceStorage::DeleteInternal(nsPIDOMWindow *aWin, 1.3657 + const nsAString& aPath, 1.3658 + DOMRequest* aRequest) 1.3659 +{ 1.3660 + MOZ_ASSERT(NS_IsMainThread()); 1.3661 + 1.3662 + nsCOMPtr<nsIRunnable> r; 1.3663 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3664 + mStorageName, 1.3665 + aPath); 1.3666 + if (!dsf->IsSafePath()) { 1.3667 + r = new PostErrorEvent(aRequest, POST_ERROR_EVENT_PERMISSION_DENIED); 1.3668 + } else { 1.3669 + r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_DELETE, 1.3670 + aWin, mPrincipal, dsf, aRequest); 1.3671 + } 1.3672 + DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(r); 1.3673 + MOZ_ASSERT(NS_SUCCEEDED(rv)); 1.3674 +} 1.3675 + 1.3676 +NS_IMETHODIMP 1.3677 +nsDOMDeviceStorage::FreeSpace(nsIDOMDOMRequest** aRetval) 1.3678 +{ 1.3679 + ErrorResult rv; 1.3680 + nsRefPtr<DOMRequest> request = FreeSpace(rv); 1.3681 + request.forget(aRetval); 1.3682 + return rv.ErrorCode(); 1.3683 +} 1.3684 + 1.3685 +already_AddRefed<DOMRequest> 1.3686 +nsDOMDeviceStorage::FreeSpace(ErrorResult& aRv) 1.3687 +{ 1.3688 + MOZ_ASSERT(NS_IsMainThread()); 1.3689 + 1.3690 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3691 + if (!win) { 1.3692 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3693 + return nullptr; 1.3694 + } 1.3695 + 1.3696 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3697 + 1.3698 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3699 + mStorageName); 1.3700 + nsCOMPtr<nsIRunnable> r 1.3701 + = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FREE_SPACE, 1.3702 + win, mPrincipal, dsf, request); 1.3703 + nsresult rv = NS_DispatchToCurrentThread(r); 1.3704 + if (NS_FAILED(rv)) { 1.3705 + aRv.Throw(rv); 1.3706 + } 1.3707 + return request.forget(); 1.3708 +} 1.3709 + 1.3710 +NS_IMETHODIMP 1.3711 +nsDOMDeviceStorage::UsedSpace(nsIDOMDOMRequest** aRetval) 1.3712 +{ 1.3713 + ErrorResult rv; 1.3714 + nsRefPtr<DOMRequest> request = UsedSpace(rv); 1.3715 + request.forget(aRetval); 1.3716 + return rv.ErrorCode(); 1.3717 +} 1.3718 + 1.3719 +already_AddRefed<DOMRequest> 1.3720 +nsDOMDeviceStorage::UsedSpace(ErrorResult& aRv) 1.3721 +{ 1.3722 + MOZ_ASSERT(NS_IsMainThread()); 1.3723 + 1.3724 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3725 + if (!win) { 1.3726 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3727 + return nullptr; 1.3728 + } 1.3729 + 1.3730 + DebugOnly<DeviceStorageUsedSpaceCache*> usedSpaceCache 1.3731 + = DeviceStorageUsedSpaceCache::CreateOrGet(); 1.3732 + MOZ_ASSERT(usedSpaceCache); 1.3733 + 1.3734 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3735 + 1.3736 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3737 + mStorageName); 1.3738 + nsCOMPtr<nsIRunnable> r 1.3739 + = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_USED_SPACE, 1.3740 + win, mPrincipal, dsf, request); 1.3741 + nsresult rv = NS_DispatchToCurrentThread(r); 1.3742 + if (NS_FAILED(rv)) { 1.3743 + aRv.Throw(rv); 1.3744 + } 1.3745 + return request.forget(); 1.3746 +} 1.3747 + 1.3748 +NS_IMETHODIMP 1.3749 +nsDOMDeviceStorage::Available(nsIDOMDOMRequest** aRetval) 1.3750 +{ 1.3751 + ErrorResult rv; 1.3752 + nsRefPtr<DOMRequest> request = Available(rv); 1.3753 + request.forget(aRetval); 1.3754 + return rv.ErrorCode(); 1.3755 +} 1.3756 + 1.3757 +already_AddRefed<DOMRequest> 1.3758 +nsDOMDeviceStorage::Available(ErrorResult& aRv) 1.3759 +{ 1.3760 + MOZ_ASSERT(NS_IsMainThread()); 1.3761 + 1.3762 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3763 + if (!win) { 1.3764 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3765 + return nullptr; 1.3766 + } 1.3767 + 1.3768 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3769 + 1.3770 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3771 + mStorageName); 1.3772 + nsCOMPtr<nsIRunnable> r 1.3773 + = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_AVAILABLE, 1.3774 + win, mPrincipal, dsf, request); 1.3775 + nsresult rv = NS_DispatchToCurrentThread(r); 1.3776 + if (NS_FAILED(rv)) { 1.3777 + aRv.Throw(rv); 1.3778 + } 1.3779 + return request.forget(); 1.3780 +} 1.3781 + 1.3782 +already_AddRefed<DOMRequest> 1.3783 +nsDOMDeviceStorage::StorageStatus(ErrorResult& aRv) 1.3784 +{ 1.3785 + MOZ_ASSERT(NS_IsMainThread()); 1.3786 + 1.3787 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3788 + if (!win) { 1.3789 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3790 + return nullptr; 1.3791 + } 1.3792 + 1.3793 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3794 + 1.3795 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3796 + mStorageName); 1.3797 + nsCOMPtr<nsIRunnable> r 1.3798 + = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_STATUS, 1.3799 + win, mPrincipal, dsf, request); 1.3800 + nsresult rv = NS_DispatchToCurrentThread(r); 1.3801 + if (NS_FAILED(rv)) { 1.3802 + aRv.Throw(rv); 1.3803 + } 1.3804 + return request.forget(); 1.3805 +} 1.3806 + 1.3807 +already_AddRefed<DOMRequest> 1.3808 +nsDOMDeviceStorage::Format(ErrorResult& aRv) 1.3809 +{ 1.3810 + MOZ_ASSERT(NS_IsMainThread()); 1.3811 + 1.3812 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3813 + if (!win) { 1.3814 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3815 + return nullptr; 1.3816 + } 1.3817 + 1.3818 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3819 + 1.3820 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3821 + mStorageName); 1.3822 + nsCOMPtr<nsIRunnable> r 1.3823 + = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FORMAT, 1.3824 + win, mPrincipal, dsf, request); 1.3825 + nsresult rv = NS_DispatchToCurrentThread(r); 1.3826 + if (NS_FAILED(rv)) { 1.3827 + aRv.Throw(rv); 1.3828 + } 1.3829 + return request.forget(); 1.3830 +} 1.3831 + 1.3832 +already_AddRefed<DOMRequest> 1.3833 +nsDOMDeviceStorage::Mount(ErrorResult& aRv) 1.3834 +{ 1.3835 + MOZ_ASSERT(NS_IsMainThread()); 1.3836 + 1.3837 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3838 + if (!win) { 1.3839 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3840 + return nullptr; 1.3841 + } 1.3842 + 1.3843 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3844 + 1.3845 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3846 + mStorageName); 1.3847 + nsCOMPtr<nsIRunnable> r 1.3848 + = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_MOUNT, 1.3849 + win, mPrincipal, dsf, request); 1.3850 + nsresult rv = NS_DispatchToCurrentThread(r); 1.3851 + if (NS_FAILED(rv)) { 1.3852 + aRv.Throw(rv); 1.3853 + } 1.3854 + return request.forget(); 1.3855 +} 1.3856 + 1.3857 +already_AddRefed<DOMRequest> 1.3858 +nsDOMDeviceStorage::Unmount(ErrorResult& aRv) 1.3859 +{ 1.3860 + MOZ_ASSERT(NS_IsMainThread()); 1.3861 + 1.3862 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3863 + if (!win) { 1.3864 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.3865 + return nullptr; 1.3866 + } 1.3867 + 1.3868 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3869 + 1.3870 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3871 + mStorageName); 1.3872 + nsCOMPtr<nsIRunnable> r 1.3873 + = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_UNMOUNT, 1.3874 + win, mPrincipal, dsf, request); 1.3875 + nsresult rv = NS_DispatchToCurrentThread(r); 1.3876 + if (NS_FAILED(rv)) { 1.3877 + aRv.Throw(rv); 1.3878 + } 1.3879 + return request.forget(); 1.3880 +} 1.3881 + 1.3882 +NS_IMETHODIMP 1.3883 +nsDOMDeviceStorage::CreateFileDescriptor(const nsAString& aPath, 1.3884 + DeviceStorageFileDescriptor* aDSFileDescriptor, 1.3885 + nsIDOMDOMRequest** aRequest) 1.3886 +{ 1.3887 + MOZ_ASSERT(NS_IsMainThread()); 1.3888 + MOZ_ASSERT(aDSFileDescriptor); 1.3889 + 1.3890 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.3891 + if (!win) { 1.3892 + return NS_ERROR_UNEXPECTED; 1.3893 + } 1.3894 + 1.3895 + DeviceStorageTypeChecker* typeChecker 1.3896 + = DeviceStorageTypeChecker::CreateOrGet(); 1.3897 + if (!typeChecker) { 1.3898 + return NS_ERROR_FAILURE; 1.3899 + } 1.3900 + 1.3901 + nsCOMPtr<nsIRunnable> r; 1.3902 + nsresult rv; 1.3903 + 1.3904 + if (IsFullPath(aPath)) { 1.3905 + nsString storagePath; 1.3906 + nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); 1.3907 + if (!ds) { 1.3908 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3909 + r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); 1.3910 + rv = NS_DispatchToCurrentThread(r); 1.3911 + if (NS_FAILED(rv)) { 1.3912 + return rv; 1.3913 + } 1.3914 + request.forget(aRequest); 1.3915 + return NS_OK; 1.3916 + } 1.3917 + return ds->CreateFileDescriptor(storagePath, aDSFileDescriptor, aRequest); 1.3918 + } 1.3919 + 1.3920 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.3921 + 1.3922 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.3923 + mStorageName, 1.3924 + aPath); 1.3925 + if (!dsf->IsSafePath()) { 1.3926 + r = new PostErrorEvent(request, POST_ERROR_EVENT_PERMISSION_DENIED); 1.3927 + } else if (!typeChecker->Check(mStorageType, dsf->mFile)) { 1.3928 + r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE); 1.3929 + } else { 1.3930 + r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_CREATEFD, 1.3931 + win, mPrincipal, dsf, request, 1.3932 + aDSFileDescriptor); 1.3933 + } 1.3934 + 1.3935 + rv = NS_DispatchToCurrentThread(r); 1.3936 + if (NS_FAILED(rv)) { 1.3937 + return rv; 1.3938 + } 1.3939 + request.forget(aRequest); 1.3940 + return NS_OK; 1.3941 +} 1.3942 + 1.3943 +bool 1.3944 +nsDOMDeviceStorage::Default() 1.3945 +{ 1.3946 + nsString defaultStorageName; 1.3947 + GetDefaultStorageName(mStorageType, defaultStorageName); 1.3948 + return mStorageName.Equals(defaultStorageName); 1.3949 +} 1.3950 + 1.3951 +already_AddRefed<Promise> 1.3952 +nsDOMDeviceStorage::GetRoot() 1.3953 +{ 1.3954 + if (!mFileSystem) { 1.3955 + mFileSystem = new DeviceStorageFileSystem(mStorageType, mStorageName); 1.3956 + mFileSystem->Init(this); 1.3957 + } 1.3958 + return mozilla::dom::Directory::GetRoot(mFileSystem); 1.3959 +} 1.3960 + 1.3961 +NS_IMETHODIMP 1.3962 +nsDOMDeviceStorage::GetDefault(bool* aDefault) 1.3963 +{ 1.3964 + *aDefault = Default(); 1.3965 + return NS_OK; 1.3966 +} 1.3967 + 1.3968 +NS_IMETHODIMP 1.3969 +nsDOMDeviceStorage::GetStorageName(nsAString& aStorageName) 1.3970 +{ 1.3971 + aStorageName = mStorageName; 1.3972 + return NS_OK; 1.3973 +} 1.3974 + 1.3975 +already_AddRefed<DOMCursor> 1.3976 +nsDOMDeviceStorage::Enumerate(const nsAString& aPath, 1.3977 + const EnumerationParameters& aOptions, 1.3978 + ErrorResult& aRv) 1.3979 +{ 1.3980 + return EnumerateInternal(aPath, aOptions, false, aRv); 1.3981 +} 1.3982 + 1.3983 +already_AddRefed<DOMCursor> 1.3984 +nsDOMDeviceStorage::EnumerateEditable(const nsAString& aPath, 1.3985 + const EnumerationParameters& aOptions, 1.3986 + ErrorResult& aRv) 1.3987 +{ 1.3988 + return EnumerateInternal(aPath, aOptions, true, aRv); 1.3989 +} 1.3990 + 1.3991 + 1.3992 +already_AddRefed<DOMCursor> 1.3993 +nsDOMDeviceStorage::EnumerateInternal(const nsAString& aPath, 1.3994 + const EnumerationParameters& aOptions, 1.3995 + bool aEditable, ErrorResult& aRv) 1.3996 +{ 1.3997 + MOZ_ASSERT(NS_IsMainThread()); 1.3998 + 1.3999 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.4000 + if (!win) { 1.4001 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.4002 + return nullptr; 1.4003 + } 1.4004 + 1.4005 + PRTime since = 0; 1.4006 + if (aOptions.mSince.WasPassed() && !aOptions.mSince.Value().IsUndefined()) { 1.4007 + since = PRTime(aOptions.mSince.Value().TimeStamp()); 1.4008 + } 1.4009 + 1.4010 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.4011 + mStorageName, 1.4012 + aPath, 1.4013 + EmptyString()); 1.4014 + dsf->SetEditable(aEditable); 1.4015 + 1.4016 + nsRefPtr<nsDOMDeviceStorageCursor> cursor 1.4017 + = new nsDOMDeviceStorageCursor(win, mPrincipal, dsf, since); 1.4018 + nsRefPtr<DeviceStorageCursorRequest> r 1.4019 + = new DeviceStorageCursorRequest(cursor); 1.4020 + 1.4021 + if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) { 1.4022 + r->Allow(JS::UndefinedHandleValue); 1.4023 + return cursor.forget(); 1.4024 + } 1.4025 + 1.4026 + if (XRE_GetProcessType() == GeckoProcessType_Content) { 1.4027 + // because owner implements nsITabChild, we can assume that it is 1.4028 + // the one and only TabChild. 1.4029 + TabChild* child = TabChild::GetFrom(win->GetDocShell()); 1.4030 + if (!child) { 1.4031 + return cursor.forget(); 1.4032 + } 1.4033 + 1.4034 + // Retain a reference so the object isn't deleted without IPDL's knowledge. 1.4035 + // Corresponding release occurs in DeallocPContentPermissionRequest. 1.4036 + r->AddRef(); 1.4037 + 1.4038 + nsCString type; 1.4039 + aRv = DeviceStorageTypeChecker::GetPermissionForType(mStorageType, type); 1.4040 + if (aRv.Failed()) { 1.4041 + return nullptr; 1.4042 + } 1.4043 + nsTArray<PermissionRequest> permArray; 1.4044 + nsTArray<nsString> emptyOptions; 1.4045 + permArray.AppendElement(PermissionRequest(type, 1.4046 + NS_LITERAL_CSTRING("read"), 1.4047 + emptyOptions)); 1.4048 + child->SendPContentPermissionRequestConstructor(r, 1.4049 + permArray, 1.4050 + IPC::Principal(mPrincipal)); 1.4051 + 1.4052 + r->Sendprompt(); 1.4053 + 1.4054 + return cursor.forget(); 1.4055 + } 1.4056 + 1.4057 + nsCOMPtr<nsIContentPermissionPrompt> prompt 1.4058 + = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); 1.4059 + if (prompt) { 1.4060 + prompt->Prompt(r); 1.4061 + } 1.4062 + 1.4063 + return cursor.forget(); 1.4064 +} 1.4065 + 1.4066 +#ifdef MOZ_WIDGET_GONK 1.4067 +void 1.4068 +nsDOMDeviceStorage::DispatchMountChangeEvent(nsAString& aVolumeStatus) 1.4069 +{ 1.4070 + if (aVolumeStatus == mLastStatus) { 1.4071 + // We've already sent this status, don't bother sending it again. 1.4072 + return; 1.4073 + } 1.4074 + mLastStatus = aVolumeStatus; 1.4075 + 1.4076 + nsCOMPtr<nsIDOMEvent> event; 1.4077 + NS_NewDOMDeviceStorageChangeEvent(getter_AddRefs(event), this, 1.4078 + nullptr, nullptr); 1.4079 + 1.4080 + nsCOMPtr<nsIDOMDeviceStorageChangeEvent> ce = do_QueryInterface(event); 1.4081 + nsresult rv = ce->InitDeviceStorageChangeEvent(NS_LITERAL_STRING("change"), 1.4082 + true, false, 1.4083 + mStorageName, 1.4084 + aVolumeStatus); 1.4085 + if (NS_FAILED(rv)) { 1.4086 + return; 1.4087 + } 1.4088 + 1.4089 + bool ignore; 1.4090 + DispatchEvent(ce, &ignore); 1.4091 +} 1.4092 +#endif 1.4093 + 1.4094 +NS_IMETHODIMP 1.4095 +nsDOMDeviceStorage::Observe(nsISupports *aSubject, 1.4096 + const char *aTopic, 1.4097 + const char16_t *aData) 1.4098 +{ 1.4099 + MOZ_ASSERT(NS_IsMainThread()); 1.4100 + 1.4101 + if (!strcmp(aTopic, "file-watcher-update")) { 1.4102 + 1.4103 + DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject); 1.4104 + Notify(NS_ConvertUTF16toUTF8(aData).get(), file); 1.4105 + return NS_OK; 1.4106 + } 1.4107 + if (!strcmp(aTopic, "disk-space-watcher")) { 1.4108 + // 'disk-space-watcher' notifications are sent when there is a modification 1.4109 + // of a file in a specific location while a low device storage situation 1.4110 + // exists or after recovery of a low storage situation. For Firefox OS, 1.4111 + // these notifications are specific for apps storage. 1.4112 + nsRefPtr<DeviceStorageFile> file = 1.4113 + new DeviceStorageFile(mStorageType, mStorageName); 1.4114 + if (!strcmp(NS_ConvertUTF16toUTF8(aData).get(), "full")) { 1.4115 + Notify("low-disk-space", file); 1.4116 + } else if (!strcmp(NS_ConvertUTF16toUTF8(aData).get(), "free")) { 1.4117 + Notify("available-disk-space", file); 1.4118 + } 1.4119 + return NS_OK; 1.4120 + } 1.4121 + 1.4122 +#ifdef MOZ_WIDGET_GONK 1.4123 + else if (!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) { 1.4124 + // We invalidate the used space cache for the volume that actually changed 1.4125 + // state. 1.4126 + nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject); 1.4127 + if (!vol) { 1.4128 + return NS_OK; 1.4129 + } 1.4130 + nsString volName; 1.4131 + vol->GetName(volName); 1.4132 + 1.4133 + DeviceStorageUsedSpaceCache* usedSpaceCache 1.4134 + = DeviceStorageUsedSpaceCache::CreateOrGet(); 1.4135 + MOZ_ASSERT(usedSpaceCache); 1.4136 + usedSpaceCache->Invalidate(volName); 1.4137 + 1.4138 + if (!volName.Equals(mStorageName)) { 1.4139 + // Not our volume - we can ignore. 1.4140 + return NS_OK; 1.4141 + } 1.4142 + 1.4143 + DeviceStorageFile dsf(mStorageType, mStorageName); 1.4144 + nsString status; 1.4145 + dsf.GetStatus(status); 1.4146 + DispatchMountChangeEvent(status); 1.4147 + return NS_OK; 1.4148 + } 1.4149 +#endif 1.4150 + return NS_OK; 1.4151 +} 1.4152 + 1.4153 +nsresult 1.4154 +nsDOMDeviceStorage::Notify(const char* aReason, DeviceStorageFile* aFile) 1.4155 +{ 1.4156 + if (!mAllowedToWatchFile) { 1.4157 + return NS_OK; 1.4158 + } 1.4159 + 1.4160 + if (!mStorageType.Equals(aFile->mStorageType) || 1.4161 + !mStorageName.Equals(aFile->mStorageName)) { 1.4162 + // Ignore this 1.4163 + return NS_OK; 1.4164 + } 1.4165 + 1.4166 + nsCOMPtr<nsIDOMEvent> event; 1.4167 + NS_NewDOMDeviceStorageChangeEvent(getter_AddRefs(event), this, 1.4168 + nullptr, nullptr); 1.4169 + 1.4170 + nsCOMPtr<nsIDOMDeviceStorageChangeEvent> ce = do_QueryInterface(event); 1.4171 + 1.4172 + nsString reason; 1.4173 + reason.AssignWithConversion(aReason); 1.4174 + 1.4175 + nsString fullPath; 1.4176 + aFile->GetFullPath(fullPath); 1.4177 + nsresult rv = ce->InitDeviceStorageChangeEvent(NS_LITERAL_STRING("change"), 1.4178 + true, false, fullPath, 1.4179 + reason); 1.4180 + NS_ENSURE_SUCCESS(rv, rv); 1.4181 + 1.4182 + bool ignore; 1.4183 + DispatchEvent(ce, &ignore); 1.4184 + return NS_OK; 1.4185 +} 1.4186 + 1.4187 +NS_IMETHODIMP 1.4188 +nsDOMDeviceStorage::AddEventListener(const nsAString & aType, 1.4189 + nsIDOMEventListener *aListener, 1.4190 + bool aUseCapture, 1.4191 + bool aWantsUntrusted, 1.4192 + uint8_t aArgc) 1.4193 +{ 1.4194 + MOZ_ASSERT(NS_IsMainThread()); 1.4195 + 1.4196 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.4197 + if (!win) { 1.4198 + return NS_ERROR_UNEXPECTED; 1.4199 + } 1.4200 + 1.4201 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.4202 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.4203 + mStorageName); 1.4204 + nsCOMPtr<nsIRunnable> r 1.4205 + = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH, 1.4206 + win, mPrincipal, dsf, request, this); 1.4207 + nsresult rv = NS_DispatchToCurrentThread(r); 1.4208 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.4209 + return rv; 1.4210 + } 1.4211 + 1.4212 + return DOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, 1.4213 + aWantsUntrusted, aArgc); 1.4214 +} 1.4215 + 1.4216 +void 1.4217 +nsDOMDeviceStorage::AddEventListener(const nsAString & aType, 1.4218 + EventListener *aListener, 1.4219 + bool aUseCapture, 1.4220 + const Nullable<bool>& aWantsUntrusted, 1.4221 + ErrorResult& aRv) 1.4222 +{ 1.4223 + MOZ_ASSERT(NS_IsMainThread()); 1.4224 + 1.4225 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.4226 + if (!win) { 1.4227 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.4228 + return; 1.4229 + } 1.4230 + 1.4231 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.4232 + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, 1.4233 + mStorageName); 1.4234 + nsCOMPtr<nsIRunnable> r 1.4235 + = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH, 1.4236 + win, mPrincipal, dsf, request, this); 1.4237 + nsresult rv = NS_DispatchToCurrentThread(r); 1.4238 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.4239 + return; 1.4240 + } 1.4241 + DOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, 1.4242 + aWantsUntrusted, aRv); 1.4243 +} 1.4244 + 1.4245 +NS_IMETHODIMP 1.4246 +nsDOMDeviceStorage::AddSystemEventListener(const nsAString & aType, 1.4247 + nsIDOMEventListener *aListener, 1.4248 + bool aUseCapture, 1.4249 + bool aWantsUntrusted, 1.4250 + uint8_t aArgc) 1.4251 +{ 1.4252 + if (!mIsWatchingFile) { 1.4253 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.4254 + obs->AddObserver(this, "file-watcher-update", false); 1.4255 + mIsWatchingFile = true; 1.4256 + } 1.4257 + 1.4258 + return nsDOMDeviceStorage::AddEventListener(aType, aListener, aUseCapture, 1.4259 + aWantsUntrusted, aArgc); 1.4260 +} 1.4261 + 1.4262 +NS_IMETHODIMP 1.4263 +nsDOMDeviceStorage::RemoveEventListener(const nsAString & aType, 1.4264 + nsIDOMEventListener *aListener, 1.4265 + bool aUseCapture) 1.4266 +{ 1.4267 + DOMEventTargetHelper::RemoveEventListener(aType, aListener, false); 1.4268 + 1.4269 + if (mIsWatchingFile && !HasListenersFor(nsGkAtoms::onchange)) { 1.4270 + mIsWatchingFile = false; 1.4271 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.4272 + obs->RemoveObserver(this, "file-watcher-update"); 1.4273 + } 1.4274 + return NS_OK; 1.4275 +} 1.4276 + 1.4277 +void 1.4278 +nsDOMDeviceStorage::RemoveEventListener(const nsAString& aType, 1.4279 + EventListener* aListener, 1.4280 + bool aCapture, 1.4281 + ErrorResult& aRv) 1.4282 +{ 1.4283 + DOMEventTargetHelper::RemoveEventListener(aType, aListener, aCapture, aRv); 1.4284 + 1.4285 + if (mIsWatchingFile && !HasListenersFor(nsGkAtoms::onchange)) { 1.4286 + mIsWatchingFile = false; 1.4287 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.4288 + obs->RemoveObserver(this, "file-watcher-update"); 1.4289 + } 1.4290 +} 1.4291 + 1.4292 +NS_IMETHODIMP 1.4293 +nsDOMDeviceStorage::RemoveSystemEventListener(const nsAString & aType, 1.4294 + nsIDOMEventListener *aListener, 1.4295 + bool aUseCapture) 1.4296 +{ 1.4297 + return nsDOMDeviceStorage::RemoveEventListener(aType, aListener, aUseCapture); 1.4298 +} 1.4299 + 1.4300 +NS_IMETHODIMP 1.4301 +nsDOMDeviceStorage::DispatchEvent(nsIDOMEvent *aEvt, 1.4302 + bool *aRetval) 1.4303 +{ 1.4304 + return DOMEventTargetHelper::DispatchEvent(aEvt, aRetval); 1.4305 +} 1.4306 + 1.4307 +EventTarget* 1.4308 +nsDOMDeviceStorage::GetTargetForDOMEvent() 1.4309 +{ 1.4310 + return DOMEventTargetHelper::GetTargetForDOMEvent(); 1.4311 +} 1.4312 + 1.4313 +EventTarget * 1.4314 +nsDOMDeviceStorage::GetTargetForEventTargetChain() 1.4315 +{ 1.4316 + return DOMEventTargetHelper::GetTargetForEventTargetChain(); 1.4317 +} 1.4318 + 1.4319 +nsresult 1.4320 +nsDOMDeviceStorage::PreHandleEvent(EventChainPreVisitor& aVisitor) 1.4321 +{ 1.4322 + return DOMEventTargetHelper::PreHandleEvent(aVisitor); 1.4323 +} 1.4324 + 1.4325 +nsresult 1.4326 +nsDOMDeviceStorage::WillHandleEvent(EventChainPostVisitor& aVisitor) 1.4327 +{ 1.4328 + return DOMEventTargetHelper::WillHandleEvent(aVisitor); 1.4329 +} 1.4330 + 1.4331 +nsresult 1.4332 +nsDOMDeviceStorage::PostHandleEvent(EventChainPostVisitor& aVisitor) 1.4333 +{ 1.4334 + return DOMEventTargetHelper::PostHandleEvent(aVisitor); 1.4335 +} 1.4336 + 1.4337 +nsresult 1.4338 +nsDOMDeviceStorage::DispatchDOMEvent(WidgetEvent* aEvent, 1.4339 + nsIDOMEvent* aDOMEvent, 1.4340 + nsPresContext* aPresContext, 1.4341 + nsEventStatus* aEventStatus) 1.4342 +{ 1.4343 + return DOMEventTargetHelper::DispatchDOMEvent(aEvent, 1.4344 + aDOMEvent, 1.4345 + aPresContext, 1.4346 + aEventStatus); 1.4347 +} 1.4348 + 1.4349 +EventListenerManager* 1.4350 +nsDOMDeviceStorage::GetOrCreateListenerManager() 1.4351 +{ 1.4352 + return DOMEventTargetHelper::GetOrCreateListenerManager(); 1.4353 +} 1.4354 + 1.4355 +EventListenerManager* 1.4356 +nsDOMDeviceStorage::GetExistingListenerManager() const 1.4357 +{ 1.4358 + return DOMEventTargetHelper::GetExistingListenerManager(); 1.4359 +} 1.4360 + 1.4361 +nsIScriptContext * 1.4362 +nsDOMDeviceStorage::GetContextForEventHandlers(nsresult *aRv) 1.4363 +{ 1.4364 + return DOMEventTargetHelper::GetContextForEventHandlers(aRv); 1.4365 +} 1.4366 + 1.4367 +JSContext * 1.4368 +nsDOMDeviceStorage::GetJSContextForEventHandlers() 1.4369 +{ 1.4370 + return DOMEventTargetHelper::GetJSContextForEventHandlers(); 1.4371 +} 1.4372 + 1.4373 +NS_IMPL_EVENT_HANDLER(nsDOMDeviceStorage, change)