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/. */
7 #include "nsDeviceStorage.h"
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/DeviceStorageChangeEvent.h"
15 #include "mozilla/dom/DeviceStorageFileSystem.h"
16 #include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
17 #include "mozilla/dom/Directory.h"
18 #include "mozilla/dom/FileSystemUtils.h"
19 #include "mozilla/dom/ipc/Blob.h"
20 #include "mozilla/dom/PBrowserChild.h"
21 #include "mozilla/dom/PermissionMessageUtils.h"
22 #include "mozilla/dom/Promise.h"
23 #include "mozilla/dom/ScriptSettings.h"
24 #include "mozilla/EventDispatcher.h"
25 #include "mozilla/EventListenerManager.h"
26 #include "mozilla/LazyIdleThread.h"
27 #include "mozilla/Preferences.h"
28 #include "mozilla/Scoped.h"
29 #include "mozilla/Services.h"
31 #include "nsArrayUtils.h"
32 #include "nsAutoPtr.h"
33 #include "nsGlobalWindow.h"
34 #include "nsServiceManagerUtils.h"
36 #include "nsIDirectoryEnumerator.h"
37 #include "nsAppDirectoryServiceDefs.h"
38 #include "nsDirectoryServiceDefs.h"
39 #include "nsIDOMFile.h"
40 #include "nsDOMBlobBuilder.h"
41 #include "nsNetUtil.h"
42 #include "nsCycleCollectionParticipant.h"
43 #include "nsIPrincipal.h"
44 #include "nsJSUtils.h"
45 #include "nsContentUtils.h"
46 #include "nsXULAppAPI.h"
47 #include "DeviceStorageFileDescriptor.h"
48 #include "DeviceStorageRequestChild.h"
50 #include "nsIObserverService.h"
51 #include "nsIMIMEService.h"
52 #include "nsCExternalHandlerService.h"
53 #include "nsIPermissionManager.h"
54 #include "nsIStringBundle.h"
55 #include "nsISupportsPrimitives.h"
56 #include "nsIDocument.h"
57 #include "nsPrintfCString.h"
59 #include "private/pprio.h"
60 #include "nsContentPermissionHelper.h"
62 #include "mozilla/dom/DeviceStorageBinding.h"
64 // Microsoft's API Name hackery sucks
67 #ifdef MOZ_WIDGET_ANDROID
68 #include "AndroidBridge.h"
71 #ifdef MOZ_WIDGET_GONK
72 #include "nsIVolume.h"
73 #include "nsIVolumeService.h"
76 #define DEVICESTORAGE_PROPERTIES \
77 "chrome://global/content/devicestorage.properties"
78 #define DEFAULT_THREAD_TIMEOUT_MS 30000
80 using namespace mozilla
;
81 using namespace mozilla::dom
;
82 using namespace mozilla::dom::devicestorage
;
83 using namespace mozilla::ipc
;
85 #include "nsDirectoryServiceDefs.h"
87 const char* kFileWatcherUpdate
= "file-watcher-update";
88 const char* kFileWatcherNotify
= "file-watcher-notify";
89 const char *kDownloadWatcherNotify
= "download-watcher-notify";
92 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc
, PRFileDesc
, PR_Close
);
95 StaticAutoPtr
<DeviceStorageUsedSpaceCache
>
96 DeviceStorageUsedSpaceCache::sDeviceStorageUsedSpaceCache
;
98 DeviceStorageUsedSpaceCache::DeviceStorageUsedSpaceCache()
100 MOZ_ASSERT(NS_IsMainThread());
102 mIOThread
= new LazyIdleThread(
103 DEFAULT_THREAD_TIMEOUT_MS
,
104 NS_LITERAL_CSTRING("DeviceStorageUsedSpaceCache I/O"));
108 DeviceStorageUsedSpaceCache::~DeviceStorageUsedSpaceCache()
112 DeviceStorageUsedSpaceCache
*
113 DeviceStorageUsedSpaceCache::CreateOrGet()
115 if (sDeviceStorageUsedSpaceCache
) {
116 return sDeviceStorageUsedSpaceCache
;
119 MOZ_ASSERT(NS_IsMainThread());
121 sDeviceStorageUsedSpaceCache
= new DeviceStorageUsedSpaceCache();
122 ClearOnShutdown(&sDeviceStorageUsedSpaceCache
);
123 return sDeviceStorageUsedSpaceCache
;
126 already_AddRefed
<DeviceStorageUsedSpaceCache::CacheEntry
>
127 DeviceStorageUsedSpaceCache::GetCacheEntry(const nsAString
& aStorageName
)
129 nsTArray
<nsRefPtr
<CacheEntry
>>::size_type numEntries
= mCacheEntries
.Length();
130 nsTArray
<nsRefPtr
<CacheEntry
>>::index_type i
;
131 for (i
= 0; i
< numEntries
; i
++) {
132 nsRefPtr
<CacheEntry
>& cacheEntry
= mCacheEntries
[i
];
133 if (cacheEntry
->mStorageName
.Equals(aStorageName
)) {
134 nsRefPtr
<CacheEntry
> addRefedCacheEntry
= cacheEntry
;
135 return addRefedCacheEntry
.forget();
142 GetFreeBytes(const nsAString
& aStorageName
)
144 // This function makes the assumption that the various types
145 // are all stored on the same filesystem. So we use pictures.
147 nsRefPtr
<DeviceStorageFile
> dsf(new DeviceStorageFile(NS_LITERAL_STRING(DEVICESTORAGE_PICTURES
),
149 int64_t freeBytes
= 0;
150 dsf
->GetDiskFreeSpace(&freeBytes
);
155 DeviceStorageUsedSpaceCache::AccumUsedSizes(const nsAString
& aStorageName
,
156 uint64_t* aPicturesSoFar
,
157 uint64_t* aVideosSoFar
,
158 uint64_t* aMusicSoFar
,
159 uint64_t* aTotalSoFar
)
161 nsRefPtr
<CacheEntry
> cacheEntry
= GetCacheEntry(aStorageName
);
162 if (!cacheEntry
|| cacheEntry
->mDirty
) {
163 return NS_ERROR_NOT_AVAILABLE
;
165 int64_t freeBytes
= GetFreeBytes(cacheEntry
->mStorageName
);
166 if (freeBytes
!= cacheEntry
->mFreeBytes
) {
167 // Free space changed, so our cached results are no longer valid.
168 return NS_ERROR_NOT_AVAILABLE
;
171 *aPicturesSoFar
+= cacheEntry
->mPicturesUsedSize
;
172 *aVideosSoFar
+= cacheEntry
->mVideosUsedSize
;
173 *aMusicSoFar
+= cacheEntry
->mMusicUsedSize
;
174 *aTotalSoFar
+= cacheEntry
->mTotalUsedSize
;
180 DeviceStorageUsedSpaceCache::SetUsedSizes(const nsAString
& aStorageName
,
181 uint64_t aPictureSize
,
182 uint64_t aVideosSize
,
184 uint64_t aTotalUsedSize
)
186 nsRefPtr
<CacheEntry
> cacheEntry
= GetCacheEntry(aStorageName
);
188 cacheEntry
= new CacheEntry
;
189 cacheEntry
->mStorageName
= aStorageName
;
190 mCacheEntries
.AppendElement(cacheEntry
);
192 cacheEntry
->mFreeBytes
= GetFreeBytes(cacheEntry
->mStorageName
);
194 cacheEntry
->mPicturesUsedSize
= aPictureSize
;
195 cacheEntry
->mVideosUsedSize
= aVideosSize
;
196 cacheEntry
->mMusicUsedSize
= aMusicSize
;
197 cacheEntry
->mTotalUsedSize
= aTotalUsedSize
;
198 cacheEntry
->mDirty
= false;
206 NS_INLINE_DECL_REFCOUNTING(GlobalDirs
)
207 #if !defined(MOZ_WIDGET_GONK)
208 nsCOMPtr
<nsIFile
> pictures
;
209 nsCOMPtr
<nsIFile
> videos
;
210 nsCOMPtr
<nsIFile
> music
;
211 nsCOMPtr
<nsIFile
> sdcard
;
213 nsCOMPtr
<nsIFile
> apps
;
214 nsCOMPtr
<nsIFile
> crashes
;
215 nsCOMPtr
<nsIFile
> overrideRootDir
;
218 static StaticRefPtr
<GlobalDirs
> sDirs
;
220 StaticAutoPtr
<DeviceStorageTypeChecker
>
221 DeviceStorageTypeChecker::sDeviceStorageTypeChecker
;
223 DeviceStorageTypeChecker::DeviceStorageTypeChecker()
227 DeviceStorageTypeChecker::~DeviceStorageTypeChecker()
231 DeviceStorageTypeChecker
*
232 DeviceStorageTypeChecker::CreateOrGet()
234 if (sDeviceStorageTypeChecker
) {
235 return sDeviceStorageTypeChecker
;
238 MOZ_ASSERT(NS_IsMainThread());
240 nsCOMPtr
<nsIStringBundleService
> stringService
241 = mozilla::services::GetStringBundleService();
242 if (!stringService
) {
246 nsCOMPtr
<nsIStringBundle
> filterBundle
;
247 if (NS_FAILED(stringService
->CreateBundle(DEVICESTORAGE_PROPERTIES
,
248 getter_AddRefs(filterBundle
)))) {
252 DeviceStorageTypeChecker
* result
= new DeviceStorageTypeChecker();
253 result
->InitFromBundle(filterBundle
);
255 sDeviceStorageTypeChecker
= result
;
256 ClearOnShutdown(&sDeviceStorageTypeChecker
);
261 DeviceStorageTypeChecker::InitFromBundle(nsIStringBundle
* aBundle
)
263 aBundle
->GetStringFromName(
264 NS_ConvertASCIItoUTF16(DEVICESTORAGE_PICTURES
).get(),
265 getter_Copies(mPicturesExtensions
));
266 aBundle
->GetStringFromName(
267 NS_ConvertASCIItoUTF16(DEVICESTORAGE_MUSIC
).get(),
268 getter_Copies(mMusicExtensions
));
269 aBundle
->GetStringFromName(
270 NS_ConvertASCIItoUTF16(DEVICESTORAGE_VIDEOS
).get(),
271 getter_Copies(mVideosExtensions
));
276 DeviceStorageTypeChecker::Check(const nsAString
& aType
, nsIDOMBlob
* aBlob
)
281 if (NS_FAILED(aBlob
->GetType(mimeType
))) {
285 if (aType
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
286 return StringBeginsWith(mimeType
, NS_LITERAL_STRING("image/"));
289 if (aType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
290 return StringBeginsWith(mimeType
, NS_LITERAL_STRING("video/"));
293 if (aType
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
294 return StringBeginsWith(mimeType
, NS_LITERAL_STRING("audio/"));
297 if (aType
.EqualsLiteral(DEVICESTORAGE_APPS
) ||
298 aType
.EqualsLiteral(DEVICESTORAGE_SDCARD
) ||
299 aType
.EqualsLiteral(DEVICESTORAGE_CRASHES
)) {
300 // Apps, crashes and sdcard have no restriction on mime types
308 DeviceStorageTypeChecker::Check(const nsAString
& aType
, nsIFile
* aFile
)
313 aFile
->GetPath(path
);
315 return Check(aType
, path
);
319 DeviceStorageTypeChecker::Check(const nsAString
& aType
, const nsString
& aPath
)
321 if (aType
.EqualsLiteral(DEVICESTORAGE_APPS
) ||
322 aType
.EqualsLiteral(DEVICESTORAGE_SDCARD
) ||
323 aType
.EqualsLiteral(DEVICESTORAGE_CRASHES
)) {
324 // Apps, crashes and sdcard have no restrictions on what file extensions used.
328 int32_t dotIdx
= aPath
.RFindChar(char16_t('.'));
329 if (dotIdx
== kNotFound
) {
333 nsAutoString extensionMatch
;
334 extensionMatch
.Assign('*');
335 extensionMatch
.Append(Substring(aPath
, dotIdx
));
336 extensionMatch
.Append(';');
338 if (aType
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
339 return CaseInsensitiveFindInReadable(extensionMatch
, mPicturesExtensions
);
342 if (aType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
343 return CaseInsensitiveFindInReadable(extensionMatch
, mVideosExtensions
);
346 if (aType
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
347 return CaseInsensitiveFindInReadable(extensionMatch
, mMusicExtensions
);
354 DeviceStorageTypeChecker::GetTypeFromFile(nsIFile
* aFile
, nsAString
& aType
)
359 aFile
->GetPath(path
);
361 GetTypeFromFileName(path
, aType
);
365 DeviceStorageTypeChecker::GetTypeFromFileName(const nsAString
& aFileName
,
368 aType
.AssignLiteral(DEVICESTORAGE_SDCARD
);
370 nsString
fileName(aFileName
);
371 int32_t dotIdx
= fileName
.RFindChar(char16_t('.'));
372 if (dotIdx
== kNotFound
) {
376 nsAutoString extensionMatch
;
377 extensionMatch
.Assign('*');
378 extensionMatch
.Append(Substring(aFileName
, dotIdx
));
379 extensionMatch
.Append(';');
381 if (CaseInsensitiveFindInReadable(extensionMatch
, mPicturesExtensions
)) {
382 aType
.AssignLiteral(DEVICESTORAGE_PICTURES
);
384 else if (CaseInsensitiveFindInReadable(extensionMatch
, mVideosExtensions
)) {
385 aType
.AssignLiteral(DEVICESTORAGE_VIDEOS
);
387 else if (CaseInsensitiveFindInReadable(extensionMatch
, mMusicExtensions
)) {
388 aType
.AssignLiteral(DEVICESTORAGE_MUSIC
);
393 DeviceStorageTypeChecker::GetPermissionForType(const nsAString
& aType
,
394 nsACString
& aPermissionResult
)
396 if (!aType
.EqualsLiteral(DEVICESTORAGE_PICTURES
) &&
397 !aType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
) &&
398 !aType
.EqualsLiteral(DEVICESTORAGE_MUSIC
) &&
399 !aType
.EqualsLiteral(DEVICESTORAGE_APPS
) &&
400 !aType
.EqualsLiteral(DEVICESTORAGE_SDCARD
) &&
401 !aType
.EqualsLiteral(DEVICESTORAGE_CRASHES
)) {
403 return NS_ERROR_FAILURE
;
406 aPermissionResult
.AssignLiteral("device-storage:");
407 aPermissionResult
.Append(NS_ConvertUTF16toUTF8(aType
));
412 DeviceStorageTypeChecker::GetAccessForRequest(
413 const DeviceStorageRequestType aRequestType
, nsACString
& aAccessResult
)
415 switch(aRequestType
) {
416 case DEVICE_STORAGE_REQUEST_READ
:
417 case DEVICE_STORAGE_REQUEST_WATCH
:
418 case DEVICE_STORAGE_REQUEST_FREE_SPACE
:
419 case DEVICE_STORAGE_REQUEST_USED_SPACE
:
420 case DEVICE_STORAGE_REQUEST_AVAILABLE
:
421 case DEVICE_STORAGE_REQUEST_STATUS
:
422 aAccessResult
.AssignLiteral("read");
424 case DEVICE_STORAGE_REQUEST_WRITE
:
425 case DEVICE_STORAGE_REQUEST_APPEND
:
426 case DEVICE_STORAGE_REQUEST_DELETE
:
427 case DEVICE_STORAGE_REQUEST_FORMAT
:
428 case DEVICE_STORAGE_REQUEST_MOUNT
:
429 case DEVICE_STORAGE_REQUEST_UNMOUNT
:
430 aAccessResult
.AssignLiteral("write");
432 case DEVICE_STORAGE_REQUEST_CREATE
:
433 case DEVICE_STORAGE_REQUEST_CREATEFD
:
434 aAccessResult
.AssignLiteral("create");
437 aAccessResult
.AssignLiteral("undefined");
442 static bool IsMediaType(const nsAString
& aType
)
444 return aType
.EqualsLiteral(DEVICESTORAGE_PICTURES
) ||
445 aType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
) ||
446 aType
.EqualsLiteral(DEVICESTORAGE_MUSIC
) ||
447 aType
.EqualsLiteral(DEVICESTORAGE_SDCARD
);
452 DeviceStorageTypeChecker::IsVolumeBased(const nsAString
& aType
)
454 #ifdef MOZ_WIDGET_GONK
455 // The apps and crashes aren't stored in the same place as the media, so
456 // we only ever return a single apps object, and not an array
457 // with one per volume (as is the case for the remaining
459 return IsMediaType(aType
);
467 DeviceStorageTypeChecker::IsSharedMediaRoot(const nsAString
& aType
)
469 // This function determines if aType shares a root directory with the
470 // other media types (so only applies to music, videos, pictures and sdcard).
471 #ifdef MOZ_WIDGET_GONK
472 return IsMediaType(aType
);
474 // For desktop, if the directories have been overridden, then they share
476 return IsMediaType(aType
) && sDirs
->overrideRootDir
;
480 NS_IMPL_ISUPPORTS(FileUpdateDispatcher
, nsIObserver
)
482 mozilla::StaticRefPtr
<FileUpdateDispatcher
> FileUpdateDispatcher::sSingleton
;
484 FileUpdateDispatcher
*
485 FileUpdateDispatcher::GetSingleton()
491 sSingleton
= new FileUpdateDispatcher();
492 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
493 obs
->AddObserver(sSingleton
, kFileWatcherNotify
, false);
494 obs
->AddObserver(sSingleton
, kDownloadWatcherNotify
, false);
495 ClearOnShutdown(&sSingleton
);
501 FileUpdateDispatcher::Observe(nsISupports
* aSubject
,
503 const char16_t
* aData
)
505 nsRefPtr
<DeviceStorageFile
> dsf
;
507 if (!strcmp(aTopic
, kDownloadWatcherNotify
)) {
508 // aSubject will be an nsISupportsString with the native path to the file
511 nsCOMPtr
<nsISupportsString
> supportsString
= do_QueryInterface(aSubject
);
512 if (!supportsString
) {
516 nsresult rv
= supportsString
->GetData(path
);
517 if (NS_WARN_IF(NS_FAILED(rv
))) {
521 // The downloader uses the sdcard storage type.
523 #ifdef MOZ_WIDGET_GONK
524 if (DeviceStorageTypeChecker::IsVolumeBased(NS_LITERAL_STRING(DEVICESTORAGE_SDCARD
))) {
525 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
526 if (NS_WARN_IF(!vs
)) {
529 nsCOMPtr
<nsIVolume
> vol
;
530 rv
= vs
->GetVolumeByPath(path
, getter_AddRefs(vol
));
531 if (NS_WARN_IF(NS_FAILED(rv
))) {
534 rv
= vol
->GetName(volName
);
535 if (NS_WARN_IF(NS_FAILED(rv
))) {
539 rv
= vol
->GetMountPoint(mountPoint
);
540 if (NS_WARN_IF(NS_FAILED(rv
))) {
543 if (!Substring(path
, 0, mountPoint
.Length()).Equals(mountPoint
)) {
546 path
= Substring(path
, mountPoint
.Length() + 1);
549 dsf
= new DeviceStorageFile(NS_LITERAL_STRING(DEVICESTORAGE_SDCARD
), volName
, path
);
551 } else if (!strcmp(aTopic
, kFileWatcherNotify
)) {
552 dsf
= static_cast<DeviceStorageFile
*>(aSubject
);
554 NS_WARNING("FileUpdateDispatcher: Unrecognized topic");
558 if (!dsf
|| !dsf
->mFile
) {
559 NS_WARNING("FileUpdateDispatcher: Device storage file looks invalid!");
563 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
564 // Child process. Forward the notification to the parent.
565 ContentChild::GetSingleton()
566 ->SendFilePathUpdateNotify(dsf
->mStorageType
,
569 NS_ConvertUTF16toUTF8(aData
));
573 // Multiple storage types may match the same files. So walk through each of
574 // the storage types, and if the extension matches, tell them about it.
575 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
576 if (DeviceStorageTypeChecker::IsSharedMediaRoot(dsf
->mStorageType
)) {
577 DeviceStorageTypeChecker
* typeChecker
578 = DeviceStorageTypeChecker::CreateOrGet();
579 MOZ_ASSERT(typeChecker
);
581 static const nsLiteralString kMediaTypes
[] = {
582 NS_LITERAL_STRING(DEVICESTORAGE_SDCARD
),
583 NS_LITERAL_STRING(DEVICESTORAGE_PICTURES
),
584 NS_LITERAL_STRING(DEVICESTORAGE_VIDEOS
),
585 NS_LITERAL_STRING(DEVICESTORAGE_MUSIC
),
588 for (size_t i
= 0; i
< MOZ_ARRAY_LENGTH(kMediaTypes
); i
++) {
589 nsRefPtr
<DeviceStorageFile
> dsf2
;
590 if (typeChecker
->Check(kMediaTypes
[i
], dsf
->mPath
)) {
591 if (dsf
->mStorageType
.Equals(kMediaTypes
[i
])) {
594 dsf2
= new DeviceStorageFile(kMediaTypes
[i
],
595 dsf
->mStorageName
, dsf
->mPath
);
597 obs
->NotifyObservers(dsf2
, kFileWatcherUpdate
, aData
);
601 obs
->NotifyObservers(dsf
, kFileWatcherUpdate
, aData
);
606 class IOEventComplete
: public nsRunnable
609 IOEventComplete(DeviceStorageFile
*aFile
, const char *aType
)
615 ~IOEventComplete() {}
619 MOZ_ASSERT(NS_IsMainThread());
621 CopyASCIItoUTF16(mType
, data
);
622 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
624 obs
->NotifyObservers(mFile
, kFileWatcherNotify
, data
.get());
626 DeviceStorageUsedSpaceCache
* usedSpaceCache
627 = DeviceStorageUsedSpaceCache::CreateOrGet();
628 MOZ_ASSERT(usedSpaceCache
);
629 usedSpaceCache
->Invalidate(mFile
->mStorageName
);
634 nsRefPtr
<DeviceStorageFile
> mFile
;
638 DeviceStorageFile::DeviceStorageFile(const nsAString
& aStorageType
,
639 const nsAString
& aStorageName
,
640 const nsAString
& aRootDir
,
641 const nsAString
& aPath
)
642 : mStorageType(aStorageType
)
643 , mStorageName(aStorageName
)
647 , mLength(UINT64_MAX
)
648 , mLastModifiedDate(UINT64_MAX
)
651 AppendRelativePath(mRootDir
);
652 if (!mPath
.EqualsLiteral("")) {
653 AppendRelativePath(mPath
);
658 DeviceStorageFile::DeviceStorageFile(const nsAString
& aStorageType
,
659 const nsAString
& aStorageName
,
660 const nsAString
& aPath
)
661 : mStorageType(aStorageType
)
662 , mStorageName(aStorageName
)
665 , mLength(UINT64_MAX
)
666 , mLastModifiedDate(UINT64_MAX
)
669 AppendRelativePath(aPath
);
673 DeviceStorageFile::DeviceStorageFile(const nsAString
& aStorageType
,
674 const nsAString
& aStorageName
)
675 : mStorageType(aStorageType
)
676 , mStorageName(aStorageName
)
678 , mLength(UINT64_MAX
)
679 , mLastModifiedDate(UINT64_MAX
)
685 DeviceStorageFile::Dump(const char* label
)
689 mFile
->GetPath(path
);
691 path
= NS_LITERAL_STRING("(null)");
694 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
700 printf_stderr("DSF (%s) %s: mStorageType '%s' mStorageName '%s' "
701 "mRootDir '%s' mPath '%s' mFile->GetPath '%s'\n",
703 NS_LossyConvertUTF16toASCII(mStorageType
).get(),
704 NS_LossyConvertUTF16toASCII(mStorageName
).get(),
705 NS_LossyConvertUTF16toASCII(mRootDir
).get(),
706 NS_LossyConvertUTF16toASCII(mPath
).get(),
707 NS_LossyConvertUTF16toASCII(path
).get());
711 DeviceStorageFile::Init()
713 DeviceStorageFile::GetRootDirectoryForType(mStorageType
,
715 getter_AddRefs(mFile
));
717 DebugOnly
<DeviceStorageTypeChecker
*> typeChecker
718 = DeviceStorageTypeChecker::CreateOrGet();
719 MOZ_ASSERT(typeChecker
);
722 // The OverrideRootDir is needed to facilitate testing of the
723 // device.storage.overrideRootDir preference. The preference is normally
724 // only read once during initialization, but since the test environment has
725 // no convenient way to restart, we use a pref watcher instead.
726 class OverrideRootDir MOZ_FINAL
: public nsIObserver
734 static OverrideRootDir
* GetSingleton();
737 static mozilla::StaticRefPtr
<OverrideRootDir
> sSingleton
;
740 NS_IMPL_ISUPPORTS(OverrideRootDir
, nsIObserver
)
742 mozilla::StaticRefPtr
<OverrideRootDir
>
743 OverrideRootDir::sSingleton
;
746 OverrideRootDir::GetSingleton()
751 // Preference changes are automatically forwarded from parent to child
752 // in ContentParent::Observe, so we'll see the change in both the parent
753 // and the child process.
755 sSingleton
= new OverrideRootDir();
756 Preferences::AddStrongObserver(sSingleton
, "device.storage.overrideRootDir");
757 Preferences::AddStrongObserver(sSingleton
, "device.storage.testing");
758 ClearOnShutdown(&sSingleton
);
763 OverrideRootDir::~OverrideRootDir()
765 Preferences::RemoveObserver(this, "device.storage.overrideRootDir");
766 Preferences::RemoveObserver(this, "device.storage.testing");
770 OverrideRootDir::Observe(nsISupports
*aSubject
,
772 const char16_t
*aData
)
774 MOZ_ASSERT(NS_IsMainThread());
783 OverrideRootDir::Init()
785 MOZ_ASSERT(NS_IsMainThread());
791 if (mozilla::Preferences::GetBool("device.storage.testing", false)) {
792 nsCOMPtr
<nsIProperties
> dirService
793 = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
);
794 MOZ_ASSERT(dirService
);
795 dirService
->Get(NS_OS_TEMP_DIR
, NS_GET_IID(nsIFile
),
796 getter_AddRefs(sDirs
->overrideRootDir
));
797 if (sDirs
->overrideRootDir
) {
798 sDirs
->overrideRootDir
->AppendRelativeNativePath(
799 NS_LITERAL_CSTRING("device-storage-testing"));
802 // For users running on desktop, it's convenient to be able to override
803 // all of the directories to point to a single tree, much like what happens
805 const nsAdoptingString
& overrideRootDir
=
806 mozilla::Preferences::GetString("device.storage.overrideRootDir");
807 if (overrideRootDir
&& overrideRootDir
.Length() > 0) {
808 NS_NewLocalFile(overrideRootDir
, false,
809 getter_AddRefs(sDirs
->overrideRootDir
));
811 sDirs
->overrideRootDir
= nullptr;
815 if (sDirs
->overrideRootDir
) {
816 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
817 // Only the parent process can create directories. In testing, because
818 // the preference is updated after startup, its entirely possible that
819 // the preference updated notification will be received by a child
820 // prior to the parent.
822 = sDirs
->overrideRootDir
->Create(nsIFile::DIRECTORY_TYPE
, 0777);
824 sDirs
->overrideRootDir
->GetPath(path
);
825 if (NS_FAILED(rv
) && rv
!= NS_ERROR_FILE_ALREADY_EXISTS
) {
826 nsPrintfCString
msg("DeviceStorage: Unable to create directory '%s'",
827 NS_LossyConvertUTF16toASCII(path
).get());
828 NS_WARNING(msg
.get());
831 sDirs
->overrideRootDir
->Normalize();
835 // Directories which don't depend on a volume should be calculated once
836 // here. Directories which depend on the root directory of a volume
837 // should be calculated in DeviceStorageFile::GetRootDirectoryForType.
844 MOZ_ASSERT(NS_IsMainThread());
845 sDirs
= new GlobalDirs
;
846 ClearOnShutdown(&sDirs
);
848 nsCOMPtr
<nsIProperties
> dirService
849 = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
);
850 MOZ_ASSERT(dirService
);
852 #if !defined(MOZ_WIDGET_GONK)
854 // Keep MOZ_WIDGET_COCOA above XP_UNIX,
855 // because both are defined in Darwin builds.
856 #if defined (MOZ_WIDGET_COCOA)
857 dirService
->Get(NS_OSX_PICTURE_DOCUMENTS_DIR
,
859 getter_AddRefs(sDirs
->pictures
));
860 dirService
->Get(NS_OSX_MOVIE_DOCUMENTS_DIR
,
862 getter_AddRefs(sDirs
->videos
));
863 dirService
->Get(NS_OSX_MUSIC_DOCUMENTS_DIR
,
865 getter_AddRefs(sDirs
->music
));
867 // Keep MOZ_WIDGET_ANDROID above XP_UNIX,
868 // because both are defined in Android builds.
869 #elif defined (MOZ_WIDGET_ANDROID)
871 if (NS_SUCCEEDED(mozilla::AndroidBridge::GetExternalPublicDirectory(
872 NS_LITERAL_STRING(DEVICESTORAGE_PICTURES
), path
))) {
873 NS_NewLocalFile(path
, /* aFollowLinks */ true,
874 getter_AddRefs(sDirs
->pictures
));
876 if (NS_SUCCEEDED(mozilla::AndroidBridge::GetExternalPublicDirectory(
877 NS_LITERAL_STRING(DEVICESTORAGE_VIDEOS
), path
))) {
878 NS_NewLocalFile(path
, /* aFollowLinks */ true,
879 getter_AddRefs(sDirs
->videos
));
881 if (NS_SUCCEEDED(mozilla::AndroidBridge::GetExternalPublicDirectory(
882 NS_LITERAL_STRING(DEVICESTORAGE_MUSIC
), path
))) {
883 NS_NewLocalFile(path
, /* aFollowLinks */ true,
884 getter_AddRefs(sDirs
->music
));
886 if (NS_SUCCEEDED(mozilla::AndroidBridge::GetExternalPublicDirectory(
887 NS_LITERAL_STRING(DEVICESTORAGE_SDCARD
), path
))) {
888 NS_NewLocalFile(path
, /* aFollowLinks */ true,
889 getter_AddRefs(sDirs
->sdcard
));
892 #elif defined (XP_UNIX)
893 dirService
->Get(NS_UNIX_XDG_PICTURES_DIR
,
895 getter_AddRefs(sDirs
->pictures
));
896 dirService
->Get(NS_UNIX_XDG_VIDEOS_DIR
,
898 getter_AddRefs(sDirs
->videos
));
899 dirService
->Get(NS_UNIX_XDG_MUSIC_DIR
,
901 getter_AddRefs(sDirs
->music
));
903 #elif defined (XP_WIN)
904 dirService
->Get(NS_WIN_PICTURES_DIR
,
906 getter_AddRefs(sDirs
->pictures
));
907 dirService
->Get(NS_WIN_VIDEOS_DIR
,
909 getter_AddRefs(sDirs
->videos
));
910 dirService
->Get(NS_WIN_MUSIC_DIR
,
912 getter_AddRefs(sDirs
->music
));
915 #ifndef MOZ_WIDGET_ANDROID
916 // Eventually, on desktop, we want to do something smarter -- for example,
917 // detect when an sdcard is inserted, and use that instead of this.
918 dirService
->Get(NS_APP_USER_PROFILE_50_DIR
, NS_GET_IID(nsIFile
),
919 getter_AddRefs(sDirs
->sdcard
));
921 sDirs
->sdcard
->AppendRelativeNativePath(NS_LITERAL_CSTRING("fake-sdcard"));
923 #endif // !MOZ_WIDGET_ANDROID
924 #endif // !MOZ_WIDGET_GONK
926 #ifdef MOZ_WIDGET_GONK
927 NS_NewLocalFile(NS_LITERAL_STRING("/data"),
929 getter_AddRefs(sDirs
->apps
));
931 dirService
->Get(NS_APP_USER_PROFILE_50_DIR
, NS_GET_IID(nsIFile
),
932 getter_AddRefs(sDirs
->apps
));
934 sDirs
->apps
->AppendRelativeNativePath(NS_LITERAL_CSTRING("webapps"));
938 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
939 NS_GetSpecialDirectory("UAppData", getter_AddRefs(sDirs
->crashes
));
940 if (sDirs
->crashes
) {
941 sDirs
->crashes
->Append(NS_LITERAL_STRING("Crash Reports"));
944 // NS_GetSpecialDirectory("UAppData") fails in content processes because
945 // gAppData from toolkit/xre/nsAppRunner.cpp is not initialized.
946 #ifdef MOZ_WIDGET_GONK
947 NS_NewLocalFile(NS_LITERAL_STRING("/data/b2g/mozilla/Crash Reports"),
949 getter_AddRefs(sDirs
->crashes
));
953 OverrideRootDir::GetSingleton()->Init();
957 DeviceStorageFile::GetFullPath(nsAString
&aFullPath
)
959 aFullPath
.Truncate();
960 if (!mStorageName
.EqualsLiteral("")) {
961 aFullPath
.Append('/');
962 aFullPath
.Append(mStorageName
);
963 aFullPath
.Append('/');
965 if (!mRootDir
.EqualsLiteral("")) {
966 aFullPath
.Append(mRootDir
);
967 aFullPath
.Append('/');
969 aFullPath
.Append(mPath
);
973 // Directories which don't depend on a volume should be calculated once
974 // in InitDirs. Directories which depend on the root directory of a volume
975 // should be calculated in this method.
977 DeviceStorageFile::GetRootDirectoryForType(const nsAString
& aStorageType
,
978 const nsAString
& aStorageName
,
983 bool allowOverride
= true;
987 #ifdef MOZ_WIDGET_GONK
988 nsString volMountPoint
;
989 if (DeviceStorageTypeChecker::IsVolumeBased(aStorageType
)) {
990 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
991 NS_ENSURE_TRUE_VOID(vs
);
993 nsCOMPtr
<nsIVolume
> vol
;
994 rv
= vs
->GetVolumeByName(aStorageName
, getter_AddRefs(vol
));
995 NS_ENSURE_SUCCESS_VOID(rv
);
996 vol
->GetMountPoint(volMountPoint
);
1000 // Picture directory
1001 if (aStorageType
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
1002 #ifdef MOZ_WIDGET_GONK
1003 NS_NewLocalFile(volMountPoint
, false, getter_AddRefs(f
));
1005 f
= sDirs
->pictures
;
1010 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
1011 #ifdef MOZ_WIDGET_GONK
1012 NS_NewLocalFile(volMountPoint
, false, getter_AddRefs(f
));
1019 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
1020 #ifdef MOZ_WIDGET_GONK
1021 NS_NewLocalFile(volMountPoint
, false, getter_AddRefs(f
));
1028 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_APPS
)) {
1030 allowOverride
= false;
1034 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_SDCARD
)) {
1035 #ifdef MOZ_WIDGET_GONK
1036 NS_NewLocalFile(volMountPoint
, false, getter_AddRefs(f
));
1042 // crash reports directory.
1043 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_CRASHES
)) {
1045 allowOverride
= false;
1047 // Not a storage type that we recognize. Return null
1051 // In testing, we default all device storage types to a temp directory.
1052 // sDirs->overrideRootDir will only have been initialized (in InitDirs)
1053 // if the preference device.storage.testing was set to true, or if
1054 // device.storage.overrideRootDir is set. We can't test the preferences
1055 // directly here, since we may not be on the main thread.
1056 if (allowOverride
&& sDirs
->overrideRootDir
) {
1057 f
= sDirs
->overrideRootDir
;
1066 already_AddRefed
<DeviceStorageFile
>
1067 DeviceStorageFile::CreateUnique(nsAString
& aFileName
,
1069 uint32_t aFileAttributes
)
1071 DeviceStorageTypeChecker
* typeChecker
1072 = DeviceStorageTypeChecker::CreateOrGet();
1073 MOZ_ASSERT(typeChecker
);
1075 nsString storageType
;
1076 typeChecker
->GetTypeFromFileName(aFileName
, storageType
);
1078 nsString storageName
;
1079 nsString storagePath
;
1080 if (!nsDOMDeviceStorage::ParseFullPath(aFileName
, storageName
, storagePath
)) {
1083 if (storageName
.IsEmpty()) {
1084 nsDOMDeviceStorage::GetDefaultStorageName(storageType
, storageName
);
1086 nsRefPtr
<DeviceStorageFile
> dsf
=
1087 new DeviceStorageFile(storageType
, storageName
, storagePath
);
1092 nsresult rv
= dsf
->mFile
->CreateUnique(aFileType
, aFileAttributes
);
1093 NS_ENSURE_SUCCESS(rv
, nullptr);
1095 // CreateUnique may cause the filename to change. So we need to update mPath
1098 dsf
->mFile
->GetLeafName(leafName
);
1100 int32_t lastSlashIndex
= dsf
->mPath
.RFindChar('/');
1101 if (lastSlashIndex
== kNotFound
) {
1102 dsf
->mPath
.Assign(leafName
);
1104 // Include the last '/'
1105 dsf
->mPath
= Substring(dsf
->mPath
, 0, lastSlashIndex
+ 1);
1106 dsf
->mPath
.Append(leafName
);
1109 return dsf
.forget();
1113 DeviceStorageFile::SetPath(const nsAString
& aPath
) {
1114 mPath
.Assign(aPath
);
1115 NormalizeFilePath();
1119 DeviceStorageFile::SetEditable(bool aEditable
) {
1120 mEditable
= aEditable
;
1123 // we want to make sure that the names of file can't reach
1124 // outside of the type of storage the user asked for.
1126 DeviceStorageFile::IsSafePath()
1128 return IsSafePath(mRootDir
) && IsSafePath(mPath
);
1132 DeviceStorageFile::IsSafePath(const nsAString
& aPath
)
1134 nsAString::const_iterator start
, end
;
1135 aPath
.BeginReading(start
);
1136 aPath
.EndReading(end
);
1138 // if the path is a '~' or starts with '~/', return false.
1139 NS_NAMED_LITERAL_STRING(tilde
, "~");
1140 NS_NAMED_LITERAL_STRING(tildeSlash
, "~/");
1141 if (aPath
.Equals(tilde
) ||
1142 StringBeginsWith(aPath
, tildeSlash
)) {
1143 NS_WARNING("Path name starts with tilde!");
1146 // split on /. if any token is "", ., or .., return false.
1147 NS_ConvertUTF16toUTF8
cname(aPath
);
1148 char* buffer
= cname
.BeginWriting();
1151 while ((token
= nsCRT::strtok(buffer
, "/", &buffer
))) {
1152 if (PL_strcmp(token
, "") == 0 ||
1153 PL_strcmp(token
, ".") == 0 ||
1154 PL_strcmp(token
, "..") == 0 ) {
1162 DeviceStorageFile::NormalizeFilePath() {
1163 FileSystemUtils::LocalPathToNormalizedPath(mPath
, mPath
);
1167 DeviceStorageFile::AppendRelativePath(const nsAString
& aPath
) {
1171 if (!IsSafePath(aPath
)) {
1172 // All of the APIs (in the child) do checks to verify that the path is
1173 // valid and return PERMISSION_DENIED if a non-safe path is entered.
1174 // This check is done in the parent and prevents a compromised
1175 // child from bypassing the check. It shouldn't be possible for this
1176 // code path to be taken with a non-compromised child.
1177 NS_WARNING("Unsafe path detected - ignoring");
1178 NS_WARNING(NS_LossyConvertUTF16toASCII(aPath
).get());
1182 FileSystemUtils::NormalizedPathToLocalPath(aPath
, localPath
);
1183 mFile
->AppendRelativePath(localPath
);
1187 DeviceStorageFile::CreateFileDescriptor(FileDescriptor
& aFileDescriptor
)
1189 ScopedPRFileDesc fd
;
1190 nsresult rv
= mFile
->OpenNSPRFileDesc(PR_RDWR
| PR_CREATE_FILE
,
1192 NS_ENSURE_SUCCESS(rv
, rv
);
1194 // NOTE: The FileDescriptor::PlatformHandleType constructor returns a dup of
1195 // the file descriptor, so we don't need the original fd after this.
1196 // Our scoped file descriptor will automatically close fd.
1197 aFileDescriptor
= FileDescriptor(
1198 FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd
)));
1203 DeviceStorageFile::Write(nsIInputStream
* aInputStream
)
1205 if (!aInputStream
|| !mFile
) {
1206 return NS_ERROR_FAILURE
;
1209 nsresult rv
= mFile
->Create(nsIFile::NORMAL_FILE_TYPE
, 00600);
1210 if (NS_WARN_IF(NS_FAILED(rv
))) {
1214 nsCOMPtr
<nsIRunnable
> iocomplete
= new IOEventComplete(this, "created");
1215 rv
= NS_DispatchToMainThread(iocomplete
);
1216 if (NS_WARN_IF(NS_FAILED(rv
))) {
1220 nsCOMPtr
<nsIOutputStream
> outputStream
;
1221 NS_NewLocalFileOutputStream(getter_AddRefs(outputStream
), mFile
);
1223 if (!outputStream
) {
1224 return NS_ERROR_FAILURE
;
1227 return Append(aInputStream
, outputStream
);
1231 DeviceStorageFile::Write(InfallibleTArray
<uint8_t>& aBits
)
1234 return NS_ERROR_FAILURE
;
1237 nsresult rv
= mFile
->Create(nsIFile::NORMAL_FILE_TYPE
, 00600);
1238 if (NS_WARN_IF(NS_FAILED(rv
))) {
1242 nsCOMPtr
<nsIRunnable
> iocomplete
= new IOEventComplete(this, "created");
1243 rv
= NS_DispatchToMainThread(iocomplete
);
1244 if (NS_WARN_IF(NS_FAILED(rv
))) {
1248 nsCOMPtr
<nsIOutputStream
> outputStream
;
1249 NS_NewLocalFileOutputStream(getter_AddRefs(outputStream
), mFile
);
1251 if (!outputStream
) {
1252 return NS_ERROR_FAILURE
;
1256 outputStream
->Write((char*) aBits
.Elements(), aBits
.Length(), &wrote
);
1257 outputStream
->Close();
1259 iocomplete
= new IOEventComplete(this, "modified");
1260 rv
= NS_DispatchToMainThread(iocomplete
);
1261 if (NS_WARN_IF(NS_FAILED(rv
))) {
1265 if (aBits
.Length() != wrote
) {
1266 return NS_ERROR_FAILURE
;
1272 DeviceStorageFile::Append(nsIInputStream
* aInputStream
)
1274 if (!aInputStream
|| !mFile
) {
1275 return NS_ERROR_FAILURE
;
1278 nsCOMPtr
<nsIOutputStream
> outputStream
;
1279 NS_NewLocalFileOutputStream(getter_AddRefs(outputStream
), mFile
, PR_WRONLY
| PR_CREATE_FILE
| PR_APPEND
, -1, 0);
1281 if (!outputStream
) {
1282 return NS_ERROR_FAILURE
;
1285 return Append(aInputStream
, outputStream
);
1290 DeviceStorageFile::Append(nsIInputStream
* aInputStream
, nsIOutputStream
* aOutputStream
)
1292 uint64_t bufSize
= 0;
1293 aInputStream
->Available(&bufSize
);
1295 nsCOMPtr
<nsIOutputStream
> bufferedOutputStream
;
1296 nsresult rv
= NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream
),
1299 NS_ENSURE_SUCCESS(rv
, rv
);
1303 rv
= bufferedOutputStream
->WriteFrom(
1305 static_cast<uint32_t>(std::min
<uint64_t>(bufSize
, UINT32_MAX
)),
1307 if (NS_FAILED(rv
)) {
1313 nsCOMPtr
<nsIRunnable
> iocomplete
= new IOEventComplete(this, "modified");
1314 rv
= NS_DispatchToMainThread(iocomplete
);
1315 if (NS_WARN_IF(NS_FAILED(rv
))) {
1319 bufferedOutputStream
->Close();
1320 aOutputStream
->Close();
1321 if (NS_WARN_IF(NS_FAILED(rv
))) {
1328 DeviceStorageFile::Remove()
1330 MOZ_ASSERT(!NS_IsMainThread());
1333 return NS_ERROR_FAILURE
;
1337 nsresult rv
= mFile
->Exists(&check
);
1338 if (NS_FAILED(rv
)) {
1346 rv
= mFile
->Remove(true);
1347 if (NS_WARN_IF(NS_FAILED(rv
))) {
1351 nsCOMPtr
<nsIRunnable
> iocomplete
= new IOEventComplete(this, "deleted");
1352 return NS_DispatchToMainThread(iocomplete
);
1356 DeviceStorageFile::CalculateMimeType()
1358 MOZ_ASSERT(NS_IsMainThread());
1360 nsAutoCString mimeType
;
1361 nsCOMPtr
<nsIMIMEService
> mimeService
=
1362 do_GetService(NS_MIMESERVICE_CONTRACTID
);
1364 nsresult rv
= mimeService
->GetTypeFromFile(mFile
, mimeType
);
1365 if (NS_FAILED(rv
)) {
1366 mimeType
.Truncate();
1371 mMimeType
= NS_ConvertUTF8toUTF16(mimeType
);
1376 DeviceStorageFile::CalculateSizeAndModifiedDate()
1378 MOZ_ASSERT(!NS_IsMainThread());
1381 nsresult rv
= mFile
->GetFileSize(&fileSize
);
1382 NS_ENSURE_SUCCESS(rv
, rv
);
1387 rv
= mFile
->GetLastModifiedTime(&modDate
);
1388 NS_ENSURE_SUCCESS(rv
, rv
);
1390 mLastModifiedDate
= modDate
;
1395 DeviceStorageFile::CollectFiles(nsTArray
<nsRefPtr
<DeviceStorageFile
> > &aFiles
,
1398 nsString fullRootPath
;
1399 mFile
->GetPath(fullRootPath
);
1400 collectFilesInternal(aFiles
, aSince
, fullRootPath
);
1404 DeviceStorageFile::collectFilesInternal(
1405 nsTArray
<nsRefPtr
<DeviceStorageFile
> > &aFiles
,
1407 nsAString
& aRootPath
)
1409 if (!mFile
|| !IsAvailable()) {
1413 nsCOMPtr
<nsISimpleEnumerator
> e
;
1414 mFile
->GetDirectoryEntries(getter_AddRefs(e
));
1420 nsCOMPtr
<nsIDirectoryEnumerator
> files
= do_QueryInterface(e
);
1421 nsCOMPtr
<nsIFile
> f
;
1423 while (NS_SUCCEEDED(files
->GetNextFile(getter_AddRefs(f
))) && f
) {
1426 f
->GetLastModifiedTime(&msecs
);
1428 if (msecs
< aSince
) {
1433 f
->IsDirectory(&isDir
);
1439 nsresult rv
= f
->GetPath(fullpath
);
1440 if (NS_FAILED(rv
)) {
1444 if (!StringBeginsWith(fullpath
, aRootPath
)) {
1445 NS_ERROR("collectFiles returned a path that does not belong!");
1449 nsAString::size_type len
= aRootPath
.Length() + 1; // +1 for the trailing /
1450 nsDependentSubstring newPath
= Substring(fullpath
, len
);
1453 DeviceStorageFile
dsf(mStorageType
, mStorageName
, mRootDir
, newPath
);
1454 dsf
.collectFilesInternal(aFiles
, aSince
, aRootPath
);
1455 } else if (isFile
) {
1456 nsRefPtr
<DeviceStorageFile
> dsf
=
1457 new DeviceStorageFile(mStorageType
, mStorageName
, mRootDir
, newPath
);
1458 dsf
->CalculateSizeAndModifiedDate();
1459 aFiles
.AppendElement(dsf
);
1465 DeviceStorageFile::AccumDiskUsage(uint64_t* aPicturesSoFar
,
1466 uint64_t* aVideosSoFar
,
1467 uint64_t* aMusicSoFar
,
1468 uint64_t* aTotalSoFar
)
1470 if (!IsAvailable()) {
1474 uint64_t pictureUsage
= 0, videoUsage
= 0, musicUsage
= 0, totalUsage
= 0;
1476 if (DeviceStorageTypeChecker::IsVolumeBased(mStorageType
)) {
1477 DeviceStorageUsedSpaceCache
* usedSpaceCache
=
1478 DeviceStorageUsedSpaceCache::CreateOrGet();
1479 MOZ_ASSERT(usedSpaceCache
);
1480 nsresult rv
= usedSpaceCache
->AccumUsedSizes(mStorageName
,
1481 aPicturesSoFar
, aVideosSoFar
,
1482 aMusicSoFar
, aTotalSoFar
);
1483 if (NS_SUCCEEDED(rv
)) {
1486 AccumDirectoryUsage(mFile
, &pictureUsage
, &videoUsage
,
1487 &musicUsage
, &totalUsage
);
1488 usedSpaceCache
->SetUsedSizes(mStorageName
, pictureUsage
, videoUsage
,
1489 musicUsage
, totalUsage
);
1491 AccumDirectoryUsage(mFile
, &pictureUsage
, &videoUsage
,
1492 &musicUsage
, &totalUsage
);
1495 *aPicturesSoFar
+= pictureUsage
;
1496 *aVideosSoFar
+= videoUsage
;
1497 *aMusicSoFar
+= musicUsage
;
1498 *aTotalSoFar
+= totalUsage
;
1502 DeviceStorageFile::AccumDirectoryUsage(nsIFile
* aFile
,
1503 uint64_t* aPicturesSoFar
,
1504 uint64_t* aVideosSoFar
,
1505 uint64_t* aMusicSoFar
,
1506 uint64_t* aTotalSoFar
)
1513 nsCOMPtr
<nsISimpleEnumerator
> e
;
1514 rv
= aFile
->GetDirectoryEntries(getter_AddRefs(e
));
1516 if (NS_FAILED(rv
) || !e
) {
1520 nsCOMPtr
<nsIDirectoryEnumerator
> files
= do_QueryInterface(e
);
1523 nsCOMPtr
<nsIFile
> f
;
1524 while (NS_SUCCEEDED(files
->GetNextFile(getter_AddRefs(f
))) && f
) {
1526 rv
= f
->IsDirectory(&isDir
);
1527 if (NS_FAILED(rv
)) {
1532 rv
= f
->IsFile(&isFile
);
1533 if (NS_FAILED(rv
)) {
1538 rv
= f
->IsSymlink(&isLink
);
1539 if (NS_FAILED(rv
)) {
1544 // for now, lets just totally ignore symlinks.
1545 NS_WARNING("DirectoryDiskUsage ignores symlinks");
1547 AccumDirectoryUsage(f
, aPicturesSoFar
, aVideosSoFar
,
1548 aMusicSoFar
, aTotalSoFar
);
1549 } else if (isFile
) {
1552 rv
= f
->GetFileSize(&size
);
1553 if (NS_FAILED(rv
)) {
1556 DeviceStorageTypeChecker
* typeChecker
1557 = DeviceStorageTypeChecker::CreateOrGet();
1558 MOZ_ASSERT(typeChecker
);
1560 typeChecker
->GetTypeFromFile(f
, type
);
1562 if (type
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
1563 *aPicturesSoFar
+= size
;
1565 else if (type
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
1566 *aVideosSoFar
+= size
;
1568 else if (type
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
1569 *aMusicSoFar
+= size
;
1571 *aTotalSoFar
+= size
;
1577 DeviceStorageFile::GetDiskFreeSpace(int64_t* aSoFar
)
1579 DeviceStorageTypeChecker
* typeChecker
1580 = DeviceStorageTypeChecker::CreateOrGet();
1584 if (!mFile
|| !IsAvailable()) {
1588 int64_t storageAvail
= 0;
1589 nsresult rv
= mFile
->GetDiskSpaceAvailable(&storageAvail
);
1590 if (NS_SUCCEEDED(rv
)) {
1591 *aSoFar
+= storageAvail
;
1596 DeviceStorageFile::IsAvailable()
1600 return status
.EqualsLiteral("available");
1604 DeviceStorageFile::DoFormat(nsAString
& aStatus
)
1606 DeviceStorageTypeChecker
* typeChecker
1607 = DeviceStorageTypeChecker::CreateOrGet();
1611 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1612 aStatus
.AssignLiteral("notVolume");
1615 #ifdef MOZ_WIDGET_GONK
1616 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1617 NS_ENSURE_TRUE_VOID(vs
);
1619 nsCOMPtr
<nsIVolume
> vol
;
1620 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1621 NS_ENSURE_SUCCESS_VOID(rv
);
1628 aStatus
.AssignLiteral("formatting");
1634 DeviceStorageFile::DoMount(nsAString
& aStatus
)
1636 DeviceStorageTypeChecker
* typeChecker
1637 = DeviceStorageTypeChecker::CreateOrGet();
1641 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1642 aStatus
.AssignLiteral("notVolume");
1645 #ifdef MOZ_WIDGET_GONK
1646 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1647 NS_ENSURE_TRUE_VOID(vs
);
1649 nsCOMPtr
<nsIVolume
> vol
;
1650 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1651 NS_ENSURE_SUCCESS_VOID(rv
);
1658 aStatus
.AssignLiteral("mounting");
1664 DeviceStorageFile::DoUnmount(nsAString
& aStatus
)
1666 DeviceStorageTypeChecker
* typeChecker
1667 = DeviceStorageTypeChecker::CreateOrGet();
1671 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1672 aStatus
.AssignLiteral("notVolume");
1675 #ifdef MOZ_WIDGET_GONK
1676 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1677 NS_ENSURE_TRUE_VOID(vs
);
1679 nsCOMPtr
<nsIVolume
> vol
;
1680 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1681 NS_ENSURE_SUCCESS_VOID(rv
);
1688 aStatus
.AssignLiteral("unmounting");
1694 DeviceStorageFile::GetStatus(nsAString
& aStatus
)
1696 aStatus
.AssignLiteral("unavailable");
1698 DeviceStorageTypeChecker
* typeChecker
1699 = DeviceStorageTypeChecker::CreateOrGet();
1703 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1704 aStatus
.AssignLiteral("available");
1708 #ifdef MOZ_WIDGET_GONK
1709 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1710 NS_ENSURE_TRUE_VOID(vs
);
1712 nsCOMPtr
<nsIVolume
> vol
;
1713 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1714 NS_ENSURE_SUCCESS_VOID(rv
);
1718 bool isMediaPresent
;
1719 rv
= vol
->GetIsMediaPresent(&isMediaPresent
);
1720 NS_ENSURE_SUCCESS_VOID(rv
);
1721 if (!isMediaPresent
) {
1725 rv
= vol
->GetIsSharing(&isSharing
);
1726 NS_ENSURE_SUCCESS_VOID(rv
);
1728 aStatus
.AssignLiteral("shared");
1732 rv
= vol
->GetIsFormatting(&isFormatting
);
1733 NS_ENSURE_SUCCESS_VOID(rv
);
1735 aStatus
.AssignLiteral("unavailable");
1739 rv
= vol
->GetIsUnmounting(&isUnmounting
);
1740 NS_ENSURE_SUCCESS_VOID(rv
);
1742 aStatus
.AssignLiteral("unavailable");
1746 rv
= vol
->GetState(&volState
);
1747 NS_ENSURE_SUCCESS_VOID(rv
);
1748 if (volState
== nsIVolume::STATE_MOUNTED
) {
1749 aStatus
.AssignLiteral("available");
1755 DeviceStorageFile::GetStorageStatus(nsAString
& aStatus
)
1757 aStatus
.AssignLiteral("undefined");
1759 DeviceStorageTypeChecker
* typeChecker
1760 = DeviceStorageTypeChecker::CreateOrGet();
1764 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1765 aStatus
.AssignLiteral("available");
1769 #ifdef MOZ_WIDGET_GONK
1770 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1771 NS_ENSURE_TRUE_VOID(vs
);
1773 nsCOMPtr
<nsIVolume
> vol
;
1774 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1775 NS_ENSURE_SUCCESS_VOID(rv
);
1781 rv
= vol
->GetState(&volState
);
1782 NS_ENSURE_SUCCESS_VOID(rv
);
1783 aStatus
.AssignASCII(mozilla::system::NS_VolumeStateStr(volState
));
1787 NS_IMPL_ISUPPORTS0(DeviceStorageFile
)
1790 RegisterForSDCardChanges(nsIObserver
* aObserver
)
1792 #ifdef MOZ_WIDGET_GONK
1793 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
1794 obs
->AddObserver(aObserver
, NS_VOLUME_STATE_CHANGED
, false);
1799 UnregisterForSDCardChanges(nsIObserver
* aObserver
)
1801 #ifdef MOZ_WIDGET_GONK
1802 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
1803 obs
->RemoveObserver(aObserver
, NS_VOLUME_STATE_CHANGED
);
1808 nsDOMDeviceStorage::SetRootDirectoryForType(const nsAString
& aStorageType
,
1809 const nsAString
& aStorageName
)
1811 MOZ_ASSERT(NS_IsMainThread());
1813 nsCOMPtr
<nsIFile
> f
;
1814 DeviceStorageFile::GetRootDirectoryForType(aStorageType
,
1817 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
1818 obs
->AddObserver(this, kFileWatcherUpdate
, false);
1819 obs
->AddObserver(this, "disk-space-watcher", false);
1821 mStorageType
= aStorageType
;
1822 mStorageName
= aStorageName
;
1826 InterfaceToJsval(nsPIDOMWindow
* aWindow
,
1827 nsISupports
* aObject
,
1830 nsCOMPtr
<nsIScriptGlobalObject
> sgo
= do_QueryInterface(aWindow
);
1832 return JS::NullValue();
1835 JSObject
*unrootedScopeObj
= sgo
->GetGlobalJSObject();
1836 NS_ENSURE_TRUE(unrootedScopeObj
, JS::NullValue());
1837 JSRuntime
*runtime
= JS_GetObjectRuntime(unrootedScopeObj
);
1838 JS::Rooted
<JS::Value
> someJsVal(runtime
);
1839 JS::Rooted
<JSObject
*> scopeObj(runtime
, unrootedScopeObj
);
1842 { // Protect someJsVal from moving GC in ~JSAutoCompartment
1844 JSAutoCompartment
ac(cx
, scopeObj
);
1846 rv
= nsContentUtils::WrapNative(cx
, aObject
, aIID
, &someJsVal
);
1848 if (NS_FAILED(rv
)) {
1849 return JS::NullValue();
1856 nsIFileToJsval(nsPIDOMWindow
* aWindow
, DeviceStorageFile
* aFile
)
1858 MOZ_ASSERT(NS_IsMainThread());
1859 MOZ_ASSERT(aWindow
);
1865 if (aFile
->mEditable
) {
1866 // TODO - needs janv's file handle support.
1871 aFile
->GetFullPath(fullPath
);
1873 // This check is useful to know if somewhere the DeviceStorageFile
1874 // has not been properly set. Mimetype is not checked because it can be
1876 MOZ_ASSERT(aFile
->mLength
!= UINT64_MAX
);
1877 MOZ_ASSERT(aFile
->mLastModifiedDate
!= UINT64_MAX
);
1879 nsCOMPtr
<nsIDOMBlob
> blob
= new DOMFile(
1880 new DOMFileImplFile(fullPath
, aFile
->mMimeType
,
1881 aFile
->mLength
, aFile
->mFile
,
1882 aFile
->mLastModifiedDate
));
1883 return InterfaceToJsval(aWindow
, blob
, &NS_GET_IID(nsIDOMBlob
));
1887 StringToJsval(nsPIDOMWindow
* aWindow
, nsAString
& aString
,
1888 JS::MutableHandle
<JS::Value
> result
)
1890 MOZ_ASSERT(NS_IsMainThread());
1891 MOZ_ASSERT(aWindow
);
1894 if (NS_WARN_IF(!jsapi
.Init(aWindow
))) {
1897 JSContext
* cx
= jsapi
.cx();
1899 if (!xpc::StringToJsval(cx
, aString
, result
)) {
1906 class DeviceStorageCursorRequest MOZ_FINAL
1907 : public nsIContentPermissionRequest
1910 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
1911 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageCursorRequest
,
1912 nsIContentPermissionRequest
)
1914 NS_FORWARD_NSICONTENTPERMISSIONREQUEST(mCursor
->);
1916 DeviceStorageCursorRequest(nsDOMDeviceStorageCursor
* aCursor
)
1917 : mCursor(aCursor
) { }
1920 ~DeviceStorageCursorRequest() {}
1922 nsRefPtr
<nsDOMDeviceStorageCursor
> mCursor
;
1925 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageCursorRequest
)
1926 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIContentPermissionRequest
)
1927 NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest
)
1928 NS_INTERFACE_MAP_END
1930 NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageCursorRequest
)
1931 NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageCursorRequest
)
1933 NS_IMPL_CYCLE_COLLECTION(DeviceStorageCursorRequest
,
1937 class PostErrorEvent
: public nsRunnable
1940 PostErrorEvent(already_AddRefed
<DOMRequest
> aRequest
, const char* aMessage
)
1941 : mRequest(aRequest
)
1943 CopyASCIItoUTF16(aMessage
, mError
);
1946 PostErrorEvent(DOMRequest
* aRequest
, const char* aMessage
)
1947 : mRequest(aRequest
)
1949 CopyASCIItoUTF16(aMessage
, mError
);
1952 ~PostErrorEvent() {}
1956 MOZ_ASSERT(NS_IsMainThread());
1957 if (!mRequest
->GetOwner()) {
1960 mRequest
->FireError(mError
);
1966 nsRefPtr
<DOMRequest
> mRequest
;
1970 ContinueCursorEvent::ContinueCursorEvent(already_AddRefed
<DOMRequest
> aRequest
)
1971 : mRequest(aRequest
)
1975 ContinueCursorEvent::ContinueCursorEvent(DOMRequest
* aRequest
)
1976 : mRequest(aRequest
)
1980 already_AddRefed
<DeviceStorageFile
>
1981 ContinueCursorEvent::GetNextFile()
1983 MOZ_ASSERT(NS_IsMainThread());
1985 nsDOMDeviceStorageCursor
* cursor
1986 = static_cast<nsDOMDeviceStorageCursor
*>(mRequest
.get());
1987 nsString cursorStorageType
;
1988 cursor
->GetStorageType(cursorStorageType
);
1990 DeviceStorageTypeChecker
* typeChecker
1991 = DeviceStorageTypeChecker::CreateOrGet();
1996 while (cursor
->mFiles
.Length() > 0) {
1997 nsRefPtr
<DeviceStorageFile
> file
= cursor
->mFiles
[0];
1998 cursor
->mFiles
.RemoveElementAt(0);
1999 if (!typeChecker
->Check(cursorStorageType
, file
->mFile
)) {
2003 file
->CalculateMimeType();
2004 return file
.forget();
2010 ContinueCursorEvent::~ContinueCursorEvent() {}
2013 ContinueCursorEvent::Continue()
2015 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
2016 DebugOnly
<nsresult
> rv
= NS_DispatchToMainThread(this);
2017 MOZ_ASSERT(NS_SUCCEEDED(rv
));
2021 nsRefPtr
<DeviceStorageFile
> file
= GetNextFile();
2024 // done with enumeration.
2025 DebugOnly
<nsresult
> rv
= NS_DispatchToMainThread(this);
2026 MOZ_ASSERT(NS_SUCCEEDED(rv
));
2030 nsDOMDeviceStorageCursor
* cursor
2031 = static_cast<nsDOMDeviceStorageCursor
*>(mRequest
.get());
2032 nsString cursorStorageType
;
2033 cursor
->GetStorageType(cursorStorageType
);
2035 DeviceStorageRequestChild
* child
2036 = new DeviceStorageRequestChild(mRequest
, file
);
2037 child
->SetCallback(cursor
);
2038 DeviceStorageGetParams
params(cursorStorageType
,
2042 ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child
,
2048 ContinueCursorEvent::Run()
2050 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2055 nsRefPtr
<DeviceStorageFile
> file
= GetNextFile();
2057 nsDOMDeviceStorageCursor
* cursor
2058 = static_cast<nsDOMDeviceStorageCursor
*>(mRequest
.get());
2061 JS::Rooted
<JS::Value
> val(cx
, nsIFileToJsval(window
, file
));
2064 cursor
->mOkToCallContinue
= true;
2065 cursor
->FireSuccess(val
);
2073 class InitCursorEvent
: public nsRunnable
2076 InitCursorEvent(DOMRequest
* aRequest
, DeviceStorageFile
* aFile
)
2078 , mRequest(aRequest
)
2082 ~InitCursorEvent() {}
2085 MOZ_ASSERT(!NS_IsMainThread());
2089 mFile
->mFile
->IsDirectory(&check
);
2091 nsCOMPtr
<nsIRunnable
> event
=
2092 new PostErrorEvent(mRequest
.forget(),
2093 POST_ERROR_EVENT_FILE_NOT_ENUMERABLE
);
2094 return NS_DispatchToMainThread(event
);
2098 nsDOMDeviceStorageCursor
* cursor
2099 = static_cast<nsDOMDeviceStorageCursor
*>(mRequest
.get());
2100 mFile
->CollectFiles(cursor
->mFiles
, cursor
->mSince
);
2102 nsRefPtr
<ContinueCursorEvent
> event
2103 = new ContinueCursorEvent(mRequest
.forget());
2111 nsRefPtr
<DeviceStorageFile
> mFile
;
2112 nsRefPtr
<DOMRequest
> mRequest
;
2115 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDeviceStorageCursor
)
2116 NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest
)
2117 NS_INTERFACE_MAP_END_INHERITING(DOMCursor
)
2119 NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageCursor
, DOMCursor
)
2120 NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageCursor
, DOMCursor
)
2122 nsDOMDeviceStorageCursor::nsDOMDeviceStorageCursor(nsPIDOMWindow
* aWindow
,
2123 nsIPrincipal
* aPrincipal
,
2124 DeviceStorageFile
* aFile
,
2126 : DOMCursor(aWindow
, nullptr)
2127 , mOkToCallContinue(false)
2130 , mPrincipal(aPrincipal
)
2134 nsDOMDeviceStorageCursor::~nsDOMDeviceStorageCursor()
2139 nsDOMDeviceStorageCursor::GetStorageType(nsAString
& aType
)
2141 aType
= mFile
->mStorageType
;
2145 nsDOMDeviceStorageCursor::GetTypes(nsIArray
** aTypes
)
2149 DeviceStorageTypeChecker::GetPermissionForType(mFile
->mStorageType
, type
);
2150 NS_ENSURE_SUCCESS(rv
, rv
);
2152 nsTArray
<nsString
> emptyOptions
;
2153 return nsContentPermissionUtils::CreatePermissionArray(type
,
2154 NS_LITERAL_CSTRING("read"),
2160 nsDOMDeviceStorageCursor::GetPrincipal(nsIPrincipal
* *aRequestingPrincipal
)
2162 NS_IF_ADDREF(*aRequestingPrincipal
= mPrincipal
);
2167 nsDOMDeviceStorageCursor::GetWindow(nsIDOMWindow
* *aRequestingWindow
)
2169 NS_IF_ADDREF(*aRequestingWindow
= GetOwner());
2174 nsDOMDeviceStorageCursor::GetElement(nsIDOMElement
* *aRequestingElement
)
2176 *aRequestingElement
= nullptr;
2181 nsDOMDeviceStorageCursor::Cancel()
2183 nsCOMPtr
<nsIRunnable
> event
2184 = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED
);
2185 return NS_DispatchToMainThread(event
);
2189 nsDOMDeviceStorageCursor::Allow(JS::HandleValue aChoices
)
2191 MOZ_ASSERT(aChoices
.isUndefined());
2193 if (!mFile
->IsSafePath()) {
2194 nsCOMPtr
<nsIRunnable
> r
2195 = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED
);
2196 return NS_DispatchToMainThread(r
);
2199 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
2200 PDeviceStorageRequestChild
* child
2201 = new DeviceStorageRequestChild(this, mFile
);
2202 DeviceStorageEnumerationParams
params(mFile
->mStorageType
,
2203 mFile
->mStorageName
,
2206 ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child
,
2211 nsCOMPtr
<nsIEventTarget
> target
2212 = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
2215 nsCOMPtr
<nsIRunnable
> event
= new InitCursorEvent(this, mFile
);
2216 target
->Dispatch(event
, NS_DISPATCH_NORMAL
);
2221 nsDOMDeviceStorageCursor::Continue(ErrorResult
& aRv
)
2223 if (!mOkToCallContinue
) {
2224 aRv
.Throw(NS_ERROR_UNEXPECTED
);
2228 if (mResult
!= JSVAL_VOID
) {
2229 // We call onsuccess multiple times. Clear the last
2231 mResult
= JSVAL_VOID
;
2235 nsRefPtr
<ContinueCursorEvent
> event
= new ContinueCursorEvent(this);
2238 mOkToCallContinue
= false;
2242 nsDOMDeviceStorageCursor::RequestComplete()
2244 MOZ_ASSERT(!mOkToCallContinue
);
2245 mOkToCallContinue
= true;
2248 class PostAvailableResultEvent
: public nsRunnable
2251 PostAvailableResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2253 , mRequest(aRequest
)
2255 MOZ_ASSERT(mRequest
);
2258 ~PostAvailableResultEvent() {}
2262 MOZ_ASSERT(NS_IsMainThread());
2263 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2268 nsString state
= NS_LITERAL_STRING("unavailable");
2270 mFile
->GetStatus(state
);
2274 JS::Rooted
<JS::Value
> result(cx
);
2275 StringToJsval(window
, state
, &result
);
2276 mRequest
->FireSuccess(result
);
2282 nsRefPtr
<DeviceStorageFile
> mFile
;
2283 nsRefPtr
<DOMRequest
> mRequest
;
2286 class PostStatusResultEvent
: public nsRunnable
2289 PostStatusResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2291 , mRequest(aRequest
)
2293 MOZ_ASSERT(mRequest
);
2296 ~PostStatusResultEvent() {}
2300 MOZ_ASSERT(NS_IsMainThread());
2301 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2306 nsString state
= NS_LITERAL_STRING("undefined");
2308 mFile
->GetStorageStatus(state
);
2312 JS::Rooted
<JS::Value
> result(cx
);
2313 StringToJsval(window
, state
, &result
);
2314 mRequest
->FireSuccess(result
);
2320 nsRefPtr
<DeviceStorageFile
> mFile
;
2321 nsRefPtr
<DOMRequest
> mRequest
;
2324 class PostFormatResultEvent
: public nsRunnable
2327 PostFormatResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2329 , mRequest(aRequest
)
2331 MOZ_ASSERT(mRequest
);
2334 ~PostFormatResultEvent() {}
2338 MOZ_ASSERT(NS_IsMainThread());
2339 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2344 nsString state
= NS_LITERAL_STRING("unavailable");
2346 mFile
->DoFormat(state
);
2350 JS::Rooted
<JS::Value
> result(cx
);
2351 StringToJsval(window
, state
, &result
);
2352 mRequest
->FireSuccess(result
);
2358 nsRefPtr
<DeviceStorageFile
> mFile
;
2359 nsRefPtr
<DOMRequest
> mRequest
;
2362 class PostMountResultEvent
: public nsRunnable
2365 PostMountResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2367 , mRequest(aRequest
)
2369 MOZ_ASSERT(mRequest
);
2372 ~PostMountResultEvent() {}
2376 MOZ_ASSERT(NS_IsMainThread());
2377 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2382 nsString state
= NS_LITERAL_STRING("unavailable");
2384 mFile
->DoMount(state
);
2388 JS::Rooted
<JS::Value
> result(cx
);
2389 StringToJsval(window
, state
, &result
);
2390 mRequest
->FireSuccess(result
);
2396 nsRefPtr
<DeviceStorageFile
> mFile
;
2397 nsRefPtr
<DOMRequest
> mRequest
;
2400 class PostUnmountResultEvent
: public nsRunnable
2403 PostUnmountResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2405 , mRequest(aRequest
)
2407 MOZ_ASSERT(mRequest
);
2410 ~PostUnmountResultEvent() {}
2414 MOZ_ASSERT(NS_IsMainThread());
2415 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2420 nsString state
= NS_LITERAL_STRING("unavailable");
2422 mFile
->DoUnmount(state
);
2426 JS::Rooted
<JS::Value
> result(cx
);
2427 StringToJsval(window
, state
, &result
);
2428 mRequest
->FireSuccess(result
);
2434 nsRefPtr
<DeviceStorageFile
> mFile
;
2435 nsRefPtr
<DOMRequest
> mRequest
;
2438 class PostResultEvent
: public nsRunnable
2441 PostResultEvent(already_AddRefed
<DOMRequest
> aRequest
,
2442 DeviceStorageFile
* aFile
)
2444 , mRequest(aRequest
)
2446 MOZ_ASSERT(mRequest
);
2449 PostResultEvent(already_AddRefed
<DOMRequest
> aRequest
,
2450 const nsAString
& aPath
)
2452 , mRequest(aRequest
)
2454 MOZ_ASSERT(mRequest
);
2457 PostResultEvent(already_AddRefed
<DOMRequest
> aRequest
,
2458 const uint64_t aValue
)
2460 , mRequest(aRequest
)
2462 MOZ_ASSERT(mRequest
);
2465 ~PostResultEvent() {}
2469 MOZ_ASSERT(NS_IsMainThread());
2470 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2476 JS::Rooted
<JS::Value
> result(cx
, JSVAL_NULL
);
2479 result
= nsIFileToJsval(window
, mFile
);
2480 } else if (mPath
.Length()) {
2481 StringToJsval(window
, mPath
, &result
);
2484 result
= JS_NumberValue(double(mValue
));
2487 mRequest
->FireSuccess(result
);
2493 nsRefPtr
<DeviceStorageFile
> mFile
;
2496 nsRefPtr
<DOMRequest
> mRequest
;
2499 class CreateFdEvent
: public nsRunnable
2502 CreateFdEvent(DeviceStorageFileDescriptor
* aDSFileDescriptor
,
2503 already_AddRefed
<DOMRequest
> aRequest
)
2504 : mDSFileDescriptor(aDSFileDescriptor
)
2505 , mRequest(aRequest
)
2507 MOZ_ASSERT(mDSFileDescriptor
);
2508 MOZ_ASSERT(mRequest
);
2513 MOZ_ASSERT(!NS_IsMainThread());
2515 DeviceStorageFile
* dsFile
= mDSFileDescriptor
->mDSFile
;
2519 dsFile
->GetFullPath(fullPath
);
2520 MOZ_ASSERT(!fullPath
.IsEmpty());
2523 dsFile
->mFile
->Exists(&check
);
2525 nsCOMPtr
<nsIRunnable
> event
=
2526 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_FILE_EXISTS
);
2527 return NS_DispatchToMainThread(event
);
2530 nsresult rv
= dsFile
->CreateFileDescriptor(mDSFileDescriptor
->mFileDescriptor
);
2532 if (NS_FAILED(rv
)) {
2533 dsFile
->mFile
->Remove(false);
2535 nsCOMPtr
<nsIRunnable
> event
=
2536 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_UNKNOWN
);
2537 return NS_DispatchToMainThread(event
);
2540 nsCOMPtr
<nsIRunnable
> event
=
2541 new PostResultEvent(mRequest
.forget(), fullPath
);
2542 return NS_DispatchToMainThread(event
);
2546 nsRefPtr
<DeviceStorageFileDescriptor
> mDSFileDescriptor
;
2547 nsRefPtr
<DOMRequest
> mRequest
;
2550 class WriteFileEvent
: public nsRunnable
2553 WriteFileEvent(DOMFileImpl
* aBlobImpl
,
2554 DeviceStorageFile
*aFile
,
2555 already_AddRefed
<DOMRequest
> aRequest
,
2556 int32_t aRequestType
)
2557 : mBlobImpl(aBlobImpl
)
2559 , mRequest(aRequest
)
2560 , mRequestType(aRequestType
)
2563 MOZ_ASSERT(mRequest
);
2564 MOZ_ASSERT(mRequestType
);
2567 ~WriteFileEvent() {}
2571 MOZ_ASSERT(!NS_IsMainThread());
2573 nsCOMPtr
<nsIInputStream
> stream
;
2574 mBlobImpl
->GetInternalStream(getter_AddRefs(stream
));
2577 mFile
->mFile
->Exists(&check
);
2580 if (mRequestType
== DEVICE_STORAGE_REQUEST_APPEND
) {
2582 nsCOMPtr
<nsIRunnable
> event
=
2583 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_FILE_DOES_NOT_EXIST
);
2584 return NS_DispatchToMainThread(event
);
2586 rv
= mFile
->Append(stream
);
2588 else if (mRequestType
== DEVICE_STORAGE_REQUEST_CREATE
) {
2590 nsCOMPtr
<nsIRunnable
> event
=
2591 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_FILE_EXISTS
);
2592 return NS_DispatchToMainThread(event
);
2594 rv
= mFile
->Write(stream
);
2595 if (NS_FAILED(rv
)) {
2596 mFile
->mFile
->Remove(false);
2599 nsCOMPtr
<nsIRunnable
> event
=
2600 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_UNKNOWN
);
2601 return NS_DispatchToMainThread(event
);
2604 if (NS_FAILED(rv
)) {
2605 nsCOMPtr
<nsIRunnable
> event
=
2606 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_UNKNOWN
);
2607 return NS_DispatchToMainThread(event
);
2611 mFile
->GetFullPath(fullPath
);
2612 nsCOMPtr
<nsIRunnable
> event
=
2613 new PostResultEvent(mRequest
.forget(), fullPath
);
2614 return NS_DispatchToMainThread(event
);
2618 nsRefPtr
<DOMFileImpl
> mBlobImpl
;
2619 nsRefPtr
<DeviceStorageFile
> mFile
;
2620 nsRefPtr
<DOMRequest
> mRequest
;
2621 int32_t mRequestType
;
2625 class ReadFileEvent
: public nsRunnable
2628 ReadFileEvent(DeviceStorageFile
* aFile
,
2629 already_AddRefed
<DOMRequest
> aRequest
)
2631 , mRequest(aRequest
)
2634 MOZ_ASSERT(mRequest
);
2635 mFile
->CalculateMimeType();
2642 MOZ_ASSERT(!NS_IsMainThread());
2644 nsCOMPtr
<nsIRunnable
> r
;
2645 if (!mFile
->mEditable
) {
2647 mFile
->mFile
->Exists(&check
);
2649 r
= new PostErrorEvent(mRequest
.forget(),
2650 POST_ERROR_EVENT_FILE_DOES_NOT_EXIST
);
2655 nsresult rv
= mFile
->CalculateSizeAndModifiedDate();
2656 if (NS_FAILED(rv
)) {
2657 r
= new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_UNKNOWN
);
2662 r
= new PostResultEvent(mRequest
.forget(), mFile
);
2664 return NS_DispatchToMainThread(r
);
2668 nsRefPtr
<DeviceStorageFile
> mFile
;
2669 nsRefPtr
<DOMRequest
> mRequest
;
2672 class DeleteFileEvent
: public nsRunnable
2675 DeleteFileEvent(DeviceStorageFile
* aFile
,
2676 already_AddRefed
<DOMRequest
> aRequest
)
2678 , mRequest(aRequest
)
2681 MOZ_ASSERT(mRequest
);
2684 ~DeleteFileEvent() {}
2688 MOZ_ASSERT(!NS_IsMainThread());
2691 nsCOMPtr
<nsIRunnable
> r
;
2693 mFile
->mFile
->Exists(&check
);
2695 r
= new PostErrorEvent(mRequest
.forget(),
2696 POST_ERROR_EVENT_FILE_DOES_NOT_EXIST
);
2700 mFile
->GetFullPath(fullPath
);
2701 r
= new PostResultEvent(mRequest
.forget(), fullPath
);
2703 return NS_DispatchToMainThread(r
);
2707 nsRefPtr
<DeviceStorageFile
> mFile
;
2708 nsRefPtr
<DOMRequest
> mRequest
;
2711 class UsedSpaceFileEvent
: public nsRunnable
2714 UsedSpaceFileEvent(DeviceStorageFile
* aFile
,
2715 already_AddRefed
<DOMRequest
> aRequest
)
2717 , mRequest(aRequest
)
2720 MOZ_ASSERT(mRequest
);
2723 ~UsedSpaceFileEvent() {}
2727 MOZ_ASSERT(!NS_IsMainThread());
2729 uint64_t picturesUsage
= 0, videosUsage
= 0, musicUsage
= 0, totalUsage
= 0;
2730 mFile
->AccumDiskUsage(&picturesUsage
, &videosUsage
,
2731 &musicUsage
, &totalUsage
);
2732 nsCOMPtr
<nsIRunnable
> r
;
2733 if (mFile
->mStorageType
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
2734 r
= new PostResultEvent(mRequest
.forget(), picturesUsage
);
2736 else if (mFile
->mStorageType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
2737 r
= new PostResultEvent(mRequest
.forget(), videosUsage
);
2739 else if (mFile
->mStorageType
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
2740 r
= new PostResultEvent(mRequest
.forget(), musicUsage
);
2742 r
= new PostResultEvent(mRequest
.forget(), totalUsage
);
2744 return NS_DispatchToMainThread(r
);
2748 nsRefPtr
<DeviceStorageFile
> mFile
;
2749 nsRefPtr
<DOMRequest
> mRequest
;
2752 class FreeSpaceFileEvent
: public nsRunnable
2755 FreeSpaceFileEvent(DeviceStorageFile
* aFile
,
2756 already_AddRefed
<DOMRequest
> aRequest
)
2758 , mRequest(aRequest
)
2761 MOZ_ASSERT(mRequest
);
2764 ~FreeSpaceFileEvent() {}
2768 MOZ_ASSERT(!NS_IsMainThread());
2770 int64_t freeSpace
= 0;
2772 mFile
->GetDiskFreeSpace(&freeSpace
);
2775 nsCOMPtr
<nsIRunnable
> r
;
2776 r
= new PostResultEvent(mRequest
.forget(),
2777 static_cast<uint64_t>(freeSpace
));
2778 return NS_DispatchToMainThread(r
);
2782 nsRefPtr
<DeviceStorageFile
> mFile
;
2783 nsRefPtr
<DOMRequest
> mRequest
;
2786 class DeviceStorageRequest MOZ_FINAL
2787 : public nsIContentPermissionRequest
2788 , public nsIRunnable
2792 DeviceStorageRequest(const DeviceStorageRequestType aRequestType
,
2793 nsPIDOMWindow
* aWindow
,
2794 nsIPrincipal
* aPrincipal
,
2795 DeviceStorageFile
* aFile
,
2796 DOMRequest
* aRequest
,
2797 nsDOMDeviceStorage
* aDeviceStorage
)
2798 : mRequestType(aRequestType
)
2800 , mPrincipal(aPrincipal
)
2802 , mRequest(aRequest
)
2803 , mDeviceStorage(aDeviceStorage
)
2805 MOZ_ASSERT(mWindow
);
2806 MOZ_ASSERT(mPrincipal
);
2808 MOZ_ASSERT(mRequest
);
2809 MOZ_ASSERT(mDeviceStorage
);
2812 DeviceStorageRequest(const DeviceStorageRequestType aRequestType
,
2813 nsPIDOMWindow
* aWindow
,
2814 nsIPrincipal
* aPrincipal
,
2815 DeviceStorageFile
* aFile
,
2816 DOMRequest
* aRequest
,
2817 nsIDOMBlob
* aBlob
= nullptr)
2818 : mRequestType(aRequestType
)
2820 , mPrincipal(aPrincipal
)
2822 , mRequest(aRequest
)
2825 MOZ_ASSERT(mWindow
);
2826 MOZ_ASSERT(mPrincipal
);
2828 MOZ_ASSERT(mRequest
);
2831 DeviceStorageRequest(const DeviceStorageRequestType aRequestType
,
2832 nsPIDOMWindow
* aWindow
,
2833 nsIPrincipal
* aPrincipal
,
2834 DeviceStorageFile
* aFile
,
2835 DOMRequest
* aRequest
,
2836 DeviceStorageFileDescriptor
* aDSFileDescriptor
)
2837 : mRequestType(aRequestType
)
2839 , mPrincipal(aPrincipal
)
2841 , mRequest(aRequest
)
2842 , mDSFileDescriptor(aDSFileDescriptor
)
2844 MOZ_ASSERT(mRequestType
== DEVICE_STORAGE_REQUEST_CREATEFD
);
2845 MOZ_ASSERT(mWindow
);
2846 MOZ_ASSERT(mPrincipal
);
2848 MOZ_ASSERT(mRequest
);
2849 MOZ_ASSERT(mDSFileDescriptor
);
2852 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
2853 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageRequest
,
2854 nsIContentPermissionRequest
)
2858 MOZ_ASSERT(NS_IsMainThread());
2860 if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
2861 Allow(JS::UndefinedHandleValue
);
2865 return nsContentPermissionUtils::AskPermission(this, mWindow
);
2868 NS_IMETHODIMP
GetTypes(nsIArray
** aTypes
)
2872 DeviceStorageTypeChecker::GetPermissionForType(mFile
->mStorageType
, type
);
2873 if (NS_FAILED(rv
)) {
2878 rv
= DeviceStorageTypeChecker::GetAccessForRequest(
2879 DeviceStorageRequestType(mRequestType
), access
);
2880 if (NS_FAILED(rv
)) {
2884 nsTArray
<nsString
> emptyOptions
;
2885 return nsContentPermissionUtils::CreatePermissionArray(type
, access
, emptyOptions
, aTypes
);
2888 NS_IMETHOD
GetPrincipal(nsIPrincipal
* *aRequestingPrincipal
)
2890 NS_IF_ADDREF(*aRequestingPrincipal
= mPrincipal
);
2894 NS_IMETHOD
GetWindow(nsIDOMWindow
* *aRequestingWindow
)
2896 NS_IF_ADDREF(*aRequestingWindow
= mWindow
);
2900 NS_IMETHOD
GetElement(nsIDOMElement
* *aRequestingElement
)
2902 *aRequestingElement
= nullptr;
2908 nsCOMPtr
<nsIRunnable
> event
2909 = new PostErrorEvent(mRequest
.forget(),
2910 POST_ERROR_EVENT_PERMISSION_DENIED
);
2911 return NS_DispatchToMainThread(event
);
2914 NS_IMETHOD
Allow(JS::HandleValue aChoices
)
2916 MOZ_ASSERT(NS_IsMainThread());
2917 MOZ_ASSERT(aChoices
.isUndefined());
2920 return NS_ERROR_FAILURE
;
2923 nsCOMPtr
<nsIRunnable
> r
;
2925 switch(mRequestType
) {
2926 case DEVICE_STORAGE_REQUEST_CREATEFD
:
2928 if (!mFile
->mFile
) {
2929 return NS_ERROR_FAILURE
;
2932 DeviceStorageTypeChecker
* typeChecker
2933 = DeviceStorageTypeChecker::CreateOrGet();
2938 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
)) {
2939 r
= new PostErrorEvent(mRequest
.forget(),
2940 POST_ERROR_EVENT_ILLEGAL_TYPE
);
2941 return NS_DispatchToCurrentThread(r
);
2944 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
2946 DeviceStorageCreateFdParams params
;
2947 params
.type() = mFile
->mStorageType
;
2948 params
.storageName() = mFile
->mStorageName
;
2949 params
.relpath() = mFile
->mPath
;
2951 mFile
->Dump("DeviceStorageCreateFdParams");
2953 PDeviceStorageRequestChild
* child
2954 = new DeviceStorageRequestChild(mRequest
, mFile
,
2955 mDSFileDescriptor
.get());
2956 ContentChild::GetSingleton()
2957 ->SendPDeviceStorageRequestConstructor(child
, params
);
2960 mDSFileDescriptor
->mDSFile
= mFile
;
2961 r
= new CreateFdEvent(mDSFileDescriptor
.get(), mRequest
.forget());
2965 case DEVICE_STORAGE_REQUEST_CREATE
:
2967 if (!mBlob
|| !mFile
->mFile
) {
2968 return NS_ERROR_FAILURE
;
2971 DeviceStorageTypeChecker
* typeChecker
2972 = DeviceStorageTypeChecker::CreateOrGet();
2977 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
) ||
2978 !typeChecker
->Check(mFile
->mStorageType
, mBlob
)) {
2979 r
= new PostErrorEvent(mRequest
.forget(),
2980 POST_ERROR_EVENT_ILLEGAL_TYPE
);
2981 return NS_DispatchToCurrentThread(r
);
2984 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
2986 = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob
);
2988 return NS_ERROR_FAILURE
;
2991 DeviceStorageAddParams params
;
2992 params
.blobChild() = actor
;
2993 params
.type() = mFile
->mStorageType
;
2994 params
.storageName() = mFile
->mStorageName
;
2995 params
.relpath() = mFile
->mPath
;
2997 PDeviceStorageRequestChild
* child
2998 = new DeviceStorageRequestChild(mRequest
, mFile
);
2999 ContentChild::GetSingleton()
3000 ->SendPDeviceStorageRequestConstructor(child
, params
);
3004 DOMFile
* blob
= static_cast<DOMFile
*>(mBlob
.get());
3005 r
= new WriteFileEvent(blob
->Impl(), mFile
, mRequest
.forget(),
3010 case DEVICE_STORAGE_REQUEST_APPEND
:
3012 if (!mBlob
|| !mFile
->mFile
) {
3013 return NS_ERROR_FAILURE
;
3016 DeviceStorageTypeChecker
* typeChecker
3017 = DeviceStorageTypeChecker::CreateOrGet();
3022 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
) ||
3023 !typeChecker
->Check(mFile
->mStorageType
, mBlob
)) {
3024 r
= new PostErrorEvent(mRequest
.forget(),
3025 POST_ERROR_EVENT_ILLEGAL_TYPE
);
3026 return NS_DispatchToCurrentThread(r
);
3029 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3031 = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob
);
3033 return NS_ERROR_FAILURE
;
3036 DeviceStorageAppendParams params
;
3037 params
.blobChild() = actor
;
3038 params
.type() = mFile
->mStorageType
;
3039 params
.storageName() = mFile
->mStorageName
;
3040 params
.relpath() = mFile
->mPath
;
3042 PDeviceStorageRequestChild
* child
3043 = new DeviceStorageRequestChild(mRequest
, mFile
);
3044 ContentChild::GetSingleton()
3045 ->SendPDeviceStorageRequestConstructor(child
, params
);
3049 DOMFile
* blob
= static_cast<DOMFile
*>(mBlob
.get());
3050 r
= new WriteFileEvent(blob
->Impl(), mFile
, mRequest
.forget(),
3055 case DEVICE_STORAGE_REQUEST_READ
:
3056 case DEVICE_STORAGE_REQUEST_WRITE
:
3058 if (!mFile
->mFile
) {
3059 return NS_ERROR_FAILURE
;
3062 DeviceStorageTypeChecker
* typeChecker
3063 = DeviceStorageTypeChecker::CreateOrGet();
3068 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
)) {
3069 r
= new PostErrorEvent(mRequest
.forget(),
3070 POST_ERROR_EVENT_ILLEGAL_TYPE
);
3071 return NS_DispatchToCurrentThread(r
);
3074 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3075 PDeviceStorageRequestChild
* child
3076 = new DeviceStorageRequestChild(mRequest
, mFile
);
3077 DeviceStorageGetParams
params(mFile
->mStorageType
,
3078 mFile
->mStorageName
,
3081 ContentChild::GetSingleton()
3082 ->SendPDeviceStorageRequestConstructor(child
, params
);
3086 r
= new ReadFileEvent(mFile
, mRequest
.forget());
3090 case DEVICE_STORAGE_REQUEST_DELETE
:
3092 if (!mFile
->mFile
) {
3093 return NS_ERROR_FAILURE
;
3096 DeviceStorageTypeChecker
* typeChecker
3097 = DeviceStorageTypeChecker::CreateOrGet();
3102 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
)) {
3103 r
= new PostErrorEvent(mRequest
.forget(),
3104 POST_ERROR_EVENT_ILLEGAL_TYPE
);
3105 return NS_DispatchToCurrentThread(r
);
3108 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3109 PDeviceStorageRequestChild
* child
3110 = new DeviceStorageRequestChild(mRequest
, mFile
);
3111 DeviceStorageDeleteParams
params(mFile
->mStorageType
,
3112 mFile
->mStorageName
,
3114 ContentChild::GetSingleton()
3115 ->SendPDeviceStorageRequestConstructor(child
, params
);
3118 r
= new DeleteFileEvent(mFile
, mRequest
.forget());
3122 case DEVICE_STORAGE_REQUEST_FREE_SPACE
:
3124 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3125 PDeviceStorageRequestChild
* child
3126 = new DeviceStorageRequestChild(mRequest
, mFile
);
3127 DeviceStorageFreeSpaceParams
params(mFile
->mStorageType
,
3128 mFile
->mStorageName
);
3129 ContentChild::GetSingleton()
3130 ->SendPDeviceStorageRequestConstructor(child
, params
);
3133 r
= new FreeSpaceFileEvent(mFile
, mRequest
.forget());
3137 case DEVICE_STORAGE_REQUEST_USED_SPACE
:
3139 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3140 PDeviceStorageRequestChild
* child
3141 = new DeviceStorageRequestChild(mRequest
, mFile
);
3142 DeviceStorageUsedSpaceParams
params(mFile
->mStorageType
,
3143 mFile
->mStorageName
);
3144 ContentChild::GetSingleton()
3145 ->SendPDeviceStorageRequestConstructor(child
, params
);
3148 // this needs to be dispatched to only one (1)
3149 // thread or we will do more work than required.
3150 DeviceStorageUsedSpaceCache
* usedSpaceCache
3151 = DeviceStorageUsedSpaceCache::CreateOrGet();
3152 MOZ_ASSERT(usedSpaceCache
);
3153 r
= new UsedSpaceFileEvent(mFile
, mRequest
.forget());
3154 usedSpaceCache
->Dispatch(r
);
3158 case DEVICE_STORAGE_REQUEST_AVAILABLE
:
3160 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3161 PDeviceStorageRequestChild
* child
3162 = new DeviceStorageRequestChild(mRequest
, mFile
);
3163 DeviceStorageAvailableParams
params(mFile
->mStorageType
,
3164 mFile
->mStorageName
);
3165 ContentChild::GetSingleton()
3166 ->SendPDeviceStorageRequestConstructor(child
, params
);
3169 r
= new PostAvailableResultEvent(mFile
, mRequest
);
3170 return NS_DispatchToCurrentThread(r
);
3173 case DEVICE_STORAGE_REQUEST_STATUS
:
3175 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3176 PDeviceStorageRequestChild
* child
3177 = new DeviceStorageRequestChild(mRequest
, mFile
);
3178 DeviceStorageStatusParams
params(mFile
->mStorageType
,
3179 mFile
->mStorageName
);
3180 ContentChild::GetSingleton()
3181 ->SendPDeviceStorageRequestConstructor(child
, params
);
3184 r
= new PostStatusResultEvent(mFile
, mRequest
);
3185 return NS_DispatchToCurrentThread(r
);
3188 case DEVICE_STORAGE_REQUEST_WATCH
:
3190 mDeviceStorage
->mAllowedToWatchFile
= true;
3194 case DEVICE_STORAGE_REQUEST_FORMAT
:
3196 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3197 PDeviceStorageRequestChild
* child
3198 = new DeviceStorageRequestChild(mRequest
, mFile
);
3199 DeviceStorageFormatParams
params(mFile
->mStorageType
,
3200 mFile
->mStorageName
);
3201 ContentChild::GetSingleton()
3202 ->SendPDeviceStorageRequestConstructor(child
, params
);
3205 r
= new PostFormatResultEvent(mFile
, mRequest
);
3206 return NS_DispatchToCurrentThread(r
);
3209 case DEVICE_STORAGE_REQUEST_MOUNT
:
3211 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3212 PDeviceStorageRequestChild
* child
3213 = new DeviceStorageRequestChild(mRequest
, mFile
);
3214 DeviceStorageMountParams
params(mFile
->mStorageType
,
3215 mFile
->mStorageName
);
3216 ContentChild::GetSingleton()
3217 ->SendPDeviceStorageRequestConstructor(child
, params
);
3220 r
= new PostMountResultEvent(mFile
, mRequest
);
3221 return NS_DispatchToCurrentThread(r
);
3224 case DEVICE_STORAGE_REQUEST_UNMOUNT
:
3226 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3227 PDeviceStorageRequestChild
* child
3228 = new DeviceStorageRequestChild(mRequest
, mFile
);
3229 DeviceStorageUnmountParams
params(mFile
->mStorageType
,
3230 mFile
->mStorageName
);
3231 ContentChild::GetSingleton()
3232 ->SendPDeviceStorageRequestConstructor(child
, params
);
3235 r
= new PostUnmountResultEvent(mFile
, mRequest
);
3236 return NS_DispatchToCurrentThread(r
);
3241 nsCOMPtr
<nsIEventTarget
> target
3242 = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
3244 target
->Dispatch(r
, NS_DISPATCH_NORMAL
);
3251 ~DeviceStorageRequest() {}
3253 int32_t mRequestType
;
3254 nsCOMPtr
<nsPIDOMWindow
> mWindow
;
3255 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
3256 nsRefPtr
<DeviceStorageFile
> mFile
;
3258 nsRefPtr
<DOMRequest
> mRequest
;
3259 nsCOMPtr
<nsIDOMBlob
> mBlob
;
3260 nsRefPtr
<nsDOMDeviceStorage
> mDeviceStorage
;
3261 nsRefPtr
<DeviceStorageFileDescriptor
> mDSFileDescriptor
;
3264 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest
)
3265 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIContentPermissionRequest
)
3266 NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest
)
3267 NS_INTERFACE_MAP_ENTRY(nsIRunnable
)
3268 NS_INTERFACE_MAP_END
3270 NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageRequest
)
3271 NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageRequest
)
3273 NS_IMPL_CYCLE_COLLECTION(DeviceStorageRequest
,
3280 NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorage
)
3281 NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorage
)
3282 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
3283 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
3285 NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorage
, DOMEventTargetHelper
)
3286 NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorage
, DOMEventTargetHelper
)
3288 nsDOMDeviceStorage::nsDOMDeviceStorage(nsPIDOMWindow
* aWindow
)
3289 : DOMEventTargetHelper(aWindow
)
3290 , mIsShareable(false)
3291 , mIsWatchingFile(false)
3292 , mAllowedToWatchFile(false)
3296 /* virtual */ JSObject
*
3297 nsDOMDeviceStorage::WrapObject(JSContext
* aCx
)
3299 return DeviceStorageBinding::Wrap(aCx
, this);
3303 nsDOMDeviceStorage::Init(nsPIDOMWindow
* aWindow
, const nsAString
&aType
,
3304 const nsAString
&aVolName
)
3306 DebugOnly
<FileUpdateDispatcher
*> observer
3307 = FileUpdateDispatcher::GetSingleton();
3308 MOZ_ASSERT(observer
);
3310 MOZ_ASSERT(aWindow
);
3312 SetRootDirectoryForType(aType
, aVolName
);
3313 if (!mRootDirectory
) {
3314 return NS_ERROR_NOT_AVAILABLE
;
3316 if (!mStorageName
.IsEmpty()) {
3317 RegisterForSDCardChanges(this);
3319 #ifdef MOZ_WIDGET_GONK
3320 if (DeviceStorageTypeChecker::IsVolumeBased(mStorageType
)) {
3321 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
3322 if (NS_WARN_IF(!vs
)) {
3323 return NS_ERROR_FAILURE
;
3326 nsCOMPtr
<nsIVolume
> vol
;
3327 rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
3328 if (NS_WARN_IF(NS_FAILED(rv
))) {
3332 rv
= vol
->GetIsFake(&isFake
);
3333 if (NS_WARN_IF(NS_FAILED(rv
))) {
3336 mIsShareable
= !isFake
;
3341 // Grab the principal of the document
3342 nsCOMPtr
<nsIDocument
> doc
= aWindow
->GetDoc();
3344 return NS_ERROR_FAILURE
;
3346 mPrincipal
= doc
->NodePrincipal();
3348 // the 'apps' type is special. We only want this exposed
3349 // if the caller has the "webapps-manage" permission.
3350 if (aType
.EqualsLiteral(DEVICESTORAGE_APPS
)) {
3351 nsCOMPtr
<nsIPermissionManager
> permissionManager
3352 = services::GetPermissionManager();
3353 NS_ENSURE_TRUE(permissionManager
, NS_ERROR_FAILURE
);
3355 uint32_t permission
;
3357 = permissionManager
->TestPermissionFromPrincipal(mPrincipal
,
3361 if (NS_FAILED(rv
) || permission
!= nsIPermissionManager::ALLOW_ACTION
) {
3362 return NS_ERROR_NOT_AVAILABLE
;
3369 nsDOMDeviceStorage::~nsDOMDeviceStorage()
3374 nsDOMDeviceStorage::Shutdown()
3376 MOZ_ASSERT(NS_IsMainThread());
3379 mFileSystem
->Shutdown();
3380 mFileSystem
= nullptr;
3383 if (!mStorageName
.IsEmpty()) {
3384 UnregisterForSDCardChanges(this);
3387 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
3388 obs
->RemoveObserver(this, kFileWatcherUpdate
);
3389 obs
->RemoveObserver(this, "disk-space-watcher");
3392 StaticAutoPtr
<nsTArray
<nsString
>> nsDOMDeviceStorage::sVolumeNameCache
;
3396 nsDOMDeviceStorage::GetOrderedVolumeNames(
3397 nsDOMDeviceStorage::VolumeNameArray
&aVolumeNames
)
3399 if (sVolumeNameCache
&& sVolumeNameCache
->Length() > 0) {
3400 aVolumeNames
.AppendElements(*sVolumeNameCache
);
3403 #ifdef MOZ_WIDGET_GONK
3404 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
3406 nsCOMPtr
<nsIArray
> volNames
;
3407 vs
->GetVolumeNames(getter_AddRefs(volNames
));
3408 uint32_t length
= -1;
3409 volNames
->GetLength(&length
);
3410 for (uint32_t i
= 0; i
< length
; i
++) {
3411 nsCOMPtr
<nsISupportsString
> str
= do_QueryElementAt(volNames
, i
);
3414 if (NS_SUCCEEDED(str
->GetData(s
)) && !s
.IsEmpty()) {
3415 aVolumeNames
.AppendElement(s
);
3420 // If the volume sdcard exists, then we want it to be first.
3422 VolumeNameArray::index_type sdcardIndex
;
3423 sdcardIndex
= aVolumeNames
.IndexOf(NS_LITERAL_STRING("sdcard"));
3424 if (sdcardIndex
!= VolumeNameArray::NoIndex
&& sdcardIndex
> 0) {
3425 aVolumeNames
.RemoveElementAt(sdcardIndex
);
3426 aVolumeNames
.InsertElementAt(0, NS_LITERAL_STRING("sdcard"));
3430 if (aVolumeNames
.IsEmpty()) {
3431 aVolumeNames
.AppendElement(EmptyString());
3433 sVolumeNameCache
= new nsTArray
<nsString
>;
3434 sVolumeNameCache
->AppendElements(aVolumeNames
);
3439 nsDOMDeviceStorage::CreateDeviceStorageFor(nsPIDOMWindow
* aWin
,
3440 const nsAString
&aType
,
3441 nsDOMDeviceStorage
** aStore
)
3443 nsString storageName
;
3444 if (!DeviceStorageTypeChecker::IsVolumeBased(aType
)) {
3445 // The storage name will be the empty string
3446 storageName
.Truncate();
3448 GetDefaultStorageName(aType
, storageName
);
3451 nsRefPtr
<nsDOMDeviceStorage
> ds
= new nsDOMDeviceStorage(aWin
);
3452 if (NS_FAILED(ds
->Init(aWin
, aType
, storageName
))) {
3456 NS_ADDREF(*aStore
= ds
.get());
3461 nsDOMDeviceStorage::CreateDeviceStoragesFor(
3462 nsPIDOMWindow
* aWin
,
3463 const nsAString
&aType
,
3464 nsTArray
<nsRefPtr
<nsDOMDeviceStorage
> > &aStores
)
3468 if (!DeviceStorageTypeChecker::IsVolumeBased(aType
)) {
3469 nsRefPtr
<nsDOMDeviceStorage
> storage
= new nsDOMDeviceStorage(aWin
);
3470 rv
= storage
->Init(aWin
, aType
, EmptyString());
3471 if (NS_SUCCEEDED(rv
)) {
3472 aStores
.AppendElement(storage
);
3476 VolumeNameArray volNames
;
3477 GetOrderedVolumeNames(volNames
);
3479 VolumeNameArray::size_type numVolumeNames
= volNames
.Length();
3480 for (VolumeNameArray::index_type i
= 0; i
< numVolumeNames
; i
++) {
3481 nsRefPtr
<nsDOMDeviceStorage
> storage
= new nsDOMDeviceStorage(aWin
);
3482 rv
= storage
->Init(aWin
, aType
, volNames
[i
]);
3483 if (NS_FAILED(rv
)) {
3486 aStores
.AppendElement(storage
);
3492 nsDOMDeviceStorage::ParseFullPath(const nsAString
& aFullPath
,
3493 nsAString
& aOutStorageName
,
3494 nsAString
& aOutStoragePath
)
3496 aOutStorageName
.Truncate();
3497 aOutStoragePath
.Truncate();
3499 NS_NAMED_LITERAL_STRING(slash
, "/");
3501 nsDependentSubstring storageName
;
3503 if (StringBeginsWith(aFullPath
, slash
)) {
3504 int32_t slashIndex
= aFullPath
.FindChar('/', 1);
3505 if (slashIndex
== kNotFound
) {
3506 // names of the form /filename are illegal
3509 storageName
.Rebind(aFullPath
, 1, slashIndex
- 1);
3510 aOutStoragePath
= Substring(aFullPath
, slashIndex
+ 1);
3512 aOutStoragePath
= aFullPath
;
3514 // If no volume name was specified in aFullPath, then aOutStorageName
3515 // will wind up being the empty string. It's up to the caller to figure
3516 // out which storage name to actually use.
3517 aOutStorageName
= storageName
;
3521 already_AddRefed
<nsDOMDeviceStorage
>
3522 nsDOMDeviceStorage::GetStorage(const nsAString
& aFullPath
,
3523 nsAString
& aOutStoragePath
)
3525 nsString storageName
;
3526 if (!ParseFullPath(aFullPath
, storageName
, aOutStoragePath
)) {
3529 nsRefPtr
<nsDOMDeviceStorage
> ds
;
3530 if (storageName
.IsEmpty()) {
3533 ds
= GetStorageByName(storageName
);
3538 already_AddRefed
<nsDOMDeviceStorage
>
3539 nsDOMDeviceStorage::GetStorageByName(const nsAString
& aStorageName
)
3541 MOZ_ASSERT(NS_IsMainThread());
3543 nsRefPtr
<nsDOMDeviceStorage
> ds
;
3545 if (mStorageName
.Equals(aStorageName
)) {
3549 VolumeNameArray volNames
;
3550 GetOrderedVolumeNames(volNames
);
3551 VolumeNameArray::size_type numVolumes
= volNames
.Length();
3552 VolumeNameArray::index_type i
;
3553 for (i
= 0; i
< numVolumes
; i
++) {
3554 if (volNames
[i
].Equals(aStorageName
)) {
3555 ds
= new nsDOMDeviceStorage(GetOwner());
3556 nsresult rv
= ds
->Init(GetOwner(), mStorageType
, aStorageName
);
3557 if (NS_FAILED(rv
)) {
3568 nsDOMDeviceStorage::GetDefaultStorageName(const nsAString
& aStorageType
,
3569 nsAString
& aStorageName
)
3571 // See if the preferred volume is available.
3572 nsRefPtr
<nsDOMDeviceStorage
> ds
;
3573 nsAdoptingString prefStorageName
=
3574 mozilla::Preferences::GetString("device.storage.writable.name");
3575 if (prefStorageName
) {
3576 aStorageName
= prefStorageName
;
3580 // No preferred storage, we'll use the first one (which should be sdcard).
3582 VolumeNameArray volNames
;
3583 GetOrderedVolumeNames(volNames
);
3584 if (volNames
.Length() > 0) {
3585 aStorageName
= volNames
[0];
3589 // No volumes available, return the empty string. This is normal for
3591 aStorageName
.Truncate();
3595 nsDOMDeviceStorage::IsAvailable()
3597 nsRefPtr
<DeviceStorageFile
> dsf(new DeviceStorageFile(mStorageType
, mStorageName
));
3598 return dsf
->IsAvailable();
3602 nsDOMDeviceStorage::Add(nsIDOMBlob
*aBlob
, nsIDOMDOMRequest
* *_retval
)
3605 nsRefPtr
<DOMRequest
> request
= Add(aBlob
, rv
);
3606 request
.forget(_retval
);
3607 return rv
.ErrorCode();
3610 already_AddRefed
<DOMRequest
>
3611 nsDOMDeviceStorage::Add(nsIDOMBlob
* aBlob
, ErrorResult
& aRv
)
3617 nsCOMPtr
<nsIMIMEService
> mimeSvc
= do_GetService(NS_MIMESERVICE_CONTRACTID
);
3619 aRv
.Throw(NS_ERROR_FAILURE
);
3623 // if mimeType isn't set, we will not get a correct
3624 // extension, and AddNamed() will fail. This will post an
3625 // onerror to the requestee.
3627 aBlob
->GetType(mimeType
);
3629 nsCString extension
;
3630 mimeSvc
->GetPrimaryExtension(NS_LossyConvertUTF16toASCII(mimeType
),
3631 EmptyCString(), extension
);
3632 // if extension is null here, we will ignore it for now.
3633 // AddNamed() will check the file path and fail. This
3634 // will post an onerror to the requestee.
3636 // possible race here w/ unique filename
3638 NS_MakeRandomString(buffer
, ArrayLength(buffer
) - 1);
3641 path
.Assign(nsDependentCString(buffer
));
3643 path
.Append(extension
);
3645 return AddNamed(aBlob
, NS_ConvertASCIItoUTF16(path
), aRv
);
3649 nsDOMDeviceStorage::AddNamed(nsIDOMBlob
*aBlob
,
3650 const nsAString
& aPath
,
3651 nsIDOMDOMRequest
* *_retval
)
3654 nsRefPtr
<DOMRequest
> request
= AddNamed(aBlob
, aPath
, rv
);
3655 request
.forget(_retval
);
3656 return rv
.ErrorCode();
3659 already_AddRefed
<DOMRequest
>
3660 nsDOMDeviceStorage::AddNamed(nsIDOMBlob
* aBlob
, const nsAString
& aPath
,
3663 return AddOrAppendNamed(aBlob
, aPath
,
3664 DEVICE_STORAGE_REQUEST_CREATE
, aRv
);
3667 already_AddRefed
<DOMRequest
>
3668 nsDOMDeviceStorage::AppendNamed(nsIDOMBlob
* aBlob
, const nsAString
& aPath
,
3671 return AddOrAppendNamed(aBlob
, aPath
,
3672 DEVICE_STORAGE_REQUEST_APPEND
, aRv
);
3676 already_AddRefed
<DOMRequest
>
3677 nsDOMDeviceStorage::AddOrAppendNamed(nsIDOMBlob
* aBlob
, const nsAString
& aPath
,
3678 const int32_t aRequestType
, ErrorResult
& aRv
)
3680 MOZ_ASSERT(NS_IsMainThread());
3682 // if the blob is null here, bail
3687 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3689 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3693 DeviceStorageTypeChecker
* typeChecker
3694 = DeviceStorageTypeChecker::CreateOrGet();
3696 aRv
.Throw(NS_ERROR_FAILURE
);
3700 nsCOMPtr
<nsIRunnable
> r
;
3703 if (IsFullPath(aPath
)) {
3704 nsString storagePath
;
3705 nsRefPtr
<nsDOMDeviceStorage
> ds
= GetStorage(aPath
, storagePath
);
3707 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3708 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_UNKNOWN
);
3709 rv
= NS_DispatchToCurrentThread(r
);
3710 if (NS_FAILED(rv
)) {
3713 return request
.forget();
3716 return ds
->AddOrAppendNamed(aBlob
, storagePath
,
3720 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3722 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3725 if (!dsf
->IsSafePath()) {
3726 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_PERMISSION_DENIED
);
3727 } else if (!typeChecker
->Check(mStorageType
, dsf
->mFile
) ||
3728 !typeChecker
->Check(mStorageType
, aBlob
)) {
3729 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_ILLEGAL_TYPE
);
3730 } else if (aRequestType
== DEVICE_STORAGE_REQUEST_APPEND
||
3731 aRequestType
== DEVICE_STORAGE_REQUEST_CREATE
) {
3732 r
= new DeviceStorageRequest(DeviceStorageRequestType(aRequestType
),
3733 win
, mPrincipal
, dsf
, request
, aBlob
);
3735 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3739 rv
= NS_DispatchToCurrentThread(r
);
3740 if (NS_FAILED(rv
)) {
3743 return request
.forget();
3747 nsDOMDeviceStorage::Get(const nsAString
& aPath
, nsIDOMDOMRequest
** aRetval
)
3750 nsRefPtr
<DOMRequest
> request
= Get(aPath
, rv
);
3751 request
.forget(aRetval
);
3752 return rv
.ErrorCode();
3756 nsDOMDeviceStorage::GetEditable(const nsAString
& aPath
,
3757 nsIDOMDOMRequest
** aRetval
)
3760 nsRefPtr
<DOMRequest
> request
= GetEditable(aPath
, rv
);
3761 request
.forget(aRetval
);
3762 return rv
.ErrorCode();
3765 already_AddRefed
<DOMRequest
>
3766 nsDOMDeviceStorage::GetInternal(const nsAString
& aPath
, bool aEditable
,
3769 MOZ_ASSERT(NS_IsMainThread());
3771 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3773 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3777 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3779 if (IsFullPath(aPath
)) {
3780 nsString storagePath
;
3781 nsRefPtr
<nsDOMDeviceStorage
> ds
= GetStorage(aPath
, storagePath
);
3783 nsCOMPtr
<nsIRunnable
> r
=
3784 new PostErrorEvent(request
, POST_ERROR_EVENT_UNKNOWN
);
3785 nsresult rv
= NS_DispatchToCurrentThread(r
);
3786 if (NS_FAILED(rv
)) {
3789 return request
.forget();
3791 ds
->GetInternal(win
, storagePath
, request
, aEditable
);
3792 return request
.forget();
3794 GetInternal(win
, aPath
, request
, aEditable
);
3795 return request
.forget();
3799 nsDOMDeviceStorage::GetInternal(nsPIDOMWindow
*aWin
,
3800 const nsAString
& aPath
,
3801 DOMRequest
* aRequest
,
3804 MOZ_ASSERT(NS_IsMainThread());
3806 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3809 dsf
->SetEditable(aEditable
);
3811 nsCOMPtr
<nsIRunnable
> r
;
3812 if (!dsf
->IsSafePath()) {
3813 r
= new PostErrorEvent(aRequest
, POST_ERROR_EVENT_PERMISSION_DENIED
);
3815 r
= new DeviceStorageRequest(aEditable
? DEVICE_STORAGE_REQUEST_WRITE
3816 : DEVICE_STORAGE_REQUEST_READ
,
3817 aWin
, mPrincipal
, dsf
, aRequest
);
3819 DebugOnly
<nsresult
> rv
= NS_DispatchToCurrentThread(r
);
3820 MOZ_ASSERT(NS_SUCCEEDED(rv
));
3824 nsDOMDeviceStorage::Delete(const nsAString
& aPath
, nsIDOMDOMRequest
** aRetval
)
3827 nsRefPtr
<DOMRequest
> request
= Delete(aPath
, rv
);
3828 request
.forget(aRetval
);
3829 return rv
.ErrorCode();
3832 already_AddRefed
<DOMRequest
>
3833 nsDOMDeviceStorage::Delete(const nsAString
& aPath
, ErrorResult
& aRv
)
3835 MOZ_ASSERT(NS_IsMainThread());
3837 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3839 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3843 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3845 if (IsFullPath(aPath
)) {
3846 nsString storagePath
;
3847 nsRefPtr
<nsDOMDeviceStorage
> ds
= GetStorage(aPath
, storagePath
);
3849 nsCOMPtr
<nsIRunnable
> r
=
3850 new PostErrorEvent(request
, POST_ERROR_EVENT_UNKNOWN
);
3851 nsresult rv
= NS_DispatchToCurrentThread(r
);
3852 if (NS_FAILED(rv
)) {
3855 return request
.forget();
3857 ds
->DeleteInternal(win
, storagePath
, request
);
3858 return request
.forget();
3860 DeleteInternal(win
, aPath
, request
);
3861 return request
.forget();
3865 nsDOMDeviceStorage::DeleteInternal(nsPIDOMWindow
*aWin
,
3866 const nsAString
& aPath
,
3867 DOMRequest
* aRequest
)
3869 MOZ_ASSERT(NS_IsMainThread());
3871 nsCOMPtr
<nsIRunnable
> r
;
3872 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3875 if (!dsf
->IsSafePath()) {
3876 r
= new PostErrorEvent(aRequest
, POST_ERROR_EVENT_PERMISSION_DENIED
);
3878 r
= new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_DELETE
,
3879 aWin
, mPrincipal
, dsf
, aRequest
);
3881 DebugOnly
<nsresult
> rv
= NS_DispatchToCurrentThread(r
);
3882 MOZ_ASSERT(NS_SUCCEEDED(rv
));
3886 nsDOMDeviceStorage::FreeSpace(nsIDOMDOMRequest
** aRetval
)
3889 nsRefPtr
<DOMRequest
> request
= FreeSpace(rv
);
3890 request
.forget(aRetval
);
3891 return rv
.ErrorCode();
3894 already_AddRefed
<DOMRequest
>
3895 nsDOMDeviceStorage::FreeSpace(ErrorResult
& aRv
)
3897 MOZ_ASSERT(NS_IsMainThread());
3899 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3901 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3905 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3907 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3909 nsCOMPtr
<nsIRunnable
> r
3910 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FREE_SPACE
,
3911 win
, mPrincipal
, dsf
, request
);
3912 nsresult rv
= NS_DispatchToCurrentThread(r
);
3913 if (NS_FAILED(rv
)) {
3916 return request
.forget();
3920 nsDOMDeviceStorage::UsedSpace(nsIDOMDOMRequest
** aRetval
)
3923 nsRefPtr
<DOMRequest
> request
= UsedSpace(rv
);
3924 request
.forget(aRetval
);
3925 return rv
.ErrorCode();
3928 already_AddRefed
<DOMRequest
>
3929 nsDOMDeviceStorage::UsedSpace(ErrorResult
& aRv
)
3931 MOZ_ASSERT(NS_IsMainThread());
3933 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3935 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3939 DebugOnly
<DeviceStorageUsedSpaceCache
*> usedSpaceCache
3940 = DeviceStorageUsedSpaceCache::CreateOrGet();
3941 MOZ_ASSERT(usedSpaceCache
);
3943 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3945 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3947 nsCOMPtr
<nsIRunnable
> r
3948 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_USED_SPACE
,
3949 win
, mPrincipal
, dsf
, request
);
3950 nsresult rv
= NS_DispatchToCurrentThread(r
);
3951 if (NS_FAILED(rv
)) {
3954 return request
.forget();
3958 nsDOMDeviceStorage::Available(nsIDOMDOMRequest
** aRetval
)
3961 nsRefPtr
<DOMRequest
> request
= Available(rv
);
3962 request
.forget(aRetval
);
3963 return rv
.ErrorCode();
3966 already_AddRefed
<DOMRequest
>
3967 nsDOMDeviceStorage::Available(ErrorResult
& aRv
)
3969 MOZ_ASSERT(NS_IsMainThread());
3971 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3973 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3977 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3979 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3981 nsCOMPtr
<nsIRunnable
> r
3982 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_AVAILABLE
,
3983 win
, mPrincipal
, dsf
, request
);
3984 nsresult rv
= NS_DispatchToCurrentThread(r
);
3985 if (NS_FAILED(rv
)) {
3988 return request
.forget();
3991 already_AddRefed
<DOMRequest
>
3992 nsDOMDeviceStorage::StorageStatus(ErrorResult
& aRv
)
3994 MOZ_ASSERT(NS_IsMainThread());
3996 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3998 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4002 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4004 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4006 nsCOMPtr
<nsIRunnable
> r
4007 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_STATUS
,
4008 win
, mPrincipal
, dsf
, request
);
4009 nsresult rv
= NS_DispatchToCurrentThread(r
);
4010 if (NS_FAILED(rv
)) {
4013 return request
.forget();
4016 already_AddRefed
<DOMRequest
>
4017 nsDOMDeviceStorage::Format(ErrorResult
& aRv
)
4019 MOZ_ASSERT(NS_IsMainThread());
4021 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4023 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4027 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4029 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4031 nsCOMPtr
<nsIRunnable
> r
4032 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FORMAT
,
4033 win
, mPrincipal
, dsf
, request
);
4034 nsresult rv
= NS_DispatchToCurrentThread(r
);
4035 if (NS_FAILED(rv
)) {
4038 return request
.forget();
4041 already_AddRefed
<DOMRequest
>
4042 nsDOMDeviceStorage::Mount(ErrorResult
& aRv
)
4044 MOZ_ASSERT(NS_IsMainThread());
4046 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4048 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4052 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4054 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4056 nsCOMPtr
<nsIRunnable
> r
4057 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_MOUNT
,
4058 win
, mPrincipal
, dsf
, request
);
4059 nsresult rv
= NS_DispatchToCurrentThread(r
);
4060 if (NS_FAILED(rv
)) {
4063 return request
.forget();
4066 already_AddRefed
<DOMRequest
>
4067 nsDOMDeviceStorage::Unmount(ErrorResult
& aRv
)
4069 MOZ_ASSERT(NS_IsMainThread());
4071 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4073 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4077 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4079 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4081 nsCOMPtr
<nsIRunnable
> r
4082 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_UNMOUNT
,
4083 win
, mPrincipal
, dsf
, request
);
4084 nsresult rv
= NS_DispatchToCurrentThread(r
);
4085 if (NS_FAILED(rv
)) {
4088 return request
.forget();
4092 nsDOMDeviceStorage::CreateFileDescriptor(const nsAString
& aPath
,
4093 DeviceStorageFileDescriptor
* aDSFileDescriptor
,
4094 nsIDOMDOMRequest
** aRequest
)
4096 MOZ_ASSERT(NS_IsMainThread());
4097 MOZ_ASSERT(aDSFileDescriptor
);
4099 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4101 return NS_ERROR_UNEXPECTED
;
4104 DeviceStorageTypeChecker
* typeChecker
4105 = DeviceStorageTypeChecker::CreateOrGet();
4107 return NS_ERROR_FAILURE
;
4110 nsCOMPtr
<nsIRunnable
> r
;
4113 if (IsFullPath(aPath
)) {
4114 nsString storagePath
;
4115 nsRefPtr
<nsDOMDeviceStorage
> ds
= GetStorage(aPath
, storagePath
);
4117 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4118 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_UNKNOWN
);
4119 rv
= NS_DispatchToCurrentThread(r
);
4120 if (NS_FAILED(rv
)) {
4123 request
.forget(aRequest
);
4126 return ds
->CreateFileDescriptor(storagePath
, aDSFileDescriptor
, aRequest
);
4129 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4131 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4134 if (!dsf
->IsSafePath()) {
4135 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_PERMISSION_DENIED
);
4136 } else if (!typeChecker
->Check(mStorageType
, dsf
->mFile
)) {
4137 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_ILLEGAL_TYPE
);
4139 r
= new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_CREATEFD
,
4140 win
, mPrincipal
, dsf
, request
,
4144 rv
= NS_DispatchToCurrentThread(r
);
4145 if (NS_FAILED(rv
)) {
4148 request
.forget(aRequest
);
4153 nsDOMDeviceStorage::Default()
4155 nsString defaultStorageName
;
4156 GetDefaultStorageName(mStorageType
, defaultStorageName
);
4157 return mStorageName
.Equals(defaultStorageName
);
4161 nsDOMDeviceStorage::CanBeFormatted()
4163 // Currently, any volume which can be shared can also be formatted.
4164 return mIsShareable
;
4168 nsDOMDeviceStorage::CanBeMounted()
4170 // Currently, any volume which can be shared can also be mounted/unmounted.
4171 return mIsShareable
;
4175 nsDOMDeviceStorage::CanBeShared()
4177 return mIsShareable
;
4180 already_AddRefed
<Promise
>
4181 nsDOMDeviceStorage::GetRoot(ErrorResult
& aRv
)
4184 mFileSystem
= new DeviceStorageFileSystem(mStorageType
, mStorageName
);
4185 mFileSystem
->Init(this);
4187 return mozilla::dom::Directory::GetRoot(mFileSystem
, aRv
);
4191 nsDOMDeviceStorage::GetDefault(bool* aDefault
)
4193 *aDefault
= Default();
4198 nsDOMDeviceStorage::GetStorageName(nsAString
& aStorageName
)
4200 aStorageName
= mStorageName
;
4204 already_AddRefed
<DOMCursor
>
4205 nsDOMDeviceStorage::Enumerate(const nsAString
& aPath
,
4206 const EnumerationParameters
& aOptions
,
4209 return EnumerateInternal(aPath
, aOptions
, false, aRv
);
4212 already_AddRefed
<DOMCursor
>
4213 nsDOMDeviceStorage::EnumerateEditable(const nsAString
& aPath
,
4214 const EnumerationParameters
& aOptions
,
4217 return EnumerateInternal(aPath
, aOptions
, true, aRv
);
4221 already_AddRefed
<DOMCursor
>
4222 nsDOMDeviceStorage::EnumerateInternal(const nsAString
& aPath
,
4223 const EnumerationParameters
& aOptions
,
4224 bool aEditable
, ErrorResult
& aRv
)
4226 MOZ_ASSERT(NS_IsMainThread());
4228 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4230 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4235 if (aOptions
.mSince
.WasPassed() && !aOptions
.mSince
.Value().IsUndefined()) {
4236 since
= PRTime(aOptions
.mSince
.Value().TimeStamp());
4239 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4243 dsf
->SetEditable(aEditable
);
4245 nsRefPtr
<nsDOMDeviceStorageCursor
> cursor
4246 = new nsDOMDeviceStorageCursor(win
, mPrincipal
, dsf
, since
);
4247 nsRefPtr
<DeviceStorageCursorRequest
> r
4248 = new DeviceStorageCursorRequest(cursor
);
4250 if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
4251 r
->Allow(JS::UndefinedHandleValue
);
4252 return cursor
.forget();
4255 nsContentPermissionUtils::AskPermission(r
, win
);
4257 return cursor
.forget();
4260 #ifdef MOZ_WIDGET_GONK
4262 nsDOMDeviceStorage::DispatchStatusChangeEvent(nsAString
& aStatus
)
4264 if (aStatus
== mLastStatus
) {
4265 // We've already sent this status, don't bother sending it again.
4268 mLastStatus
= aStatus
;
4270 DeviceStorageChangeEventInit init
;
4271 init
.mBubbles
= true;
4272 init
.mCancelable
= false;
4273 init
.mPath
= mStorageName
;
4274 init
.mReason
= aStatus
;
4276 nsRefPtr
<DeviceStorageChangeEvent
> event
=
4277 DeviceStorageChangeEvent::Constructor(this, NS_LITERAL_STRING("change"),
4279 event
->SetTrusted(true);
4282 DispatchEvent(event
, &ignore
);
4286 nsDOMDeviceStorage::DispatchStorageStatusChangeEvent(nsAString
& aStorageStatus
)
4288 if (aStorageStatus
== mLastStorageStatus
) {
4289 // We've already sent this status, don't bother sending it again.
4292 mLastStorageStatus
= aStorageStatus
;
4294 DeviceStorageChangeEventInit init
;
4295 init
.mBubbles
= true;
4296 init
.mCancelable
= false;
4297 init
.mPath
= mStorageName
;
4298 init
.mReason
= aStorageStatus
;
4300 nsRefPtr
<DeviceStorageChangeEvent
> event
=
4301 DeviceStorageChangeEvent::Constructor(this, NS_LITERAL_STRING("storage-state-change"),
4303 event
->SetTrusted(true);
4306 DispatchEvent(event
, &ignore
);
4311 nsDOMDeviceStorage::Observe(nsISupports
*aSubject
,
4313 const char16_t
*aData
)
4315 MOZ_ASSERT(NS_IsMainThread());
4317 if (!strcmp(aTopic
, kFileWatcherUpdate
)) {
4319 DeviceStorageFile
* file
= static_cast<DeviceStorageFile
*>(aSubject
);
4320 Notify(NS_ConvertUTF16toUTF8(aData
).get(), file
);
4323 if (!strcmp(aTopic
, "disk-space-watcher")) {
4324 // 'disk-space-watcher' notifications are sent when there is a modification
4325 // of a file in a specific location while a low device storage situation
4326 // exists or after recovery of a low storage situation. For Firefox OS,
4327 // these notifications are specific for apps storage.
4328 nsRefPtr
<DeviceStorageFile
> file
=
4329 new DeviceStorageFile(mStorageType
, mStorageName
);
4330 if (!NS_strcmp(aData
, MOZ_UTF16("full"))) {
4331 Notify("low-disk-space", file
);
4332 } else if (!NS_strcmp(aData
, MOZ_UTF16("free"))) {
4333 Notify("available-disk-space", file
);
4338 #ifdef MOZ_WIDGET_GONK
4339 else if (!strcmp(aTopic
, NS_VOLUME_STATE_CHANGED
)) {
4340 // We invalidate the used space cache for the volume that actually changed
4342 nsCOMPtr
<nsIVolume
> vol
= do_QueryInterface(aSubject
);
4347 vol
->GetName(volName
);
4349 DeviceStorageUsedSpaceCache
* usedSpaceCache
4350 = DeviceStorageUsedSpaceCache::CreateOrGet();
4351 MOZ_ASSERT(usedSpaceCache
);
4352 usedSpaceCache
->Invalidate(volName
);
4354 if (!volName
.Equals(mStorageName
)) {
4355 // Not our volume - we can ignore.
4359 nsRefPtr
<DeviceStorageFile
> dsf(new DeviceStorageFile(mStorageType
, mStorageName
));
4360 nsString status
, storageStatus
;
4362 // Get Status (one of "available, unavailable, shared")
4363 dsf
->GetStatus(status
);
4364 DispatchStatusChangeEvent(status
);
4366 // Get real volume status (defined in dom/system/gonk/nsIVolume.idl)
4367 dsf
->GetStorageStatus(storageStatus
);
4368 DispatchStorageStatusChangeEvent(storageStatus
);
4376 nsDOMDeviceStorage::Notify(const char* aReason
, DeviceStorageFile
* aFile
)
4378 if (!mAllowedToWatchFile
) {
4382 if (!mStorageType
.Equals(aFile
->mStorageType
) ||
4383 !mStorageName
.Equals(aFile
->mStorageName
)) {
4388 DeviceStorageChangeEventInit init
;
4389 init
.mBubbles
= true;
4390 init
.mCancelable
= false;
4391 aFile
->GetFullPath(init
.mPath
);
4392 init
.mReason
.AssignWithConversion(aReason
);
4394 nsRefPtr
<DeviceStorageChangeEvent
> event
=
4395 DeviceStorageChangeEvent::Constructor(this, NS_LITERAL_STRING("change"),
4397 event
->SetTrusted(true);
4400 DispatchEvent(event
, &ignore
);
4405 nsDOMDeviceStorage::AddEventListener(const nsAString
& aType
,
4406 nsIDOMEventListener
*aListener
,
4408 bool aWantsUntrusted
,
4411 MOZ_ASSERT(NS_IsMainThread());
4413 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4415 return NS_ERROR_UNEXPECTED
;
4418 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4419 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4421 nsCOMPtr
<nsIRunnable
> r
4422 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH
,
4423 win
, mPrincipal
, dsf
, request
, this);
4424 nsresult rv
= NS_DispatchToCurrentThread(r
);
4425 if (NS_WARN_IF(NS_FAILED(rv
))) {
4429 return DOMEventTargetHelper::AddEventListener(aType
, aListener
, aUseCapture
,
4430 aWantsUntrusted
, aArgc
);
4434 nsDOMDeviceStorage::AddEventListener(const nsAString
& aType
,
4435 EventListener
*aListener
,
4437 const Nullable
<bool>& aWantsUntrusted
,
4440 MOZ_ASSERT(NS_IsMainThread());
4442 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4444 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4448 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4449 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4451 nsCOMPtr
<nsIRunnable
> r
4452 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH
,
4453 win
, mPrincipal
, dsf
, request
, this);
4454 nsresult rv
= NS_DispatchToCurrentThread(r
);
4455 if (NS_WARN_IF(NS_FAILED(rv
))) {
4458 DOMEventTargetHelper::AddEventListener(aType
, aListener
, aUseCapture
,
4459 aWantsUntrusted
, aRv
);
4463 nsDOMDeviceStorage::AddSystemEventListener(const nsAString
& aType
,
4464 nsIDOMEventListener
*aListener
,
4466 bool aWantsUntrusted
,
4469 if (!mIsWatchingFile
) {
4470 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
4471 obs
->AddObserver(this, kFileWatcherUpdate
, false);
4472 mIsWatchingFile
= true;
4475 return nsDOMDeviceStorage::AddEventListener(aType
, aListener
, aUseCapture
,
4476 aWantsUntrusted
, aArgc
);
4480 nsDOMDeviceStorage::RemoveEventListener(const nsAString
& aType
,
4481 nsIDOMEventListener
*aListener
,
4484 DOMEventTargetHelper::RemoveEventListener(aType
, aListener
, false);
4486 if (mIsWatchingFile
&& !HasListenersFor(nsGkAtoms::onchange
)) {
4487 mIsWatchingFile
= false;
4488 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
4489 obs
->RemoveObserver(this, kFileWatcherUpdate
);
4495 nsDOMDeviceStorage::RemoveEventListener(const nsAString
& aType
,
4496 EventListener
* aListener
,
4500 DOMEventTargetHelper::RemoveEventListener(aType
, aListener
, aCapture
, aRv
);
4502 if (mIsWatchingFile
&& !HasListenersFor(nsGkAtoms::onchange
)) {
4503 mIsWatchingFile
= false;
4504 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
4505 obs
->RemoveObserver(this, kFileWatcherUpdate
);
4510 nsDOMDeviceStorage::RemoveSystemEventListener(const nsAString
& aType
,
4511 nsIDOMEventListener
*aListener
,
4514 return nsDOMDeviceStorage::RemoveEventListener(aType
, aListener
, aUseCapture
);
4518 nsDOMDeviceStorage::DispatchEvent(nsIDOMEvent
*aEvt
,
4521 return DOMEventTargetHelper::DispatchEvent(aEvt
, aRetval
);
4525 nsDOMDeviceStorage::GetTargetForDOMEvent()
4527 return DOMEventTargetHelper::GetTargetForDOMEvent();
4531 nsDOMDeviceStorage::GetTargetForEventTargetChain()
4533 return DOMEventTargetHelper::GetTargetForEventTargetChain();
4537 nsDOMDeviceStorage::PreHandleEvent(EventChainPreVisitor
& aVisitor
)
4539 return DOMEventTargetHelper::PreHandleEvent(aVisitor
);
4543 nsDOMDeviceStorage::WillHandleEvent(EventChainPostVisitor
& aVisitor
)
4545 return DOMEventTargetHelper::WillHandleEvent(aVisitor
);
4549 nsDOMDeviceStorage::PostHandleEvent(EventChainPostVisitor
& aVisitor
)
4551 return DOMEventTargetHelper::PostHandleEvent(aVisitor
);
4555 nsDOMDeviceStorage::DispatchDOMEvent(WidgetEvent
* aEvent
,
4556 nsIDOMEvent
* aDOMEvent
,
4557 nsPresContext
* aPresContext
,
4558 nsEventStatus
* aEventStatus
)
4560 return DOMEventTargetHelper::DispatchDOMEvent(aEvent
,
4566 EventListenerManager
*
4567 nsDOMDeviceStorage::GetOrCreateListenerManager()
4569 return DOMEventTargetHelper::GetOrCreateListenerManager();
4572 EventListenerManager
*
4573 nsDOMDeviceStorage::GetExistingListenerManager() const
4575 return DOMEventTargetHelper::GetExistingListenerManager();
4579 nsDOMDeviceStorage::GetContextForEventHandlers(nsresult
*aRv
)
4581 return DOMEventTargetHelper::GetContextForEventHandlers(aRv
);
4585 nsDOMDeviceStorage::GetJSContextForEventHandlers()
4587 return DOMEventTargetHelper::GetJSContextForEventHandlers();
4590 NS_IMPL_EVENT_HANDLER(nsDOMDeviceStorage
, change
)