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