Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 sw=2 et tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 5 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "nsDeviceStorage.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "mozilla/Attributes.h" |
michael@0 | 10 | #include "mozilla/ClearOnShutdown.h" |
michael@0 | 11 | #include "mozilla/DebugOnly.h" |
michael@0 | 12 | #include "mozilla/dom/ContentChild.h" |
michael@0 | 13 | #include "mozilla/dom/DeviceStorageBinding.h" |
michael@0 | 14 | #include "mozilla/dom/DeviceStorageFileSystem.h" |
michael@0 | 15 | #include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h" |
michael@0 | 16 | #include "mozilla/dom/Directory.h" |
michael@0 | 17 | #include "mozilla/dom/FileSystemUtils.h" |
michael@0 | 18 | #include "mozilla/dom/ipc/Blob.h" |
michael@0 | 19 | #include "mozilla/dom/PBrowserChild.h" |
michael@0 | 20 | #include "mozilla/dom/PContentPermissionRequestChild.h" |
michael@0 | 21 | #include "mozilla/dom/PermissionMessageUtils.h" |
michael@0 | 22 | #include "mozilla/dom/Promise.h" |
michael@0 | 23 | #include "mozilla/EventDispatcher.h" |
michael@0 | 24 | #include "mozilla/EventListenerManager.h" |
michael@0 | 25 | #include "mozilla/LazyIdleThread.h" |
michael@0 | 26 | #include "mozilla/Preferences.h" |
michael@0 | 27 | #include "mozilla/Scoped.h" |
michael@0 | 28 | #include "mozilla/Services.h" |
michael@0 | 29 | |
michael@0 | 30 | #include "nsAutoPtr.h" |
michael@0 | 31 | #include "nsServiceManagerUtils.h" |
michael@0 | 32 | #include "nsIFile.h" |
michael@0 | 33 | #include "nsIDirectoryEnumerator.h" |
michael@0 | 34 | #include "nsAppDirectoryServiceDefs.h" |
michael@0 | 35 | #include "nsDirectoryServiceDefs.h" |
michael@0 | 36 | #include "nsIDOMFile.h" |
michael@0 | 37 | #include "nsDOMBlobBuilder.h" |
michael@0 | 38 | #include "nsNetUtil.h" |
michael@0 | 39 | #include "nsCycleCollectionParticipant.h" |
michael@0 | 40 | #include "nsIPrincipal.h" |
michael@0 | 41 | #include "nsJSUtils.h" |
michael@0 | 42 | #include "nsContentUtils.h" |
michael@0 | 43 | #include "nsCxPusher.h" |
michael@0 | 44 | #include "nsXULAppAPI.h" |
michael@0 | 45 | #include "TabChild.h" |
michael@0 | 46 | #include "DeviceStorageFileDescriptor.h" |
michael@0 | 47 | #include "DeviceStorageRequestChild.h" |
michael@0 | 48 | #include "nsIDOMDeviceStorageChangeEvent.h" |
michael@0 | 49 | #include "nsCRT.h" |
michael@0 | 50 | #include "nsIObserverService.h" |
michael@0 | 51 | #include "GeneratedEvents.h" |
michael@0 | 52 | #include "nsIMIMEService.h" |
michael@0 | 53 | #include "nsCExternalHandlerService.h" |
michael@0 | 54 | #include "nsIPermissionManager.h" |
michael@0 | 55 | #include "nsIStringBundle.h" |
michael@0 | 56 | #include "nsIDocument.h" |
michael@0 | 57 | #include "nsPrintfCString.h" |
michael@0 | 58 | #include <algorithm> |
michael@0 | 59 | #include "private/pprio.h" |
michael@0 | 60 | #include "nsContentPermissionHelper.h" |
michael@0 | 61 | |
michael@0 | 62 | #include "mozilla/dom/DeviceStorageBinding.h" |
michael@0 | 63 | |
michael@0 | 64 | // Microsoft's API Name hackery sucks |
michael@0 | 65 | #undef CreateEvent |
michael@0 | 66 | |
michael@0 | 67 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 68 | #include "nsIVolume.h" |
michael@0 | 69 | #include "nsIVolumeService.h" |
michael@0 | 70 | #endif |
michael@0 | 71 | |
michael@0 | 72 | #define DEVICESTORAGE_PROPERTIES \ |
michael@0 | 73 | "chrome://global/content/devicestorage.properties" |
michael@0 | 74 | #define DEFAULT_THREAD_TIMEOUT_MS 30000 |
michael@0 | 75 | |
michael@0 | 76 | using namespace mozilla; |
michael@0 | 77 | using namespace mozilla::dom; |
michael@0 | 78 | using namespace mozilla::dom::devicestorage; |
michael@0 | 79 | using namespace mozilla::ipc; |
michael@0 | 80 | |
michael@0 | 81 | #include "nsDirectoryServiceDefs.h" |
michael@0 | 82 | |
michael@0 | 83 | namespace mozilla { |
michael@0 | 84 | MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, PR_Close); |
michael@0 | 85 | } |
michael@0 | 86 | |
michael@0 | 87 | StaticAutoPtr<DeviceStorageUsedSpaceCache> |
michael@0 | 88 | DeviceStorageUsedSpaceCache::sDeviceStorageUsedSpaceCache; |
michael@0 | 89 | |
michael@0 | 90 | DeviceStorageUsedSpaceCache::DeviceStorageUsedSpaceCache() |
michael@0 | 91 | { |
michael@0 | 92 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 93 | |
michael@0 | 94 | mIOThread = new LazyIdleThread( |
michael@0 | 95 | DEFAULT_THREAD_TIMEOUT_MS, |
michael@0 | 96 | NS_LITERAL_CSTRING("DeviceStorageUsedSpaceCache I/O")); |
michael@0 | 97 | |
michael@0 | 98 | } |
michael@0 | 99 | |
michael@0 | 100 | DeviceStorageUsedSpaceCache::~DeviceStorageUsedSpaceCache() |
michael@0 | 101 | { |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | DeviceStorageUsedSpaceCache* |
michael@0 | 105 | DeviceStorageUsedSpaceCache::CreateOrGet() |
michael@0 | 106 | { |
michael@0 | 107 | if (sDeviceStorageUsedSpaceCache) { |
michael@0 | 108 | return sDeviceStorageUsedSpaceCache; |
michael@0 | 109 | } |
michael@0 | 110 | |
michael@0 | 111 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 112 | |
michael@0 | 113 | sDeviceStorageUsedSpaceCache = new DeviceStorageUsedSpaceCache(); |
michael@0 | 114 | ClearOnShutdown(&sDeviceStorageUsedSpaceCache); |
michael@0 | 115 | return sDeviceStorageUsedSpaceCache; |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | already_AddRefed<DeviceStorageUsedSpaceCache::CacheEntry> |
michael@0 | 119 | DeviceStorageUsedSpaceCache::GetCacheEntry(const nsAString& aStorageName) |
michael@0 | 120 | { |
michael@0 | 121 | nsTArray<nsRefPtr<CacheEntry>>::size_type numEntries = mCacheEntries.Length(); |
michael@0 | 122 | nsTArray<nsRefPtr<CacheEntry>>::index_type i; |
michael@0 | 123 | for (i = 0; i < numEntries; i++) { |
michael@0 | 124 | nsRefPtr<CacheEntry>& cacheEntry = mCacheEntries[i]; |
michael@0 | 125 | if (cacheEntry->mStorageName.Equals(aStorageName)) { |
michael@0 | 126 | nsRefPtr<CacheEntry> addRefedCacheEntry = cacheEntry; |
michael@0 | 127 | return addRefedCacheEntry.forget(); |
michael@0 | 128 | } |
michael@0 | 129 | } |
michael@0 | 130 | return nullptr; |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | static int64_t |
michael@0 | 134 | GetFreeBytes(const nsAString& aStorageName) |
michael@0 | 135 | { |
michael@0 | 136 | // This function makes the assumption that the various types |
michael@0 | 137 | // are all stored on the same filesystem. So we use pictures. |
michael@0 | 138 | |
michael@0 | 139 | DeviceStorageFile dsf(NS_LITERAL_STRING(DEVICESTORAGE_PICTURES), |
michael@0 | 140 | aStorageName); |
michael@0 | 141 | int64_t freeBytes = 0; |
michael@0 | 142 | dsf.GetDiskFreeSpace(&freeBytes); |
michael@0 | 143 | return freeBytes; |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | nsresult |
michael@0 | 147 | DeviceStorageUsedSpaceCache::AccumUsedSizes(const nsAString& aStorageName, |
michael@0 | 148 | uint64_t* aPicturesSoFar, |
michael@0 | 149 | uint64_t* aVideosSoFar, |
michael@0 | 150 | uint64_t* aMusicSoFar, |
michael@0 | 151 | uint64_t* aTotalSoFar) |
michael@0 | 152 | { |
michael@0 | 153 | nsRefPtr<CacheEntry> cacheEntry = GetCacheEntry(aStorageName); |
michael@0 | 154 | if (!cacheEntry || cacheEntry->mDirty) { |
michael@0 | 155 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 156 | } |
michael@0 | 157 | int64_t freeBytes = GetFreeBytes(cacheEntry->mStorageName); |
michael@0 | 158 | if (freeBytes != cacheEntry->mFreeBytes) { |
michael@0 | 159 | // Free space changed, so our cached results are no longer valid. |
michael@0 | 160 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | *aPicturesSoFar += cacheEntry->mPicturesUsedSize; |
michael@0 | 164 | *aVideosSoFar += cacheEntry->mVideosUsedSize; |
michael@0 | 165 | *aMusicSoFar += cacheEntry->mMusicUsedSize; |
michael@0 | 166 | *aTotalSoFar += cacheEntry->mTotalUsedSize; |
michael@0 | 167 | |
michael@0 | 168 | return NS_OK; |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | void |
michael@0 | 172 | DeviceStorageUsedSpaceCache::SetUsedSizes(const nsAString& aStorageName, |
michael@0 | 173 | uint64_t aPictureSize, |
michael@0 | 174 | uint64_t aVideosSize, |
michael@0 | 175 | uint64_t aMusicSize, |
michael@0 | 176 | uint64_t aTotalUsedSize) |
michael@0 | 177 | { |
michael@0 | 178 | nsRefPtr<CacheEntry> cacheEntry = GetCacheEntry(aStorageName); |
michael@0 | 179 | if (!cacheEntry) { |
michael@0 | 180 | cacheEntry = new CacheEntry; |
michael@0 | 181 | cacheEntry->mStorageName = aStorageName; |
michael@0 | 182 | mCacheEntries.AppendElement(cacheEntry); |
michael@0 | 183 | } |
michael@0 | 184 | cacheEntry->mFreeBytes = GetFreeBytes(cacheEntry->mStorageName); |
michael@0 | 185 | |
michael@0 | 186 | cacheEntry->mPicturesUsedSize = aPictureSize; |
michael@0 | 187 | cacheEntry->mVideosUsedSize = aVideosSize; |
michael@0 | 188 | cacheEntry->mMusicUsedSize = aMusicSize; |
michael@0 | 189 | cacheEntry->mTotalUsedSize = aTotalUsedSize; |
michael@0 | 190 | cacheEntry->mDirty = false; |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | class GlobalDirs |
michael@0 | 194 | { |
michael@0 | 195 | public: |
michael@0 | 196 | NS_INLINE_DECL_REFCOUNTING(GlobalDirs) |
michael@0 | 197 | #if !defined(MOZ_WIDGET_GONK) |
michael@0 | 198 | nsCOMPtr<nsIFile> pictures; |
michael@0 | 199 | nsCOMPtr<nsIFile> videos; |
michael@0 | 200 | nsCOMPtr<nsIFile> music; |
michael@0 | 201 | nsCOMPtr<nsIFile> sdcard; |
michael@0 | 202 | #endif |
michael@0 | 203 | nsCOMPtr<nsIFile> apps; |
michael@0 | 204 | nsCOMPtr<nsIFile> crashes; |
michael@0 | 205 | nsCOMPtr<nsIFile> overrideRootDir; |
michael@0 | 206 | }; |
michael@0 | 207 | |
michael@0 | 208 | static StaticRefPtr<GlobalDirs> sDirs; |
michael@0 | 209 | |
michael@0 | 210 | StaticAutoPtr<DeviceStorageTypeChecker> |
michael@0 | 211 | DeviceStorageTypeChecker::sDeviceStorageTypeChecker; |
michael@0 | 212 | |
michael@0 | 213 | DeviceStorageTypeChecker::DeviceStorageTypeChecker() |
michael@0 | 214 | { |
michael@0 | 215 | } |
michael@0 | 216 | |
michael@0 | 217 | DeviceStorageTypeChecker::~DeviceStorageTypeChecker() |
michael@0 | 218 | { |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | DeviceStorageTypeChecker* |
michael@0 | 222 | DeviceStorageTypeChecker::CreateOrGet() |
michael@0 | 223 | { |
michael@0 | 224 | if (sDeviceStorageTypeChecker) { |
michael@0 | 225 | return sDeviceStorageTypeChecker; |
michael@0 | 226 | } |
michael@0 | 227 | |
michael@0 | 228 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 229 | |
michael@0 | 230 | nsCOMPtr<nsIStringBundleService> stringService |
michael@0 | 231 | = mozilla::services::GetStringBundleService(); |
michael@0 | 232 | if (!stringService) { |
michael@0 | 233 | return nullptr; |
michael@0 | 234 | } |
michael@0 | 235 | |
michael@0 | 236 | nsCOMPtr<nsIStringBundle> filterBundle; |
michael@0 | 237 | if (NS_FAILED(stringService->CreateBundle(DEVICESTORAGE_PROPERTIES, |
michael@0 | 238 | getter_AddRefs(filterBundle)))) { |
michael@0 | 239 | return nullptr; |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | DeviceStorageTypeChecker* result = new DeviceStorageTypeChecker(); |
michael@0 | 243 | result->InitFromBundle(filterBundle); |
michael@0 | 244 | |
michael@0 | 245 | sDeviceStorageTypeChecker = result; |
michael@0 | 246 | ClearOnShutdown(&sDeviceStorageTypeChecker); |
michael@0 | 247 | return result; |
michael@0 | 248 | } |
michael@0 | 249 | |
michael@0 | 250 | void |
michael@0 | 251 | DeviceStorageTypeChecker::InitFromBundle(nsIStringBundle* aBundle) |
michael@0 | 252 | { |
michael@0 | 253 | aBundle->GetStringFromName( |
michael@0 | 254 | NS_ConvertASCIItoUTF16(DEVICESTORAGE_PICTURES).get(), |
michael@0 | 255 | getter_Copies(mPicturesExtensions)); |
michael@0 | 256 | aBundle->GetStringFromName( |
michael@0 | 257 | NS_ConvertASCIItoUTF16(DEVICESTORAGE_MUSIC).get(), |
michael@0 | 258 | getter_Copies(mMusicExtensions)); |
michael@0 | 259 | aBundle->GetStringFromName( |
michael@0 | 260 | NS_ConvertASCIItoUTF16(DEVICESTORAGE_VIDEOS).get(), |
michael@0 | 261 | getter_Copies(mVideosExtensions)); |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | |
michael@0 | 265 | bool |
michael@0 | 266 | DeviceStorageTypeChecker::Check(const nsAString& aType, nsIDOMBlob* aBlob) |
michael@0 | 267 | { |
michael@0 | 268 | MOZ_ASSERT(aBlob); |
michael@0 | 269 | |
michael@0 | 270 | nsString mimeType; |
michael@0 | 271 | if (NS_FAILED(aBlob->GetType(mimeType))) { |
michael@0 | 272 | return false; |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | if (aType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { |
michael@0 | 276 | return StringBeginsWith(mimeType, NS_LITERAL_STRING("image/")); |
michael@0 | 277 | } |
michael@0 | 278 | |
michael@0 | 279 | if (aType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { |
michael@0 | 280 | return StringBeginsWith(mimeType, NS_LITERAL_STRING("video/")); |
michael@0 | 281 | } |
michael@0 | 282 | |
michael@0 | 283 | if (aType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { |
michael@0 | 284 | return StringBeginsWith(mimeType, NS_LITERAL_STRING("audio/")); |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | if (aType.EqualsLiteral(DEVICESTORAGE_APPS) || |
michael@0 | 288 | aType.EqualsLiteral(DEVICESTORAGE_SDCARD) || |
michael@0 | 289 | aType.EqualsLiteral(DEVICESTORAGE_CRASHES)) { |
michael@0 | 290 | // Apps, crashes and sdcard have no restriction on mime types |
michael@0 | 291 | return true; |
michael@0 | 292 | } |
michael@0 | 293 | |
michael@0 | 294 | return false; |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | bool |
michael@0 | 298 | DeviceStorageTypeChecker::Check(const nsAString& aType, nsIFile* aFile) |
michael@0 | 299 | { |
michael@0 | 300 | MOZ_ASSERT(aFile); |
michael@0 | 301 | |
michael@0 | 302 | if (aType.EqualsLiteral(DEVICESTORAGE_APPS) || |
michael@0 | 303 | aType.EqualsLiteral(DEVICESTORAGE_SDCARD) || |
michael@0 | 304 | aType.EqualsLiteral(DEVICESTORAGE_CRASHES)) { |
michael@0 | 305 | // Apps, crashes and sdcard have no restrictions on what file extensions used. |
michael@0 | 306 | return true; |
michael@0 | 307 | } |
michael@0 | 308 | |
michael@0 | 309 | nsString path; |
michael@0 | 310 | aFile->GetPath(path); |
michael@0 | 311 | |
michael@0 | 312 | int32_t dotIdx = path.RFindChar(char16_t('.')); |
michael@0 | 313 | if (dotIdx == kNotFound) { |
michael@0 | 314 | return false; |
michael@0 | 315 | } |
michael@0 | 316 | |
michael@0 | 317 | nsAutoString extensionMatch; |
michael@0 | 318 | extensionMatch.AssignLiteral("*"); |
michael@0 | 319 | extensionMatch.Append(Substring(path, dotIdx)); |
michael@0 | 320 | extensionMatch.AppendLiteral(";"); |
michael@0 | 321 | |
michael@0 | 322 | if (aType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { |
michael@0 | 323 | return CaseInsensitiveFindInReadable(extensionMatch, mPicturesExtensions); |
michael@0 | 324 | } |
michael@0 | 325 | |
michael@0 | 326 | if (aType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { |
michael@0 | 327 | return CaseInsensitiveFindInReadable(extensionMatch, mVideosExtensions); |
michael@0 | 328 | } |
michael@0 | 329 | |
michael@0 | 330 | if (aType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { |
michael@0 | 331 | return CaseInsensitiveFindInReadable(extensionMatch, mMusicExtensions); |
michael@0 | 332 | } |
michael@0 | 333 | |
michael@0 | 334 | return false; |
michael@0 | 335 | } |
michael@0 | 336 | |
michael@0 | 337 | void |
michael@0 | 338 | DeviceStorageTypeChecker::GetTypeFromFile(nsIFile* aFile, nsAString& aType) |
michael@0 | 339 | { |
michael@0 | 340 | MOZ_ASSERT(aFile); |
michael@0 | 341 | |
michael@0 | 342 | nsString path; |
michael@0 | 343 | aFile->GetPath(path); |
michael@0 | 344 | |
michael@0 | 345 | GetTypeFromFileName(path, aType); |
michael@0 | 346 | } |
michael@0 | 347 | |
michael@0 | 348 | void |
michael@0 | 349 | DeviceStorageTypeChecker::GetTypeFromFileName(const nsAString& aFileName, |
michael@0 | 350 | nsAString& aType) |
michael@0 | 351 | { |
michael@0 | 352 | aType.AssignLiteral(DEVICESTORAGE_SDCARD); |
michael@0 | 353 | |
michael@0 | 354 | nsString fileName(aFileName); |
michael@0 | 355 | int32_t dotIdx = fileName.RFindChar(char16_t('.')); |
michael@0 | 356 | if (dotIdx == kNotFound) { |
michael@0 | 357 | return; |
michael@0 | 358 | } |
michael@0 | 359 | |
michael@0 | 360 | nsAutoString extensionMatch; |
michael@0 | 361 | extensionMatch.AssignLiteral("*"); |
michael@0 | 362 | extensionMatch.Append(Substring(aFileName, dotIdx)); |
michael@0 | 363 | extensionMatch.AppendLiteral(";"); |
michael@0 | 364 | |
michael@0 | 365 | if (CaseInsensitiveFindInReadable(extensionMatch, mPicturesExtensions)) { |
michael@0 | 366 | aType.AssignLiteral(DEVICESTORAGE_PICTURES); |
michael@0 | 367 | } |
michael@0 | 368 | else if (CaseInsensitiveFindInReadable(extensionMatch, mVideosExtensions)) { |
michael@0 | 369 | aType.AssignLiteral(DEVICESTORAGE_VIDEOS); |
michael@0 | 370 | } |
michael@0 | 371 | else if (CaseInsensitiveFindInReadable(extensionMatch, mMusicExtensions)) { |
michael@0 | 372 | aType.AssignLiteral(DEVICESTORAGE_MUSIC); |
michael@0 | 373 | } |
michael@0 | 374 | } |
michael@0 | 375 | |
michael@0 | 376 | nsresult |
michael@0 | 377 | DeviceStorageTypeChecker::GetPermissionForType(const nsAString& aType, |
michael@0 | 378 | nsACString& aPermissionResult) |
michael@0 | 379 | { |
michael@0 | 380 | if (!aType.EqualsLiteral(DEVICESTORAGE_PICTURES) && |
michael@0 | 381 | !aType.EqualsLiteral(DEVICESTORAGE_VIDEOS) && |
michael@0 | 382 | !aType.EqualsLiteral(DEVICESTORAGE_MUSIC) && |
michael@0 | 383 | !aType.EqualsLiteral(DEVICESTORAGE_APPS) && |
michael@0 | 384 | !aType.EqualsLiteral(DEVICESTORAGE_SDCARD) && |
michael@0 | 385 | !aType.EqualsLiteral(DEVICESTORAGE_CRASHES)) { |
michael@0 | 386 | // unknown type |
michael@0 | 387 | return NS_ERROR_FAILURE; |
michael@0 | 388 | } |
michael@0 | 389 | |
michael@0 | 390 | aPermissionResult.AssignLiteral("device-storage:"); |
michael@0 | 391 | aPermissionResult.Append(NS_ConvertUTF16toUTF8(aType)); |
michael@0 | 392 | return NS_OK; |
michael@0 | 393 | } |
michael@0 | 394 | |
michael@0 | 395 | nsresult |
michael@0 | 396 | DeviceStorageTypeChecker::GetAccessForRequest( |
michael@0 | 397 | const DeviceStorageRequestType aRequestType, nsACString& aAccessResult) |
michael@0 | 398 | { |
michael@0 | 399 | switch(aRequestType) { |
michael@0 | 400 | case DEVICE_STORAGE_REQUEST_READ: |
michael@0 | 401 | case DEVICE_STORAGE_REQUEST_WATCH: |
michael@0 | 402 | case DEVICE_STORAGE_REQUEST_FREE_SPACE: |
michael@0 | 403 | case DEVICE_STORAGE_REQUEST_USED_SPACE: |
michael@0 | 404 | case DEVICE_STORAGE_REQUEST_AVAILABLE: |
michael@0 | 405 | case DEVICE_STORAGE_REQUEST_STATUS: |
michael@0 | 406 | aAccessResult.AssignLiteral("read"); |
michael@0 | 407 | break; |
michael@0 | 408 | case DEVICE_STORAGE_REQUEST_WRITE: |
michael@0 | 409 | case DEVICE_STORAGE_REQUEST_DELETE: |
michael@0 | 410 | case DEVICE_STORAGE_REQUEST_FORMAT: |
michael@0 | 411 | case DEVICE_STORAGE_REQUEST_MOUNT: |
michael@0 | 412 | case DEVICE_STORAGE_REQUEST_UNMOUNT: |
michael@0 | 413 | aAccessResult.AssignLiteral("write"); |
michael@0 | 414 | break; |
michael@0 | 415 | case DEVICE_STORAGE_REQUEST_CREATE: |
michael@0 | 416 | case DEVICE_STORAGE_REQUEST_CREATEFD: |
michael@0 | 417 | aAccessResult.AssignLiteral("create"); |
michael@0 | 418 | break; |
michael@0 | 419 | default: |
michael@0 | 420 | aAccessResult.AssignLiteral("undefined"); |
michael@0 | 421 | } |
michael@0 | 422 | return NS_OK; |
michael@0 | 423 | } |
michael@0 | 424 | |
michael@0 | 425 | //static |
michael@0 | 426 | bool |
michael@0 | 427 | DeviceStorageTypeChecker::IsVolumeBased(const nsAString& aType) |
michael@0 | 428 | { |
michael@0 | 429 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 430 | // The apps and crashes aren't stored in the same place as the media, so |
michael@0 | 431 | // we only ever return a single apps object, and not an array |
michael@0 | 432 | // with one per volume (as is the case for the remaining |
michael@0 | 433 | // storage types). |
michael@0 | 434 | return !aType.EqualsLiteral(DEVICESTORAGE_APPS) && |
michael@0 | 435 | !aType.EqualsLiteral(DEVICESTORAGE_CRASHES); |
michael@0 | 436 | #else |
michael@0 | 437 | return false; |
michael@0 | 438 | #endif |
michael@0 | 439 | } |
michael@0 | 440 | |
michael@0 | 441 | NS_IMPL_ISUPPORTS(FileUpdateDispatcher, nsIObserver) |
michael@0 | 442 | |
michael@0 | 443 | mozilla::StaticRefPtr<FileUpdateDispatcher> FileUpdateDispatcher::sSingleton; |
michael@0 | 444 | |
michael@0 | 445 | FileUpdateDispatcher* |
michael@0 | 446 | FileUpdateDispatcher::GetSingleton() |
michael@0 | 447 | { |
michael@0 | 448 | if (sSingleton) { |
michael@0 | 449 | return sSingleton; |
michael@0 | 450 | } |
michael@0 | 451 | |
michael@0 | 452 | sSingleton = new FileUpdateDispatcher(); |
michael@0 | 453 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 454 | obs->AddObserver(sSingleton, "file-watcher-notify", false); |
michael@0 | 455 | ClearOnShutdown(&sSingleton); |
michael@0 | 456 | |
michael@0 | 457 | return sSingleton; |
michael@0 | 458 | } |
michael@0 | 459 | |
michael@0 | 460 | NS_IMETHODIMP |
michael@0 | 461 | FileUpdateDispatcher::Observe(nsISupports *aSubject, |
michael@0 | 462 | const char *aTopic, |
michael@0 | 463 | const char16_t *aData) |
michael@0 | 464 | { |
michael@0 | 465 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 466 | |
michael@0 | 467 | DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject); |
michael@0 | 468 | if (!file || !file->mFile) { |
michael@0 | 469 | NS_WARNING("Device storage file looks invalid!"); |
michael@0 | 470 | return NS_OK; |
michael@0 | 471 | } |
michael@0 | 472 | ContentChild::GetSingleton() |
michael@0 | 473 | ->SendFilePathUpdateNotify(file->mStorageType, |
michael@0 | 474 | file->mStorageName, |
michael@0 | 475 | file->mPath, |
michael@0 | 476 | NS_ConvertUTF16toUTF8(aData)); |
michael@0 | 477 | } else { |
michael@0 | 478 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 479 | obs->NotifyObservers(aSubject, "file-watcher-update", aData); |
michael@0 | 480 | } |
michael@0 | 481 | return NS_OK; |
michael@0 | 482 | } |
michael@0 | 483 | |
michael@0 | 484 | class IOEventComplete : public nsRunnable |
michael@0 | 485 | { |
michael@0 | 486 | public: |
michael@0 | 487 | IOEventComplete(DeviceStorageFile *aFile, const char *aType) |
michael@0 | 488 | : mFile(aFile) |
michael@0 | 489 | , mType(aType) |
michael@0 | 490 | { |
michael@0 | 491 | } |
michael@0 | 492 | |
michael@0 | 493 | ~IOEventComplete() {} |
michael@0 | 494 | |
michael@0 | 495 | NS_IMETHOD Run() |
michael@0 | 496 | { |
michael@0 | 497 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 498 | nsString data; |
michael@0 | 499 | CopyASCIItoUTF16(mType, data); |
michael@0 | 500 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 501 | |
michael@0 | 502 | obs->NotifyObservers(mFile, "file-watcher-notify", data.get()); |
michael@0 | 503 | |
michael@0 | 504 | DeviceStorageUsedSpaceCache* usedSpaceCache |
michael@0 | 505 | = DeviceStorageUsedSpaceCache::CreateOrGet(); |
michael@0 | 506 | MOZ_ASSERT(usedSpaceCache); |
michael@0 | 507 | usedSpaceCache->Invalidate(mFile->mStorageName); |
michael@0 | 508 | return NS_OK; |
michael@0 | 509 | } |
michael@0 | 510 | |
michael@0 | 511 | private: |
michael@0 | 512 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 513 | nsCString mType; |
michael@0 | 514 | }; |
michael@0 | 515 | |
michael@0 | 516 | DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, |
michael@0 | 517 | const nsAString& aStorageName, |
michael@0 | 518 | const nsAString& aRootDir, |
michael@0 | 519 | const nsAString& aPath) |
michael@0 | 520 | : mStorageType(aStorageType) |
michael@0 | 521 | , mStorageName(aStorageName) |
michael@0 | 522 | , mRootDir(aRootDir) |
michael@0 | 523 | , mPath(aPath) |
michael@0 | 524 | , mEditable(false) |
michael@0 | 525 | , mLength(UINT64_MAX) |
michael@0 | 526 | , mLastModifiedDate(UINT64_MAX) |
michael@0 | 527 | { |
michael@0 | 528 | Init(); |
michael@0 | 529 | AppendRelativePath(mRootDir); |
michael@0 | 530 | if (!mPath.EqualsLiteral("")) { |
michael@0 | 531 | AppendRelativePath(mPath); |
michael@0 | 532 | } |
michael@0 | 533 | NormalizeFilePath(); |
michael@0 | 534 | } |
michael@0 | 535 | |
michael@0 | 536 | DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, |
michael@0 | 537 | const nsAString& aStorageName, |
michael@0 | 538 | const nsAString& aPath) |
michael@0 | 539 | : mStorageType(aStorageType) |
michael@0 | 540 | , mStorageName(aStorageName) |
michael@0 | 541 | , mPath(aPath) |
michael@0 | 542 | , mEditable(false) |
michael@0 | 543 | , mLength(UINT64_MAX) |
michael@0 | 544 | , mLastModifiedDate(UINT64_MAX) |
michael@0 | 545 | { |
michael@0 | 546 | Init(); |
michael@0 | 547 | AppendRelativePath(aPath); |
michael@0 | 548 | NormalizeFilePath(); |
michael@0 | 549 | } |
michael@0 | 550 | |
michael@0 | 551 | DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, |
michael@0 | 552 | const nsAString& aStorageName) |
michael@0 | 553 | : mStorageType(aStorageType) |
michael@0 | 554 | , mStorageName(aStorageName) |
michael@0 | 555 | , mEditable(false) |
michael@0 | 556 | , mLength(UINT64_MAX) |
michael@0 | 557 | , mLastModifiedDate(UINT64_MAX) |
michael@0 | 558 | { |
michael@0 | 559 | Init(); |
michael@0 | 560 | } |
michael@0 | 561 | |
michael@0 | 562 | void |
michael@0 | 563 | DeviceStorageFile::Dump(const char* label) |
michael@0 | 564 | { |
michael@0 | 565 | nsString path; |
michael@0 | 566 | if (mFile) { |
michael@0 | 567 | mFile->GetPath(path); |
michael@0 | 568 | } else { |
michael@0 | 569 | path = NS_LITERAL_STRING("(null)"); |
michael@0 | 570 | } |
michael@0 | 571 | const char* ptStr; |
michael@0 | 572 | if (XRE_GetProcessType() == GeckoProcessType_Default) { |
michael@0 | 573 | ptStr = "parent"; |
michael@0 | 574 | } else { |
michael@0 | 575 | ptStr = "child"; |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | printf_stderr("DSF (%s) %s: mStorageType '%s' mStorageName '%s' " |
michael@0 | 579 | "mRootDir '%s' mPath '%s' mFile->GetPath '%s'\n", |
michael@0 | 580 | ptStr, label, |
michael@0 | 581 | NS_LossyConvertUTF16toASCII(mStorageType).get(), |
michael@0 | 582 | NS_LossyConvertUTF16toASCII(mStorageName).get(), |
michael@0 | 583 | NS_LossyConvertUTF16toASCII(mRootDir).get(), |
michael@0 | 584 | NS_LossyConvertUTF16toASCII(mPath).get(), |
michael@0 | 585 | NS_LossyConvertUTF16toASCII(path).get()); |
michael@0 | 586 | } |
michael@0 | 587 | |
michael@0 | 588 | void |
michael@0 | 589 | DeviceStorageFile::Init() |
michael@0 | 590 | { |
michael@0 | 591 | DeviceStorageFile::GetRootDirectoryForType(mStorageType, |
michael@0 | 592 | mStorageName, |
michael@0 | 593 | getter_AddRefs(mFile)); |
michael@0 | 594 | |
michael@0 | 595 | DebugOnly<DeviceStorageTypeChecker*> typeChecker |
michael@0 | 596 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 597 | MOZ_ASSERT(typeChecker); |
michael@0 | 598 | } |
michael@0 | 599 | |
michael@0 | 600 | // The OverrideRootDir is needed to facilitate testing of the |
michael@0 | 601 | // device.storage.overrideRootDir preference. The preference is normally |
michael@0 | 602 | // only read once during initialization, but since the test environment has |
michael@0 | 603 | // no convenient way to restart, we use a pref watcher instead. |
michael@0 | 604 | class OverrideRootDir MOZ_FINAL : public nsIObserver |
michael@0 | 605 | { |
michael@0 | 606 | public: |
michael@0 | 607 | NS_DECL_ISUPPORTS |
michael@0 | 608 | NS_DECL_NSIOBSERVER |
michael@0 | 609 | |
michael@0 | 610 | static OverrideRootDir* GetSingleton(); |
michael@0 | 611 | ~OverrideRootDir(); |
michael@0 | 612 | void Init(); |
michael@0 | 613 | private: |
michael@0 | 614 | static mozilla::StaticRefPtr<OverrideRootDir> sSingleton; |
michael@0 | 615 | }; |
michael@0 | 616 | |
michael@0 | 617 | NS_IMPL_ISUPPORTS(OverrideRootDir, nsIObserver) |
michael@0 | 618 | |
michael@0 | 619 | mozilla::StaticRefPtr<OverrideRootDir> |
michael@0 | 620 | OverrideRootDir::sSingleton; |
michael@0 | 621 | |
michael@0 | 622 | OverrideRootDir* |
michael@0 | 623 | OverrideRootDir::GetSingleton() |
michael@0 | 624 | { |
michael@0 | 625 | if (sSingleton) { |
michael@0 | 626 | return sSingleton; |
michael@0 | 627 | } |
michael@0 | 628 | // Preference changes are automatically forwarded from parent to child |
michael@0 | 629 | // in ContentParent::Observe, so we'll see the change in both the parent |
michael@0 | 630 | // and the child process. |
michael@0 | 631 | |
michael@0 | 632 | sSingleton = new OverrideRootDir(); |
michael@0 | 633 | Preferences::AddStrongObserver(sSingleton, "device.storage.overrideRootDir"); |
michael@0 | 634 | ClearOnShutdown(&sSingleton); |
michael@0 | 635 | |
michael@0 | 636 | return sSingleton; |
michael@0 | 637 | } |
michael@0 | 638 | |
michael@0 | 639 | OverrideRootDir::~OverrideRootDir() |
michael@0 | 640 | { |
michael@0 | 641 | Preferences::RemoveObserver(this, "device.storage.overrideRootDir"); |
michael@0 | 642 | } |
michael@0 | 643 | |
michael@0 | 644 | NS_IMETHODIMP |
michael@0 | 645 | OverrideRootDir::Observe(nsISupports *aSubject, |
michael@0 | 646 | const char *aTopic, |
michael@0 | 647 | const char16_t *aData) |
michael@0 | 648 | { |
michael@0 | 649 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 650 | |
michael@0 | 651 | if (sSingleton) { |
michael@0 | 652 | sSingleton->Init(); |
michael@0 | 653 | } |
michael@0 | 654 | return NS_OK; |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | void |
michael@0 | 658 | OverrideRootDir::Init() |
michael@0 | 659 | { |
michael@0 | 660 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 661 | |
michael@0 | 662 | if (!sDirs) { |
michael@0 | 663 | return; |
michael@0 | 664 | } |
michael@0 | 665 | |
michael@0 | 666 | if (mozilla::Preferences::GetBool("device.storage.testing", false)) { |
michael@0 | 667 | nsCOMPtr<nsIProperties> dirService |
michael@0 | 668 | = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); |
michael@0 | 669 | MOZ_ASSERT(dirService); |
michael@0 | 670 | dirService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile), |
michael@0 | 671 | getter_AddRefs(sDirs->overrideRootDir)); |
michael@0 | 672 | if (sDirs->overrideRootDir) { |
michael@0 | 673 | sDirs->overrideRootDir->AppendRelativeNativePath( |
michael@0 | 674 | NS_LITERAL_CSTRING("device-storage-testing")); |
michael@0 | 675 | } |
michael@0 | 676 | } else { |
michael@0 | 677 | // For users running on desktop, it's convenient to be able to override |
michael@0 | 678 | // all of the directories to point to a single tree, much like what happens |
michael@0 | 679 | // on a real device. |
michael@0 | 680 | const nsAdoptingString& overrideRootDir = |
michael@0 | 681 | mozilla::Preferences::GetString("device.storage.overrideRootDir"); |
michael@0 | 682 | if (overrideRootDir && overrideRootDir.Length() > 0) { |
michael@0 | 683 | NS_NewLocalFile(overrideRootDir, false, |
michael@0 | 684 | getter_AddRefs(sDirs->overrideRootDir)); |
michael@0 | 685 | } else { |
michael@0 | 686 | sDirs->overrideRootDir = nullptr; |
michael@0 | 687 | } |
michael@0 | 688 | } |
michael@0 | 689 | |
michael@0 | 690 | if (sDirs->overrideRootDir) { |
michael@0 | 691 | if (XRE_GetProcessType() == GeckoProcessType_Default) { |
michael@0 | 692 | // Only the parent process can create directories. In testing, because |
michael@0 | 693 | // the preference is updated after startup, its entirely possible that |
michael@0 | 694 | // the preference updated notification will be received by a child |
michael@0 | 695 | // prior to the parent. |
michael@0 | 696 | nsresult rv |
michael@0 | 697 | = sDirs->overrideRootDir->Create(nsIFile::DIRECTORY_TYPE, 0777); |
michael@0 | 698 | nsString path; |
michael@0 | 699 | sDirs->overrideRootDir->GetPath(path); |
michael@0 | 700 | if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) { |
michael@0 | 701 | nsPrintfCString msg("DeviceStorage: Unable to create directory '%s'", |
michael@0 | 702 | NS_LossyConvertUTF16toASCII(path).get()); |
michael@0 | 703 | NS_WARNING(msg.get()); |
michael@0 | 704 | } |
michael@0 | 705 | } |
michael@0 | 706 | sDirs->overrideRootDir->Normalize(); |
michael@0 | 707 | } |
michael@0 | 708 | } |
michael@0 | 709 | |
michael@0 | 710 | // Directories which don't depend on a volume should be calculated once |
michael@0 | 711 | // here. Directories which depend on the root directory of a volume |
michael@0 | 712 | // should be calculated in DeviceStorageFile::GetRootDirectoryForType. |
michael@0 | 713 | static void |
michael@0 | 714 | InitDirs() |
michael@0 | 715 | { |
michael@0 | 716 | if (sDirs) { |
michael@0 | 717 | return; |
michael@0 | 718 | } |
michael@0 | 719 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 720 | sDirs = new GlobalDirs; |
michael@0 | 721 | ClearOnShutdown(&sDirs); |
michael@0 | 722 | |
michael@0 | 723 | nsCOMPtr<nsIProperties> dirService |
michael@0 | 724 | = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); |
michael@0 | 725 | MOZ_ASSERT(dirService); |
michael@0 | 726 | |
michael@0 | 727 | #if !defined(MOZ_WIDGET_GONK) |
michael@0 | 728 | |
michael@0 | 729 | #if defined (MOZ_WIDGET_COCOA) |
michael@0 | 730 | dirService->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, |
michael@0 | 731 | NS_GET_IID(nsIFile), |
michael@0 | 732 | getter_AddRefs(sDirs->pictures)); |
michael@0 | 733 | dirService->Get(NS_OSX_MOVIE_DOCUMENTS_DIR, |
michael@0 | 734 | NS_GET_IID(nsIFile), |
michael@0 | 735 | getter_AddRefs(sDirs->videos)); |
michael@0 | 736 | dirService->Get(NS_OSX_MUSIC_DOCUMENTS_DIR, |
michael@0 | 737 | NS_GET_IID(nsIFile), |
michael@0 | 738 | getter_AddRefs(sDirs->music)); |
michael@0 | 739 | #elif defined (XP_UNIX) |
michael@0 | 740 | dirService->Get(NS_UNIX_XDG_PICTURES_DIR, |
michael@0 | 741 | NS_GET_IID(nsIFile), |
michael@0 | 742 | getter_AddRefs(sDirs->pictures)); |
michael@0 | 743 | dirService->Get(NS_UNIX_XDG_VIDEOS_DIR, |
michael@0 | 744 | NS_GET_IID(nsIFile), |
michael@0 | 745 | getter_AddRefs(sDirs->videos)); |
michael@0 | 746 | dirService->Get(NS_UNIX_XDG_MUSIC_DIR, |
michael@0 | 747 | NS_GET_IID(nsIFile), |
michael@0 | 748 | getter_AddRefs(sDirs->music)); |
michael@0 | 749 | #elif defined (XP_WIN) |
michael@0 | 750 | dirService->Get(NS_WIN_PICTURES_DIR, |
michael@0 | 751 | NS_GET_IID(nsIFile), |
michael@0 | 752 | getter_AddRefs(sDirs->pictures)); |
michael@0 | 753 | dirService->Get(NS_WIN_VIDEOS_DIR, |
michael@0 | 754 | NS_GET_IID(nsIFile), |
michael@0 | 755 | getter_AddRefs(sDirs->videos)); |
michael@0 | 756 | dirService->Get(NS_WIN_MUSIC_DIR, |
michael@0 | 757 | NS_GET_IID(nsIFile), |
michael@0 | 758 | getter_AddRefs(sDirs->music)); |
michael@0 | 759 | #endif |
michael@0 | 760 | |
michael@0 | 761 | // Eventually, on desktop, we want to do something smarter -- for example, |
michael@0 | 762 | // detect when an sdcard is inserted, and use that instead of this. |
michael@0 | 763 | dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile), |
michael@0 | 764 | getter_AddRefs(sDirs->sdcard)); |
michael@0 | 765 | if (sDirs->sdcard) { |
michael@0 | 766 | sDirs->sdcard->AppendRelativeNativePath(NS_LITERAL_CSTRING("fake-sdcard")); |
michael@0 | 767 | } |
michael@0 | 768 | #endif // !MOZ_WIDGET_GONK |
michael@0 | 769 | |
michael@0 | 770 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 771 | NS_NewLocalFile(NS_LITERAL_STRING("/data"), |
michael@0 | 772 | false, |
michael@0 | 773 | getter_AddRefs(sDirs->apps)); |
michael@0 | 774 | #else |
michael@0 | 775 | dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile), |
michael@0 | 776 | getter_AddRefs(sDirs->apps)); |
michael@0 | 777 | if (sDirs->apps) { |
michael@0 | 778 | sDirs->apps->AppendRelativeNativePath(NS_LITERAL_CSTRING("webapps")); |
michael@0 | 779 | } |
michael@0 | 780 | #endif |
michael@0 | 781 | |
michael@0 | 782 | if (XRE_GetProcessType() == GeckoProcessType_Default) { |
michael@0 | 783 | NS_GetSpecialDirectory("UAppData", getter_AddRefs(sDirs->crashes)); |
michael@0 | 784 | if (sDirs->crashes) { |
michael@0 | 785 | sDirs->crashes->Append(NS_LITERAL_STRING("Crash Reports")); |
michael@0 | 786 | } |
michael@0 | 787 | } else { |
michael@0 | 788 | // NS_GetSpecialDirectory("UAppData") fails in content processes because |
michael@0 | 789 | // gAppData from toolkit/xre/nsAppRunner.cpp is not initialized. |
michael@0 | 790 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 791 | NS_NewLocalFile(NS_LITERAL_STRING("/data/b2g/mozilla/Crash Reports"), |
michael@0 | 792 | false, |
michael@0 | 793 | getter_AddRefs(sDirs->crashes)); |
michael@0 | 794 | #endif |
michael@0 | 795 | } |
michael@0 | 796 | |
michael@0 | 797 | OverrideRootDir::GetSingleton()->Init(); |
michael@0 | 798 | } |
michael@0 | 799 | |
michael@0 | 800 | void |
michael@0 | 801 | DeviceStorageFile::GetFullPath(nsAString &aFullPath) |
michael@0 | 802 | { |
michael@0 | 803 | aFullPath.Truncate(); |
michael@0 | 804 | if (!mStorageName.EqualsLiteral("")) { |
michael@0 | 805 | aFullPath.AppendLiteral("/"); |
michael@0 | 806 | aFullPath.Append(mStorageName); |
michael@0 | 807 | aFullPath.AppendLiteral("/"); |
michael@0 | 808 | } |
michael@0 | 809 | if (!mRootDir.EqualsLiteral("")) { |
michael@0 | 810 | aFullPath.Append(mRootDir); |
michael@0 | 811 | aFullPath.AppendLiteral("/"); |
michael@0 | 812 | } |
michael@0 | 813 | aFullPath.Append(mPath); |
michael@0 | 814 | } |
michael@0 | 815 | |
michael@0 | 816 | |
michael@0 | 817 | // Directories which don't depend on a volume should be calculated once |
michael@0 | 818 | // in InitDirs. Directories which depend on the root directory of a volume |
michael@0 | 819 | // should be calculated in this method. |
michael@0 | 820 | void |
michael@0 | 821 | DeviceStorageFile::GetRootDirectoryForType(const nsAString& aStorageType, |
michael@0 | 822 | const nsAString& aStorageName, |
michael@0 | 823 | nsIFile** aFile) |
michael@0 | 824 | { |
michael@0 | 825 | nsCOMPtr<nsIFile> f; |
michael@0 | 826 | *aFile = nullptr; |
michael@0 | 827 | bool allowOverride = true; |
michael@0 | 828 | |
michael@0 | 829 | InitDirs(); |
michael@0 | 830 | |
michael@0 | 831 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 832 | nsString volMountPoint; |
michael@0 | 833 | if (DeviceStorageTypeChecker::IsVolumeBased(aStorageType)) { |
michael@0 | 834 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); |
michael@0 | 835 | NS_ENSURE_TRUE_VOID(vs); |
michael@0 | 836 | nsresult rv; |
michael@0 | 837 | nsCOMPtr<nsIVolume> vol; |
michael@0 | 838 | rv = vs->GetVolumeByName(aStorageName, getter_AddRefs(vol)); |
michael@0 | 839 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 840 | vol->GetMountPoint(volMountPoint); |
michael@0 | 841 | } |
michael@0 | 842 | #endif |
michael@0 | 843 | |
michael@0 | 844 | // Picture directory |
michael@0 | 845 | if (aStorageType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { |
michael@0 | 846 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 847 | NS_NewLocalFile(volMountPoint, false, getter_AddRefs(f)); |
michael@0 | 848 | #else |
michael@0 | 849 | f = sDirs->pictures; |
michael@0 | 850 | #endif |
michael@0 | 851 | } |
michael@0 | 852 | |
michael@0 | 853 | // Video directory |
michael@0 | 854 | else if (aStorageType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { |
michael@0 | 855 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 856 | NS_NewLocalFile(volMountPoint, false, getter_AddRefs(f)); |
michael@0 | 857 | #else |
michael@0 | 858 | f = sDirs->videos; |
michael@0 | 859 | #endif |
michael@0 | 860 | } |
michael@0 | 861 | |
michael@0 | 862 | // Music directory |
michael@0 | 863 | else if (aStorageType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { |
michael@0 | 864 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 865 | NS_NewLocalFile(volMountPoint, false, getter_AddRefs(f)); |
michael@0 | 866 | #else |
michael@0 | 867 | f = sDirs->music; |
michael@0 | 868 | #endif |
michael@0 | 869 | } |
michael@0 | 870 | |
michael@0 | 871 | // Apps directory |
michael@0 | 872 | else if (aStorageType.EqualsLiteral(DEVICESTORAGE_APPS)) { |
michael@0 | 873 | f = sDirs->apps; |
michael@0 | 874 | allowOverride = false; |
michael@0 | 875 | } |
michael@0 | 876 | |
michael@0 | 877 | // default SDCard |
michael@0 | 878 | else if (aStorageType.EqualsLiteral(DEVICESTORAGE_SDCARD)) { |
michael@0 | 879 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 880 | NS_NewLocalFile(volMountPoint, false, getter_AddRefs(f)); |
michael@0 | 881 | #else |
michael@0 | 882 | f = sDirs->sdcard; |
michael@0 | 883 | #endif |
michael@0 | 884 | } |
michael@0 | 885 | |
michael@0 | 886 | // crash reports directory. |
michael@0 | 887 | else if (aStorageType.EqualsLiteral(DEVICESTORAGE_CRASHES)) { |
michael@0 | 888 | f = sDirs->crashes; |
michael@0 | 889 | allowOverride = false; |
michael@0 | 890 | } else { |
michael@0 | 891 | // Not a storage type that we recognize. Return null |
michael@0 | 892 | return; |
michael@0 | 893 | } |
michael@0 | 894 | |
michael@0 | 895 | // In testing, we default all device storage types to a temp directory. |
michael@0 | 896 | // sDirs->overrideRootDir will only have been initialized (in InitDirs) |
michael@0 | 897 | // if the preference device.storage.testing was set to true, or if |
michael@0 | 898 | // device.storage.overrideRootDir is set. We can't test the preferences |
michael@0 | 899 | // directly here, since we may not be on the main thread. |
michael@0 | 900 | if (allowOverride && sDirs->overrideRootDir) { |
michael@0 | 901 | f = sDirs->overrideRootDir; |
michael@0 | 902 | } |
michael@0 | 903 | |
michael@0 | 904 | if (f) { |
michael@0 | 905 | f->Clone(aFile); |
michael@0 | 906 | } |
michael@0 | 907 | } |
michael@0 | 908 | |
michael@0 | 909 | //static |
michael@0 | 910 | already_AddRefed<DeviceStorageFile> |
michael@0 | 911 | DeviceStorageFile::CreateUnique(nsAString& aFileName, |
michael@0 | 912 | uint32_t aFileType, |
michael@0 | 913 | uint32_t aFileAttributes) |
michael@0 | 914 | { |
michael@0 | 915 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 916 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 917 | MOZ_ASSERT(typeChecker); |
michael@0 | 918 | |
michael@0 | 919 | nsString storageType; |
michael@0 | 920 | typeChecker->GetTypeFromFileName(aFileName, storageType); |
michael@0 | 921 | |
michael@0 | 922 | nsString storageName; |
michael@0 | 923 | nsString storagePath; |
michael@0 | 924 | if (!nsDOMDeviceStorage::ParseFullPath(aFileName, storageName, storagePath)) { |
michael@0 | 925 | return nullptr; |
michael@0 | 926 | } |
michael@0 | 927 | if (storageName.IsEmpty()) { |
michael@0 | 928 | nsDOMDeviceStorage::GetDefaultStorageName(storageType, storageName); |
michael@0 | 929 | } |
michael@0 | 930 | nsRefPtr<DeviceStorageFile> dsf = |
michael@0 | 931 | new DeviceStorageFile(storageType, storageName, storagePath); |
michael@0 | 932 | if (!dsf->mFile) { |
michael@0 | 933 | return nullptr; |
michael@0 | 934 | } |
michael@0 | 935 | |
michael@0 | 936 | nsresult rv = dsf->mFile->CreateUnique(aFileType, aFileAttributes); |
michael@0 | 937 | NS_ENSURE_SUCCESS(rv, nullptr); |
michael@0 | 938 | |
michael@0 | 939 | // CreateUnique may cause the filename to change. So we need to update mPath |
michael@0 | 940 | // to reflect that. |
michael@0 | 941 | nsString leafName; |
michael@0 | 942 | dsf->mFile->GetLeafName(leafName); |
michael@0 | 943 | |
michael@0 | 944 | int32_t lastSlashIndex = dsf->mPath.RFindChar('/'); |
michael@0 | 945 | if (lastSlashIndex == kNotFound) { |
michael@0 | 946 | dsf->mPath.Assign(leafName); |
michael@0 | 947 | } else { |
michael@0 | 948 | // Include the last '/' |
michael@0 | 949 | dsf->mPath = Substring(dsf->mPath, 0, lastSlashIndex + 1); |
michael@0 | 950 | dsf->mPath.Append(leafName); |
michael@0 | 951 | } |
michael@0 | 952 | |
michael@0 | 953 | return dsf.forget(); |
michael@0 | 954 | } |
michael@0 | 955 | |
michael@0 | 956 | void |
michael@0 | 957 | DeviceStorageFile::SetPath(const nsAString& aPath) { |
michael@0 | 958 | mPath.Assign(aPath); |
michael@0 | 959 | NormalizeFilePath(); |
michael@0 | 960 | } |
michael@0 | 961 | |
michael@0 | 962 | void |
michael@0 | 963 | DeviceStorageFile::SetEditable(bool aEditable) { |
michael@0 | 964 | mEditable = aEditable; |
michael@0 | 965 | } |
michael@0 | 966 | |
michael@0 | 967 | // we want to make sure that the names of file can't reach |
michael@0 | 968 | // outside of the type of storage the user asked for. |
michael@0 | 969 | bool |
michael@0 | 970 | DeviceStorageFile::IsSafePath() |
michael@0 | 971 | { |
michael@0 | 972 | return IsSafePath(mRootDir) && IsSafePath(mPath); |
michael@0 | 973 | } |
michael@0 | 974 | |
michael@0 | 975 | bool |
michael@0 | 976 | DeviceStorageFile::IsSafePath(const nsAString& aPath) |
michael@0 | 977 | { |
michael@0 | 978 | nsAString::const_iterator start, end; |
michael@0 | 979 | aPath.BeginReading(start); |
michael@0 | 980 | aPath.EndReading(end); |
michael@0 | 981 | |
michael@0 | 982 | // if the path is a '~' or starts with '~/', return false. |
michael@0 | 983 | NS_NAMED_LITERAL_STRING(tilde, "~"); |
michael@0 | 984 | NS_NAMED_LITERAL_STRING(tildeSlash, "~/"); |
michael@0 | 985 | if (aPath.Equals(tilde) || |
michael@0 | 986 | StringBeginsWith(aPath, tildeSlash)) { |
michael@0 | 987 | NS_WARNING("Path name starts with tilde!"); |
michael@0 | 988 | return false; |
michael@0 | 989 | } |
michael@0 | 990 | // split on /. if any token is "", ., or .., return false. |
michael@0 | 991 | NS_ConvertUTF16toUTF8 cname(aPath); |
michael@0 | 992 | char* buffer = cname.BeginWriting(); |
michael@0 | 993 | const char* token; |
michael@0 | 994 | |
michael@0 | 995 | while ((token = nsCRT::strtok(buffer, "/", &buffer))) { |
michael@0 | 996 | if (PL_strcmp(token, "") == 0 || |
michael@0 | 997 | PL_strcmp(token, ".") == 0 || |
michael@0 | 998 | PL_strcmp(token, "..") == 0 ) { |
michael@0 | 999 | return false; |
michael@0 | 1000 | } |
michael@0 | 1001 | } |
michael@0 | 1002 | return true; |
michael@0 | 1003 | } |
michael@0 | 1004 | |
michael@0 | 1005 | void |
michael@0 | 1006 | DeviceStorageFile::NormalizeFilePath() { |
michael@0 | 1007 | FileSystemUtils::LocalPathToNormalizedPath(mPath, mPath); |
michael@0 | 1008 | } |
michael@0 | 1009 | |
michael@0 | 1010 | void |
michael@0 | 1011 | DeviceStorageFile::AppendRelativePath(const nsAString& aPath) { |
michael@0 | 1012 | if (!mFile) { |
michael@0 | 1013 | return; |
michael@0 | 1014 | } |
michael@0 | 1015 | if (!IsSafePath(aPath)) { |
michael@0 | 1016 | // All of the APIs (in the child) do checks to verify that the path is |
michael@0 | 1017 | // valid and return PERMISSION_DENIED if a non-safe path is entered. |
michael@0 | 1018 | // This check is done in the parent and prevents a compromised |
michael@0 | 1019 | // child from bypassing the check. It shouldn't be possible for this |
michael@0 | 1020 | // code path to be taken with a non-compromised child. |
michael@0 | 1021 | NS_WARNING("Unsafe path detected - ignoring"); |
michael@0 | 1022 | NS_WARNING(NS_LossyConvertUTF16toASCII(aPath).get()); |
michael@0 | 1023 | return; |
michael@0 | 1024 | } |
michael@0 | 1025 | nsString localPath; |
michael@0 | 1026 | FileSystemUtils::NormalizedPathToLocalPath(aPath, localPath); |
michael@0 | 1027 | mFile->AppendRelativePath(localPath); |
michael@0 | 1028 | } |
michael@0 | 1029 | |
michael@0 | 1030 | nsresult |
michael@0 | 1031 | DeviceStorageFile::CreateFileDescriptor(FileDescriptor& aFileDescriptor) |
michael@0 | 1032 | { |
michael@0 | 1033 | ScopedPRFileDesc fd; |
michael@0 | 1034 | nsresult rv = mFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE, |
michael@0 | 1035 | 0660, &fd.rwget()); |
michael@0 | 1036 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1037 | |
michael@0 | 1038 | // NOTE: The FileDescriptor::PlatformHandleType constructor returns a dup of |
michael@0 | 1039 | // the file descriptor, so we don't need the original fd after this. |
michael@0 | 1040 | // Our scoped file descriptor will automatically close fd. |
michael@0 | 1041 | aFileDescriptor = |
michael@0 | 1042 | FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd)); |
michael@0 | 1043 | return NS_OK; |
michael@0 | 1044 | } |
michael@0 | 1045 | |
michael@0 | 1046 | nsresult |
michael@0 | 1047 | DeviceStorageFile::Write(nsIInputStream* aInputStream) |
michael@0 | 1048 | { |
michael@0 | 1049 | if (!aInputStream || !mFile) { |
michael@0 | 1050 | return NS_ERROR_FAILURE; |
michael@0 | 1051 | } |
michael@0 | 1052 | |
michael@0 | 1053 | nsresult rv = mFile->Create(nsIFile::NORMAL_FILE_TYPE, 00600); |
michael@0 | 1054 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1055 | return rv; |
michael@0 | 1056 | } |
michael@0 | 1057 | |
michael@0 | 1058 | nsCOMPtr<nsIRunnable> iocomplete = new IOEventComplete(this, "created"); |
michael@0 | 1059 | rv = NS_DispatchToMainThread(iocomplete); |
michael@0 | 1060 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1061 | return rv; |
michael@0 | 1062 | } |
michael@0 | 1063 | |
michael@0 | 1064 | uint64_t bufSize = 0; |
michael@0 | 1065 | aInputStream->Available(&bufSize); |
michael@0 | 1066 | |
michael@0 | 1067 | nsCOMPtr<nsIOutputStream> outputStream; |
michael@0 | 1068 | NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile); |
michael@0 | 1069 | |
michael@0 | 1070 | if (!outputStream) { |
michael@0 | 1071 | return NS_ERROR_FAILURE; |
michael@0 | 1072 | } |
michael@0 | 1073 | |
michael@0 | 1074 | nsCOMPtr<nsIOutputStream> bufferedOutputStream; |
michael@0 | 1075 | rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), |
michael@0 | 1076 | outputStream, |
michael@0 | 1077 | 4096*4); |
michael@0 | 1078 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1079 | |
michael@0 | 1080 | while (bufSize) { |
michael@0 | 1081 | uint32_t wrote; |
michael@0 | 1082 | rv = bufferedOutputStream->WriteFrom( |
michael@0 | 1083 | aInputStream, |
michael@0 | 1084 | static_cast<uint32_t>(std::min<uint64_t>(bufSize, UINT32_MAX)), |
michael@0 | 1085 | &wrote); |
michael@0 | 1086 | if (NS_FAILED(rv)) { |
michael@0 | 1087 | break; |
michael@0 | 1088 | } |
michael@0 | 1089 | bufSize -= wrote; |
michael@0 | 1090 | } |
michael@0 | 1091 | |
michael@0 | 1092 | iocomplete = new IOEventComplete(this, "modified"); |
michael@0 | 1093 | rv = NS_DispatchToMainThread(iocomplete); |
michael@0 | 1094 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1095 | return rv; |
michael@0 | 1096 | } |
michael@0 | 1097 | |
michael@0 | 1098 | bufferedOutputStream->Close(); |
michael@0 | 1099 | outputStream->Close(); |
michael@0 | 1100 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1101 | return rv; |
michael@0 | 1102 | } |
michael@0 | 1103 | return NS_OK; |
michael@0 | 1104 | } |
michael@0 | 1105 | |
michael@0 | 1106 | nsresult |
michael@0 | 1107 | DeviceStorageFile::Write(InfallibleTArray<uint8_t>& aBits) |
michael@0 | 1108 | { |
michael@0 | 1109 | if (!mFile) { |
michael@0 | 1110 | return NS_ERROR_FAILURE; |
michael@0 | 1111 | } |
michael@0 | 1112 | |
michael@0 | 1113 | nsresult rv = mFile->Create(nsIFile::NORMAL_FILE_TYPE, 00600); |
michael@0 | 1114 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1115 | return rv; |
michael@0 | 1116 | } |
michael@0 | 1117 | |
michael@0 | 1118 | nsCOMPtr<nsIRunnable> iocomplete = new IOEventComplete(this, "created"); |
michael@0 | 1119 | rv = NS_DispatchToMainThread(iocomplete); |
michael@0 | 1120 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1121 | return rv; |
michael@0 | 1122 | } |
michael@0 | 1123 | |
michael@0 | 1124 | nsCOMPtr<nsIOutputStream> outputStream; |
michael@0 | 1125 | NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile); |
michael@0 | 1126 | |
michael@0 | 1127 | if (!outputStream) { |
michael@0 | 1128 | return NS_ERROR_FAILURE; |
michael@0 | 1129 | } |
michael@0 | 1130 | |
michael@0 | 1131 | uint32_t wrote; |
michael@0 | 1132 | outputStream->Write((char*) aBits.Elements(), aBits.Length(), &wrote); |
michael@0 | 1133 | outputStream->Close(); |
michael@0 | 1134 | |
michael@0 | 1135 | iocomplete = new IOEventComplete(this, "modified"); |
michael@0 | 1136 | rv = NS_DispatchToMainThread(iocomplete); |
michael@0 | 1137 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1138 | return rv; |
michael@0 | 1139 | } |
michael@0 | 1140 | |
michael@0 | 1141 | if (aBits.Length() != wrote) { |
michael@0 | 1142 | return NS_ERROR_FAILURE; |
michael@0 | 1143 | } |
michael@0 | 1144 | return NS_OK; |
michael@0 | 1145 | } |
michael@0 | 1146 | |
michael@0 | 1147 | nsresult |
michael@0 | 1148 | DeviceStorageFile::Remove() |
michael@0 | 1149 | { |
michael@0 | 1150 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 1151 | |
michael@0 | 1152 | if (!mFile) { |
michael@0 | 1153 | return NS_ERROR_FAILURE; |
michael@0 | 1154 | } |
michael@0 | 1155 | |
michael@0 | 1156 | bool check; |
michael@0 | 1157 | nsresult rv = mFile->Exists(&check); |
michael@0 | 1158 | if (NS_FAILED(rv)) { |
michael@0 | 1159 | return rv; |
michael@0 | 1160 | } |
michael@0 | 1161 | |
michael@0 | 1162 | if (!check) { |
michael@0 | 1163 | return NS_OK; |
michael@0 | 1164 | } |
michael@0 | 1165 | |
michael@0 | 1166 | rv = mFile->Remove(true); |
michael@0 | 1167 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1168 | return rv; |
michael@0 | 1169 | } |
michael@0 | 1170 | |
michael@0 | 1171 | nsCOMPtr<nsIRunnable> iocomplete = new IOEventComplete(this, "deleted"); |
michael@0 | 1172 | return NS_DispatchToMainThread(iocomplete); |
michael@0 | 1173 | } |
michael@0 | 1174 | |
michael@0 | 1175 | nsresult |
michael@0 | 1176 | DeviceStorageFile::CalculateMimeType() |
michael@0 | 1177 | { |
michael@0 | 1178 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1179 | |
michael@0 | 1180 | nsAutoCString mimeType; |
michael@0 | 1181 | nsCOMPtr<nsIMIMEService> mimeService = |
michael@0 | 1182 | do_GetService(NS_MIMESERVICE_CONTRACTID); |
michael@0 | 1183 | if (mimeService) { |
michael@0 | 1184 | nsresult rv = mimeService->GetTypeFromFile(mFile, mimeType); |
michael@0 | 1185 | if (NS_FAILED(rv)) { |
michael@0 | 1186 | mimeType.Truncate(); |
michael@0 | 1187 | return rv; |
michael@0 | 1188 | } |
michael@0 | 1189 | } |
michael@0 | 1190 | |
michael@0 | 1191 | mMimeType = NS_ConvertUTF8toUTF16(mimeType); |
michael@0 | 1192 | return NS_OK; |
michael@0 | 1193 | } |
michael@0 | 1194 | |
michael@0 | 1195 | nsresult |
michael@0 | 1196 | DeviceStorageFile::CalculateSizeAndModifiedDate() |
michael@0 | 1197 | { |
michael@0 | 1198 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 1199 | |
michael@0 | 1200 | int64_t fileSize; |
michael@0 | 1201 | nsresult rv = mFile->GetFileSize(&fileSize); |
michael@0 | 1202 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1203 | |
michael@0 | 1204 | mLength = fileSize; |
michael@0 | 1205 | |
michael@0 | 1206 | PRTime modDate; |
michael@0 | 1207 | rv = mFile->GetLastModifiedTime(&modDate); |
michael@0 | 1208 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1209 | |
michael@0 | 1210 | mLastModifiedDate = modDate; |
michael@0 | 1211 | return NS_OK; |
michael@0 | 1212 | } |
michael@0 | 1213 | |
michael@0 | 1214 | void |
michael@0 | 1215 | DeviceStorageFile::CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, |
michael@0 | 1216 | PRTime aSince) |
michael@0 | 1217 | { |
michael@0 | 1218 | nsString fullRootPath; |
michael@0 | 1219 | mFile->GetPath(fullRootPath); |
michael@0 | 1220 | collectFilesInternal(aFiles, aSince, fullRootPath); |
michael@0 | 1221 | } |
michael@0 | 1222 | |
michael@0 | 1223 | void |
michael@0 | 1224 | DeviceStorageFile::collectFilesInternal( |
michael@0 | 1225 | nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, |
michael@0 | 1226 | PRTime aSince, |
michael@0 | 1227 | nsAString& aRootPath) |
michael@0 | 1228 | { |
michael@0 | 1229 | if (!mFile || !IsAvailable()) { |
michael@0 | 1230 | return; |
michael@0 | 1231 | } |
michael@0 | 1232 | |
michael@0 | 1233 | nsCOMPtr<nsISimpleEnumerator> e; |
michael@0 | 1234 | mFile->GetDirectoryEntries(getter_AddRefs(e)); |
michael@0 | 1235 | |
michael@0 | 1236 | if (!e) { |
michael@0 | 1237 | return; |
michael@0 | 1238 | } |
michael@0 | 1239 | |
michael@0 | 1240 | nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e); |
michael@0 | 1241 | nsCOMPtr<nsIFile> f; |
michael@0 | 1242 | |
michael@0 | 1243 | while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(f))) && f) { |
michael@0 | 1244 | |
michael@0 | 1245 | PRTime msecs; |
michael@0 | 1246 | f->GetLastModifiedTime(&msecs); |
michael@0 | 1247 | |
michael@0 | 1248 | if (msecs < aSince) { |
michael@0 | 1249 | continue; |
michael@0 | 1250 | } |
michael@0 | 1251 | |
michael@0 | 1252 | bool isDir; |
michael@0 | 1253 | f->IsDirectory(&isDir); |
michael@0 | 1254 | |
michael@0 | 1255 | bool isFile; |
michael@0 | 1256 | f->IsFile(&isFile); |
michael@0 | 1257 | |
michael@0 | 1258 | nsString fullpath; |
michael@0 | 1259 | nsresult rv = f->GetPath(fullpath); |
michael@0 | 1260 | if (NS_FAILED(rv)) { |
michael@0 | 1261 | continue; |
michael@0 | 1262 | } |
michael@0 | 1263 | |
michael@0 | 1264 | if (!StringBeginsWith(fullpath, aRootPath)) { |
michael@0 | 1265 | NS_ERROR("collectFiles returned a path that does not belong!"); |
michael@0 | 1266 | continue; |
michael@0 | 1267 | } |
michael@0 | 1268 | |
michael@0 | 1269 | nsAString::size_type len = aRootPath.Length() + 1; // +1 for the trailing / |
michael@0 | 1270 | nsDependentSubstring newPath = Substring(fullpath, len); |
michael@0 | 1271 | |
michael@0 | 1272 | if (isDir) { |
michael@0 | 1273 | DeviceStorageFile dsf(mStorageType, mStorageName, mRootDir, newPath); |
michael@0 | 1274 | dsf.collectFilesInternal(aFiles, aSince, aRootPath); |
michael@0 | 1275 | } else if (isFile) { |
michael@0 | 1276 | nsRefPtr<DeviceStorageFile> dsf = |
michael@0 | 1277 | new DeviceStorageFile(mStorageType, mStorageName, mRootDir, newPath); |
michael@0 | 1278 | dsf->CalculateSizeAndModifiedDate(); |
michael@0 | 1279 | aFiles.AppendElement(dsf); |
michael@0 | 1280 | } |
michael@0 | 1281 | } |
michael@0 | 1282 | } |
michael@0 | 1283 | |
michael@0 | 1284 | void |
michael@0 | 1285 | DeviceStorageFile::AccumDiskUsage(uint64_t* aPicturesSoFar, |
michael@0 | 1286 | uint64_t* aVideosSoFar, |
michael@0 | 1287 | uint64_t* aMusicSoFar, |
michael@0 | 1288 | uint64_t* aTotalSoFar) |
michael@0 | 1289 | { |
michael@0 | 1290 | if (!IsAvailable()) { |
michael@0 | 1291 | return; |
michael@0 | 1292 | } |
michael@0 | 1293 | |
michael@0 | 1294 | uint64_t pictureUsage = 0, videoUsage = 0, musicUsage = 0, totalUsage = 0; |
michael@0 | 1295 | |
michael@0 | 1296 | if (DeviceStorageTypeChecker::IsVolumeBased(mStorageType)) { |
michael@0 | 1297 | DeviceStorageUsedSpaceCache* usedSpaceCache = |
michael@0 | 1298 | DeviceStorageUsedSpaceCache::CreateOrGet(); |
michael@0 | 1299 | MOZ_ASSERT(usedSpaceCache); |
michael@0 | 1300 | nsresult rv = usedSpaceCache->AccumUsedSizes(mStorageName, |
michael@0 | 1301 | aPicturesSoFar, aVideosSoFar, |
michael@0 | 1302 | aMusicSoFar, aTotalSoFar); |
michael@0 | 1303 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1304 | return; |
michael@0 | 1305 | } |
michael@0 | 1306 | AccumDirectoryUsage(mFile, &pictureUsage, &videoUsage, |
michael@0 | 1307 | &musicUsage, &totalUsage); |
michael@0 | 1308 | usedSpaceCache->SetUsedSizes(mStorageName, pictureUsage, videoUsage, |
michael@0 | 1309 | musicUsage, totalUsage); |
michael@0 | 1310 | } else { |
michael@0 | 1311 | AccumDirectoryUsage(mFile, &pictureUsage, &videoUsage, |
michael@0 | 1312 | &musicUsage, &totalUsage); |
michael@0 | 1313 | } |
michael@0 | 1314 | |
michael@0 | 1315 | *aPicturesSoFar += pictureUsage; |
michael@0 | 1316 | *aVideosSoFar += videoUsage; |
michael@0 | 1317 | *aMusicSoFar += musicUsage; |
michael@0 | 1318 | *aTotalSoFar += totalUsage; |
michael@0 | 1319 | } |
michael@0 | 1320 | |
michael@0 | 1321 | void |
michael@0 | 1322 | DeviceStorageFile::AccumDirectoryUsage(nsIFile* aFile, |
michael@0 | 1323 | uint64_t* aPicturesSoFar, |
michael@0 | 1324 | uint64_t* aVideosSoFar, |
michael@0 | 1325 | uint64_t* aMusicSoFar, |
michael@0 | 1326 | uint64_t* aTotalSoFar) |
michael@0 | 1327 | { |
michael@0 | 1328 | if (!aFile) { |
michael@0 | 1329 | return; |
michael@0 | 1330 | } |
michael@0 | 1331 | |
michael@0 | 1332 | nsresult rv; |
michael@0 | 1333 | nsCOMPtr<nsISimpleEnumerator> e; |
michael@0 | 1334 | rv = aFile->GetDirectoryEntries(getter_AddRefs(e)); |
michael@0 | 1335 | |
michael@0 | 1336 | if (NS_FAILED(rv) || !e) { |
michael@0 | 1337 | return; |
michael@0 | 1338 | } |
michael@0 | 1339 | |
michael@0 | 1340 | nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e); |
michael@0 | 1341 | MOZ_ASSERT(files); |
michael@0 | 1342 | |
michael@0 | 1343 | nsCOMPtr<nsIFile> f; |
michael@0 | 1344 | while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(f))) && f) { |
michael@0 | 1345 | bool isDir; |
michael@0 | 1346 | rv = f->IsDirectory(&isDir); |
michael@0 | 1347 | if (NS_FAILED(rv)) { |
michael@0 | 1348 | continue; |
michael@0 | 1349 | } |
michael@0 | 1350 | |
michael@0 | 1351 | bool isFile; |
michael@0 | 1352 | rv = f->IsFile(&isFile); |
michael@0 | 1353 | if (NS_FAILED(rv)) { |
michael@0 | 1354 | continue; |
michael@0 | 1355 | } |
michael@0 | 1356 | |
michael@0 | 1357 | bool isLink; |
michael@0 | 1358 | rv = f->IsSymlink(&isLink); |
michael@0 | 1359 | if (NS_FAILED(rv)) { |
michael@0 | 1360 | continue; |
michael@0 | 1361 | } |
michael@0 | 1362 | |
michael@0 | 1363 | if (isLink) { |
michael@0 | 1364 | // for now, lets just totally ignore symlinks. |
michael@0 | 1365 | NS_WARNING("DirectoryDiskUsage ignores symlinks"); |
michael@0 | 1366 | } else if (isDir) { |
michael@0 | 1367 | AccumDirectoryUsage(f, aPicturesSoFar, aVideosSoFar, |
michael@0 | 1368 | aMusicSoFar, aTotalSoFar); |
michael@0 | 1369 | } else if (isFile) { |
michael@0 | 1370 | |
michael@0 | 1371 | int64_t size; |
michael@0 | 1372 | rv = f->GetFileSize(&size); |
michael@0 | 1373 | if (NS_FAILED(rv)) { |
michael@0 | 1374 | continue; |
michael@0 | 1375 | } |
michael@0 | 1376 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 1377 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 1378 | MOZ_ASSERT(typeChecker); |
michael@0 | 1379 | nsString type; |
michael@0 | 1380 | typeChecker->GetTypeFromFile(f, type); |
michael@0 | 1381 | |
michael@0 | 1382 | if (type.EqualsLiteral(DEVICESTORAGE_PICTURES)) { |
michael@0 | 1383 | *aPicturesSoFar += size; |
michael@0 | 1384 | } |
michael@0 | 1385 | else if (type.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { |
michael@0 | 1386 | *aVideosSoFar += size; |
michael@0 | 1387 | } |
michael@0 | 1388 | else if (type.EqualsLiteral(DEVICESTORAGE_MUSIC)) { |
michael@0 | 1389 | *aMusicSoFar += size; |
michael@0 | 1390 | } |
michael@0 | 1391 | *aTotalSoFar += size; |
michael@0 | 1392 | } |
michael@0 | 1393 | } |
michael@0 | 1394 | } |
michael@0 | 1395 | |
michael@0 | 1396 | void |
michael@0 | 1397 | DeviceStorageFile::GetDiskFreeSpace(int64_t* aSoFar) |
michael@0 | 1398 | { |
michael@0 | 1399 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 1400 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 1401 | if (!typeChecker) { |
michael@0 | 1402 | return; |
michael@0 | 1403 | } |
michael@0 | 1404 | if (!mFile || !IsAvailable()) { |
michael@0 | 1405 | return; |
michael@0 | 1406 | } |
michael@0 | 1407 | |
michael@0 | 1408 | int64_t storageAvail = 0; |
michael@0 | 1409 | nsresult rv = mFile->GetDiskSpaceAvailable(&storageAvail); |
michael@0 | 1410 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1411 | *aSoFar += storageAvail; |
michael@0 | 1412 | } |
michael@0 | 1413 | } |
michael@0 | 1414 | |
michael@0 | 1415 | bool |
michael@0 | 1416 | DeviceStorageFile::IsAvailable() |
michael@0 | 1417 | { |
michael@0 | 1418 | nsString status; |
michael@0 | 1419 | GetStatus(status); |
michael@0 | 1420 | return status.EqualsLiteral("available"); |
michael@0 | 1421 | } |
michael@0 | 1422 | |
michael@0 | 1423 | void |
michael@0 | 1424 | DeviceStorageFile::DoFormat(nsAString& aStatus) |
michael@0 | 1425 | { |
michael@0 | 1426 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 1427 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 1428 | if (!typeChecker) { |
michael@0 | 1429 | return; |
michael@0 | 1430 | } |
michael@0 | 1431 | if (!typeChecker->IsVolumeBased(mStorageType)) { |
michael@0 | 1432 | aStatus.AssignLiteral("notVolume"); |
michael@0 | 1433 | return; |
michael@0 | 1434 | } |
michael@0 | 1435 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 1436 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); |
michael@0 | 1437 | NS_ENSURE_TRUE_VOID(vs); |
michael@0 | 1438 | |
michael@0 | 1439 | nsCOMPtr<nsIVolume> vol; |
michael@0 | 1440 | nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); |
michael@0 | 1441 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1442 | if (!vol) { |
michael@0 | 1443 | return; |
michael@0 | 1444 | } |
michael@0 | 1445 | |
michael@0 | 1446 | vol->Format(); |
michael@0 | 1447 | |
michael@0 | 1448 | aStatus.AssignLiteral("formatting"); |
michael@0 | 1449 | #endif |
michael@0 | 1450 | return; |
michael@0 | 1451 | } |
michael@0 | 1452 | |
michael@0 | 1453 | void |
michael@0 | 1454 | DeviceStorageFile::DoMount(nsAString& aStatus) |
michael@0 | 1455 | { |
michael@0 | 1456 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 1457 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 1458 | if (!typeChecker) { |
michael@0 | 1459 | return; |
michael@0 | 1460 | } |
michael@0 | 1461 | if (!typeChecker->IsVolumeBased(mStorageType)) { |
michael@0 | 1462 | aStatus.AssignLiteral("notVolume"); |
michael@0 | 1463 | return; |
michael@0 | 1464 | } |
michael@0 | 1465 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 1466 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); |
michael@0 | 1467 | NS_ENSURE_TRUE_VOID(vs); |
michael@0 | 1468 | |
michael@0 | 1469 | nsCOMPtr<nsIVolume> vol; |
michael@0 | 1470 | nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); |
michael@0 | 1471 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1472 | if (!vol) { |
michael@0 | 1473 | return; |
michael@0 | 1474 | } |
michael@0 | 1475 | |
michael@0 | 1476 | vol->Mount(); |
michael@0 | 1477 | |
michael@0 | 1478 | aStatus.AssignLiteral("mounting"); |
michael@0 | 1479 | #endif |
michael@0 | 1480 | return; |
michael@0 | 1481 | } |
michael@0 | 1482 | |
michael@0 | 1483 | void |
michael@0 | 1484 | DeviceStorageFile::DoUnmount(nsAString& aStatus) |
michael@0 | 1485 | { |
michael@0 | 1486 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 1487 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 1488 | if (!typeChecker) { |
michael@0 | 1489 | return; |
michael@0 | 1490 | } |
michael@0 | 1491 | if (!typeChecker->IsVolumeBased(mStorageType)) { |
michael@0 | 1492 | aStatus.AssignLiteral("notVolume"); |
michael@0 | 1493 | return; |
michael@0 | 1494 | } |
michael@0 | 1495 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 1496 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); |
michael@0 | 1497 | NS_ENSURE_TRUE_VOID(vs); |
michael@0 | 1498 | |
michael@0 | 1499 | nsCOMPtr<nsIVolume> vol; |
michael@0 | 1500 | nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); |
michael@0 | 1501 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1502 | if (!vol) { |
michael@0 | 1503 | return; |
michael@0 | 1504 | } |
michael@0 | 1505 | |
michael@0 | 1506 | vol->Unmount(); |
michael@0 | 1507 | |
michael@0 | 1508 | aStatus.AssignLiteral("unmounting"); |
michael@0 | 1509 | #endif |
michael@0 | 1510 | return; |
michael@0 | 1511 | } |
michael@0 | 1512 | |
michael@0 | 1513 | void |
michael@0 | 1514 | DeviceStorageFile::GetStatus(nsAString& aStatus) |
michael@0 | 1515 | { |
michael@0 | 1516 | aStatus.AssignLiteral("unavailable"); |
michael@0 | 1517 | |
michael@0 | 1518 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 1519 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 1520 | if (!typeChecker) { |
michael@0 | 1521 | return; |
michael@0 | 1522 | } |
michael@0 | 1523 | if (!typeChecker->IsVolumeBased(mStorageType)) { |
michael@0 | 1524 | aStatus.AssignLiteral("available"); |
michael@0 | 1525 | return; |
michael@0 | 1526 | } |
michael@0 | 1527 | |
michael@0 | 1528 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 1529 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); |
michael@0 | 1530 | NS_ENSURE_TRUE_VOID(vs); |
michael@0 | 1531 | |
michael@0 | 1532 | nsCOMPtr<nsIVolume> vol; |
michael@0 | 1533 | nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); |
michael@0 | 1534 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1535 | if (!vol) { |
michael@0 | 1536 | return; |
michael@0 | 1537 | } |
michael@0 | 1538 | bool isMediaPresent; |
michael@0 | 1539 | rv = vol->GetIsMediaPresent(&isMediaPresent); |
michael@0 | 1540 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1541 | if (!isMediaPresent) { |
michael@0 | 1542 | return; |
michael@0 | 1543 | } |
michael@0 | 1544 | bool isSharing; |
michael@0 | 1545 | rv = vol->GetIsSharing(&isSharing); |
michael@0 | 1546 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1547 | if (isSharing) { |
michael@0 | 1548 | aStatus.AssignLiteral("shared"); |
michael@0 | 1549 | return; |
michael@0 | 1550 | } |
michael@0 | 1551 | bool isFormatting; |
michael@0 | 1552 | rv = vol->GetIsFormatting(&isFormatting); |
michael@0 | 1553 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1554 | if (isFormatting) { |
michael@0 | 1555 | aStatus.AssignLiteral("unavailable"); |
michael@0 | 1556 | return; |
michael@0 | 1557 | } |
michael@0 | 1558 | int32_t volState; |
michael@0 | 1559 | rv = vol->GetState(&volState); |
michael@0 | 1560 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1561 | if (volState == nsIVolume::STATE_MOUNTED) { |
michael@0 | 1562 | aStatus.AssignLiteral("available"); |
michael@0 | 1563 | } |
michael@0 | 1564 | #endif |
michael@0 | 1565 | } |
michael@0 | 1566 | |
michael@0 | 1567 | void |
michael@0 | 1568 | DeviceStorageFile::GetStorageStatus(nsAString& aStatus) |
michael@0 | 1569 | { |
michael@0 | 1570 | aStatus.AssignLiteral("undefined"); |
michael@0 | 1571 | |
michael@0 | 1572 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 1573 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 1574 | if (!typeChecker) { |
michael@0 | 1575 | return; |
michael@0 | 1576 | } |
michael@0 | 1577 | if (!typeChecker->IsVolumeBased(mStorageType)) { |
michael@0 | 1578 | aStatus.AssignLiteral("available"); |
michael@0 | 1579 | return; |
michael@0 | 1580 | } |
michael@0 | 1581 | |
michael@0 | 1582 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 1583 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); |
michael@0 | 1584 | NS_ENSURE_TRUE_VOID(vs); |
michael@0 | 1585 | |
michael@0 | 1586 | nsCOMPtr<nsIVolume> vol; |
michael@0 | 1587 | nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); |
michael@0 | 1588 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1589 | if (!vol) { |
michael@0 | 1590 | return; |
michael@0 | 1591 | } |
michael@0 | 1592 | |
michael@0 | 1593 | int32_t volState; |
michael@0 | 1594 | rv = vol->GetState(&volState); |
michael@0 | 1595 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 1596 | aStatus.AssignASCII(mozilla::system::NS_VolumeStateStr(volState)); |
michael@0 | 1597 | #endif |
michael@0 | 1598 | } |
michael@0 | 1599 | |
michael@0 | 1600 | NS_IMPL_ISUPPORTS0(DeviceStorageFile) |
michael@0 | 1601 | |
michael@0 | 1602 | static void |
michael@0 | 1603 | RegisterForSDCardChanges(nsIObserver* aObserver) |
michael@0 | 1604 | { |
michael@0 | 1605 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 1606 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 1607 | obs->AddObserver(aObserver, NS_VOLUME_STATE_CHANGED, false); |
michael@0 | 1608 | #endif |
michael@0 | 1609 | } |
michael@0 | 1610 | |
michael@0 | 1611 | static void |
michael@0 | 1612 | UnregisterForSDCardChanges(nsIObserver* aObserver) |
michael@0 | 1613 | { |
michael@0 | 1614 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 1615 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 1616 | obs->RemoveObserver(aObserver, NS_VOLUME_STATE_CHANGED); |
michael@0 | 1617 | #endif |
michael@0 | 1618 | } |
michael@0 | 1619 | |
michael@0 | 1620 | void |
michael@0 | 1621 | nsDOMDeviceStorage::SetRootDirectoryForType(const nsAString& aStorageType, |
michael@0 | 1622 | const nsAString& aStorageName) |
michael@0 | 1623 | { |
michael@0 | 1624 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1625 | |
michael@0 | 1626 | nsCOMPtr<nsIFile> f; |
michael@0 | 1627 | DeviceStorageFile::GetRootDirectoryForType(aStorageType, |
michael@0 | 1628 | aStorageName, |
michael@0 | 1629 | getter_AddRefs(f)); |
michael@0 | 1630 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 1631 | obs->AddObserver(this, "file-watcher-update", false); |
michael@0 | 1632 | obs->AddObserver(this, "disk-space-watcher", false); |
michael@0 | 1633 | mRootDirectory = f; |
michael@0 | 1634 | mStorageType = aStorageType; |
michael@0 | 1635 | mStorageName = aStorageName; |
michael@0 | 1636 | } |
michael@0 | 1637 | |
michael@0 | 1638 | JS::Value |
michael@0 | 1639 | InterfaceToJsval(nsPIDOMWindow* aWindow, |
michael@0 | 1640 | nsISupports* aObject, |
michael@0 | 1641 | const nsIID* aIID) |
michael@0 | 1642 | { |
michael@0 | 1643 | nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow); |
michael@0 | 1644 | if (!sgo) { |
michael@0 | 1645 | return JS::NullValue(); |
michael@0 | 1646 | } |
michael@0 | 1647 | |
michael@0 | 1648 | JSObject *unrootedScopeObj = sgo->GetGlobalJSObject(); |
michael@0 | 1649 | NS_ENSURE_TRUE(unrootedScopeObj, JS::NullValue()); |
michael@0 | 1650 | JSRuntime *runtime = JS_GetObjectRuntime(unrootedScopeObj); |
michael@0 | 1651 | JS::Rooted<JS::Value> someJsVal(runtime); |
michael@0 | 1652 | nsresult rv; |
michael@0 | 1653 | |
michael@0 | 1654 | { // Protect someJsVal from moving GC in ~JSAutoCompartment |
michael@0 | 1655 | AutoJSContext cx; |
michael@0 | 1656 | |
michael@0 | 1657 | JS::Rooted<JSObject*> scopeObj(cx, unrootedScopeObj); |
michael@0 | 1658 | JSAutoCompartment ac(cx, scopeObj); |
michael@0 | 1659 | |
michael@0 | 1660 | rv = nsContentUtils::WrapNative(cx, aObject, aIID, &someJsVal); |
michael@0 | 1661 | } |
michael@0 | 1662 | if (NS_FAILED(rv)) { |
michael@0 | 1663 | return JS::NullValue(); |
michael@0 | 1664 | } |
michael@0 | 1665 | |
michael@0 | 1666 | return someJsVal; |
michael@0 | 1667 | } |
michael@0 | 1668 | |
michael@0 | 1669 | JS::Value |
michael@0 | 1670 | nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile) |
michael@0 | 1671 | { |
michael@0 | 1672 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1673 | MOZ_ASSERT(aWindow); |
michael@0 | 1674 | |
michael@0 | 1675 | if (!aFile) { |
michael@0 | 1676 | return JSVAL_NULL; |
michael@0 | 1677 | } |
michael@0 | 1678 | |
michael@0 | 1679 | if (aFile->mEditable) { |
michael@0 | 1680 | // TODO - needs janv's file handle support. |
michael@0 | 1681 | return JSVAL_NULL; |
michael@0 | 1682 | } |
michael@0 | 1683 | |
michael@0 | 1684 | nsString fullPath; |
michael@0 | 1685 | aFile->GetFullPath(fullPath); |
michael@0 | 1686 | |
michael@0 | 1687 | // This check is useful to know if somewhere the DeviceStorageFile |
michael@0 | 1688 | // has not been properly set. Mimetype is not checked because it can be |
michael@0 | 1689 | // empty. |
michael@0 | 1690 | MOZ_ASSERT(aFile->mLength != UINT64_MAX); |
michael@0 | 1691 | MOZ_ASSERT(aFile->mLastModifiedDate != UINT64_MAX); |
michael@0 | 1692 | |
michael@0 | 1693 | nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(fullPath, aFile->mMimeType, |
michael@0 | 1694 | aFile->mLength, aFile->mFile, |
michael@0 | 1695 | aFile->mLastModifiedDate); |
michael@0 | 1696 | return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob)); |
michael@0 | 1697 | } |
michael@0 | 1698 | |
michael@0 | 1699 | JS::Value StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString) |
michael@0 | 1700 | { |
michael@0 | 1701 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1702 | MOZ_ASSERT(aWindow); |
michael@0 | 1703 | |
michael@0 | 1704 | nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow); |
michael@0 | 1705 | if (!sgo) { |
michael@0 | 1706 | return JSVAL_NULL; |
michael@0 | 1707 | } |
michael@0 | 1708 | |
michael@0 | 1709 | nsIScriptContext *scriptContext = sgo->GetScriptContext(); |
michael@0 | 1710 | if (!scriptContext) { |
michael@0 | 1711 | return JSVAL_NULL; |
michael@0 | 1712 | } |
michael@0 | 1713 | |
michael@0 | 1714 | AutoPushJSContext cx(scriptContext->GetNativeContext()); |
michael@0 | 1715 | if (!cx) { |
michael@0 | 1716 | return JSVAL_NULL; |
michael@0 | 1717 | } |
michael@0 | 1718 | |
michael@0 | 1719 | JS::Rooted<JS::Value> result(cx); |
michael@0 | 1720 | if (!xpc::StringToJsval(cx, aString, &result)) { |
michael@0 | 1721 | return JSVAL_NULL; |
michael@0 | 1722 | } |
michael@0 | 1723 | |
michael@0 | 1724 | return result; |
michael@0 | 1725 | } |
michael@0 | 1726 | |
michael@0 | 1727 | class DeviceStorageCursorRequest MOZ_FINAL |
michael@0 | 1728 | : public nsIContentPermissionRequest |
michael@0 | 1729 | , public PCOMContentPermissionRequestChild |
michael@0 | 1730 | { |
michael@0 | 1731 | public: |
michael@0 | 1732 | NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
michael@0 | 1733 | NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageCursorRequest, |
michael@0 | 1734 | nsIContentPermissionRequest) |
michael@0 | 1735 | |
michael@0 | 1736 | NS_FORWARD_NSICONTENTPERMISSIONREQUEST(mCursor->); |
michael@0 | 1737 | |
michael@0 | 1738 | DeviceStorageCursorRequest(nsDOMDeviceStorageCursor* aCursor) |
michael@0 | 1739 | : mCursor(aCursor) { } |
michael@0 | 1740 | |
michael@0 | 1741 | ~DeviceStorageCursorRequest() {} |
michael@0 | 1742 | |
michael@0 | 1743 | bool Recv__delete__(const bool& allow, |
michael@0 | 1744 | const InfallibleTArray<PermissionChoice>& choices) |
michael@0 | 1745 | { |
michael@0 | 1746 | MOZ_ASSERT(choices.IsEmpty(), "DeviceStorageCursor doesn't support permission choice"); |
michael@0 | 1747 | if (allow) { |
michael@0 | 1748 | Allow(JS::UndefinedHandleValue); |
michael@0 | 1749 | } |
michael@0 | 1750 | else { |
michael@0 | 1751 | Cancel(); |
michael@0 | 1752 | } |
michael@0 | 1753 | return true; |
michael@0 | 1754 | } |
michael@0 | 1755 | |
michael@0 | 1756 | void IPDLRelease() |
michael@0 | 1757 | { |
michael@0 | 1758 | Release(); |
michael@0 | 1759 | } |
michael@0 | 1760 | |
michael@0 | 1761 | private: |
michael@0 | 1762 | nsRefPtr<nsDOMDeviceStorageCursor> mCursor; |
michael@0 | 1763 | }; |
michael@0 | 1764 | |
michael@0 | 1765 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageCursorRequest) |
michael@0 | 1766 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest) |
michael@0 | 1767 | NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest) |
michael@0 | 1768 | NS_INTERFACE_MAP_END |
michael@0 | 1769 | |
michael@0 | 1770 | NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageCursorRequest) |
michael@0 | 1771 | NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageCursorRequest) |
michael@0 | 1772 | |
michael@0 | 1773 | NS_IMPL_CYCLE_COLLECTION(DeviceStorageCursorRequest, |
michael@0 | 1774 | mCursor) |
michael@0 | 1775 | |
michael@0 | 1776 | |
michael@0 | 1777 | class PostErrorEvent : public nsRunnable |
michael@0 | 1778 | { |
michael@0 | 1779 | public: |
michael@0 | 1780 | PostErrorEvent(already_AddRefed<DOMRequest> aRequest, const char* aMessage) |
michael@0 | 1781 | : mRequest(aRequest) |
michael@0 | 1782 | { |
michael@0 | 1783 | CopyASCIItoUTF16(aMessage, mError); |
michael@0 | 1784 | } |
michael@0 | 1785 | |
michael@0 | 1786 | PostErrorEvent(DOMRequest* aRequest, const char* aMessage) |
michael@0 | 1787 | : mRequest(aRequest) |
michael@0 | 1788 | { |
michael@0 | 1789 | CopyASCIItoUTF16(aMessage, mError); |
michael@0 | 1790 | } |
michael@0 | 1791 | |
michael@0 | 1792 | ~PostErrorEvent() {} |
michael@0 | 1793 | |
michael@0 | 1794 | NS_IMETHOD Run() |
michael@0 | 1795 | { |
michael@0 | 1796 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1797 | if (!mRequest->GetOwner()) { |
michael@0 | 1798 | return NS_OK; |
michael@0 | 1799 | } |
michael@0 | 1800 | mRequest->FireError(mError); |
michael@0 | 1801 | mRequest = nullptr; |
michael@0 | 1802 | return NS_OK; |
michael@0 | 1803 | } |
michael@0 | 1804 | |
michael@0 | 1805 | private: |
michael@0 | 1806 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 1807 | nsString mError; |
michael@0 | 1808 | }; |
michael@0 | 1809 | |
michael@0 | 1810 | ContinueCursorEvent::ContinueCursorEvent(already_AddRefed<DOMRequest> aRequest) |
michael@0 | 1811 | : mRequest(aRequest) |
michael@0 | 1812 | { |
michael@0 | 1813 | } |
michael@0 | 1814 | |
michael@0 | 1815 | ContinueCursorEvent::ContinueCursorEvent(DOMRequest* aRequest) |
michael@0 | 1816 | : mRequest(aRequest) |
michael@0 | 1817 | { |
michael@0 | 1818 | } |
michael@0 | 1819 | |
michael@0 | 1820 | already_AddRefed<DeviceStorageFile> |
michael@0 | 1821 | ContinueCursorEvent::GetNextFile() |
michael@0 | 1822 | { |
michael@0 | 1823 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1824 | |
michael@0 | 1825 | nsDOMDeviceStorageCursor* cursor |
michael@0 | 1826 | = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); |
michael@0 | 1827 | nsString cursorStorageType; |
michael@0 | 1828 | cursor->GetStorageType(cursorStorageType); |
michael@0 | 1829 | |
michael@0 | 1830 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 1831 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 1832 | if (!typeChecker) { |
michael@0 | 1833 | return nullptr; |
michael@0 | 1834 | } |
michael@0 | 1835 | |
michael@0 | 1836 | while (cursor->mFiles.Length() > 0) { |
michael@0 | 1837 | nsRefPtr<DeviceStorageFile> file = cursor->mFiles[0]; |
michael@0 | 1838 | cursor->mFiles.RemoveElementAt(0); |
michael@0 | 1839 | if (!typeChecker->Check(cursorStorageType, file->mFile)) { |
michael@0 | 1840 | continue; |
michael@0 | 1841 | } |
michael@0 | 1842 | |
michael@0 | 1843 | file->CalculateMimeType(); |
michael@0 | 1844 | return file.forget(); |
michael@0 | 1845 | } |
michael@0 | 1846 | |
michael@0 | 1847 | return nullptr; |
michael@0 | 1848 | } |
michael@0 | 1849 | |
michael@0 | 1850 | ContinueCursorEvent::~ContinueCursorEvent() {} |
michael@0 | 1851 | |
michael@0 | 1852 | void |
michael@0 | 1853 | ContinueCursorEvent::Continue() |
michael@0 | 1854 | { |
michael@0 | 1855 | if (XRE_GetProcessType() == GeckoProcessType_Default) { |
michael@0 | 1856 | DebugOnly<nsresult> rv = NS_DispatchToMainThread(this); |
michael@0 | 1857 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 1858 | return; |
michael@0 | 1859 | } |
michael@0 | 1860 | |
michael@0 | 1861 | nsRefPtr<DeviceStorageFile> file = GetNextFile(); |
michael@0 | 1862 | |
michael@0 | 1863 | if (!file) { |
michael@0 | 1864 | // done with enumeration. |
michael@0 | 1865 | DebugOnly<nsresult> rv = NS_DispatchToMainThread(this); |
michael@0 | 1866 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 1867 | return; |
michael@0 | 1868 | } |
michael@0 | 1869 | |
michael@0 | 1870 | nsDOMDeviceStorageCursor* cursor |
michael@0 | 1871 | = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); |
michael@0 | 1872 | nsString cursorStorageType; |
michael@0 | 1873 | cursor->GetStorageType(cursorStorageType); |
michael@0 | 1874 | |
michael@0 | 1875 | DeviceStorageRequestChild* child |
michael@0 | 1876 | = new DeviceStorageRequestChild(mRequest, file); |
michael@0 | 1877 | child->SetCallback(cursor); |
michael@0 | 1878 | DeviceStorageGetParams params(cursorStorageType, |
michael@0 | 1879 | file->mStorageName, |
michael@0 | 1880 | file->mRootDir, |
michael@0 | 1881 | file->mPath); |
michael@0 | 1882 | ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, |
michael@0 | 1883 | params); |
michael@0 | 1884 | mRequest = nullptr; |
michael@0 | 1885 | } |
michael@0 | 1886 | |
michael@0 | 1887 | NS_IMETHODIMP |
michael@0 | 1888 | ContinueCursorEvent::Run() |
michael@0 | 1889 | { |
michael@0 | 1890 | nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); |
michael@0 | 1891 | if (!window) { |
michael@0 | 1892 | return NS_OK; |
michael@0 | 1893 | } |
michael@0 | 1894 | |
michael@0 | 1895 | nsRefPtr<DeviceStorageFile> file = GetNextFile(); |
michael@0 | 1896 | |
michael@0 | 1897 | nsDOMDeviceStorageCursor* cursor |
michael@0 | 1898 | = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); |
michael@0 | 1899 | |
michael@0 | 1900 | AutoJSContext cx; |
michael@0 | 1901 | JS::Rooted<JS::Value> val(cx, nsIFileToJsval(window, file)); |
michael@0 | 1902 | |
michael@0 | 1903 | if (file) { |
michael@0 | 1904 | cursor->mOkToCallContinue = true; |
michael@0 | 1905 | cursor->FireSuccess(val); |
michael@0 | 1906 | } else { |
michael@0 | 1907 | cursor->FireDone(); |
michael@0 | 1908 | } |
michael@0 | 1909 | mRequest = nullptr; |
michael@0 | 1910 | return NS_OK; |
michael@0 | 1911 | } |
michael@0 | 1912 | |
michael@0 | 1913 | class InitCursorEvent : public nsRunnable |
michael@0 | 1914 | { |
michael@0 | 1915 | public: |
michael@0 | 1916 | InitCursorEvent(DOMRequest* aRequest, DeviceStorageFile* aFile) |
michael@0 | 1917 | : mFile(aFile) |
michael@0 | 1918 | , mRequest(aRequest) |
michael@0 | 1919 | { |
michael@0 | 1920 | } |
michael@0 | 1921 | |
michael@0 | 1922 | ~InitCursorEvent() {} |
michael@0 | 1923 | |
michael@0 | 1924 | NS_IMETHOD Run() { |
michael@0 | 1925 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 1926 | |
michael@0 | 1927 | if (mFile->mFile) { |
michael@0 | 1928 | bool check; |
michael@0 | 1929 | mFile->mFile->IsDirectory(&check); |
michael@0 | 1930 | if (!check) { |
michael@0 | 1931 | nsCOMPtr<nsIRunnable> event = |
michael@0 | 1932 | new PostErrorEvent(mRequest.forget(), |
michael@0 | 1933 | POST_ERROR_EVENT_FILE_NOT_ENUMERABLE); |
michael@0 | 1934 | return NS_DispatchToMainThread(event); |
michael@0 | 1935 | } |
michael@0 | 1936 | } |
michael@0 | 1937 | |
michael@0 | 1938 | nsDOMDeviceStorageCursor* cursor |
michael@0 | 1939 | = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); |
michael@0 | 1940 | mFile->CollectFiles(cursor->mFiles, cursor->mSince); |
michael@0 | 1941 | |
michael@0 | 1942 | nsRefPtr<ContinueCursorEvent> event |
michael@0 | 1943 | = new ContinueCursorEvent(mRequest.forget()); |
michael@0 | 1944 | event->Continue(); |
michael@0 | 1945 | |
michael@0 | 1946 | return NS_OK; |
michael@0 | 1947 | } |
michael@0 | 1948 | |
michael@0 | 1949 | |
michael@0 | 1950 | private: |
michael@0 | 1951 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 1952 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 1953 | }; |
michael@0 | 1954 | |
michael@0 | 1955 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDeviceStorageCursor) |
michael@0 | 1956 | NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest) |
michael@0 | 1957 | NS_INTERFACE_MAP_END_INHERITING(DOMCursor) |
michael@0 | 1958 | |
michael@0 | 1959 | NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageCursor, DOMCursor) |
michael@0 | 1960 | NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageCursor, DOMCursor) |
michael@0 | 1961 | |
michael@0 | 1962 | nsDOMDeviceStorageCursor::nsDOMDeviceStorageCursor(nsPIDOMWindow* aWindow, |
michael@0 | 1963 | nsIPrincipal* aPrincipal, |
michael@0 | 1964 | DeviceStorageFile* aFile, |
michael@0 | 1965 | PRTime aSince) |
michael@0 | 1966 | : DOMCursor(aWindow, nullptr) |
michael@0 | 1967 | , mOkToCallContinue(false) |
michael@0 | 1968 | , mSince(aSince) |
michael@0 | 1969 | , mFile(aFile) |
michael@0 | 1970 | , mPrincipal(aPrincipal) |
michael@0 | 1971 | { |
michael@0 | 1972 | } |
michael@0 | 1973 | |
michael@0 | 1974 | nsDOMDeviceStorageCursor::~nsDOMDeviceStorageCursor() |
michael@0 | 1975 | { |
michael@0 | 1976 | } |
michael@0 | 1977 | |
michael@0 | 1978 | void |
michael@0 | 1979 | nsDOMDeviceStorageCursor::GetStorageType(nsAString & aType) |
michael@0 | 1980 | { |
michael@0 | 1981 | aType = mFile->mStorageType; |
michael@0 | 1982 | } |
michael@0 | 1983 | |
michael@0 | 1984 | NS_IMETHODIMP |
michael@0 | 1985 | nsDOMDeviceStorageCursor::GetTypes(nsIArray** aTypes) |
michael@0 | 1986 | { |
michael@0 | 1987 | nsCString type; |
michael@0 | 1988 | nsresult rv = |
michael@0 | 1989 | DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type); |
michael@0 | 1990 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1991 | |
michael@0 | 1992 | nsTArray<nsString> emptyOptions; |
michael@0 | 1993 | return CreatePermissionArray(type, |
michael@0 | 1994 | NS_LITERAL_CSTRING("read"), |
michael@0 | 1995 | emptyOptions, |
michael@0 | 1996 | aTypes); |
michael@0 | 1997 | } |
michael@0 | 1998 | |
michael@0 | 1999 | NS_IMETHODIMP |
michael@0 | 2000 | nsDOMDeviceStorageCursor::GetPrincipal(nsIPrincipal * *aRequestingPrincipal) |
michael@0 | 2001 | { |
michael@0 | 2002 | NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal); |
michael@0 | 2003 | return NS_OK; |
michael@0 | 2004 | } |
michael@0 | 2005 | |
michael@0 | 2006 | NS_IMETHODIMP |
michael@0 | 2007 | nsDOMDeviceStorageCursor::GetWindow(nsIDOMWindow * *aRequestingWindow) |
michael@0 | 2008 | { |
michael@0 | 2009 | NS_IF_ADDREF(*aRequestingWindow = GetOwner()); |
michael@0 | 2010 | return NS_OK; |
michael@0 | 2011 | } |
michael@0 | 2012 | |
michael@0 | 2013 | NS_IMETHODIMP |
michael@0 | 2014 | nsDOMDeviceStorageCursor::GetElement(nsIDOMElement * *aRequestingElement) |
michael@0 | 2015 | { |
michael@0 | 2016 | *aRequestingElement = nullptr; |
michael@0 | 2017 | return NS_OK; |
michael@0 | 2018 | } |
michael@0 | 2019 | |
michael@0 | 2020 | NS_IMETHODIMP |
michael@0 | 2021 | nsDOMDeviceStorageCursor::Cancel() |
michael@0 | 2022 | { |
michael@0 | 2023 | nsCOMPtr<nsIRunnable> event |
michael@0 | 2024 | = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED); |
michael@0 | 2025 | return NS_DispatchToMainThread(event); |
michael@0 | 2026 | } |
michael@0 | 2027 | |
michael@0 | 2028 | NS_IMETHODIMP |
michael@0 | 2029 | nsDOMDeviceStorageCursor::Allow(JS::HandleValue aChoices) |
michael@0 | 2030 | { |
michael@0 | 2031 | MOZ_ASSERT(aChoices.isUndefined()); |
michael@0 | 2032 | |
michael@0 | 2033 | if (!mFile->IsSafePath()) { |
michael@0 | 2034 | nsCOMPtr<nsIRunnable> r |
michael@0 | 2035 | = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED); |
michael@0 | 2036 | return NS_DispatchToMainThread(r); |
michael@0 | 2037 | } |
michael@0 | 2038 | |
michael@0 | 2039 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 2040 | PDeviceStorageRequestChild* child |
michael@0 | 2041 | = new DeviceStorageRequestChild(this, mFile); |
michael@0 | 2042 | DeviceStorageEnumerationParams params(mFile->mStorageType, |
michael@0 | 2043 | mFile->mStorageName, |
michael@0 | 2044 | mFile->mRootDir, |
michael@0 | 2045 | mSince); |
michael@0 | 2046 | ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, |
michael@0 | 2047 | params); |
michael@0 | 2048 | return NS_OK; |
michael@0 | 2049 | } |
michael@0 | 2050 | |
michael@0 | 2051 | nsCOMPtr<nsIEventTarget> target |
michael@0 | 2052 | = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); |
michael@0 | 2053 | MOZ_ASSERT(target); |
michael@0 | 2054 | |
michael@0 | 2055 | nsCOMPtr<nsIRunnable> event = new InitCursorEvent(this, mFile); |
michael@0 | 2056 | target->Dispatch(event, NS_DISPATCH_NORMAL); |
michael@0 | 2057 | return NS_OK; |
michael@0 | 2058 | } |
michael@0 | 2059 | |
michael@0 | 2060 | void |
michael@0 | 2061 | nsDOMDeviceStorageCursor::Continue(ErrorResult& aRv) |
michael@0 | 2062 | { |
michael@0 | 2063 | if (!mOkToCallContinue) { |
michael@0 | 2064 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 2065 | return; |
michael@0 | 2066 | } |
michael@0 | 2067 | |
michael@0 | 2068 | if (mResult != JSVAL_VOID) { |
michael@0 | 2069 | // We call onsuccess multiple times. Clear the last |
michael@0 | 2070 | // result. |
michael@0 | 2071 | mResult = JSVAL_VOID; |
michael@0 | 2072 | mDone = false; |
michael@0 | 2073 | } |
michael@0 | 2074 | |
michael@0 | 2075 | nsRefPtr<ContinueCursorEvent> event = new ContinueCursorEvent(this); |
michael@0 | 2076 | event->Continue(); |
michael@0 | 2077 | |
michael@0 | 2078 | mOkToCallContinue = false; |
michael@0 | 2079 | } |
michael@0 | 2080 | |
michael@0 | 2081 | bool |
michael@0 | 2082 | nsDOMDeviceStorageCursor::Recv__delete__(const bool& allow, |
michael@0 | 2083 | const InfallibleTArray<PermissionChoice>& choices) |
michael@0 | 2084 | { |
michael@0 | 2085 | MOZ_ASSERT(choices.IsEmpty(), "DeviceStorageCursor doesn't support permission choice"); |
michael@0 | 2086 | |
michael@0 | 2087 | if (allow) { |
michael@0 | 2088 | Allow(JS::UndefinedHandleValue); |
michael@0 | 2089 | } |
michael@0 | 2090 | else { |
michael@0 | 2091 | Cancel(); |
michael@0 | 2092 | } |
michael@0 | 2093 | return true; |
michael@0 | 2094 | } |
michael@0 | 2095 | |
michael@0 | 2096 | void |
michael@0 | 2097 | nsDOMDeviceStorageCursor::IPDLRelease() |
michael@0 | 2098 | { |
michael@0 | 2099 | Release(); |
michael@0 | 2100 | } |
michael@0 | 2101 | |
michael@0 | 2102 | void |
michael@0 | 2103 | nsDOMDeviceStorageCursor::RequestComplete() |
michael@0 | 2104 | { |
michael@0 | 2105 | MOZ_ASSERT(!mOkToCallContinue); |
michael@0 | 2106 | mOkToCallContinue = true; |
michael@0 | 2107 | } |
michael@0 | 2108 | |
michael@0 | 2109 | class PostAvailableResultEvent : public nsRunnable |
michael@0 | 2110 | { |
michael@0 | 2111 | public: |
michael@0 | 2112 | PostAvailableResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) |
michael@0 | 2113 | : mFile(aFile) |
michael@0 | 2114 | , mRequest(aRequest) |
michael@0 | 2115 | { |
michael@0 | 2116 | MOZ_ASSERT(mRequest); |
michael@0 | 2117 | } |
michael@0 | 2118 | |
michael@0 | 2119 | ~PostAvailableResultEvent() {} |
michael@0 | 2120 | |
michael@0 | 2121 | NS_IMETHOD Run() |
michael@0 | 2122 | { |
michael@0 | 2123 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2124 | nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); |
michael@0 | 2125 | if (!window) { |
michael@0 | 2126 | return NS_OK; |
michael@0 | 2127 | } |
michael@0 | 2128 | |
michael@0 | 2129 | nsString state = NS_LITERAL_STRING("unavailable"); |
michael@0 | 2130 | if (mFile) { |
michael@0 | 2131 | mFile->GetStatus(state); |
michael@0 | 2132 | } |
michael@0 | 2133 | |
michael@0 | 2134 | AutoJSContext cx; |
michael@0 | 2135 | JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); |
michael@0 | 2136 | mRequest->FireSuccess(result); |
michael@0 | 2137 | mRequest = nullptr; |
michael@0 | 2138 | return NS_OK; |
michael@0 | 2139 | } |
michael@0 | 2140 | |
michael@0 | 2141 | private: |
michael@0 | 2142 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2143 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2144 | }; |
michael@0 | 2145 | |
michael@0 | 2146 | class PostStatusResultEvent : public nsRunnable |
michael@0 | 2147 | { |
michael@0 | 2148 | public: |
michael@0 | 2149 | PostStatusResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) |
michael@0 | 2150 | : mFile(aFile) |
michael@0 | 2151 | , mRequest(aRequest) |
michael@0 | 2152 | { |
michael@0 | 2153 | MOZ_ASSERT(mRequest); |
michael@0 | 2154 | } |
michael@0 | 2155 | |
michael@0 | 2156 | ~PostStatusResultEvent() {} |
michael@0 | 2157 | |
michael@0 | 2158 | NS_IMETHOD Run() |
michael@0 | 2159 | { |
michael@0 | 2160 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2161 | nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); |
michael@0 | 2162 | if (!window) { |
michael@0 | 2163 | return NS_OK; |
michael@0 | 2164 | } |
michael@0 | 2165 | |
michael@0 | 2166 | nsString state = NS_LITERAL_STRING("undefined"); |
michael@0 | 2167 | if (mFile) { |
michael@0 | 2168 | mFile->GetStorageStatus(state); |
michael@0 | 2169 | } |
michael@0 | 2170 | |
michael@0 | 2171 | AutoJSContext cx; |
michael@0 | 2172 | JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); |
michael@0 | 2173 | mRequest->FireSuccess(result); |
michael@0 | 2174 | mRequest = nullptr; |
michael@0 | 2175 | return NS_OK; |
michael@0 | 2176 | } |
michael@0 | 2177 | |
michael@0 | 2178 | private: |
michael@0 | 2179 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2180 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2181 | }; |
michael@0 | 2182 | |
michael@0 | 2183 | class PostFormatResultEvent : public nsRunnable |
michael@0 | 2184 | { |
michael@0 | 2185 | public: |
michael@0 | 2186 | PostFormatResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) |
michael@0 | 2187 | : mFile(aFile) |
michael@0 | 2188 | , mRequest(aRequest) |
michael@0 | 2189 | { |
michael@0 | 2190 | MOZ_ASSERT(mRequest); |
michael@0 | 2191 | } |
michael@0 | 2192 | |
michael@0 | 2193 | ~PostFormatResultEvent() {} |
michael@0 | 2194 | |
michael@0 | 2195 | NS_IMETHOD Run() |
michael@0 | 2196 | { |
michael@0 | 2197 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2198 | nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); |
michael@0 | 2199 | if (!window) { |
michael@0 | 2200 | return NS_OK; |
michael@0 | 2201 | } |
michael@0 | 2202 | |
michael@0 | 2203 | nsString state = NS_LITERAL_STRING("unavailable"); |
michael@0 | 2204 | if (mFile) { |
michael@0 | 2205 | mFile->DoFormat(state); |
michael@0 | 2206 | } |
michael@0 | 2207 | |
michael@0 | 2208 | AutoJSContext cx; |
michael@0 | 2209 | JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); |
michael@0 | 2210 | mRequest->FireSuccess(result); |
michael@0 | 2211 | mRequest = nullptr; |
michael@0 | 2212 | return NS_OK; |
michael@0 | 2213 | } |
michael@0 | 2214 | |
michael@0 | 2215 | private: |
michael@0 | 2216 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2217 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2218 | }; |
michael@0 | 2219 | |
michael@0 | 2220 | class PostMountResultEvent : public nsRunnable |
michael@0 | 2221 | { |
michael@0 | 2222 | public: |
michael@0 | 2223 | PostMountResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) |
michael@0 | 2224 | : mFile(aFile) |
michael@0 | 2225 | , mRequest(aRequest) |
michael@0 | 2226 | { |
michael@0 | 2227 | MOZ_ASSERT(mRequest); |
michael@0 | 2228 | } |
michael@0 | 2229 | |
michael@0 | 2230 | ~PostMountResultEvent() {} |
michael@0 | 2231 | |
michael@0 | 2232 | NS_IMETHOD Run() |
michael@0 | 2233 | { |
michael@0 | 2234 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2235 | nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); |
michael@0 | 2236 | if (!window) { |
michael@0 | 2237 | return NS_OK; |
michael@0 | 2238 | } |
michael@0 | 2239 | |
michael@0 | 2240 | nsString state = NS_LITERAL_STRING("unavailable"); |
michael@0 | 2241 | if (mFile) { |
michael@0 | 2242 | mFile->DoMount(state); |
michael@0 | 2243 | } |
michael@0 | 2244 | |
michael@0 | 2245 | AutoJSContext cx; |
michael@0 | 2246 | JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); |
michael@0 | 2247 | mRequest->FireSuccess(result); |
michael@0 | 2248 | mRequest = nullptr; |
michael@0 | 2249 | return NS_OK; |
michael@0 | 2250 | } |
michael@0 | 2251 | |
michael@0 | 2252 | private: |
michael@0 | 2253 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2254 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2255 | }; |
michael@0 | 2256 | |
michael@0 | 2257 | class PostUnmountResultEvent : public nsRunnable |
michael@0 | 2258 | { |
michael@0 | 2259 | public: |
michael@0 | 2260 | PostUnmountResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) |
michael@0 | 2261 | : mFile(aFile) |
michael@0 | 2262 | , mRequest(aRequest) |
michael@0 | 2263 | { |
michael@0 | 2264 | MOZ_ASSERT(mRequest); |
michael@0 | 2265 | } |
michael@0 | 2266 | |
michael@0 | 2267 | ~PostUnmountResultEvent() {} |
michael@0 | 2268 | |
michael@0 | 2269 | NS_IMETHOD Run() |
michael@0 | 2270 | { |
michael@0 | 2271 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2272 | nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); |
michael@0 | 2273 | if (!window) { |
michael@0 | 2274 | return NS_OK; |
michael@0 | 2275 | } |
michael@0 | 2276 | |
michael@0 | 2277 | nsString state = NS_LITERAL_STRING("unavailable"); |
michael@0 | 2278 | if (mFile) { |
michael@0 | 2279 | mFile->DoUnmount(state); |
michael@0 | 2280 | } |
michael@0 | 2281 | |
michael@0 | 2282 | AutoJSContext cx; |
michael@0 | 2283 | JS::Rooted<JS::Value> result(cx, StringToJsval(window, state)); |
michael@0 | 2284 | mRequest->FireSuccess(result); |
michael@0 | 2285 | mRequest = nullptr; |
michael@0 | 2286 | return NS_OK; |
michael@0 | 2287 | } |
michael@0 | 2288 | |
michael@0 | 2289 | private: |
michael@0 | 2290 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2291 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2292 | }; |
michael@0 | 2293 | |
michael@0 | 2294 | class PostResultEvent : public nsRunnable |
michael@0 | 2295 | { |
michael@0 | 2296 | public: |
michael@0 | 2297 | PostResultEvent(already_AddRefed<DOMRequest> aRequest, |
michael@0 | 2298 | DeviceStorageFile* aFile) |
michael@0 | 2299 | : mFile(aFile) |
michael@0 | 2300 | , mRequest(aRequest) |
michael@0 | 2301 | { |
michael@0 | 2302 | MOZ_ASSERT(mRequest); |
michael@0 | 2303 | } |
michael@0 | 2304 | |
michael@0 | 2305 | PostResultEvent(already_AddRefed<DOMRequest> aRequest, |
michael@0 | 2306 | const nsAString & aPath) |
michael@0 | 2307 | : mPath(aPath) |
michael@0 | 2308 | , mRequest(aRequest) |
michael@0 | 2309 | { |
michael@0 | 2310 | MOZ_ASSERT(mRequest); |
michael@0 | 2311 | } |
michael@0 | 2312 | |
michael@0 | 2313 | PostResultEvent(already_AddRefed<DOMRequest> aRequest, |
michael@0 | 2314 | const uint64_t aValue) |
michael@0 | 2315 | : mValue(aValue) |
michael@0 | 2316 | , mRequest(aRequest) |
michael@0 | 2317 | { |
michael@0 | 2318 | MOZ_ASSERT(mRequest); |
michael@0 | 2319 | } |
michael@0 | 2320 | |
michael@0 | 2321 | ~PostResultEvent() {} |
michael@0 | 2322 | |
michael@0 | 2323 | NS_IMETHOD Run() |
michael@0 | 2324 | { |
michael@0 | 2325 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2326 | nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner(); |
michael@0 | 2327 | if (!window) { |
michael@0 | 2328 | return NS_OK; |
michael@0 | 2329 | } |
michael@0 | 2330 | |
michael@0 | 2331 | AutoJSContext cx; |
michael@0 | 2332 | JS::Rooted<JS::Value> result(cx, JSVAL_NULL); |
michael@0 | 2333 | |
michael@0 | 2334 | if (mFile) { |
michael@0 | 2335 | result = nsIFileToJsval(window, mFile); |
michael@0 | 2336 | } else if (mPath.Length()) { |
michael@0 | 2337 | result = StringToJsval(window, mPath); |
michael@0 | 2338 | } |
michael@0 | 2339 | else { |
michael@0 | 2340 | result = JS_NumberValue(double(mValue)); |
michael@0 | 2341 | } |
michael@0 | 2342 | |
michael@0 | 2343 | mRequest->FireSuccess(result); |
michael@0 | 2344 | mRequest = nullptr; |
michael@0 | 2345 | return NS_OK; |
michael@0 | 2346 | } |
michael@0 | 2347 | |
michael@0 | 2348 | private: |
michael@0 | 2349 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2350 | nsString mPath; |
michael@0 | 2351 | uint64_t mValue; |
michael@0 | 2352 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2353 | }; |
michael@0 | 2354 | |
michael@0 | 2355 | class CreateFdEvent : public nsRunnable |
michael@0 | 2356 | { |
michael@0 | 2357 | public: |
michael@0 | 2358 | CreateFdEvent(DeviceStorageFileDescriptor* aDSFileDescriptor, |
michael@0 | 2359 | already_AddRefed<DOMRequest> aRequest) |
michael@0 | 2360 | : mDSFileDescriptor(aDSFileDescriptor) |
michael@0 | 2361 | , mRequest(aRequest) |
michael@0 | 2362 | { |
michael@0 | 2363 | MOZ_ASSERT(mDSFileDescriptor); |
michael@0 | 2364 | MOZ_ASSERT(mRequest); |
michael@0 | 2365 | } |
michael@0 | 2366 | |
michael@0 | 2367 | NS_IMETHOD Run() |
michael@0 | 2368 | { |
michael@0 | 2369 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 2370 | |
michael@0 | 2371 | DeviceStorageFile* dsFile = mDSFileDescriptor->mDSFile; |
michael@0 | 2372 | MOZ_ASSERT(dsFile); |
michael@0 | 2373 | |
michael@0 | 2374 | nsString fullPath; |
michael@0 | 2375 | dsFile->GetFullPath(fullPath); |
michael@0 | 2376 | MOZ_ASSERT(!fullPath.IsEmpty()); |
michael@0 | 2377 | |
michael@0 | 2378 | bool check = false; |
michael@0 | 2379 | dsFile->mFile->Exists(&check); |
michael@0 | 2380 | if (check) { |
michael@0 | 2381 | nsCOMPtr<nsIRunnable> event = |
michael@0 | 2382 | new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_EXISTS); |
michael@0 | 2383 | return NS_DispatchToMainThread(event); |
michael@0 | 2384 | } |
michael@0 | 2385 | |
michael@0 | 2386 | nsresult rv = dsFile->CreateFileDescriptor(mDSFileDescriptor->mFileDescriptor); |
michael@0 | 2387 | |
michael@0 | 2388 | if (NS_FAILED(rv)) { |
michael@0 | 2389 | dsFile->mFile->Remove(false); |
michael@0 | 2390 | |
michael@0 | 2391 | nsCOMPtr<nsIRunnable> event = |
michael@0 | 2392 | new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN); |
michael@0 | 2393 | return NS_DispatchToMainThread(event); |
michael@0 | 2394 | } |
michael@0 | 2395 | |
michael@0 | 2396 | nsCOMPtr<nsIRunnable> event = |
michael@0 | 2397 | new PostResultEvent(mRequest.forget(), fullPath); |
michael@0 | 2398 | return NS_DispatchToMainThread(event); |
michael@0 | 2399 | } |
michael@0 | 2400 | |
michael@0 | 2401 | private: |
michael@0 | 2402 | nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor; |
michael@0 | 2403 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2404 | }; |
michael@0 | 2405 | |
michael@0 | 2406 | class WriteFileEvent : public nsRunnable |
michael@0 | 2407 | { |
michael@0 | 2408 | public: |
michael@0 | 2409 | WriteFileEvent(nsIDOMBlob* aBlob, |
michael@0 | 2410 | DeviceStorageFile *aFile, |
michael@0 | 2411 | already_AddRefed<DOMRequest> aRequest) |
michael@0 | 2412 | : mBlob(aBlob) |
michael@0 | 2413 | , mFile(aFile) |
michael@0 | 2414 | , mRequest(aRequest) |
michael@0 | 2415 | { |
michael@0 | 2416 | MOZ_ASSERT(mFile); |
michael@0 | 2417 | MOZ_ASSERT(mRequest); |
michael@0 | 2418 | } |
michael@0 | 2419 | |
michael@0 | 2420 | ~WriteFileEvent() {} |
michael@0 | 2421 | |
michael@0 | 2422 | NS_IMETHOD Run() |
michael@0 | 2423 | { |
michael@0 | 2424 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 2425 | |
michael@0 | 2426 | nsCOMPtr<nsIInputStream> stream; |
michael@0 | 2427 | mBlob->GetInternalStream(getter_AddRefs(stream)); |
michael@0 | 2428 | |
michael@0 | 2429 | bool check = false; |
michael@0 | 2430 | mFile->mFile->Exists(&check); |
michael@0 | 2431 | if (check) { |
michael@0 | 2432 | nsCOMPtr<nsIRunnable> event = |
michael@0 | 2433 | new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_EXISTS); |
michael@0 | 2434 | return NS_DispatchToMainThread(event); |
michael@0 | 2435 | } |
michael@0 | 2436 | |
michael@0 | 2437 | nsresult rv = mFile->Write(stream); |
michael@0 | 2438 | |
michael@0 | 2439 | if (NS_FAILED(rv)) { |
michael@0 | 2440 | mFile->mFile->Remove(false); |
michael@0 | 2441 | |
michael@0 | 2442 | nsCOMPtr<nsIRunnable> event = |
michael@0 | 2443 | new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN); |
michael@0 | 2444 | return NS_DispatchToMainThread(event); |
michael@0 | 2445 | } |
michael@0 | 2446 | |
michael@0 | 2447 | nsString fullPath; |
michael@0 | 2448 | mFile->GetFullPath(fullPath); |
michael@0 | 2449 | nsCOMPtr<nsIRunnable> event = |
michael@0 | 2450 | new PostResultEvent(mRequest.forget(), fullPath); |
michael@0 | 2451 | return NS_DispatchToMainThread(event); |
michael@0 | 2452 | } |
michael@0 | 2453 | |
michael@0 | 2454 | private: |
michael@0 | 2455 | nsCOMPtr<nsIDOMBlob> mBlob; |
michael@0 | 2456 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2457 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2458 | }; |
michael@0 | 2459 | |
michael@0 | 2460 | class ReadFileEvent : public nsRunnable |
michael@0 | 2461 | { |
michael@0 | 2462 | public: |
michael@0 | 2463 | ReadFileEvent(DeviceStorageFile* aFile, |
michael@0 | 2464 | already_AddRefed<DOMRequest> aRequest) |
michael@0 | 2465 | : mFile(aFile) |
michael@0 | 2466 | , mRequest(aRequest) |
michael@0 | 2467 | { |
michael@0 | 2468 | MOZ_ASSERT(mFile); |
michael@0 | 2469 | MOZ_ASSERT(mRequest); |
michael@0 | 2470 | mFile->CalculateMimeType(); |
michael@0 | 2471 | } |
michael@0 | 2472 | |
michael@0 | 2473 | ~ReadFileEvent() {} |
michael@0 | 2474 | |
michael@0 | 2475 | NS_IMETHOD Run() |
michael@0 | 2476 | { |
michael@0 | 2477 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 2478 | |
michael@0 | 2479 | nsCOMPtr<nsIRunnable> r; |
michael@0 | 2480 | if (!mFile->mEditable) { |
michael@0 | 2481 | bool check = false; |
michael@0 | 2482 | mFile->mFile->Exists(&check); |
michael@0 | 2483 | if (!check) { |
michael@0 | 2484 | r = new PostErrorEvent(mRequest.forget(), |
michael@0 | 2485 | POST_ERROR_EVENT_FILE_DOES_NOT_EXIST); |
michael@0 | 2486 | } |
michael@0 | 2487 | } |
michael@0 | 2488 | |
michael@0 | 2489 | if (!r) { |
michael@0 | 2490 | nsresult rv = mFile->CalculateSizeAndModifiedDate(); |
michael@0 | 2491 | if (NS_FAILED(rv)) { |
michael@0 | 2492 | r = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN); |
michael@0 | 2493 | } |
michael@0 | 2494 | } |
michael@0 | 2495 | |
michael@0 | 2496 | if (!r) { |
michael@0 | 2497 | r = new PostResultEvent(mRequest.forget(), mFile); |
michael@0 | 2498 | } |
michael@0 | 2499 | return NS_DispatchToMainThread(r); |
michael@0 | 2500 | } |
michael@0 | 2501 | |
michael@0 | 2502 | private: |
michael@0 | 2503 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2504 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2505 | }; |
michael@0 | 2506 | |
michael@0 | 2507 | class DeleteFileEvent : public nsRunnable |
michael@0 | 2508 | { |
michael@0 | 2509 | public: |
michael@0 | 2510 | DeleteFileEvent(DeviceStorageFile* aFile, |
michael@0 | 2511 | already_AddRefed<DOMRequest> aRequest) |
michael@0 | 2512 | : mFile(aFile) |
michael@0 | 2513 | , mRequest(aRequest) |
michael@0 | 2514 | { |
michael@0 | 2515 | MOZ_ASSERT(mFile); |
michael@0 | 2516 | MOZ_ASSERT(mRequest); |
michael@0 | 2517 | } |
michael@0 | 2518 | |
michael@0 | 2519 | ~DeleteFileEvent() {} |
michael@0 | 2520 | |
michael@0 | 2521 | NS_IMETHOD Run() |
michael@0 | 2522 | { |
michael@0 | 2523 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 2524 | mFile->Remove(); |
michael@0 | 2525 | |
michael@0 | 2526 | nsCOMPtr<nsIRunnable> r; |
michael@0 | 2527 | bool check = false; |
michael@0 | 2528 | mFile->mFile->Exists(&check); |
michael@0 | 2529 | if (check) { |
michael@0 | 2530 | r = new PostErrorEvent(mRequest.forget(), |
michael@0 | 2531 | POST_ERROR_EVENT_FILE_DOES_NOT_EXIST); |
michael@0 | 2532 | } |
michael@0 | 2533 | else { |
michael@0 | 2534 | nsString fullPath; |
michael@0 | 2535 | mFile->GetFullPath(fullPath); |
michael@0 | 2536 | r = new PostResultEvent(mRequest.forget(), fullPath); |
michael@0 | 2537 | } |
michael@0 | 2538 | return NS_DispatchToMainThread(r); |
michael@0 | 2539 | } |
michael@0 | 2540 | |
michael@0 | 2541 | private: |
michael@0 | 2542 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2543 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2544 | }; |
michael@0 | 2545 | |
michael@0 | 2546 | class UsedSpaceFileEvent : public nsRunnable |
michael@0 | 2547 | { |
michael@0 | 2548 | public: |
michael@0 | 2549 | UsedSpaceFileEvent(DeviceStorageFile* aFile, |
michael@0 | 2550 | already_AddRefed<DOMRequest> aRequest) |
michael@0 | 2551 | : mFile(aFile) |
michael@0 | 2552 | , mRequest(aRequest) |
michael@0 | 2553 | { |
michael@0 | 2554 | MOZ_ASSERT(mFile); |
michael@0 | 2555 | MOZ_ASSERT(mRequest); |
michael@0 | 2556 | } |
michael@0 | 2557 | |
michael@0 | 2558 | ~UsedSpaceFileEvent() {} |
michael@0 | 2559 | |
michael@0 | 2560 | NS_IMETHOD Run() |
michael@0 | 2561 | { |
michael@0 | 2562 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 2563 | |
michael@0 | 2564 | uint64_t picturesUsage = 0, videosUsage = 0, musicUsage = 0, totalUsage = 0; |
michael@0 | 2565 | mFile->AccumDiskUsage(&picturesUsage, &videosUsage, |
michael@0 | 2566 | &musicUsage, &totalUsage); |
michael@0 | 2567 | nsCOMPtr<nsIRunnable> r; |
michael@0 | 2568 | if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { |
michael@0 | 2569 | r = new PostResultEvent(mRequest.forget(), picturesUsage); |
michael@0 | 2570 | } |
michael@0 | 2571 | else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { |
michael@0 | 2572 | r = new PostResultEvent(mRequest.forget(), videosUsage); |
michael@0 | 2573 | } |
michael@0 | 2574 | else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { |
michael@0 | 2575 | r = new PostResultEvent(mRequest.forget(), musicUsage); |
michael@0 | 2576 | } else { |
michael@0 | 2577 | r = new PostResultEvent(mRequest.forget(), totalUsage); |
michael@0 | 2578 | } |
michael@0 | 2579 | return NS_DispatchToMainThread(r); |
michael@0 | 2580 | } |
michael@0 | 2581 | |
michael@0 | 2582 | private: |
michael@0 | 2583 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2584 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2585 | }; |
michael@0 | 2586 | |
michael@0 | 2587 | class FreeSpaceFileEvent : public nsRunnable |
michael@0 | 2588 | { |
michael@0 | 2589 | public: |
michael@0 | 2590 | FreeSpaceFileEvent(DeviceStorageFile* aFile, |
michael@0 | 2591 | already_AddRefed<DOMRequest> aRequest) |
michael@0 | 2592 | : mFile(aFile) |
michael@0 | 2593 | , mRequest(aRequest) |
michael@0 | 2594 | { |
michael@0 | 2595 | MOZ_ASSERT(mFile); |
michael@0 | 2596 | MOZ_ASSERT(mRequest); |
michael@0 | 2597 | } |
michael@0 | 2598 | |
michael@0 | 2599 | ~FreeSpaceFileEvent() {} |
michael@0 | 2600 | |
michael@0 | 2601 | NS_IMETHOD Run() |
michael@0 | 2602 | { |
michael@0 | 2603 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 2604 | |
michael@0 | 2605 | int64_t freeSpace = 0; |
michael@0 | 2606 | if (mFile) { |
michael@0 | 2607 | mFile->GetDiskFreeSpace(&freeSpace); |
michael@0 | 2608 | } |
michael@0 | 2609 | |
michael@0 | 2610 | nsCOMPtr<nsIRunnable> r; |
michael@0 | 2611 | r = new PostResultEvent(mRequest.forget(), |
michael@0 | 2612 | static_cast<uint64_t>(freeSpace)); |
michael@0 | 2613 | return NS_DispatchToMainThread(r); |
michael@0 | 2614 | } |
michael@0 | 2615 | |
michael@0 | 2616 | private: |
michael@0 | 2617 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 2618 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 2619 | }; |
michael@0 | 2620 | |
michael@0 | 2621 | class DeviceStorageRequest MOZ_FINAL |
michael@0 | 2622 | : public nsIContentPermissionRequest |
michael@0 | 2623 | , public nsIRunnable |
michael@0 | 2624 | , public PCOMContentPermissionRequestChild |
michael@0 | 2625 | { |
michael@0 | 2626 | public: |
michael@0 | 2627 | |
michael@0 | 2628 | DeviceStorageRequest(const DeviceStorageRequestType aRequestType, |
michael@0 | 2629 | nsPIDOMWindow* aWindow, |
michael@0 | 2630 | nsIPrincipal* aPrincipal, |
michael@0 | 2631 | DeviceStorageFile* aFile, |
michael@0 | 2632 | DOMRequest* aRequest, |
michael@0 | 2633 | nsDOMDeviceStorage* aDeviceStorage) |
michael@0 | 2634 | : mRequestType(aRequestType) |
michael@0 | 2635 | , mWindow(aWindow) |
michael@0 | 2636 | , mPrincipal(aPrincipal) |
michael@0 | 2637 | , mFile(aFile) |
michael@0 | 2638 | , mRequest(aRequest) |
michael@0 | 2639 | , mDeviceStorage(aDeviceStorage) |
michael@0 | 2640 | { |
michael@0 | 2641 | MOZ_ASSERT(mWindow); |
michael@0 | 2642 | MOZ_ASSERT(mPrincipal); |
michael@0 | 2643 | MOZ_ASSERT(mFile); |
michael@0 | 2644 | MOZ_ASSERT(mRequest); |
michael@0 | 2645 | MOZ_ASSERT(mDeviceStorage); |
michael@0 | 2646 | } |
michael@0 | 2647 | |
michael@0 | 2648 | DeviceStorageRequest(const DeviceStorageRequestType aRequestType, |
michael@0 | 2649 | nsPIDOMWindow* aWindow, |
michael@0 | 2650 | nsIPrincipal* aPrincipal, |
michael@0 | 2651 | DeviceStorageFile* aFile, |
michael@0 | 2652 | DOMRequest* aRequest, |
michael@0 | 2653 | nsIDOMBlob* aBlob = nullptr) |
michael@0 | 2654 | : mRequestType(aRequestType) |
michael@0 | 2655 | , mWindow(aWindow) |
michael@0 | 2656 | , mPrincipal(aPrincipal) |
michael@0 | 2657 | , mFile(aFile) |
michael@0 | 2658 | , mRequest(aRequest) |
michael@0 | 2659 | , mBlob(aBlob) |
michael@0 | 2660 | { |
michael@0 | 2661 | MOZ_ASSERT(mWindow); |
michael@0 | 2662 | MOZ_ASSERT(mPrincipal); |
michael@0 | 2663 | MOZ_ASSERT(mFile); |
michael@0 | 2664 | MOZ_ASSERT(mRequest); |
michael@0 | 2665 | } |
michael@0 | 2666 | |
michael@0 | 2667 | DeviceStorageRequest(const DeviceStorageRequestType aRequestType, |
michael@0 | 2668 | nsPIDOMWindow* aWindow, |
michael@0 | 2669 | nsIPrincipal* aPrincipal, |
michael@0 | 2670 | DeviceStorageFile* aFile, |
michael@0 | 2671 | DOMRequest* aRequest, |
michael@0 | 2672 | DeviceStorageFileDescriptor* aDSFileDescriptor) |
michael@0 | 2673 | : mRequestType(aRequestType) |
michael@0 | 2674 | , mWindow(aWindow) |
michael@0 | 2675 | , mPrincipal(aPrincipal) |
michael@0 | 2676 | , mFile(aFile) |
michael@0 | 2677 | , mRequest(aRequest) |
michael@0 | 2678 | , mDSFileDescriptor(aDSFileDescriptor) |
michael@0 | 2679 | { |
michael@0 | 2680 | MOZ_ASSERT(mRequestType == DEVICE_STORAGE_REQUEST_CREATEFD); |
michael@0 | 2681 | MOZ_ASSERT(mWindow); |
michael@0 | 2682 | MOZ_ASSERT(mPrincipal); |
michael@0 | 2683 | MOZ_ASSERT(mFile); |
michael@0 | 2684 | MOZ_ASSERT(mRequest); |
michael@0 | 2685 | MOZ_ASSERT(mDSFileDescriptor); |
michael@0 | 2686 | } |
michael@0 | 2687 | |
michael@0 | 2688 | NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
michael@0 | 2689 | NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageRequest, |
michael@0 | 2690 | nsIContentPermissionRequest) |
michael@0 | 2691 | |
michael@0 | 2692 | NS_IMETHOD Run() { |
michael@0 | 2693 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2694 | |
michael@0 | 2695 | if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) { |
michael@0 | 2696 | Allow(JS::UndefinedHandleValue); |
michael@0 | 2697 | return NS_OK; |
michael@0 | 2698 | } |
michael@0 | 2699 | |
michael@0 | 2700 | if (XRE_GetProcessType() == GeckoProcessType_Content) { |
michael@0 | 2701 | |
michael@0 | 2702 | // because owner implements nsITabChild, we can assume that it is |
michael@0 | 2703 | // the one and only TabChild. |
michael@0 | 2704 | TabChild* child = TabChild::GetFrom(mWindow->GetDocShell()); |
michael@0 | 2705 | if (!child) { |
michael@0 | 2706 | return NS_OK; |
michael@0 | 2707 | } |
michael@0 | 2708 | |
michael@0 | 2709 | // Retain a reference so the object isn't deleted without IPDL's |
michael@0 | 2710 | // knowledge. Corresponding release occurs in |
michael@0 | 2711 | // DeallocPContentPermissionRequest. |
michael@0 | 2712 | AddRef(); |
michael@0 | 2713 | |
michael@0 | 2714 | nsCString type; |
michael@0 | 2715 | nsresult rv = DeviceStorageTypeChecker::GetPermissionForType( |
michael@0 | 2716 | mFile->mStorageType, type); |
michael@0 | 2717 | if (NS_FAILED(rv)) { |
michael@0 | 2718 | return rv; |
michael@0 | 2719 | } |
michael@0 | 2720 | nsCString access; |
michael@0 | 2721 | rv = DeviceStorageTypeChecker::GetAccessForRequest( |
michael@0 | 2722 | DeviceStorageRequestType(mRequestType), access); |
michael@0 | 2723 | if (NS_FAILED(rv)) { |
michael@0 | 2724 | return rv; |
michael@0 | 2725 | } |
michael@0 | 2726 | nsTArray<PermissionRequest> permArray; |
michael@0 | 2727 | nsTArray<nsString> emptyOptions; |
michael@0 | 2728 | permArray.AppendElement(PermissionRequest(type, access, emptyOptions)); |
michael@0 | 2729 | child->SendPContentPermissionRequestConstructor( |
michael@0 | 2730 | this, permArray, IPC::Principal(mPrincipal)); |
michael@0 | 2731 | |
michael@0 | 2732 | Sendprompt(); |
michael@0 | 2733 | return NS_OK; |
michael@0 | 2734 | } |
michael@0 | 2735 | |
michael@0 | 2736 | nsCOMPtr<nsIContentPermissionPrompt> prompt |
michael@0 | 2737 | = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); |
michael@0 | 2738 | if (prompt) { |
michael@0 | 2739 | prompt->Prompt(this); |
michael@0 | 2740 | } |
michael@0 | 2741 | return NS_OK; |
michael@0 | 2742 | } |
michael@0 | 2743 | |
michael@0 | 2744 | NS_IMETHODIMP GetTypes(nsIArray** aTypes) |
michael@0 | 2745 | { |
michael@0 | 2746 | nsCString type; |
michael@0 | 2747 | nsresult rv = |
michael@0 | 2748 | DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type); |
michael@0 | 2749 | if (NS_FAILED(rv)) { |
michael@0 | 2750 | return rv; |
michael@0 | 2751 | } |
michael@0 | 2752 | |
michael@0 | 2753 | nsCString access; |
michael@0 | 2754 | rv = DeviceStorageTypeChecker::GetAccessForRequest( |
michael@0 | 2755 | DeviceStorageRequestType(mRequestType), access); |
michael@0 | 2756 | if (NS_FAILED(rv)) { |
michael@0 | 2757 | return rv; |
michael@0 | 2758 | } |
michael@0 | 2759 | |
michael@0 | 2760 | nsTArray<nsString> emptyOptions; |
michael@0 | 2761 | return CreatePermissionArray(type, access, emptyOptions, aTypes); |
michael@0 | 2762 | } |
michael@0 | 2763 | |
michael@0 | 2764 | NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal) |
michael@0 | 2765 | { |
michael@0 | 2766 | NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal); |
michael@0 | 2767 | return NS_OK; |
michael@0 | 2768 | } |
michael@0 | 2769 | |
michael@0 | 2770 | NS_IMETHOD GetWindow(nsIDOMWindow * *aRequestingWindow) |
michael@0 | 2771 | { |
michael@0 | 2772 | NS_IF_ADDREF(*aRequestingWindow = mWindow); |
michael@0 | 2773 | return NS_OK; |
michael@0 | 2774 | } |
michael@0 | 2775 | |
michael@0 | 2776 | NS_IMETHOD GetElement(nsIDOMElement * *aRequestingElement) |
michael@0 | 2777 | { |
michael@0 | 2778 | *aRequestingElement = nullptr; |
michael@0 | 2779 | return NS_OK; |
michael@0 | 2780 | } |
michael@0 | 2781 | |
michael@0 | 2782 | NS_IMETHOD Cancel() |
michael@0 | 2783 | { |
michael@0 | 2784 | nsCOMPtr<nsIRunnable> event |
michael@0 | 2785 | = new PostErrorEvent(mRequest.forget(), |
michael@0 | 2786 | POST_ERROR_EVENT_PERMISSION_DENIED); |
michael@0 | 2787 | return NS_DispatchToMainThread(event); |
michael@0 | 2788 | } |
michael@0 | 2789 | |
michael@0 | 2790 | NS_IMETHOD Allow(JS::HandleValue aChoices) |
michael@0 | 2791 | { |
michael@0 | 2792 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2793 | MOZ_ASSERT(aChoices.isUndefined()); |
michael@0 | 2794 | |
michael@0 | 2795 | if (!mRequest) { |
michael@0 | 2796 | return NS_ERROR_FAILURE; |
michael@0 | 2797 | } |
michael@0 | 2798 | |
michael@0 | 2799 | nsCOMPtr<nsIRunnable> r; |
michael@0 | 2800 | |
michael@0 | 2801 | switch(mRequestType) { |
michael@0 | 2802 | case DEVICE_STORAGE_REQUEST_CREATEFD: |
michael@0 | 2803 | { |
michael@0 | 2804 | if (!mFile->mFile) { |
michael@0 | 2805 | return NS_ERROR_FAILURE; |
michael@0 | 2806 | } |
michael@0 | 2807 | |
michael@0 | 2808 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 2809 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 2810 | if (!typeChecker) { |
michael@0 | 2811 | return NS_OK; |
michael@0 | 2812 | } |
michael@0 | 2813 | |
michael@0 | 2814 | if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) { |
michael@0 | 2815 | r = new PostErrorEvent(mRequest.forget(), |
michael@0 | 2816 | POST_ERROR_EVENT_ILLEGAL_TYPE); |
michael@0 | 2817 | return NS_DispatchToCurrentThread(r); |
michael@0 | 2818 | } |
michael@0 | 2819 | |
michael@0 | 2820 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 2821 | |
michael@0 | 2822 | DeviceStorageCreateFdParams params; |
michael@0 | 2823 | params.type() = mFile->mStorageType; |
michael@0 | 2824 | params.storageName() = mFile->mStorageName; |
michael@0 | 2825 | params.relpath() = mFile->mPath; |
michael@0 | 2826 | |
michael@0 | 2827 | mFile->Dump("DeviceStorageCreateFdParams"); |
michael@0 | 2828 | |
michael@0 | 2829 | PDeviceStorageRequestChild* child |
michael@0 | 2830 | = new DeviceStorageRequestChild(mRequest, mFile, |
michael@0 | 2831 | mDSFileDescriptor.get()); |
michael@0 | 2832 | ContentChild::GetSingleton() |
michael@0 | 2833 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 2834 | return NS_OK; |
michael@0 | 2835 | } |
michael@0 | 2836 | mDSFileDescriptor->mDSFile = mFile; |
michael@0 | 2837 | r = new CreateFdEvent(mDSFileDescriptor.get(), mRequest.forget()); |
michael@0 | 2838 | break; |
michael@0 | 2839 | } |
michael@0 | 2840 | |
michael@0 | 2841 | case DEVICE_STORAGE_REQUEST_CREATE: |
michael@0 | 2842 | { |
michael@0 | 2843 | if (!mBlob || !mFile->mFile) { |
michael@0 | 2844 | return NS_ERROR_FAILURE; |
michael@0 | 2845 | } |
michael@0 | 2846 | |
michael@0 | 2847 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 2848 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 2849 | if (!typeChecker) { |
michael@0 | 2850 | return NS_OK; |
michael@0 | 2851 | } |
michael@0 | 2852 | |
michael@0 | 2853 | if (!typeChecker->Check(mFile->mStorageType, mFile->mFile) || |
michael@0 | 2854 | !typeChecker->Check(mFile->mStorageType, mBlob)) { |
michael@0 | 2855 | r = new PostErrorEvent(mRequest.forget(), |
michael@0 | 2856 | POST_ERROR_EVENT_ILLEGAL_TYPE); |
michael@0 | 2857 | return NS_DispatchToCurrentThread(r); |
michael@0 | 2858 | } |
michael@0 | 2859 | |
michael@0 | 2860 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 2861 | BlobChild* actor |
michael@0 | 2862 | = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob); |
michael@0 | 2863 | if (!actor) { |
michael@0 | 2864 | return NS_ERROR_FAILURE; |
michael@0 | 2865 | } |
michael@0 | 2866 | |
michael@0 | 2867 | DeviceStorageAddParams params; |
michael@0 | 2868 | params.blobChild() = actor; |
michael@0 | 2869 | params.type() = mFile->mStorageType; |
michael@0 | 2870 | params.storageName() = mFile->mStorageName; |
michael@0 | 2871 | params.relpath() = mFile->mPath; |
michael@0 | 2872 | |
michael@0 | 2873 | PDeviceStorageRequestChild* child |
michael@0 | 2874 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 2875 | ContentChild::GetSingleton() |
michael@0 | 2876 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 2877 | return NS_OK; |
michael@0 | 2878 | } |
michael@0 | 2879 | r = new WriteFileEvent(mBlob, mFile, mRequest.forget()); |
michael@0 | 2880 | break; |
michael@0 | 2881 | } |
michael@0 | 2882 | |
michael@0 | 2883 | case DEVICE_STORAGE_REQUEST_READ: |
michael@0 | 2884 | case DEVICE_STORAGE_REQUEST_WRITE: |
michael@0 | 2885 | { |
michael@0 | 2886 | if (!mFile->mFile) { |
michael@0 | 2887 | return NS_ERROR_FAILURE; |
michael@0 | 2888 | } |
michael@0 | 2889 | |
michael@0 | 2890 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 2891 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 2892 | if (!typeChecker) { |
michael@0 | 2893 | return NS_OK; |
michael@0 | 2894 | } |
michael@0 | 2895 | |
michael@0 | 2896 | if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) { |
michael@0 | 2897 | r = new PostErrorEvent(mRequest.forget(), |
michael@0 | 2898 | POST_ERROR_EVENT_ILLEGAL_TYPE); |
michael@0 | 2899 | return NS_DispatchToCurrentThread(r); |
michael@0 | 2900 | } |
michael@0 | 2901 | |
michael@0 | 2902 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 2903 | PDeviceStorageRequestChild* child |
michael@0 | 2904 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 2905 | DeviceStorageGetParams params(mFile->mStorageType, |
michael@0 | 2906 | mFile->mStorageName, |
michael@0 | 2907 | mFile->mRootDir, |
michael@0 | 2908 | mFile->mPath); |
michael@0 | 2909 | ContentChild::GetSingleton() |
michael@0 | 2910 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 2911 | return NS_OK; |
michael@0 | 2912 | } |
michael@0 | 2913 | |
michael@0 | 2914 | r = new ReadFileEvent(mFile, mRequest.forget()); |
michael@0 | 2915 | break; |
michael@0 | 2916 | } |
michael@0 | 2917 | |
michael@0 | 2918 | case DEVICE_STORAGE_REQUEST_DELETE: |
michael@0 | 2919 | { |
michael@0 | 2920 | if (!mFile->mFile) { |
michael@0 | 2921 | return NS_ERROR_FAILURE; |
michael@0 | 2922 | } |
michael@0 | 2923 | |
michael@0 | 2924 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 2925 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 2926 | if (!typeChecker) { |
michael@0 | 2927 | return NS_OK; |
michael@0 | 2928 | } |
michael@0 | 2929 | |
michael@0 | 2930 | if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) { |
michael@0 | 2931 | r = new PostErrorEvent(mRequest.forget(), |
michael@0 | 2932 | POST_ERROR_EVENT_ILLEGAL_TYPE); |
michael@0 | 2933 | return NS_DispatchToCurrentThread(r); |
michael@0 | 2934 | } |
michael@0 | 2935 | |
michael@0 | 2936 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 2937 | PDeviceStorageRequestChild* child |
michael@0 | 2938 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 2939 | DeviceStorageDeleteParams params(mFile->mStorageType, |
michael@0 | 2940 | mFile->mStorageName, |
michael@0 | 2941 | mFile->mPath); |
michael@0 | 2942 | ContentChild::GetSingleton() |
michael@0 | 2943 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 2944 | return NS_OK; |
michael@0 | 2945 | } |
michael@0 | 2946 | r = new DeleteFileEvent(mFile, mRequest.forget()); |
michael@0 | 2947 | break; |
michael@0 | 2948 | } |
michael@0 | 2949 | |
michael@0 | 2950 | case DEVICE_STORAGE_REQUEST_FREE_SPACE: |
michael@0 | 2951 | { |
michael@0 | 2952 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 2953 | PDeviceStorageRequestChild* child |
michael@0 | 2954 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 2955 | DeviceStorageFreeSpaceParams params(mFile->mStorageType, |
michael@0 | 2956 | mFile->mStorageName); |
michael@0 | 2957 | ContentChild::GetSingleton() |
michael@0 | 2958 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 2959 | return NS_OK; |
michael@0 | 2960 | } |
michael@0 | 2961 | r = new FreeSpaceFileEvent(mFile, mRequest.forget()); |
michael@0 | 2962 | break; |
michael@0 | 2963 | } |
michael@0 | 2964 | |
michael@0 | 2965 | case DEVICE_STORAGE_REQUEST_USED_SPACE: |
michael@0 | 2966 | { |
michael@0 | 2967 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 2968 | PDeviceStorageRequestChild* child |
michael@0 | 2969 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 2970 | DeviceStorageUsedSpaceParams params(mFile->mStorageType, |
michael@0 | 2971 | mFile->mStorageName); |
michael@0 | 2972 | ContentChild::GetSingleton() |
michael@0 | 2973 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 2974 | return NS_OK; |
michael@0 | 2975 | } |
michael@0 | 2976 | // this needs to be dispatched to only one (1) |
michael@0 | 2977 | // thread or we will do more work than required. |
michael@0 | 2978 | DeviceStorageUsedSpaceCache* usedSpaceCache |
michael@0 | 2979 | = DeviceStorageUsedSpaceCache::CreateOrGet(); |
michael@0 | 2980 | MOZ_ASSERT(usedSpaceCache); |
michael@0 | 2981 | r = new UsedSpaceFileEvent(mFile, mRequest.forget()); |
michael@0 | 2982 | usedSpaceCache->Dispatch(r); |
michael@0 | 2983 | return NS_OK; |
michael@0 | 2984 | } |
michael@0 | 2985 | |
michael@0 | 2986 | case DEVICE_STORAGE_REQUEST_AVAILABLE: |
michael@0 | 2987 | { |
michael@0 | 2988 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 2989 | PDeviceStorageRequestChild* child |
michael@0 | 2990 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 2991 | DeviceStorageAvailableParams params(mFile->mStorageType, |
michael@0 | 2992 | mFile->mStorageName); |
michael@0 | 2993 | ContentChild::GetSingleton() |
michael@0 | 2994 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 2995 | return NS_OK; |
michael@0 | 2996 | } |
michael@0 | 2997 | r = new PostAvailableResultEvent(mFile, mRequest); |
michael@0 | 2998 | return NS_DispatchToCurrentThread(r); |
michael@0 | 2999 | } |
michael@0 | 3000 | |
michael@0 | 3001 | case DEVICE_STORAGE_REQUEST_STATUS: |
michael@0 | 3002 | { |
michael@0 | 3003 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 3004 | PDeviceStorageRequestChild* child |
michael@0 | 3005 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 3006 | DeviceStorageStatusParams params(mFile->mStorageType, |
michael@0 | 3007 | mFile->mStorageName); |
michael@0 | 3008 | ContentChild::GetSingleton() |
michael@0 | 3009 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 3010 | return NS_OK; |
michael@0 | 3011 | } |
michael@0 | 3012 | r = new PostStatusResultEvent(mFile, mRequest); |
michael@0 | 3013 | return NS_DispatchToCurrentThread(r); |
michael@0 | 3014 | } |
michael@0 | 3015 | |
michael@0 | 3016 | case DEVICE_STORAGE_REQUEST_WATCH: |
michael@0 | 3017 | { |
michael@0 | 3018 | mDeviceStorage->mAllowedToWatchFile = true; |
michael@0 | 3019 | return NS_OK; |
michael@0 | 3020 | } |
michael@0 | 3021 | |
michael@0 | 3022 | case DEVICE_STORAGE_REQUEST_FORMAT: |
michael@0 | 3023 | { |
michael@0 | 3024 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 3025 | PDeviceStorageRequestChild* child |
michael@0 | 3026 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 3027 | DeviceStorageFormatParams params(mFile->mStorageType, |
michael@0 | 3028 | mFile->mStorageName); |
michael@0 | 3029 | ContentChild::GetSingleton() |
michael@0 | 3030 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 3031 | return NS_OK; |
michael@0 | 3032 | } |
michael@0 | 3033 | r = new PostFormatResultEvent(mFile, mRequest); |
michael@0 | 3034 | return NS_DispatchToCurrentThread(r); |
michael@0 | 3035 | } |
michael@0 | 3036 | |
michael@0 | 3037 | case DEVICE_STORAGE_REQUEST_MOUNT: |
michael@0 | 3038 | { |
michael@0 | 3039 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 3040 | PDeviceStorageRequestChild* child |
michael@0 | 3041 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 3042 | DeviceStorageMountParams params(mFile->mStorageType, |
michael@0 | 3043 | mFile->mStorageName); |
michael@0 | 3044 | ContentChild::GetSingleton() |
michael@0 | 3045 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 3046 | return NS_OK; |
michael@0 | 3047 | } |
michael@0 | 3048 | r = new PostMountResultEvent(mFile, mRequest); |
michael@0 | 3049 | return NS_DispatchToCurrentThread(r); |
michael@0 | 3050 | } |
michael@0 | 3051 | |
michael@0 | 3052 | case DEVICE_STORAGE_REQUEST_UNMOUNT: |
michael@0 | 3053 | { |
michael@0 | 3054 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 3055 | PDeviceStorageRequestChild* child |
michael@0 | 3056 | = new DeviceStorageRequestChild(mRequest, mFile); |
michael@0 | 3057 | DeviceStorageUnmountParams params(mFile->mStorageType, |
michael@0 | 3058 | mFile->mStorageName); |
michael@0 | 3059 | ContentChild::GetSingleton() |
michael@0 | 3060 | ->SendPDeviceStorageRequestConstructor(child, params); |
michael@0 | 3061 | return NS_OK; |
michael@0 | 3062 | } |
michael@0 | 3063 | r = new PostUnmountResultEvent(mFile, mRequest); |
michael@0 | 3064 | return NS_DispatchToCurrentThread(r); |
michael@0 | 3065 | } |
michael@0 | 3066 | } |
michael@0 | 3067 | |
michael@0 | 3068 | if (r) { |
michael@0 | 3069 | nsCOMPtr<nsIEventTarget> target |
michael@0 | 3070 | = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); |
michael@0 | 3071 | MOZ_ASSERT(target); |
michael@0 | 3072 | target->Dispatch(r, NS_DISPATCH_NORMAL); |
michael@0 | 3073 | } |
michael@0 | 3074 | |
michael@0 | 3075 | return NS_OK; |
michael@0 | 3076 | } |
michael@0 | 3077 | |
michael@0 | 3078 | bool Recv__delete__(const bool& allow, |
michael@0 | 3079 | const InfallibleTArray<PermissionChoice>& choices) |
michael@0 | 3080 | { |
michael@0 | 3081 | MOZ_ASSERT(choices.IsEmpty(), "DeviceStorage doesn't support permission choice"); |
michael@0 | 3082 | |
michael@0 | 3083 | if (allow) { |
michael@0 | 3084 | Allow(JS::UndefinedHandleValue); |
michael@0 | 3085 | } |
michael@0 | 3086 | else { |
michael@0 | 3087 | Cancel(); |
michael@0 | 3088 | } |
michael@0 | 3089 | return true; |
michael@0 | 3090 | } |
michael@0 | 3091 | |
michael@0 | 3092 | void IPDLRelease() |
michael@0 | 3093 | { |
michael@0 | 3094 | Release(); |
michael@0 | 3095 | } |
michael@0 | 3096 | |
michael@0 | 3097 | private: |
michael@0 | 3098 | int32_t mRequestType; |
michael@0 | 3099 | nsCOMPtr<nsPIDOMWindow> mWindow; |
michael@0 | 3100 | nsCOMPtr<nsIPrincipal> mPrincipal; |
michael@0 | 3101 | nsRefPtr<DeviceStorageFile> mFile; |
michael@0 | 3102 | |
michael@0 | 3103 | nsRefPtr<DOMRequest> mRequest; |
michael@0 | 3104 | nsCOMPtr<nsIDOMBlob> mBlob; |
michael@0 | 3105 | nsRefPtr<nsDOMDeviceStorage> mDeviceStorage; |
michael@0 | 3106 | nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor; |
michael@0 | 3107 | }; |
michael@0 | 3108 | |
michael@0 | 3109 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest) |
michael@0 | 3110 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest) |
michael@0 | 3111 | NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest) |
michael@0 | 3112 | NS_INTERFACE_MAP_ENTRY(nsIRunnable) |
michael@0 | 3113 | NS_INTERFACE_MAP_END |
michael@0 | 3114 | |
michael@0 | 3115 | NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageRequest) |
michael@0 | 3116 | NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageRequest) |
michael@0 | 3117 | |
michael@0 | 3118 | NS_IMPL_CYCLE_COLLECTION(DeviceStorageRequest, |
michael@0 | 3119 | mRequest, |
michael@0 | 3120 | mWindow, |
michael@0 | 3121 | mBlob, |
michael@0 | 3122 | mDeviceStorage) |
michael@0 | 3123 | |
michael@0 | 3124 | |
michael@0 | 3125 | NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorage) |
michael@0 | 3126 | NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorage) |
michael@0 | 3127 | NS_INTERFACE_MAP_ENTRY(nsIObserver) |
michael@0 | 3128 | NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
michael@0 | 3129 | |
michael@0 | 3130 | NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorage, DOMEventTargetHelper) |
michael@0 | 3131 | NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorage, DOMEventTargetHelper) |
michael@0 | 3132 | |
michael@0 | 3133 | nsDOMDeviceStorage::nsDOMDeviceStorage(nsPIDOMWindow* aWindow) |
michael@0 | 3134 | : DOMEventTargetHelper(aWindow) |
michael@0 | 3135 | , mIsWatchingFile(false) |
michael@0 | 3136 | , mAllowedToWatchFile(false) |
michael@0 | 3137 | { |
michael@0 | 3138 | } |
michael@0 | 3139 | |
michael@0 | 3140 | /* virtual */ JSObject* |
michael@0 | 3141 | nsDOMDeviceStorage::WrapObject(JSContext* aCx) |
michael@0 | 3142 | { |
michael@0 | 3143 | return DeviceStorageBinding::Wrap(aCx, this); |
michael@0 | 3144 | } |
michael@0 | 3145 | |
michael@0 | 3146 | nsresult |
michael@0 | 3147 | nsDOMDeviceStorage::Init(nsPIDOMWindow* aWindow, const nsAString &aType, |
michael@0 | 3148 | const nsAString &aVolName) |
michael@0 | 3149 | { |
michael@0 | 3150 | DebugOnly<FileUpdateDispatcher*> observer |
michael@0 | 3151 | = FileUpdateDispatcher::GetSingleton(); |
michael@0 | 3152 | MOZ_ASSERT(observer); |
michael@0 | 3153 | |
michael@0 | 3154 | MOZ_ASSERT(aWindow); |
michael@0 | 3155 | |
michael@0 | 3156 | SetRootDirectoryForType(aType, aVolName); |
michael@0 | 3157 | if (!mRootDirectory) { |
michael@0 | 3158 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 3159 | } |
michael@0 | 3160 | if (!mStorageName.IsEmpty()) { |
michael@0 | 3161 | RegisterForSDCardChanges(this); |
michael@0 | 3162 | } |
michael@0 | 3163 | |
michael@0 | 3164 | // Grab the principal of the document |
michael@0 | 3165 | nsCOMPtr<nsIDocument> doc = aWindow->GetDoc(); |
michael@0 | 3166 | if (!doc) { |
michael@0 | 3167 | return NS_ERROR_FAILURE; |
michael@0 | 3168 | } |
michael@0 | 3169 | mPrincipal = doc->NodePrincipal(); |
michael@0 | 3170 | |
michael@0 | 3171 | // the 'apps' type is special. We only want this exposed |
michael@0 | 3172 | // if the caller has the "webapps-manage" permission. |
michael@0 | 3173 | if (aType.EqualsLiteral(DEVICESTORAGE_APPS)) { |
michael@0 | 3174 | nsCOMPtr<nsIPermissionManager> permissionManager |
michael@0 | 3175 | = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); |
michael@0 | 3176 | NS_ENSURE_TRUE(permissionManager, NS_ERROR_FAILURE); |
michael@0 | 3177 | |
michael@0 | 3178 | uint32_t permission; |
michael@0 | 3179 | nsresult rv |
michael@0 | 3180 | = permissionManager->TestPermissionFromPrincipal(mPrincipal, |
michael@0 | 3181 | "webapps-manage", |
michael@0 | 3182 | &permission); |
michael@0 | 3183 | |
michael@0 | 3184 | if (NS_FAILED(rv) || permission != nsIPermissionManager::ALLOW_ACTION) { |
michael@0 | 3185 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 3186 | } |
michael@0 | 3187 | } |
michael@0 | 3188 | |
michael@0 | 3189 | return NS_OK; |
michael@0 | 3190 | } |
michael@0 | 3191 | |
michael@0 | 3192 | nsDOMDeviceStorage::~nsDOMDeviceStorage() |
michael@0 | 3193 | { |
michael@0 | 3194 | } |
michael@0 | 3195 | |
michael@0 | 3196 | void |
michael@0 | 3197 | nsDOMDeviceStorage::Shutdown() |
michael@0 | 3198 | { |
michael@0 | 3199 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3200 | |
michael@0 | 3201 | if (mFileSystem) { |
michael@0 | 3202 | mFileSystem->Shutdown(); |
michael@0 | 3203 | mFileSystem = nullptr; |
michael@0 | 3204 | } |
michael@0 | 3205 | |
michael@0 | 3206 | if (!mStorageName.IsEmpty()) { |
michael@0 | 3207 | UnregisterForSDCardChanges(this); |
michael@0 | 3208 | } |
michael@0 | 3209 | |
michael@0 | 3210 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 3211 | obs->RemoveObserver(this, "file-watcher-update"); |
michael@0 | 3212 | obs->RemoveObserver(this, "disk-space-watcher"); |
michael@0 | 3213 | } |
michael@0 | 3214 | |
michael@0 | 3215 | StaticAutoPtr<nsTArray<nsString>> nsDOMDeviceStorage::sVolumeNameCache; |
michael@0 | 3216 | |
michael@0 | 3217 | // static |
michael@0 | 3218 | void |
michael@0 | 3219 | nsDOMDeviceStorage::GetOrderedVolumeNames( |
michael@0 | 3220 | nsDOMDeviceStorage::VolumeNameArray &aVolumeNames) |
michael@0 | 3221 | { |
michael@0 | 3222 | if (sVolumeNameCache && sVolumeNameCache->Length() > 0) { |
michael@0 | 3223 | aVolumeNames.AppendElements(*sVolumeNameCache); |
michael@0 | 3224 | return; |
michael@0 | 3225 | } |
michael@0 | 3226 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 3227 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); |
michael@0 | 3228 | if (vs) { |
michael@0 | 3229 | vs->GetVolumeNames(aVolumeNames); |
michael@0 | 3230 | |
michael@0 | 3231 | // If the volume sdcard exists, then we want it to be first. |
michael@0 | 3232 | |
michael@0 | 3233 | VolumeNameArray::index_type sdcardIndex; |
michael@0 | 3234 | sdcardIndex = aVolumeNames.IndexOf(NS_LITERAL_STRING("sdcard")); |
michael@0 | 3235 | if (sdcardIndex != VolumeNameArray::NoIndex && sdcardIndex > 0) { |
michael@0 | 3236 | aVolumeNames.RemoveElementAt(sdcardIndex); |
michael@0 | 3237 | aVolumeNames.InsertElementAt(0, NS_LITERAL_STRING("sdcard")); |
michael@0 | 3238 | } |
michael@0 | 3239 | } |
michael@0 | 3240 | #endif |
michael@0 | 3241 | if (aVolumeNames.IsEmpty()) { |
michael@0 | 3242 | aVolumeNames.AppendElement(EmptyString()); |
michael@0 | 3243 | } |
michael@0 | 3244 | sVolumeNameCache = new nsTArray<nsString>; |
michael@0 | 3245 | sVolumeNameCache->AppendElements(aVolumeNames); |
michael@0 | 3246 | } |
michael@0 | 3247 | |
michael@0 | 3248 | // static |
michael@0 | 3249 | void |
michael@0 | 3250 | nsDOMDeviceStorage::CreateDeviceStorageFor(nsPIDOMWindow* aWin, |
michael@0 | 3251 | const nsAString &aType, |
michael@0 | 3252 | nsDOMDeviceStorage** aStore) |
michael@0 | 3253 | { |
michael@0 | 3254 | nsString storageName; |
michael@0 | 3255 | if (!DeviceStorageTypeChecker::IsVolumeBased(aType)) { |
michael@0 | 3256 | // The storage name will be the empty string |
michael@0 | 3257 | storageName.Truncate(); |
michael@0 | 3258 | } else { |
michael@0 | 3259 | GetDefaultStorageName(aType, storageName); |
michael@0 | 3260 | } |
michael@0 | 3261 | |
michael@0 | 3262 | nsRefPtr<nsDOMDeviceStorage> ds = new nsDOMDeviceStorage(aWin); |
michael@0 | 3263 | if (NS_FAILED(ds->Init(aWin, aType, storageName))) { |
michael@0 | 3264 | *aStore = nullptr; |
michael@0 | 3265 | return; |
michael@0 | 3266 | } |
michael@0 | 3267 | NS_ADDREF(*aStore = ds.get()); |
michael@0 | 3268 | } |
michael@0 | 3269 | |
michael@0 | 3270 | // static |
michael@0 | 3271 | void |
michael@0 | 3272 | nsDOMDeviceStorage::CreateDeviceStoragesFor( |
michael@0 | 3273 | nsPIDOMWindow* aWin, |
michael@0 | 3274 | const nsAString &aType, |
michael@0 | 3275 | nsTArray<nsRefPtr<nsDOMDeviceStorage> > &aStores) |
michael@0 | 3276 | { |
michael@0 | 3277 | nsresult rv; |
michael@0 | 3278 | |
michael@0 | 3279 | if (!DeviceStorageTypeChecker::IsVolumeBased(aType)) { |
michael@0 | 3280 | nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage(aWin); |
michael@0 | 3281 | rv = storage->Init(aWin, aType, EmptyString()); |
michael@0 | 3282 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 3283 | aStores.AppendElement(storage); |
michael@0 | 3284 | } |
michael@0 | 3285 | return; |
michael@0 | 3286 | } |
michael@0 | 3287 | VolumeNameArray volNames; |
michael@0 | 3288 | GetOrderedVolumeNames(volNames); |
michael@0 | 3289 | |
michael@0 | 3290 | VolumeNameArray::size_type numVolumeNames = volNames.Length(); |
michael@0 | 3291 | for (VolumeNameArray::index_type i = 0; i < numVolumeNames; i++) { |
michael@0 | 3292 | nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage(aWin); |
michael@0 | 3293 | rv = storage->Init(aWin, aType, volNames[i]); |
michael@0 | 3294 | if (NS_FAILED(rv)) { |
michael@0 | 3295 | break; |
michael@0 | 3296 | } |
michael@0 | 3297 | aStores.AppendElement(storage); |
michael@0 | 3298 | } |
michael@0 | 3299 | } |
michael@0 | 3300 | |
michael@0 | 3301 | // static |
michael@0 | 3302 | bool |
michael@0 | 3303 | nsDOMDeviceStorage::ParseFullPath(const nsAString& aFullPath, |
michael@0 | 3304 | nsAString& aOutStorageName, |
michael@0 | 3305 | nsAString& aOutStoragePath) |
michael@0 | 3306 | { |
michael@0 | 3307 | aOutStorageName.Truncate(); |
michael@0 | 3308 | aOutStoragePath.Truncate(); |
michael@0 | 3309 | |
michael@0 | 3310 | NS_NAMED_LITERAL_STRING(slash, "/"); |
michael@0 | 3311 | |
michael@0 | 3312 | nsDependentSubstring storageName; |
michael@0 | 3313 | |
michael@0 | 3314 | if (StringBeginsWith(aFullPath, slash)) { |
michael@0 | 3315 | int32_t slashIndex = aFullPath.FindChar('/', 1); |
michael@0 | 3316 | if (slashIndex == kNotFound) { |
michael@0 | 3317 | // names of the form /filename are illegal |
michael@0 | 3318 | return false; |
michael@0 | 3319 | } |
michael@0 | 3320 | storageName.Rebind(aFullPath, 1, slashIndex - 1); |
michael@0 | 3321 | aOutStoragePath = Substring(aFullPath, slashIndex + 1); |
michael@0 | 3322 | } else { |
michael@0 | 3323 | aOutStoragePath = aFullPath; |
michael@0 | 3324 | } |
michael@0 | 3325 | // If no volume name was specified in aFullPath, then aOutStorageName |
michael@0 | 3326 | // will wind up being the empty string. It's up to the caller to figure |
michael@0 | 3327 | // out which storage name to actually use. |
michael@0 | 3328 | aOutStorageName = storageName; |
michael@0 | 3329 | return true; |
michael@0 | 3330 | } |
michael@0 | 3331 | |
michael@0 | 3332 | already_AddRefed<nsDOMDeviceStorage> |
michael@0 | 3333 | nsDOMDeviceStorage::GetStorage(const nsAString& aFullPath, |
michael@0 | 3334 | nsAString& aOutStoragePath) |
michael@0 | 3335 | { |
michael@0 | 3336 | nsString storageName; |
michael@0 | 3337 | if (!ParseFullPath(aFullPath, storageName, aOutStoragePath)) { |
michael@0 | 3338 | return nullptr; |
michael@0 | 3339 | } |
michael@0 | 3340 | nsRefPtr<nsDOMDeviceStorage> ds; |
michael@0 | 3341 | if (storageName.IsEmpty()) { |
michael@0 | 3342 | ds = this; |
michael@0 | 3343 | } else { |
michael@0 | 3344 | ds = GetStorageByName(storageName); |
michael@0 | 3345 | } |
michael@0 | 3346 | return ds.forget(); |
michael@0 | 3347 | } |
michael@0 | 3348 | |
michael@0 | 3349 | already_AddRefed<nsDOMDeviceStorage> |
michael@0 | 3350 | nsDOMDeviceStorage::GetStorageByName(const nsAString& aStorageName) |
michael@0 | 3351 | { |
michael@0 | 3352 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3353 | |
michael@0 | 3354 | nsRefPtr<nsDOMDeviceStorage> ds; |
michael@0 | 3355 | |
michael@0 | 3356 | if (mStorageName.Equals(aStorageName)) { |
michael@0 | 3357 | ds = this; |
michael@0 | 3358 | return ds.forget(); |
michael@0 | 3359 | } |
michael@0 | 3360 | VolumeNameArray volNames; |
michael@0 | 3361 | GetOrderedVolumeNames(volNames); |
michael@0 | 3362 | VolumeNameArray::size_type numVolumes = volNames.Length(); |
michael@0 | 3363 | VolumeNameArray::index_type i; |
michael@0 | 3364 | for (i = 0; i < numVolumes; i++) { |
michael@0 | 3365 | if (volNames[i].Equals(aStorageName)) { |
michael@0 | 3366 | ds = new nsDOMDeviceStorage(GetOwner()); |
michael@0 | 3367 | nsresult rv = ds->Init(GetOwner(), mStorageType, aStorageName); |
michael@0 | 3368 | if (NS_FAILED(rv)) { |
michael@0 | 3369 | return nullptr; |
michael@0 | 3370 | } |
michael@0 | 3371 | return ds.forget(); |
michael@0 | 3372 | } |
michael@0 | 3373 | } |
michael@0 | 3374 | return nullptr; |
michael@0 | 3375 | } |
michael@0 | 3376 | |
michael@0 | 3377 | // static |
michael@0 | 3378 | void |
michael@0 | 3379 | nsDOMDeviceStorage::GetDefaultStorageName(const nsAString& aStorageType, |
michael@0 | 3380 | nsAString& aStorageName) |
michael@0 | 3381 | { |
michael@0 | 3382 | // See if the preferred volume is available. |
michael@0 | 3383 | nsRefPtr<nsDOMDeviceStorage> ds; |
michael@0 | 3384 | nsAdoptingString prefStorageName = |
michael@0 | 3385 | mozilla::Preferences::GetString("device.storage.writable.name"); |
michael@0 | 3386 | if (prefStorageName) { |
michael@0 | 3387 | aStorageName = prefStorageName; |
michael@0 | 3388 | return; |
michael@0 | 3389 | } |
michael@0 | 3390 | |
michael@0 | 3391 | // No preferred storage, we'll use the first one (which should be sdcard). |
michael@0 | 3392 | |
michael@0 | 3393 | VolumeNameArray volNames; |
michael@0 | 3394 | GetOrderedVolumeNames(volNames); |
michael@0 | 3395 | if (volNames.Length() > 0) { |
michael@0 | 3396 | aStorageName = volNames[0]; |
michael@0 | 3397 | return; |
michael@0 | 3398 | } |
michael@0 | 3399 | |
michael@0 | 3400 | // No volumes available, return the empty string. This is normal for |
michael@0 | 3401 | // b2g-desktop. |
michael@0 | 3402 | aStorageName.Truncate(); |
michael@0 | 3403 | } |
michael@0 | 3404 | |
michael@0 | 3405 | bool |
michael@0 | 3406 | nsDOMDeviceStorage::IsAvailable() |
michael@0 | 3407 | { |
michael@0 | 3408 | DeviceStorageFile dsf(mStorageType, mStorageName); |
michael@0 | 3409 | return dsf.IsAvailable(); |
michael@0 | 3410 | } |
michael@0 | 3411 | |
michael@0 | 3412 | NS_IMETHODIMP |
michael@0 | 3413 | nsDOMDeviceStorage::Add(nsIDOMBlob *aBlob, nsIDOMDOMRequest * *_retval) |
michael@0 | 3414 | { |
michael@0 | 3415 | ErrorResult rv; |
michael@0 | 3416 | nsRefPtr<DOMRequest> request = Add(aBlob, rv); |
michael@0 | 3417 | request.forget(_retval); |
michael@0 | 3418 | return rv.ErrorCode(); |
michael@0 | 3419 | } |
michael@0 | 3420 | |
michael@0 | 3421 | already_AddRefed<DOMRequest> |
michael@0 | 3422 | nsDOMDeviceStorage::Add(nsIDOMBlob* aBlob, ErrorResult& aRv) |
michael@0 | 3423 | { |
michael@0 | 3424 | if (!aBlob) { |
michael@0 | 3425 | return nullptr; |
michael@0 | 3426 | } |
michael@0 | 3427 | |
michael@0 | 3428 | nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID); |
michael@0 | 3429 | if (!mimeSvc) { |
michael@0 | 3430 | aRv.Throw(NS_ERROR_FAILURE); |
michael@0 | 3431 | return nullptr; |
michael@0 | 3432 | } |
michael@0 | 3433 | |
michael@0 | 3434 | // if mimeType isn't set, we will not get a correct |
michael@0 | 3435 | // extension, and AddNamed() will fail. This will post an |
michael@0 | 3436 | // onerror to the requestee. |
michael@0 | 3437 | nsString mimeType; |
michael@0 | 3438 | aBlob->GetType(mimeType); |
michael@0 | 3439 | |
michael@0 | 3440 | nsCString extension; |
michael@0 | 3441 | mimeSvc->GetPrimaryExtension(NS_LossyConvertUTF16toASCII(mimeType), |
michael@0 | 3442 | EmptyCString(), extension); |
michael@0 | 3443 | // if extension is null here, we will ignore it for now. |
michael@0 | 3444 | // AddNamed() will check the file path and fail. This |
michael@0 | 3445 | // will post an onerror to the requestee. |
michael@0 | 3446 | |
michael@0 | 3447 | // possible race here w/ unique filename |
michael@0 | 3448 | char buffer[32]; |
michael@0 | 3449 | NS_MakeRandomString(buffer, ArrayLength(buffer) - 1); |
michael@0 | 3450 | |
michael@0 | 3451 | nsAutoCString path; |
michael@0 | 3452 | path.Assign(nsDependentCString(buffer)); |
michael@0 | 3453 | path.Append("."); |
michael@0 | 3454 | path.Append(extension); |
michael@0 | 3455 | |
michael@0 | 3456 | return AddNamed(aBlob, NS_ConvertASCIItoUTF16(path), aRv); |
michael@0 | 3457 | } |
michael@0 | 3458 | |
michael@0 | 3459 | NS_IMETHODIMP |
michael@0 | 3460 | nsDOMDeviceStorage::AddNamed(nsIDOMBlob *aBlob, |
michael@0 | 3461 | const nsAString & aPath, |
michael@0 | 3462 | nsIDOMDOMRequest * *_retval) |
michael@0 | 3463 | { |
michael@0 | 3464 | ErrorResult rv; |
michael@0 | 3465 | nsRefPtr<DOMRequest> request = AddNamed(aBlob, aPath, rv); |
michael@0 | 3466 | request.forget(_retval); |
michael@0 | 3467 | return rv.ErrorCode(); |
michael@0 | 3468 | } |
michael@0 | 3469 | |
michael@0 | 3470 | already_AddRefed<DOMRequest> |
michael@0 | 3471 | nsDOMDeviceStorage::AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath, |
michael@0 | 3472 | ErrorResult& aRv) |
michael@0 | 3473 | { |
michael@0 | 3474 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3475 | |
michael@0 | 3476 | // if the blob is null here, bail |
michael@0 | 3477 | if (!aBlob) { |
michael@0 | 3478 | return nullptr; |
michael@0 | 3479 | } |
michael@0 | 3480 | |
michael@0 | 3481 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3482 | if (!win) { |
michael@0 | 3483 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3484 | return nullptr; |
michael@0 | 3485 | } |
michael@0 | 3486 | |
michael@0 | 3487 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 3488 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 3489 | if (!typeChecker) { |
michael@0 | 3490 | aRv.Throw(NS_ERROR_FAILURE); |
michael@0 | 3491 | return nullptr; |
michael@0 | 3492 | } |
michael@0 | 3493 | |
michael@0 | 3494 | nsCOMPtr<nsIRunnable> r; |
michael@0 | 3495 | nsresult rv; |
michael@0 | 3496 | |
michael@0 | 3497 | if (IsFullPath(aPath)) { |
michael@0 | 3498 | nsString storagePath; |
michael@0 | 3499 | nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); |
michael@0 | 3500 | if (!ds) { |
michael@0 | 3501 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3502 | r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); |
michael@0 | 3503 | rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3504 | if (NS_FAILED(rv)) { |
michael@0 | 3505 | aRv.Throw(rv); |
michael@0 | 3506 | } |
michael@0 | 3507 | return request.forget(); |
michael@0 | 3508 | } |
michael@0 | 3509 | return ds->AddNamed(aBlob, storagePath, aRv); |
michael@0 | 3510 | } |
michael@0 | 3511 | |
michael@0 | 3512 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3513 | |
michael@0 | 3514 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3515 | mStorageName, |
michael@0 | 3516 | aPath); |
michael@0 | 3517 | if (!dsf->IsSafePath()) { |
michael@0 | 3518 | r = new PostErrorEvent(request, POST_ERROR_EVENT_PERMISSION_DENIED); |
michael@0 | 3519 | } else if (!typeChecker->Check(mStorageType, dsf->mFile) || |
michael@0 | 3520 | !typeChecker->Check(mStorageType, aBlob)) { |
michael@0 | 3521 | r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE); |
michael@0 | 3522 | } else { |
michael@0 | 3523 | r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_CREATE, |
michael@0 | 3524 | win, mPrincipal, dsf, request, aBlob); |
michael@0 | 3525 | } |
michael@0 | 3526 | |
michael@0 | 3527 | rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3528 | if (NS_FAILED(rv)) { |
michael@0 | 3529 | aRv.Throw(rv); |
michael@0 | 3530 | } |
michael@0 | 3531 | return request.forget(); |
michael@0 | 3532 | } |
michael@0 | 3533 | |
michael@0 | 3534 | NS_IMETHODIMP |
michael@0 | 3535 | nsDOMDeviceStorage::Get(const nsAString& aPath, nsIDOMDOMRequest** aRetval) |
michael@0 | 3536 | { |
michael@0 | 3537 | ErrorResult rv; |
michael@0 | 3538 | nsRefPtr<DOMRequest> request = Get(aPath, rv); |
michael@0 | 3539 | request.forget(aRetval); |
michael@0 | 3540 | return rv.ErrorCode(); |
michael@0 | 3541 | } |
michael@0 | 3542 | |
michael@0 | 3543 | NS_IMETHODIMP |
michael@0 | 3544 | nsDOMDeviceStorage::GetEditable(const nsAString& aPath, |
michael@0 | 3545 | nsIDOMDOMRequest** aRetval) |
michael@0 | 3546 | { |
michael@0 | 3547 | ErrorResult rv; |
michael@0 | 3548 | nsRefPtr<DOMRequest> request = GetEditable(aPath, rv); |
michael@0 | 3549 | request.forget(aRetval); |
michael@0 | 3550 | return rv.ErrorCode(); |
michael@0 | 3551 | } |
michael@0 | 3552 | |
michael@0 | 3553 | already_AddRefed<DOMRequest> |
michael@0 | 3554 | nsDOMDeviceStorage::GetInternal(const nsAString& aPath, bool aEditable, |
michael@0 | 3555 | ErrorResult& aRv) |
michael@0 | 3556 | { |
michael@0 | 3557 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3558 | |
michael@0 | 3559 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3560 | if (!win) { |
michael@0 | 3561 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3562 | return nullptr; |
michael@0 | 3563 | } |
michael@0 | 3564 | |
michael@0 | 3565 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3566 | |
michael@0 | 3567 | if (IsFullPath(aPath)) { |
michael@0 | 3568 | nsString storagePath; |
michael@0 | 3569 | nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); |
michael@0 | 3570 | if (!ds) { |
michael@0 | 3571 | nsCOMPtr<nsIRunnable> r = |
michael@0 | 3572 | new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); |
michael@0 | 3573 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3574 | if (NS_FAILED(rv)) { |
michael@0 | 3575 | aRv.Throw(rv); |
michael@0 | 3576 | } |
michael@0 | 3577 | return request.forget(); |
michael@0 | 3578 | } |
michael@0 | 3579 | ds->GetInternal(win, storagePath, request, aEditable); |
michael@0 | 3580 | return request.forget(); |
michael@0 | 3581 | } |
michael@0 | 3582 | GetInternal(win, aPath, request, aEditable); |
michael@0 | 3583 | return request.forget(); |
michael@0 | 3584 | } |
michael@0 | 3585 | |
michael@0 | 3586 | void |
michael@0 | 3587 | nsDOMDeviceStorage::GetInternal(nsPIDOMWindow *aWin, |
michael@0 | 3588 | const nsAString& aPath, |
michael@0 | 3589 | DOMRequest* aRequest, |
michael@0 | 3590 | bool aEditable) |
michael@0 | 3591 | { |
michael@0 | 3592 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3593 | |
michael@0 | 3594 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3595 | mStorageName, |
michael@0 | 3596 | aPath); |
michael@0 | 3597 | dsf->SetEditable(aEditable); |
michael@0 | 3598 | |
michael@0 | 3599 | nsCOMPtr<nsIRunnable> r; |
michael@0 | 3600 | if (!dsf->IsSafePath()) { |
michael@0 | 3601 | r = new PostErrorEvent(aRequest, POST_ERROR_EVENT_PERMISSION_DENIED); |
michael@0 | 3602 | } else { |
michael@0 | 3603 | r = new DeviceStorageRequest(aEditable ? DEVICE_STORAGE_REQUEST_WRITE |
michael@0 | 3604 | : DEVICE_STORAGE_REQUEST_READ, |
michael@0 | 3605 | aWin, mPrincipal, dsf, aRequest); |
michael@0 | 3606 | } |
michael@0 | 3607 | DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3608 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 3609 | } |
michael@0 | 3610 | |
michael@0 | 3611 | NS_IMETHODIMP |
michael@0 | 3612 | nsDOMDeviceStorage::Delete(const nsAString& aPath, nsIDOMDOMRequest** aRetval) |
michael@0 | 3613 | { |
michael@0 | 3614 | ErrorResult rv; |
michael@0 | 3615 | nsRefPtr<DOMRequest> request = Delete(aPath, rv); |
michael@0 | 3616 | request.forget(aRetval); |
michael@0 | 3617 | return rv.ErrorCode(); |
michael@0 | 3618 | } |
michael@0 | 3619 | |
michael@0 | 3620 | already_AddRefed<DOMRequest> |
michael@0 | 3621 | nsDOMDeviceStorage::Delete(const nsAString& aPath, ErrorResult& aRv) |
michael@0 | 3622 | { |
michael@0 | 3623 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3624 | |
michael@0 | 3625 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3626 | if (!win) { |
michael@0 | 3627 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3628 | return nullptr; |
michael@0 | 3629 | } |
michael@0 | 3630 | |
michael@0 | 3631 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3632 | |
michael@0 | 3633 | if (IsFullPath(aPath)) { |
michael@0 | 3634 | nsString storagePath; |
michael@0 | 3635 | nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); |
michael@0 | 3636 | if (!ds) { |
michael@0 | 3637 | nsCOMPtr<nsIRunnable> r = |
michael@0 | 3638 | new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); |
michael@0 | 3639 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3640 | if (NS_FAILED(rv)) { |
michael@0 | 3641 | aRv.Throw(rv); |
michael@0 | 3642 | } |
michael@0 | 3643 | return request.forget(); |
michael@0 | 3644 | } |
michael@0 | 3645 | ds->DeleteInternal(win, storagePath, request); |
michael@0 | 3646 | return request.forget(); |
michael@0 | 3647 | } |
michael@0 | 3648 | DeleteInternal(win, aPath, request); |
michael@0 | 3649 | return request.forget(); |
michael@0 | 3650 | } |
michael@0 | 3651 | |
michael@0 | 3652 | void |
michael@0 | 3653 | nsDOMDeviceStorage::DeleteInternal(nsPIDOMWindow *aWin, |
michael@0 | 3654 | const nsAString& aPath, |
michael@0 | 3655 | DOMRequest* aRequest) |
michael@0 | 3656 | { |
michael@0 | 3657 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3658 | |
michael@0 | 3659 | nsCOMPtr<nsIRunnable> r; |
michael@0 | 3660 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3661 | mStorageName, |
michael@0 | 3662 | aPath); |
michael@0 | 3663 | if (!dsf->IsSafePath()) { |
michael@0 | 3664 | r = new PostErrorEvent(aRequest, POST_ERROR_EVENT_PERMISSION_DENIED); |
michael@0 | 3665 | } else { |
michael@0 | 3666 | r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_DELETE, |
michael@0 | 3667 | aWin, mPrincipal, dsf, aRequest); |
michael@0 | 3668 | } |
michael@0 | 3669 | DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3670 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 3671 | } |
michael@0 | 3672 | |
michael@0 | 3673 | NS_IMETHODIMP |
michael@0 | 3674 | nsDOMDeviceStorage::FreeSpace(nsIDOMDOMRequest** aRetval) |
michael@0 | 3675 | { |
michael@0 | 3676 | ErrorResult rv; |
michael@0 | 3677 | nsRefPtr<DOMRequest> request = FreeSpace(rv); |
michael@0 | 3678 | request.forget(aRetval); |
michael@0 | 3679 | return rv.ErrorCode(); |
michael@0 | 3680 | } |
michael@0 | 3681 | |
michael@0 | 3682 | already_AddRefed<DOMRequest> |
michael@0 | 3683 | nsDOMDeviceStorage::FreeSpace(ErrorResult& aRv) |
michael@0 | 3684 | { |
michael@0 | 3685 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3686 | |
michael@0 | 3687 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3688 | if (!win) { |
michael@0 | 3689 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3690 | return nullptr; |
michael@0 | 3691 | } |
michael@0 | 3692 | |
michael@0 | 3693 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3694 | |
michael@0 | 3695 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3696 | mStorageName); |
michael@0 | 3697 | nsCOMPtr<nsIRunnable> r |
michael@0 | 3698 | = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FREE_SPACE, |
michael@0 | 3699 | win, mPrincipal, dsf, request); |
michael@0 | 3700 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3701 | if (NS_FAILED(rv)) { |
michael@0 | 3702 | aRv.Throw(rv); |
michael@0 | 3703 | } |
michael@0 | 3704 | return request.forget(); |
michael@0 | 3705 | } |
michael@0 | 3706 | |
michael@0 | 3707 | NS_IMETHODIMP |
michael@0 | 3708 | nsDOMDeviceStorage::UsedSpace(nsIDOMDOMRequest** aRetval) |
michael@0 | 3709 | { |
michael@0 | 3710 | ErrorResult rv; |
michael@0 | 3711 | nsRefPtr<DOMRequest> request = UsedSpace(rv); |
michael@0 | 3712 | request.forget(aRetval); |
michael@0 | 3713 | return rv.ErrorCode(); |
michael@0 | 3714 | } |
michael@0 | 3715 | |
michael@0 | 3716 | already_AddRefed<DOMRequest> |
michael@0 | 3717 | nsDOMDeviceStorage::UsedSpace(ErrorResult& aRv) |
michael@0 | 3718 | { |
michael@0 | 3719 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3720 | |
michael@0 | 3721 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3722 | if (!win) { |
michael@0 | 3723 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3724 | return nullptr; |
michael@0 | 3725 | } |
michael@0 | 3726 | |
michael@0 | 3727 | DebugOnly<DeviceStorageUsedSpaceCache*> usedSpaceCache |
michael@0 | 3728 | = DeviceStorageUsedSpaceCache::CreateOrGet(); |
michael@0 | 3729 | MOZ_ASSERT(usedSpaceCache); |
michael@0 | 3730 | |
michael@0 | 3731 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3732 | |
michael@0 | 3733 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3734 | mStorageName); |
michael@0 | 3735 | nsCOMPtr<nsIRunnable> r |
michael@0 | 3736 | = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_USED_SPACE, |
michael@0 | 3737 | win, mPrincipal, dsf, request); |
michael@0 | 3738 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3739 | if (NS_FAILED(rv)) { |
michael@0 | 3740 | aRv.Throw(rv); |
michael@0 | 3741 | } |
michael@0 | 3742 | return request.forget(); |
michael@0 | 3743 | } |
michael@0 | 3744 | |
michael@0 | 3745 | NS_IMETHODIMP |
michael@0 | 3746 | nsDOMDeviceStorage::Available(nsIDOMDOMRequest** aRetval) |
michael@0 | 3747 | { |
michael@0 | 3748 | ErrorResult rv; |
michael@0 | 3749 | nsRefPtr<DOMRequest> request = Available(rv); |
michael@0 | 3750 | request.forget(aRetval); |
michael@0 | 3751 | return rv.ErrorCode(); |
michael@0 | 3752 | } |
michael@0 | 3753 | |
michael@0 | 3754 | already_AddRefed<DOMRequest> |
michael@0 | 3755 | nsDOMDeviceStorage::Available(ErrorResult& aRv) |
michael@0 | 3756 | { |
michael@0 | 3757 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3758 | |
michael@0 | 3759 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3760 | if (!win) { |
michael@0 | 3761 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3762 | return nullptr; |
michael@0 | 3763 | } |
michael@0 | 3764 | |
michael@0 | 3765 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3766 | |
michael@0 | 3767 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3768 | mStorageName); |
michael@0 | 3769 | nsCOMPtr<nsIRunnable> r |
michael@0 | 3770 | = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_AVAILABLE, |
michael@0 | 3771 | win, mPrincipal, dsf, request); |
michael@0 | 3772 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3773 | if (NS_FAILED(rv)) { |
michael@0 | 3774 | aRv.Throw(rv); |
michael@0 | 3775 | } |
michael@0 | 3776 | return request.forget(); |
michael@0 | 3777 | } |
michael@0 | 3778 | |
michael@0 | 3779 | already_AddRefed<DOMRequest> |
michael@0 | 3780 | nsDOMDeviceStorage::StorageStatus(ErrorResult& aRv) |
michael@0 | 3781 | { |
michael@0 | 3782 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3783 | |
michael@0 | 3784 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3785 | if (!win) { |
michael@0 | 3786 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3787 | return nullptr; |
michael@0 | 3788 | } |
michael@0 | 3789 | |
michael@0 | 3790 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3791 | |
michael@0 | 3792 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3793 | mStorageName); |
michael@0 | 3794 | nsCOMPtr<nsIRunnable> r |
michael@0 | 3795 | = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_STATUS, |
michael@0 | 3796 | win, mPrincipal, dsf, request); |
michael@0 | 3797 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3798 | if (NS_FAILED(rv)) { |
michael@0 | 3799 | aRv.Throw(rv); |
michael@0 | 3800 | } |
michael@0 | 3801 | return request.forget(); |
michael@0 | 3802 | } |
michael@0 | 3803 | |
michael@0 | 3804 | already_AddRefed<DOMRequest> |
michael@0 | 3805 | nsDOMDeviceStorage::Format(ErrorResult& aRv) |
michael@0 | 3806 | { |
michael@0 | 3807 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3808 | |
michael@0 | 3809 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3810 | if (!win) { |
michael@0 | 3811 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3812 | return nullptr; |
michael@0 | 3813 | } |
michael@0 | 3814 | |
michael@0 | 3815 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3816 | |
michael@0 | 3817 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3818 | mStorageName); |
michael@0 | 3819 | nsCOMPtr<nsIRunnable> r |
michael@0 | 3820 | = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FORMAT, |
michael@0 | 3821 | win, mPrincipal, dsf, request); |
michael@0 | 3822 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3823 | if (NS_FAILED(rv)) { |
michael@0 | 3824 | aRv.Throw(rv); |
michael@0 | 3825 | } |
michael@0 | 3826 | return request.forget(); |
michael@0 | 3827 | } |
michael@0 | 3828 | |
michael@0 | 3829 | already_AddRefed<DOMRequest> |
michael@0 | 3830 | nsDOMDeviceStorage::Mount(ErrorResult& aRv) |
michael@0 | 3831 | { |
michael@0 | 3832 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3833 | |
michael@0 | 3834 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3835 | if (!win) { |
michael@0 | 3836 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3837 | return nullptr; |
michael@0 | 3838 | } |
michael@0 | 3839 | |
michael@0 | 3840 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3841 | |
michael@0 | 3842 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3843 | mStorageName); |
michael@0 | 3844 | nsCOMPtr<nsIRunnable> r |
michael@0 | 3845 | = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_MOUNT, |
michael@0 | 3846 | win, mPrincipal, dsf, request); |
michael@0 | 3847 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3848 | if (NS_FAILED(rv)) { |
michael@0 | 3849 | aRv.Throw(rv); |
michael@0 | 3850 | } |
michael@0 | 3851 | return request.forget(); |
michael@0 | 3852 | } |
michael@0 | 3853 | |
michael@0 | 3854 | already_AddRefed<DOMRequest> |
michael@0 | 3855 | nsDOMDeviceStorage::Unmount(ErrorResult& aRv) |
michael@0 | 3856 | { |
michael@0 | 3857 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3858 | |
michael@0 | 3859 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3860 | if (!win) { |
michael@0 | 3861 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3862 | return nullptr; |
michael@0 | 3863 | } |
michael@0 | 3864 | |
michael@0 | 3865 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3866 | |
michael@0 | 3867 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3868 | mStorageName); |
michael@0 | 3869 | nsCOMPtr<nsIRunnable> r |
michael@0 | 3870 | = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_UNMOUNT, |
michael@0 | 3871 | win, mPrincipal, dsf, request); |
michael@0 | 3872 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3873 | if (NS_FAILED(rv)) { |
michael@0 | 3874 | aRv.Throw(rv); |
michael@0 | 3875 | } |
michael@0 | 3876 | return request.forget(); |
michael@0 | 3877 | } |
michael@0 | 3878 | |
michael@0 | 3879 | NS_IMETHODIMP |
michael@0 | 3880 | nsDOMDeviceStorage::CreateFileDescriptor(const nsAString& aPath, |
michael@0 | 3881 | DeviceStorageFileDescriptor* aDSFileDescriptor, |
michael@0 | 3882 | nsIDOMDOMRequest** aRequest) |
michael@0 | 3883 | { |
michael@0 | 3884 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3885 | MOZ_ASSERT(aDSFileDescriptor); |
michael@0 | 3886 | |
michael@0 | 3887 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3888 | if (!win) { |
michael@0 | 3889 | return NS_ERROR_UNEXPECTED; |
michael@0 | 3890 | } |
michael@0 | 3891 | |
michael@0 | 3892 | DeviceStorageTypeChecker* typeChecker |
michael@0 | 3893 | = DeviceStorageTypeChecker::CreateOrGet(); |
michael@0 | 3894 | if (!typeChecker) { |
michael@0 | 3895 | return NS_ERROR_FAILURE; |
michael@0 | 3896 | } |
michael@0 | 3897 | |
michael@0 | 3898 | nsCOMPtr<nsIRunnable> r; |
michael@0 | 3899 | nsresult rv; |
michael@0 | 3900 | |
michael@0 | 3901 | if (IsFullPath(aPath)) { |
michael@0 | 3902 | nsString storagePath; |
michael@0 | 3903 | nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); |
michael@0 | 3904 | if (!ds) { |
michael@0 | 3905 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3906 | r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); |
michael@0 | 3907 | rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3908 | if (NS_FAILED(rv)) { |
michael@0 | 3909 | return rv; |
michael@0 | 3910 | } |
michael@0 | 3911 | request.forget(aRequest); |
michael@0 | 3912 | return NS_OK; |
michael@0 | 3913 | } |
michael@0 | 3914 | return ds->CreateFileDescriptor(storagePath, aDSFileDescriptor, aRequest); |
michael@0 | 3915 | } |
michael@0 | 3916 | |
michael@0 | 3917 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 3918 | |
michael@0 | 3919 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 3920 | mStorageName, |
michael@0 | 3921 | aPath); |
michael@0 | 3922 | if (!dsf->IsSafePath()) { |
michael@0 | 3923 | r = new PostErrorEvent(request, POST_ERROR_EVENT_PERMISSION_DENIED); |
michael@0 | 3924 | } else if (!typeChecker->Check(mStorageType, dsf->mFile)) { |
michael@0 | 3925 | r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE); |
michael@0 | 3926 | } else { |
michael@0 | 3927 | r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_CREATEFD, |
michael@0 | 3928 | win, mPrincipal, dsf, request, |
michael@0 | 3929 | aDSFileDescriptor); |
michael@0 | 3930 | } |
michael@0 | 3931 | |
michael@0 | 3932 | rv = NS_DispatchToCurrentThread(r); |
michael@0 | 3933 | if (NS_FAILED(rv)) { |
michael@0 | 3934 | return rv; |
michael@0 | 3935 | } |
michael@0 | 3936 | request.forget(aRequest); |
michael@0 | 3937 | return NS_OK; |
michael@0 | 3938 | } |
michael@0 | 3939 | |
michael@0 | 3940 | bool |
michael@0 | 3941 | nsDOMDeviceStorage::Default() |
michael@0 | 3942 | { |
michael@0 | 3943 | nsString defaultStorageName; |
michael@0 | 3944 | GetDefaultStorageName(mStorageType, defaultStorageName); |
michael@0 | 3945 | return mStorageName.Equals(defaultStorageName); |
michael@0 | 3946 | } |
michael@0 | 3947 | |
michael@0 | 3948 | already_AddRefed<Promise> |
michael@0 | 3949 | nsDOMDeviceStorage::GetRoot() |
michael@0 | 3950 | { |
michael@0 | 3951 | if (!mFileSystem) { |
michael@0 | 3952 | mFileSystem = new DeviceStorageFileSystem(mStorageType, mStorageName); |
michael@0 | 3953 | mFileSystem->Init(this); |
michael@0 | 3954 | } |
michael@0 | 3955 | return mozilla::dom::Directory::GetRoot(mFileSystem); |
michael@0 | 3956 | } |
michael@0 | 3957 | |
michael@0 | 3958 | NS_IMETHODIMP |
michael@0 | 3959 | nsDOMDeviceStorage::GetDefault(bool* aDefault) |
michael@0 | 3960 | { |
michael@0 | 3961 | *aDefault = Default(); |
michael@0 | 3962 | return NS_OK; |
michael@0 | 3963 | } |
michael@0 | 3964 | |
michael@0 | 3965 | NS_IMETHODIMP |
michael@0 | 3966 | nsDOMDeviceStorage::GetStorageName(nsAString& aStorageName) |
michael@0 | 3967 | { |
michael@0 | 3968 | aStorageName = mStorageName; |
michael@0 | 3969 | return NS_OK; |
michael@0 | 3970 | } |
michael@0 | 3971 | |
michael@0 | 3972 | already_AddRefed<DOMCursor> |
michael@0 | 3973 | nsDOMDeviceStorage::Enumerate(const nsAString& aPath, |
michael@0 | 3974 | const EnumerationParameters& aOptions, |
michael@0 | 3975 | ErrorResult& aRv) |
michael@0 | 3976 | { |
michael@0 | 3977 | return EnumerateInternal(aPath, aOptions, false, aRv); |
michael@0 | 3978 | } |
michael@0 | 3979 | |
michael@0 | 3980 | already_AddRefed<DOMCursor> |
michael@0 | 3981 | nsDOMDeviceStorage::EnumerateEditable(const nsAString& aPath, |
michael@0 | 3982 | const EnumerationParameters& aOptions, |
michael@0 | 3983 | ErrorResult& aRv) |
michael@0 | 3984 | { |
michael@0 | 3985 | return EnumerateInternal(aPath, aOptions, true, aRv); |
michael@0 | 3986 | } |
michael@0 | 3987 | |
michael@0 | 3988 | |
michael@0 | 3989 | already_AddRefed<DOMCursor> |
michael@0 | 3990 | nsDOMDeviceStorage::EnumerateInternal(const nsAString& aPath, |
michael@0 | 3991 | const EnumerationParameters& aOptions, |
michael@0 | 3992 | bool aEditable, ErrorResult& aRv) |
michael@0 | 3993 | { |
michael@0 | 3994 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 3995 | |
michael@0 | 3996 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 3997 | if (!win) { |
michael@0 | 3998 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 3999 | return nullptr; |
michael@0 | 4000 | } |
michael@0 | 4001 | |
michael@0 | 4002 | PRTime since = 0; |
michael@0 | 4003 | if (aOptions.mSince.WasPassed() && !aOptions.mSince.Value().IsUndefined()) { |
michael@0 | 4004 | since = PRTime(aOptions.mSince.Value().TimeStamp()); |
michael@0 | 4005 | } |
michael@0 | 4006 | |
michael@0 | 4007 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 4008 | mStorageName, |
michael@0 | 4009 | aPath, |
michael@0 | 4010 | EmptyString()); |
michael@0 | 4011 | dsf->SetEditable(aEditable); |
michael@0 | 4012 | |
michael@0 | 4013 | nsRefPtr<nsDOMDeviceStorageCursor> cursor |
michael@0 | 4014 | = new nsDOMDeviceStorageCursor(win, mPrincipal, dsf, since); |
michael@0 | 4015 | nsRefPtr<DeviceStorageCursorRequest> r |
michael@0 | 4016 | = new DeviceStorageCursorRequest(cursor); |
michael@0 | 4017 | |
michael@0 | 4018 | if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) { |
michael@0 | 4019 | r->Allow(JS::UndefinedHandleValue); |
michael@0 | 4020 | return cursor.forget(); |
michael@0 | 4021 | } |
michael@0 | 4022 | |
michael@0 | 4023 | if (XRE_GetProcessType() == GeckoProcessType_Content) { |
michael@0 | 4024 | // because owner implements nsITabChild, we can assume that it is |
michael@0 | 4025 | // the one and only TabChild. |
michael@0 | 4026 | TabChild* child = TabChild::GetFrom(win->GetDocShell()); |
michael@0 | 4027 | if (!child) { |
michael@0 | 4028 | return cursor.forget(); |
michael@0 | 4029 | } |
michael@0 | 4030 | |
michael@0 | 4031 | // Retain a reference so the object isn't deleted without IPDL's knowledge. |
michael@0 | 4032 | // Corresponding release occurs in DeallocPContentPermissionRequest. |
michael@0 | 4033 | r->AddRef(); |
michael@0 | 4034 | |
michael@0 | 4035 | nsCString type; |
michael@0 | 4036 | aRv = DeviceStorageTypeChecker::GetPermissionForType(mStorageType, type); |
michael@0 | 4037 | if (aRv.Failed()) { |
michael@0 | 4038 | return nullptr; |
michael@0 | 4039 | } |
michael@0 | 4040 | nsTArray<PermissionRequest> permArray; |
michael@0 | 4041 | nsTArray<nsString> emptyOptions; |
michael@0 | 4042 | permArray.AppendElement(PermissionRequest(type, |
michael@0 | 4043 | NS_LITERAL_CSTRING("read"), |
michael@0 | 4044 | emptyOptions)); |
michael@0 | 4045 | child->SendPContentPermissionRequestConstructor(r, |
michael@0 | 4046 | permArray, |
michael@0 | 4047 | IPC::Principal(mPrincipal)); |
michael@0 | 4048 | |
michael@0 | 4049 | r->Sendprompt(); |
michael@0 | 4050 | |
michael@0 | 4051 | return cursor.forget(); |
michael@0 | 4052 | } |
michael@0 | 4053 | |
michael@0 | 4054 | nsCOMPtr<nsIContentPermissionPrompt> prompt |
michael@0 | 4055 | = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); |
michael@0 | 4056 | if (prompt) { |
michael@0 | 4057 | prompt->Prompt(r); |
michael@0 | 4058 | } |
michael@0 | 4059 | |
michael@0 | 4060 | return cursor.forget(); |
michael@0 | 4061 | } |
michael@0 | 4062 | |
michael@0 | 4063 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 4064 | void |
michael@0 | 4065 | nsDOMDeviceStorage::DispatchMountChangeEvent(nsAString& aVolumeStatus) |
michael@0 | 4066 | { |
michael@0 | 4067 | if (aVolumeStatus == mLastStatus) { |
michael@0 | 4068 | // We've already sent this status, don't bother sending it again. |
michael@0 | 4069 | return; |
michael@0 | 4070 | } |
michael@0 | 4071 | mLastStatus = aVolumeStatus; |
michael@0 | 4072 | |
michael@0 | 4073 | nsCOMPtr<nsIDOMEvent> event; |
michael@0 | 4074 | NS_NewDOMDeviceStorageChangeEvent(getter_AddRefs(event), this, |
michael@0 | 4075 | nullptr, nullptr); |
michael@0 | 4076 | |
michael@0 | 4077 | nsCOMPtr<nsIDOMDeviceStorageChangeEvent> ce = do_QueryInterface(event); |
michael@0 | 4078 | nsresult rv = ce->InitDeviceStorageChangeEvent(NS_LITERAL_STRING("change"), |
michael@0 | 4079 | true, false, |
michael@0 | 4080 | mStorageName, |
michael@0 | 4081 | aVolumeStatus); |
michael@0 | 4082 | if (NS_FAILED(rv)) { |
michael@0 | 4083 | return; |
michael@0 | 4084 | } |
michael@0 | 4085 | |
michael@0 | 4086 | bool ignore; |
michael@0 | 4087 | DispatchEvent(ce, &ignore); |
michael@0 | 4088 | } |
michael@0 | 4089 | #endif |
michael@0 | 4090 | |
michael@0 | 4091 | NS_IMETHODIMP |
michael@0 | 4092 | nsDOMDeviceStorage::Observe(nsISupports *aSubject, |
michael@0 | 4093 | const char *aTopic, |
michael@0 | 4094 | const char16_t *aData) |
michael@0 | 4095 | { |
michael@0 | 4096 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4097 | |
michael@0 | 4098 | if (!strcmp(aTopic, "file-watcher-update")) { |
michael@0 | 4099 | |
michael@0 | 4100 | DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject); |
michael@0 | 4101 | Notify(NS_ConvertUTF16toUTF8(aData).get(), file); |
michael@0 | 4102 | return NS_OK; |
michael@0 | 4103 | } |
michael@0 | 4104 | if (!strcmp(aTopic, "disk-space-watcher")) { |
michael@0 | 4105 | // 'disk-space-watcher' notifications are sent when there is a modification |
michael@0 | 4106 | // of a file in a specific location while a low device storage situation |
michael@0 | 4107 | // exists or after recovery of a low storage situation. For Firefox OS, |
michael@0 | 4108 | // these notifications are specific for apps storage. |
michael@0 | 4109 | nsRefPtr<DeviceStorageFile> file = |
michael@0 | 4110 | new DeviceStorageFile(mStorageType, mStorageName); |
michael@0 | 4111 | if (!strcmp(NS_ConvertUTF16toUTF8(aData).get(), "full")) { |
michael@0 | 4112 | Notify("low-disk-space", file); |
michael@0 | 4113 | } else if (!strcmp(NS_ConvertUTF16toUTF8(aData).get(), "free")) { |
michael@0 | 4114 | Notify("available-disk-space", file); |
michael@0 | 4115 | } |
michael@0 | 4116 | return NS_OK; |
michael@0 | 4117 | } |
michael@0 | 4118 | |
michael@0 | 4119 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 4120 | else if (!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) { |
michael@0 | 4121 | // We invalidate the used space cache for the volume that actually changed |
michael@0 | 4122 | // state. |
michael@0 | 4123 | nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject); |
michael@0 | 4124 | if (!vol) { |
michael@0 | 4125 | return NS_OK; |
michael@0 | 4126 | } |
michael@0 | 4127 | nsString volName; |
michael@0 | 4128 | vol->GetName(volName); |
michael@0 | 4129 | |
michael@0 | 4130 | DeviceStorageUsedSpaceCache* usedSpaceCache |
michael@0 | 4131 | = DeviceStorageUsedSpaceCache::CreateOrGet(); |
michael@0 | 4132 | MOZ_ASSERT(usedSpaceCache); |
michael@0 | 4133 | usedSpaceCache->Invalidate(volName); |
michael@0 | 4134 | |
michael@0 | 4135 | if (!volName.Equals(mStorageName)) { |
michael@0 | 4136 | // Not our volume - we can ignore. |
michael@0 | 4137 | return NS_OK; |
michael@0 | 4138 | } |
michael@0 | 4139 | |
michael@0 | 4140 | DeviceStorageFile dsf(mStorageType, mStorageName); |
michael@0 | 4141 | nsString status; |
michael@0 | 4142 | dsf.GetStatus(status); |
michael@0 | 4143 | DispatchMountChangeEvent(status); |
michael@0 | 4144 | return NS_OK; |
michael@0 | 4145 | } |
michael@0 | 4146 | #endif |
michael@0 | 4147 | return NS_OK; |
michael@0 | 4148 | } |
michael@0 | 4149 | |
michael@0 | 4150 | nsresult |
michael@0 | 4151 | nsDOMDeviceStorage::Notify(const char* aReason, DeviceStorageFile* aFile) |
michael@0 | 4152 | { |
michael@0 | 4153 | if (!mAllowedToWatchFile) { |
michael@0 | 4154 | return NS_OK; |
michael@0 | 4155 | } |
michael@0 | 4156 | |
michael@0 | 4157 | if (!mStorageType.Equals(aFile->mStorageType) || |
michael@0 | 4158 | !mStorageName.Equals(aFile->mStorageName)) { |
michael@0 | 4159 | // Ignore this |
michael@0 | 4160 | return NS_OK; |
michael@0 | 4161 | } |
michael@0 | 4162 | |
michael@0 | 4163 | nsCOMPtr<nsIDOMEvent> event; |
michael@0 | 4164 | NS_NewDOMDeviceStorageChangeEvent(getter_AddRefs(event), this, |
michael@0 | 4165 | nullptr, nullptr); |
michael@0 | 4166 | |
michael@0 | 4167 | nsCOMPtr<nsIDOMDeviceStorageChangeEvent> ce = do_QueryInterface(event); |
michael@0 | 4168 | |
michael@0 | 4169 | nsString reason; |
michael@0 | 4170 | reason.AssignWithConversion(aReason); |
michael@0 | 4171 | |
michael@0 | 4172 | nsString fullPath; |
michael@0 | 4173 | aFile->GetFullPath(fullPath); |
michael@0 | 4174 | nsresult rv = ce->InitDeviceStorageChangeEvent(NS_LITERAL_STRING("change"), |
michael@0 | 4175 | true, false, fullPath, |
michael@0 | 4176 | reason); |
michael@0 | 4177 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4178 | |
michael@0 | 4179 | bool ignore; |
michael@0 | 4180 | DispatchEvent(ce, &ignore); |
michael@0 | 4181 | return NS_OK; |
michael@0 | 4182 | } |
michael@0 | 4183 | |
michael@0 | 4184 | NS_IMETHODIMP |
michael@0 | 4185 | nsDOMDeviceStorage::AddEventListener(const nsAString & aType, |
michael@0 | 4186 | nsIDOMEventListener *aListener, |
michael@0 | 4187 | bool aUseCapture, |
michael@0 | 4188 | bool aWantsUntrusted, |
michael@0 | 4189 | uint8_t aArgc) |
michael@0 | 4190 | { |
michael@0 | 4191 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4192 | |
michael@0 | 4193 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 4194 | if (!win) { |
michael@0 | 4195 | return NS_ERROR_UNEXPECTED; |
michael@0 | 4196 | } |
michael@0 | 4197 | |
michael@0 | 4198 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 4199 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 4200 | mStorageName); |
michael@0 | 4201 | nsCOMPtr<nsIRunnable> r |
michael@0 | 4202 | = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH, |
michael@0 | 4203 | win, mPrincipal, dsf, request, this); |
michael@0 | 4204 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 4205 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 4206 | return rv; |
michael@0 | 4207 | } |
michael@0 | 4208 | |
michael@0 | 4209 | return DOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, |
michael@0 | 4210 | aWantsUntrusted, aArgc); |
michael@0 | 4211 | } |
michael@0 | 4212 | |
michael@0 | 4213 | void |
michael@0 | 4214 | nsDOMDeviceStorage::AddEventListener(const nsAString & aType, |
michael@0 | 4215 | EventListener *aListener, |
michael@0 | 4216 | bool aUseCapture, |
michael@0 | 4217 | const Nullable<bool>& aWantsUntrusted, |
michael@0 | 4218 | ErrorResult& aRv) |
michael@0 | 4219 | { |
michael@0 | 4220 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4221 | |
michael@0 | 4222 | nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
michael@0 | 4223 | if (!win) { |
michael@0 | 4224 | aRv.Throw(NS_ERROR_UNEXPECTED); |
michael@0 | 4225 | return; |
michael@0 | 4226 | } |
michael@0 | 4227 | |
michael@0 | 4228 | nsRefPtr<DOMRequest> request = new DOMRequest(win); |
michael@0 | 4229 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, |
michael@0 | 4230 | mStorageName); |
michael@0 | 4231 | nsCOMPtr<nsIRunnable> r |
michael@0 | 4232 | = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH, |
michael@0 | 4233 | win, mPrincipal, dsf, request, this); |
michael@0 | 4234 | nsresult rv = NS_DispatchToCurrentThread(r); |
michael@0 | 4235 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 4236 | return; |
michael@0 | 4237 | } |
michael@0 | 4238 | DOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, |
michael@0 | 4239 | aWantsUntrusted, aRv); |
michael@0 | 4240 | } |
michael@0 | 4241 | |
michael@0 | 4242 | NS_IMETHODIMP |
michael@0 | 4243 | nsDOMDeviceStorage::AddSystemEventListener(const nsAString & aType, |
michael@0 | 4244 | nsIDOMEventListener *aListener, |
michael@0 | 4245 | bool aUseCapture, |
michael@0 | 4246 | bool aWantsUntrusted, |
michael@0 | 4247 | uint8_t aArgc) |
michael@0 | 4248 | { |
michael@0 | 4249 | if (!mIsWatchingFile) { |
michael@0 | 4250 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 4251 | obs->AddObserver(this, "file-watcher-update", false); |
michael@0 | 4252 | mIsWatchingFile = true; |
michael@0 | 4253 | } |
michael@0 | 4254 | |
michael@0 | 4255 | return nsDOMDeviceStorage::AddEventListener(aType, aListener, aUseCapture, |
michael@0 | 4256 | aWantsUntrusted, aArgc); |
michael@0 | 4257 | } |
michael@0 | 4258 | |
michael@0 | 4259 | NS_IMETHODIMP |
michael@0 | 4260 | nsDOMDeviceStorage::RemoveEventListener(const nsAString & aType, |
michael@0 | 4261 | nsIDOMEventListener *aListener, |
michael@0 | 4262 | bool aUseCapture) |
michael@0 | 4263 | { |
michael@0 | 4264 | DOMEventTargetHelper::RemoveEventListener(aType, aListener, false); |
michael@0 | 4265 | |
michael@0 | 4266 | if (mIsWatchingFile && !HasListenersFor(nsGkAtoms::onchange)) { |
michael@0 | 4267 | mIsWatchingFile = false; |
michael@0 | 4268 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 4269 | obs->RemoveObserver(this, "file-watcher-update"); |
michael@0 | 4270 | } |
michael@0 | 4271 | return NS_OK; |
michael@0 | 4272 | } |
michael@0 | 4273 | |
michael@0 | 4274 | void |
michael@0 | 4275 | nsDOMDeviceStorage::RemoveEventListener(const nsAString& aType, |
michael@0 | 4276 | EventListener* aListener, |
michael@0 | 4277 | bool aCapture, |
michael@0 | 4278 | ErrorResult& aRv) |
michael@0 | 4279 | { |
michael@0 | 4280 | DOMEventTargetHelper::RemoveEventListener(aType, aListener, aCapture, aRv); |
michael@0 | 4281 | |
michael@0 | 4282 | if (mIsWatchingFile && !HasListenersFor(nsGkAtoms::onchange)) { |
michael@0 | 4283 | mIsWatchingFile = false; |
michael@0 | 4284 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 4285 | obs->RemoveObserver(this, "file-watcher-update"); |
michael@0 | 4286 | } |
michael@0 | 4287 | } |
michael@0 | 4288 | |
michael@0 | 4289 | NS_IMETHODIMP |
michael@0 | 4290 | nsDOMDeviceStorage::RemoveSystemEventListener(const nsAString & aType, |
michael@0 | 4291 | nsIDOMEventListener *aListener, |
michael@0 | 4292 | bool aUseCapture) |
michael@0 | 4293 | { |
michael@0 | 4294 | return nsDOMDeviceStorage::RemoveEventListener(aType, aListener, aUseCapture); |
michael@0 | 4295 | } |
michael@0 | 4296 | |
michael@0 | 4297 | NS_IMETHODIMP |
michael@0 | 4298 | nsDOMDeviceStorage::DispatchEvent(nsIDOMEvent *aEvt, |
michael@0 | 4299 | bool *aRetval) |
michael@0 | 4300 | { |
michael@0 | 4301 | return DOMEventTargetHelper::DispatchEvent(aEvt, aRetval); |
michael@0 | 4302 | } |
michael@0 | 4303 | |
michael@0 | 4304 | EventTarget* |
michael@0 | 4305 | nsDOMDeviceStorage::GetTargetForDOMEvent() |
michael@0 | 4306 | { |
michael@0 | 4307 | return DOMEventTargetHelper::GetTargetForDOMEvent(); |
michael@0 | 4308 | } |
michael@0 | 4309 | |
michael@0 | 4310 | EventTarget * |
michael@0 | 4311 | nsDOMDeviceStorage::GetTargetForEventTargetChain() |
michael@0 | 4312 | { |
michael@0 | 4313 | return DOMEventTargetHelper::GetTargetForEventTargetChain(); |
michael@0 | 4314 | } |
michael@0 | 4315 | |
michael@0 | 4316 | nsresult |
michael@0 | 4317 | nsDOMDeviceStorage::PreHandleEvent(EventChainPreVisitor& aVisitor) |
michael@0 | 4318 | { |
michael@0 | 4319 | return DOMEventTargetHelper::PreHandleEvent(aVisitor); |
michael@0 | 4320 | } |
michael@0 | 4321 | |
michael@0 | 4322 | nsresult |
michael@0 | 4323 | nsDOMDeviceStorage::WillHandleEvent(EventChainPostVisitor& aVisitor) |
michael@0 | 4324 | { |
michael@0 | 4325 | return DOMEventTargetHelper::WillHandleEvent(aVisitor); |
michael@0 | 4326 | } |
michael@0 | 4327 | |
michael@0 | 4328 | nsresult |
michael@0 | 4329 | nsDOMDeviceStorage::PostHandleEvent(EventChainPostVisitor& aVisitor) |
michael@0 | 4330 | { |
michael@0 | 4331 | return DOMEventTargetHelper::PostHandleEvent(aVisitor); |
michael@0 | 4332 | } |
michael@0 | 4333 | |
michael@0 | 4334 | nsresult |
michael@0 | 4335 | nsDOMDeviceStorage::DispatchDOMEvent(WidgetEvent* aEvent, |
michael@0 | 4336 | nsIDOMEvent* aDOMEvent, |
michael@0 | 4337 | nsPresContext* aPresContext, |
michael@0 | 4338 | nsEventStatus* aEventStatus) |
michael@0 | 4339 | { |
michael@0 | 4340 | return DOMEventTargetHelper::DispatchDOMEvent(aEvent, |
michael@0 | 4341 | aDOMEvent, |
michael@0 | 4342 | aPresContext, |
michael@0 | 4343 | aEventStatus); |
michael@0 | 4344 | } |
michael@0 | 4345 | |
michael@0 | 4346 | EventListenerManager* |
michael@0 | 4347 | nsDOMDeviceStorage::GetOrCreateListenerManager() |
michael@0 | 4348 | { |
michael@0 | 4349 | return DOMEventTargetHelper::GetOrCreateListenerManager(); |
michael@0 | 4350 | } |
michael@0 | 4351 | |
michael@0 | 4352 | EventListenerManager* |
michael@0 | 4353 | nsDOMDeviceStorage::GetExistingListenerManager() const |
michael@0 | 4354 | { |
michael@0 | 4355 | return DOMEventTargetHelper::GetExistingListenerManager(); |
michael@0 | 4356 | } |
michael@0 | 4357 | |
michael@0 | 4358 | nsIScriptContext * |
michael@0 | 4359 | nsDOMDeviceStorage::GetContextForEventHandlers(nsresult *aRv) |
michael@0 | 4360 | { |
michael@0 | 4361 | return DOMEventTargetHelper::GetContextForEventHandlers(aRv); |
michael@0 | 4362 | } |
michael@0 | 4363 | |
michael@0 | 4364 | JSContext * |
michael@0 | 4365 | nsDOMDeviceStorage::GetJSContextForEventHandlers() |
michael@0 | 4366 | { |
michael@0 | 4367 | return DOMEventTargetHelper::GetJSContextForEventHandlers(); |
michael@0 | 4368 | } |
michael@0 | 4369 | |
michael@0 | 4370 | NS_IMPL_EVENT_HANDLER(nsDOMDeviceStorage, change) |