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/BlobChild.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 "nsNetUtil.h"
40 #include "nsCycleCollectionParticipant.h"
41 #include "nsIPrincipal.h"
42 #include "nsJSUtils.h"
43 #include "nsContentUtils.h"
44 #include "nsXULAppAPI.h"
45 #include "DeviceStorageFileDescriptor.h"
46 #include "DeviceStorageRequestChild.h"
48 #include "nsIObserverService.h"
49 #include "nsIMIMEService.h"
50 #include "nsCExternalHandlerService.h"
51 #include "nsIPermissionManager.h"
52 #include "nsIStringBundle.h"
53 #include "nsISupportsPrimitives.h"
54 #include "nsIDocument.h"
55 #include "nsPrintfCString.h"
57 #include "private/pprio.h"
58 #include "nsContentPermissionHelper.h"
60 #include "mozilla/dom/DeviceStorageBinding.h"
62 // Microsoft's API Name hackery sucks
65 #ifdef MOZ_WIDGET_ANDROID
66 #include "AndroidBridge.h"
69 #ifdef MOZ_WIDGET_GONK
70 #include "nsIVolume.h"
71 #include "nsIVolumeService.h"
74 #define DEVICESTORAGE_PROPERTIES \
75 "chrome://global/content/devicestorage.properties"
76 #define DEFAULT_THREAD_TIMEOUT_MS 30000
78 using namespace mozilla
;
79 using namespace mozilla::dom
;
80 using namespace mozilla::dom::devicestorage
;
81 using namespace mozilla::ipc
;
83 #include "nsDirectoryServiceDefs.h"
85 const char* kFileWatcherUpdate
= "file-watcher-update";
86 const char* kFileWatcherNotify
= "file-watcher-notify";
87 const char *kDownloadWatcherNotify
= "download-watcher-notify";
90 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc
, PRFileDesc
, PR_Close
);
93 StaticAutoPtr
<DeviceStorageUsedSpaceCache
>
94 DeviceStorageUsedSpaceCache::sDeviceStorageUsedSpaceCache
;
96 DeviceStorageUsedSpaceCache::DeviceStorageUsedSpaceCache()
98 MOZ_ASSERT(NS_IsMainThread());
100 mIOThread
= new LazyIdleThread(
101 DEFAULT_THREAD_TIMEOUT_MS
,
102 NS_LITERAL_CSTRING("DeviceStorageUsedSpaceCache I/O"));
106 DeviceStorageUsedSpaceCache::~DeviceStorageUsedSpaceCache()
110 DeviceStorageUsedSpaceCache
*
111 DeviceStorageUsedSpaceCache::CreateOrGet()
113 if (sDeviceStorageUsedSpaceCache
) {
114 return sDeviceStorageUsedSpaceCache
;
117 MOZ_ASSERT(NS_IsMainThread());
119 sDeviceStorageUsedSpaceCache
= new DeviceStorageUsedSpaceCache();
120 ClearOnShutdown(&sDeviceStorageUsedSpaceCache
);
121 return sDeviceStorageUsedSpaceCache
;
124 already_AddRefed
<DeviceStorageUsedSpaceCache::CacheEntry
>
125 DeviceStorageUsedSpaceCache::GetCacheEntry(const nsAString
& aStorageName
)
127 nsTArray
<nsRefPtr
<CacheEntry
>>::size_type numEntries
= mCacheEntries
.Length();
128 nsTArray
<nsRefPtr
<CacheEntry
>>::index_type i
;
129 for (i
= 0; i
< numEntries
; i
++) {
130 nsRefPtr
<CacheEntry
>& cacheEntry
= mCacheEntries
[i
];
131 if (cacheEntry
->mStorageName
.Equals(aStorageName
)) {
132 nsRefPtr
<CacheEntry
> addRefedCacheEntry
= cacheEntry
;
133 return addRefedCacheEntry
.forget();
140 GetFreeBytes(const nsAString
& aStorageName
)
142 // This function makes the assumption that the various types
143 // are all stored on the same filesystem. So we use pictures.
145 nsRefPtr
<DeviceStorageFile
> dsf(new DeviceStorageFile(NS_LITERAL_STRING(DEVICESTORAGE_PICTURES
),
147 int64_t freeBytes
= 0;
148 dsf
->GetDiskFreeSpace(&freeBytes
);
153 DeviceStorageUsedSpaceCache::AccumUsedSizes(const nsAString
& aStorageName
,
154 uint64_t* aPicturesSoFar
,
155 uint64_t* aVideosSoFar
,
156 uint64_t* aMusicSoFar
,
157 uint64_t* aTotalSoFar
)
159 nsRefPtr
<CacheEntry
> cacheEntry
= GetCacheEntry(aStorageName
);
160 if (!cacheEntry
|| cacheEntry
->mDirty
) {
161 return NS_ERROR_NOT_AVAILABLE
;
163 int64_t freeBytes
= GetFreeBytes(cacheEntry
->mStorageName
);
164 if (freeBytes
!= cacheEntry
->mFreeBytes
) {
165 // Free space changed, so our cached results are no longer valid.
166 return NS_ERROR_NOT_AVAILABLE
;
169 *aPicturesSoFar
+= cacheEntry
->mPicturesUsedSize
;
170 *aVideosSoFar
+= cacheEntry
->mVideosUsedSize
;
171 *aMusicSoFar
+= cacheEntry
->mMusicUsedSize
;
172 *aTotalSoFar
+= cacheEntry
->mTotalUsedSize
;
178 DeviceStorageUsedSpaceCache::SetUsedSizes(const nsAString
& aStorageName
,
179 uint64_t aPictureSize
,
180 uint64_t aVideosSize
,
182 uint64_t aTotalUsedSize
)
184 nsRefPtr
<CacheEntry
> cacheEntry
= GetCacheEntry(aStorageName
);
186 cacheEntry
= new CacheEntry
;
187 cacheEntry
->mStorageName
= aStorageName
;
188 mCacheEntries
.AppendElement(cacheEntry
);
190 cacheEntry
->mFreeBytes
= GetFreeBytes(cacheEntry
->mStorageName
);
192 cacheEntry
->mPicturesUsedSize
= aPictureSize
;
193 cacheEntry
->mVideosUsedSize
= aVideosSize
;
194 cacheEntry
->mMusicUsedSize
= aMusicSize
;
195 cacheEntry
->mTotalUsedSize
= aTotalUsedSize
;
196 cacheEntry
->mDirty
= false;
204 NS_INLINE_DECL_REFCOUNTING(GlobalDirs
)
205 #if !defined(MOZ_WIDGET_GONK)
206 nsCOMPtr
<nsIFile
> pictures
;
207 nsCOMPtr
<nsIFile
> videos
;
208 nsCOMPtr
<nsIFile
> music
;
209 nsCOMPtr
<nsIFile
> sdcard
;
211 nsCOMPtr
<nsIFile
> apps
;
212 nsCOMPtr
<nsIFile
> crashes
;
213 nsCOMPtr
<nsIFile
> overrideRootDir
;
216 static StaticRefPtr
<GlobalDirs
> sDirs
;
218 StaticAutoPtr
<DeviceStorageTypeChecker
>
219 DeviceStorageTypeChecker::sDeviceStorageTypeChecker
;
221 DeviceStorageTypeChecker::DeviceStorageTypeChecker()
225 DeviceStorageTypeChecker::~DeviceStorageTypeChecker()
229 DeviceStorageTypeChecker
*
230 DeviceStorageTypeChecker::CreateOrGet()
232 if (sDeviceStorageTypeChecker
) {
233 return sDeviceStorageTypeChecker
;
236 MOZ_ASSERT(NS_IsMainThread());
238 nsCOMPtr
<nsIStringBundleService
> stringService
239 = mozilla::services::GetStringBundleService();
240 if (!stringService
) {
244 nsCOMPtr
<nsIStringBundle
> filterBundle
;
245 if (NS_FAILED(stringService
->CreateBundle(DEVICESTORAGE_PROPERTIES
,
246 getter_AddRefs(filterBundle
)))) {
250 DeviceStorageTypeChecker
* result
= new DeviceStorageTypeChecker();
251 result
->InitFromBundle(filterBundle
);
253 sDeviceStorageTypeChecker
= result
;
254 ClearOnShutdown(&sDeviceStorageTypeChecker
);
259 DeviceStorageTypeChecker::InitFromBundle(nsIStringBundle
* aBundle
)
261 aBundle
->GetStringFromName(
262 NS_ConvertASCIItoUTF16(DEVICESTORAGE_PICTURES
).get(),
263 getter_Copies(mPicturesExtensions
));
264 aBundle
->GetStringFromName(
265 NS_ConvertASCIItoUTF16(DEVICESTORAGE_MUSIC
).get(),
266 getter_Copies(mMusicExtensions
));
267 aBundle
->GetStringFromName(
268 NS_ConvertASCIItoUTF16(DEVICESTORAGE_VIDEOS
).get(),
269 getter_Copies(mVideosExtensions
));
274 DeviceStorageTypeChecker::Check(const nsAString
& aType
, nsIDOMBlob
* aBlob
)
279 if (NS_FAILED(aBlob
->GetType(mimeType
))) {
283 if (aType
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
284 return StringBeginsWith(mimeType
, NS_LITERAL_STRING("image/"));
287 if (aType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
288 return StringBeginsWith(mimeType
, NS_LITERAL_STRING("video/"));
291 if (aType
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
292 return StringBeginsWith(mimeType
, NS_LITERAL_STRING("audio/"));
295 if (aType
.EqualsLiteral(DEVICESTORAGE_APPS
) ||
296 aType
.EqualsLiteral(DEVICESTORAGE_SDCARD
) ||
297 aType
.EqualsLiteral(DEVICESTORAGE_CRASHES
)) {
298 // Apps, crashes and sdcard have no restriction on mime types
306 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
989 nsString volMountPoint
;
990 if (DeviceStorageTypeChecker::IsVolumeBased(aStorageType
)) {
991 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
992 NS_ENSURE_TRUE_VOID(vs
);
993 nsCOMPtr
<nsIVolume
> vol
;
994 rv
= vs
->GetVolumeByName(aStorageName
, getter_AddRefs(vol
));
996 printf_stderr("##### DeviceStorage: GetVolumeByName('%s') failed\n",
997 NS_LossyConvertUTF16toASCII(aStorageName
).get());
999 NS_ENSURE_SUCCESS_VOID(rv
);
1000 vol
->GetMountPoint(volMountPoint
);
1004 // Picture directory
1005 if (aStorageType
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
1006 #ifdef MOZ_WIDGET_GONK
1007 rv
= NS_NewLocalFile(volMountPoint
, false, getter_AddRefs(f
));
1009 printf_stderr("##### DeviceStorage: NS_NewLocalFile failed StorageType: '%s' path '%s'\n",
1010 NS_LossyConvertUTF16toASCII(volMountPoint
).get(),
1011 NS_LossyConvertUTF16toASCII(aStorageType
).get());
1014 f
= sDirs
->pictures
;
1019 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
1020 #ifdef MOZ_WIDGET_GONK
1021 rv
= NS_NewLocalFile(volMountPoint
, false, getter_AddRefs(f
));
1023 printf_stderr("##### DeviceStorage: NS_NewLocalFile failed StorageType: '%s' path '%s'\n",
1024 NS_LossyConvertUTF16toASCII(volMountPoint
).get(),
1025 NS_LossyConvertUTF16toASCII(aStorageType
).get());
1033 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
1034 #ifdef MOZ_WIDGET_GONK
1035 rv
= NS_NewLocalFile(volMountPoint
, false, getter_AddRefs(f
));
1037 printf_stderr("##### DeviceStorage: NS_NewLocalFile failed StorageType: '%s' path '%s'\n",
1038 NS_LossyConvertUTF16toASCII(volMountPoint
).get(),
1039 NS_LossyConvertUTF16toASCII(aStorageType
).get());
1047 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_APPS
)) {
1049 allowOverride
= false;
1053 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_SDCARD
)) {
1054 #ifdef MOZ_WIDGET_GONK
1055 rv
= NS_NewLocalFile(volMountPoint
, false, getter_AddRefs(f
));
1057 printf_stderr("##### DeviceStorage: NS_NewLocalFile failed StorageType: '%s' path '%s'\n",
1058 NS_LossyConvertUTF16toASCII(volMountPoint
).get(),
1059 NS_LossyConvertUTF16toASCII(aStorageType
).get());
1066 // crash reports directory.
1067 else if (aStorageType
.EqualsLiteral(DEVICESTORAGE_CRASHES
)) {
1069 allowOverride
= false;
1071 // Not a storage type that we recognize. Return null
1075 // In testing, we default all device storage types to a temp directory.
1076 // sDirs->overrideRootDir will only have been initialized (in InitDirs)
1077 // if the preference device.storage.testing was set to true, or if
1078 // device.storage.overrideRootDir is set. We can't test the preferences
1079 // directly here, since we may not be on the main thread.
1080 if (allowOverride
&& sDirs
->overrideRootDir
) {
1081 f
= sDirs
->overrideRootDir
;
1087 // This should never happen unless something is severely wrong. So
1089 printf_stderr("##### GetRootDirectoryForType('%s', '%s') failed #####",
1090 NS_LossyConvertUTF16toASCII(aStorageType
).get(),
1091 NS_LossyConvertUTF16toASCII(aStorageName
).get());
1096 already_AddRefed
<DeviceStorageFile
>
1097 DeviceStorageFile::CreateUnique(nsAString
& aFileName
,
1099 uint32_t aFileAttributes
)
1101 DeviceStorageTypeChecker
* typeChecker
1102 = DeviceStorageTypeChecker::CreateOrGet();
1103 MOZ_ASSERT(typeChecker
);
1105 nsString storageType
;
1106 typeChecker
->GetTypeFromFileName(aFileName
, storageType
);
1108 nsString storageName
;
1109 nsString storagePath
;
1110 if (!nsDOMDeviceStorage::ParseFullPath(aFileName
, storageName
, storagePath
)) {
1113 if (storageName
.IsEmpty()) {
1114 nsDOMDeviceStorage::GetDefaultStorageName(storageType
, storageName
);
1116 nsRefPtr
<DeviceStorageFile
> dsf
=
1117 new DeviceStorageFile(storageType
, storageName
, storagePath
);
1122 nsresult rv
= dsf
->mFile
->CreateUnique(aFileType
, aFileAttributes
);
1123 NS_ENSURE_SUCCESS(rv
, nullptr);
1125 // CreateUnique may cause the filename to change. So we need to update mPath
1128 dsf
->mFile
->GetLeafName(leafName
);
1130 int32_t lastSlashIndex
= dsf
->mPath
.RFindChar('/');
1131 if (lastSlashIndex
== kNotFound
) {
1132 dsf
->mPath
.Assign(leafName
);
1134 // Include the last '/'
1135 dsf
->mPath
= Substring(dsf
->mPath
, 0, lastSlashIndex
+ 1);
1136 dsf
->mPath
.Append(leafName
);
1139 return dsf
.forget();
1143 DeviceStorageFile::SetPath(const nsAString
& aPath
) {
1144 mPath
.Assign(aPath
);
1145 NormalizeFilePath();
1149 DeviceStorageFile::SetEditable(bool aEditable
) {
1150 mEditable
= aEditable
;
1153 // we want to make sure that the names of file can't reach
1154 // outside of the type of storage the user asked for.
1156 DeviceStorageFile::IsSafePath()
1158 return IsSafePath(mRootDir
) && IsSafePath(mPath
);
1162 DeviceStorageFile::IsSafePath(const nsAString
& aPath
)
1164 nsAString::const_iterator start
, end
;
1165 aPath
.BeginReading(start
);
1166 aPath
.EndReading(end
);
1168 // if the path is a '~' or starts with '~/', return false.
1169 NS_NAMED_LITERAL_STRING(tilde
, "~");
1170 NS_NAMED_LITERAL_STRING(tildeSlash
, "~/");
1171 if (aPath
.Equals(tilde
) ||
1172 StringBeginsWith(aPath
, tildeSlash
)) {
1173 NS_WARNING("Path name starts with tilde!");
1176 // split on /. if any token is "", ., or .., return false.
1177 NS_ConvertUTF16toUTF8
cname(aPath
);
1178 char* buffer
= cname
.BeginWriting();
1181 while ((token
= nsCRT::strtok(buffer
, "/", &buffer
))) {
1182 if (PL_strcmp(token
, "") == 0 ||
1183 PL_strcmp(token
, ".") == 0 ||
1184 PL_strcmp(token
, "..") == 0 ) {
1192 DeviceStorageFile::NormalizeFilePath() {
1193 FileSystemUtils::LocalPathToNormalizedPath(mPath
, mPath
);
1197 DeviceStorageFile::AppendRelativePath(const nsAString
& aPath
) {
1201 if (!IsSafePath(aPath
)) {
1202 // All of the APIs (in the child) do checks to verify that the path is
1203 // valid and return PERMISSION_DENIED if a non-safe path is entered.
1204 // This check is done in the parent and prevents a compromised
1205 // child from bypassing the check. It shouldn't be possible for this
1206 // code path to be taken with a non-compromised child.
1207 NS_WARNING("Unsafe path detected - ignoring");
1208 NS_WARNING(NS_LossyConvertUTF16toASCII(aPath
).get());
1212 FileSystemUtils::NormalizedPathToLocalPath(aPath
, localPath
);
1213 mFile
->AppendRelativePath(localPath
);
1217 DeviceStorageFile::CreateFileDescriptor(FileDescriptor
& aFileDescriptor
)
1220 return NS_ERROR_FAILURE
;
1222 ScopedPRFileDesc fd
;
1223 nsresult rv
= mFile
->OpenNSPRFileDesc(PR_RDWR
| PR_CREATE_FILE
,
1225 NS_ENSURE_SUCCESS(rv
, rv
);
1227 // NOTE: The FileDescriptor::PlatformHandleType constructor returns a dup of
1228 // the file descriptor, so we don't need the original fd after this.
1229 // Our scoped file descriptor will automatically close fd.
1230 aFileDescriptor
= FileDescriptor(
1231 FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd
)));
1236 DeviceStorageFile::Write(nsIInputStream
* aInputStream
)
1238 if (!aInputStream
|| !mFile
) {
1239 return NS_ERROR_FAILURE
;
1242 nsresult rv
= mFile
->Create(nsIFile::NORMAL_FILE_TYPE
, 00600);
1243 if (NS_WARN_IF(NS_FAILED(rv
))) {
1247 nsCOMPtr
<nsIRunnable
> iocomplete
= new IOEventComplete(this, "created");
1248 rv
= NS_DispatchToMainThread(iocomplete
);
1249 if (NS_WARN_IF(NS_FAILED(rv
))) {
1253 nsCOMPtr
<nsIOutputStream
> outputStream
;
1254 NS_NewLocalFileOutputStream(getter_AddRefs(outputStream
), mFile
);
1256 if (!outputStream
) {
1257 return NS_ERROR_FAILURE
;
1260 return Append(aInputStream
, outputStream
);
1264 DeviceStorageFile::Write(InfallibleTArray
<uint8_t>& aBits
)
1267 return NS_ERROR_FAILURE
;
1270 nsresult rv
= mFile
->Create(nsIFile::NORMAL_FILE_TYPE
, 00600);
1271 if (NS_WARN_IF(NS_FAILED(rv
))) {
1275 nsCOMPtr
<nsIRunnable
> iocomplete
= new IOEventComplete(this, "created");
1276 rv
= NS_DispatchToMainThread(iocomplete
);
1277 if (NS_WARN_IF(NS_FAILED(rv
))) {
1281 nsCOMPtr
<nsIOutputStream
> outputStream
;
1282 NS_NewLocalFileOutputStream(getter_AddRefs(outputStream
), mFile
);
1284 if (!outputStream
) {
1285 return NS_ERROR_FAILURE
;
1289 outputStream
->Write((char*) aBits
.Elements(), aBits
.Length(), &wrote
);
1290 outputStream
->Close();
1292 iocomplete
= new IOEventComplete(this, "modified");
1293 rv
= NS_DispatchToMainThread(iocomplete
);
1294 if (NS_WARN_IF(NS_FAILED(rv
))) {
1298 if (aBits
.Length() != wrote
) {
1299 return NS_ERROR_FAILURE
;
1305 DeviceStorageFile::Append(nsIInputStream
* aInputStream
)
1307 if (!aInputStream
|| !mFile
) {
1308 return NS_ERROR_FAILURE
;
1311 nsCOMPtr
<nsIOutputStream
> outputStream
;
1312 NS_NewLocalFileOutputStream(getter_AddRefs(outputStream
), mFile
, PR_WRONLY
| PR_CREATE_FILE
| PR_APPEND
, -1, 0);
1314 if (!outputStream
) {
1315 return NS_ERROR_FAILURE
;
1318 return Append(aInputStream
, outputStream
);
1323 DeviceStorageFile::Append(nsIInputStream
* aInputStream
, nsIOutputStream
* aOutputStream
)
1325 uint64_t bufSize
= 0;
1326 aInputStream
->Available(&bufSize
);
1328 nsCOMPtr
<nsIOutputStream
> bufferedOutputStream
;
1329 nsresult rv
= NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream
),
1332 NS_ENSURE_SUCCESS(rv
, rv
);
1336 rv
= bufferedOutputStream
->WriteFrom(
1338 static_cast<uint32_t>(std::min
<uint64_t>(bufSize
, UINT32_MAX
)),
1340 if (NS_FAILED(rv
)) {
1346 nsCOMPtr
<nsIRunnable
> iocomplete
= new IOEventComplete(this, "modified");
1347 rv
= NS_DispatchToMainThread(iocomplete
);
1348 if (NS_WARN_IF(NS_FAILED(rv
))) {
1352 bufferedOutputStream
->Close();
1353 aOutputStream
->Close();
1354 if (NS_WARN_IF(NS_FAILED(rv
))) {
1361 DeviceStorageFile::Remove()
1363 MOZ_ASSERT(!NS_IsMainThread());
1366 return NS_ERROR_FAILURE
;
1370 nsresult rv
= mFile
->Exists(&check
);
1371 if (NS_FAILED(rv
)) {
1379 rv
= mFile
->Remove(true);
1380 if (NS_WARN_IF(NS_FAILED(rv
))) {
1384 nsCOMPtr
<nsIRunnable
> iocomplete
= new IOEventComplete(this, "deleted");
1385 return NS_DispatchToMainThread(iocomplete
);
1389 DeviceStorageFile::CalculateMimeType()
1391 MOZ_ASSERT(NS_IsMainThread());
1394 return NS_ERROR_FAILURE
;
1396 nsAutoCString mimeType
;
1397 nsCOMPtr
<nsIMIMEService
> mimeService
=
1398 do_GetService(NS_MIMESERVICE_CONTRACTID
);
1400 nsresult rv
= mimeService
->GetTypeFromFile(mFile
, mimeType
);
1401 if (NS_FAILED(rv
)) {
1402 mimeType
.Truncate();
1407 mMimeType
= NS_ConvertUTF8toUTF16(mimeType
);
1412 DeviceStorageFile::CalculateSizeAndModifiedDate()
1414 MOZ_ASSERT(!NS_IsMainThread());
1417 return NS_ERROR_FAILURE
;
1421 nsresult rv
= mFile
->GetFileSize(&fileSize
);
1422 NS_ENSURE_SUCCESS(rv
, rv
);
1427 rv
= mFile
->GetLastModifiedTime(&modDate
);
1428 NS_ENSURE_SUCCESS(rv
, rv
);
1430 mLastModifiedDate
= modDate
;
1435 DeviceStorageFile::CollectFiles(nsTArray
<nsRefPtr
<DeviceStorageFile
> > &aFiles
,
1441 nsString fullRootPath
;
1442 mFile
->GetPath(fullRootPath
);
1443 collectFilesInternal(aFiles
, aSince
, fullRootPath
);
1447 DeviceStorageFile::collectFilesInternal(
1448 nsTArray
<nsRefPtr
<DeviceStorageFile
> > &aFiles
,
1450 nsAString
& aRootPath
)
1452 if (!mFile
|| !IsAvailable()) {
1456 nsCOMPtr
<nsISimpleEnumerator
> e
;
1457 mFile
->GetDirectoryEntries(getter_AddRefs(e
));
1463 nsCOMPtr
<nsIDirectoryEnumerator
> files
= do_QueryInterface(e
);
1464 nsCOMPtr
<nsIFile
> f
;
1466 while (NS_SUCCEEDED(files
->GetNextFile(getter_AddRefs(f
))) && f
) {
1473 f
->GetLastModifiedTime(&msecs
);
1475 if (msecs
< aSince
) {
1481 f
->IsDirectory(&isDir
);
1484 nsresult rv
= f
->GetPath(fullpath
);
1485 if (NS_FAILED(rv
)) {
1489 if (!StringBeginsWith(fullpath
, aRootPath
)) {
1490 NS_ERROR("collectFiles returned a path that does not belong!");
1494 nsAString::size_type len
= aRootPath
.Length() + 1; // +1 for the trailing /
1495 nsDependentSubstring newPath
= Substring(fullpath
, len
);
1498 DeviceStorageFile
dsf(mStorageType
, mStorageName
, mRootDir
, newPath
);
1499 dsf
.collectFilesInternal(aFiles
, aSince
, aRootPath
);
1500 } else if (isFile
) {
1501 nsRefPtr
<DeviceStorageFile
> dsf
=
1502 new DeviceStorageFile(mStorageType
, mStorageName
, mRootDir
, newPath
);
1503 dsf
->CalculateSizeAndModifiedDate();
1504 aFiles
.AppendElement(dsf
);
1510 DeviceStorageFile::AccumDiskUsage(uint64_t* aPicturesSoFar
,
1511 uint64_t* aVideosSoFar
,
1512 uint64_t* aMusicSoFar
,
1513 uint64_t* aTotalSoFar
)
1515 if (!IsAvailable()) {
1519 uint64_t pictureUsage
= 0, videoUsage
= 0, musicUsage
= 0, totalUsage
= 0;
1521 if (DeviceStorageTypeChecker::IsVolumeBased(mStorageType
)) {
1522 DeviceStorageUsedSpaceCache
* usedSpaceCache
=
1523 DeviceStorageUsedSpaceCache::CreateOrGet();
1524 MOZ_ASSERT(usedSpaceCache
);
1525 nsresult rv
= usedSpaceCache
->AccumUsedSizes(mStorageName
,
1526 aPicturesSoFar
, aVideosSoFar
,
1527 aMusicSoFar
, aTotalSoFar
);
1528 if (NS_SUCCEEDED(rv
)) {
1531 AccumDirectoryUsage(mFile
, &pictureUsage
, &videoUsage
,
1532 &musicUsage
, &totalUsage
);
1533 usedSpaceCache
->SetUsedSizes(mStorageName
, pictureUsage
, videoUsage
,
1534 musicUsage
, totalUsage
);
1536 AccumDirectoryUsage(mFile
, &pictureUsage
, &videoUsage
,
1537 &musicUsage
, &totalUsage
);
1540 *aPicturesSoFar
+= pictureUsage
;
1541 *aVideosSoFar
+= videoUsage
;
1542 *aMusicSoFar
+= musicUsage
;
1543 *aTotalSoFar
+= totalUsage
;
1547 DeviceStorageFile::AccumDirectoryUsage(nsIFile
* aFile
,
1548 uint64_t* aPicturesSoFar
,
1549 uint64_t* aVideosSoFar
,
1550 uint64_t* aMusicSoFar
,
1551 uint64_t* aTotalSoFar
)
1558 nsCOMPtr
<nsISimpleEnumerator
> e
;
1559 rv
= aFile
->GetDirectoryEntries(getter_AddRefs(e
));
1561 if (NS_FAILED(rv
) || !e
) {
1565 nsCOMPtr
<nsIDirectoryEnumerator
> files
= do_QueryInterface(e
);
1568 nsCOMPtr
<nsIFile
> f
;
1569 while (NS_SUCCEEDED(files
->GetNextFile(getter_AddRefs(f
))) && f
) {
1571 rv
= f
->IsDirectory(&isDir
);
1572 if (NS_FAILED(rv
)) {
1577 rv
= f
->IsFile(&isFile
);
1578 if (NS_FAILED(rv
)) {
1583 rv
= f
->IsSymlink(&isLink
);
1584 if (NS_FAILED(rv
)) {
1589 // for now, lets just totally ignore symlinks.
1590 NS_WARNING("DirectoryDiskUsage ignores symlinks");
1592 AccumDirectoryUsage(f
, aPicturesSoFar
, aVideosSoFar
,
1593 aMusicSoFar
, aTotalSoFar
);
1594 } else if (isFile
) {
1597 rv
= f
->GetFileSize(&size
);
1598 if (NS_FAILED(rv
)) {
1601 DeviceStorageTypeChecker
* typeChecker
1602 = DeviceStorageTypeChecker::CreateOrGet();
1603 MOZ_ASSERT(typeChecker
);
1605 typeChecker
->GetTypeFromFile(f
, type
);
1607 if (type
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
1608 *aPicturesSoFar
+= size
;
1610 else if (type
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
1611 *aVideosSoFar
+= size
;
1613 else if (type
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
1614 *aMusicSoFar
+= size
;
1616 *aTotalSoFar
+= size
;
1622 DeviceStorageFile::GetDiskFreeSpace(int64_t* aSoFar
)
1624 DeviceStorageTypeChecker
* typeChecker
1625 = DeviceStorageTypeChecker::CreateOrGet();
1629 if (!mFile
|| !IsAvailable()) {
1633 int64_t storageAvail
= 0;
1634 nsresult rv
= mFile
->GetDiskSpaceAvailable(&storageAvail
);
1635 if (NS_SUCCEEDED(rv
)) {
1636 *aSoFar
+= storageAvail
;
1641 DeviceStorageFile::IsAvailable()
1645 return status
.EqualsLiteral("available");
1649 DeviceStorageFile::DoFormat(nsAString
& aStatus
)
1651 DeviceStorageTypeChecker
* typeChecker
1652 = DeviceStorageTypeChecker::CreateOrGet();
1653 if (!typeChecker
|| !mFile
) {
1656 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1657 aStatus
.AssignLiteral("notVolume");
1660 #ifdef MOZ_WIDGET_GONK
1661 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1662 NS_ENSURE_TRUE_VOID(vs
);
1664 nsCOMPtr
<nsIVolume
> vol
;
1665 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1666 NS_ENSURE_SUCCESS_VOID(rv
);
1673 aStatus
.AssignLiteral("formatting");
1679 DeviceStorageFile::DoMount(nsAString
& aStatus
)
1681 DeviceStorageTypeChecker
* typeChecker
1682 = DeviceStorageTypeChecker::CreateOrGet();
1683 if (!typeChecker
|| !mFile
) {
1686 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1687 aStatus
.AssignLiteral("notVolume");
1690 #ifdef MOZ_WIDGET_GONK
1691 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1692 NS_ENSURE_TRUE_VOID(vs
);
1694 nsCOMPtr
<nsIVolume
> vol
;
1695 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1696 NS_ENSURE_SUCCESS_VOID(rv
);
1703 aStatus
.AssignLiteral("mounting");
1709 DeviceStorageFile::DoUnmount(nsAString
& aStatus
)
1711 DeviceStorageTypeChecker
* typeChecker
1712 = DeviceStorageTypeChecker::CreateOrGet();
1713 if (!typeChecker
|| !mFile
) {
1716 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1717 aStatus
.AssignLiteral("notVolume");
1720 #ifdef MOZ_WIDGET_GONK
1721 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1722 NS_ENSURE_TRUE_VOID(vs
);
1724 nsCOMPtr
<nsIVolume
> vol
;
1725 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1726 NS_ENSURE_SUCCESS_VOID(rv
);
1733 aStatus
.AssignLiteral("unmounting");
1739 DeviceStorageFile::GetStatus(nsAString
& aStatus
)
1741 aStatus
.AssignLiteral("unavailable");
1743 DeviceStorageTypeChecker
* typeChecker
1744 = DeviceStorageTypeChecker::CreateOrGet();
1745 if (!typeChecker
|| !mFile
) {
1748 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1749 aStatus
.AssignLiteral("available");
1753 #ifdef MOZ_WIDGET_GONK
1754 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1755 NS_ENSURE_TRUE_VOID(vs
);
1757 nsCOMPtr
<nsIVolume
> vol
;
1758 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1759 NS_ENSURE_SUCCESS_VOID(rv
);
1763 bool isMediaPresent
;
1764 rv
= vol
->GetIsMediaPresent(&isMediaPresent
);
1765 NS_ENSURE_SUCCESS_VOID(rv
);
1766 if (!isMediaPresent
) {
1770 rv
= vol
->GetIsSharing(&isSharing
);
1771 NS_ENSURE_SUCCESS_VOID(rv
);
1773 aStatus
.AssignLiteral("shared");
1777 rv
= vol
->GetIsFormatting(&isFormatting
);
1778 NS_ENSURE_SUCCESS_VOID(rv
);
1780 aStatus
.AssignLiteral("unavailable");
1784 rv
= vol
->GetIsUnmounting(&isUnmounting
);
1785 NS_ENSURE_SUCCESS_VOID(rv
);
1787 aStatus
.AssignLiteral("unavailable");
1791 rv
= vol
->GetState(&volState
);
1792 NS_ENSURE_SUCCESS_VOID(rv
);
1793 if (volState
== nsIVolume::STATE_MOUNTED
) {
1794 aStatus
.AssignLiteral("available");
1800 DeviceStorageFile::GetStorageStatus(nsAString
& aStatus
)
1802 aStatus
.AssignLiteral("undefined");
1804 DeviceStorageTypeChecker
* typeChecker
1805 = DeviceStorageTypeChecker::CreateOrGet();
1806 if (!typeChecker
|| !mFile
) {
1809 if (!typeChecker
->IsVolumeBased(mStorageType
)) {
1810 aStatus
.AssignLiteral("available");
1814 #ifdef MOZ_WIDGET_GONK
1815 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
1816 NS_ENSURE_TRUE_VOID(vs
);
1818 nsCOMPtr
<nsIVolume
> vol
;
1819 nsresult rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
1820 NS_ENSURE_SUCCESS_VOID(rv
);
1826 rv
= vol
->GetState(&volState
);
1827 NS_ENSURE_SUCCESS_VOID(rv
);
1828 aStatus
.AssignASCII(mozilla::system::NS_VolumeStateStr(volState
));
1832 NS_IMPL_ISUPPORTS0(DeviceStorageFile
)
1835 RegisterForSDCardChanges(nsIObserver
* aObserver
)
1837 #ifdef MOZ_WIDGET_GONK
1838 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
1839 obs
->AddObserver(aObserver
, NS_VOLUME_STATE_CHANGED
, false);
1844 UnregisterForSDCardChanges(nsIObserver
* aObserver
)
1846 #ifdef MOZ_WIDGET_GONK
1847 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
1848 obs
->RemoveObserver(aObserver
, NS_VOLUME_STATE_CHANGED
);
1853 nsDOMDeviceStorage::SetRootDirectoryForType(const nsAString
& aStorageType
,
1854 const nsAString
& aStorageName
)
1856 MOZ_ASSERT(NS_IsMainThread());
1858 nsCOMPtr
<nsIFile
> f
;
1859 DeviceStorageFile::GetRootDirectoryForType(aStorageType
,
1862 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
1863 obs
->AddObserver(this, kFileWatcherUpdate
, false);
1864 obs
->AddObserver(this, "disk-space-watcher", false);
1866 mStorageType
= aStorageType
;
1867 mStorageName
= aStorageName
;
1871 InterfaceToJsval(nsPIDOMWindow
* aWindow
,
1872 nsISupports
* aObject
,
1875 nsCOMPtr
<nsIScriptGlobalObject
> sgo
= do_QueryInterface(aWindow
);
1877 return JS::NullValue();
1880 JSObject
*unrootedScopeObj
= sgo
->GetGlobalJSObject();
1881 NS_ENSURE_TRUE(unrootedScopeObj
, JS::NullValue());
1882 JSRuntime
*runtime
= JS_GetObjectRuntime(unrootedScopeObj
);
1883 JS::Rooted
<JS::Value
> someJsVal(runtime
);
1884 JS::Rooted
<JSObject
*> scopeObj(runtime
, unrootedScopeObj
);
1887 { // Protect someJsVal from moving GC in ~JSAutoCompartment
1889 JSAutoCompartment
ac(cx
, scopeObj
);
1891 rv
= nsContentUtils::WrapNative(cx
, aObject
, aIID
, &someJsVal
);
1893 if (NS_FAILED(rv
)) {
1894 return JS::NullValue();
1901 nsIFileToJsval(nsPIDOMWindow
* aWindow
, DeviceStorageFile
* aFile
)
1903 MOZ_ASSERT(NS_IsMainThread());
1904 MOZ_ASSERT(aWindow
);
1910 if (aFile
->mEditable
) {
1911 // TODO - needs janv's file handle support.
1916 aFile
->GetFullPath(fullPath
);
1918 // This check is useful to know if somewhere the DeviceStorageFile
1919 // has not been properly set. Mimetype is not checked because it can be
1921 MOZ_ASSERT(aFile
->mLength
!= UINT64_MAX
);
1922 MOZ_ASSERT(aFile
->mLastModifiedDate
!= UINT64_MAX
);
1924 nsCOMPtr
<nsIDOMBlob
> blob
= new File(aWindow
,
1925 new FileImplFile(fullPath
, aFile
->mMimeType
,
1926 aFile
->mLength
, aFile
->mFile
,
1927 aFile
->mLastModifiedDate
));
1928 return InterfaceToJsval(aWindow
, blob
, &NS_GET_IID(nsIDOMBlob
));
1932 StringToJsval(nsPIDOMWindow
* aWindow
, nsAString
& aString
,
1933 JS::MutableHandle
<JS::Value
> result
)
1935 MOZ_ASSERT(NS_IsMainThread());
1936 MOZ_ASSERT(aWindow
);
1939 if (NS_WARN_IF(!jsapi
.Init(aWindow
))) {
1942 JSContext
* cx
= jsapi
.cx();
1944 if (!xpc::StringToJsval(cx
, aString
, result
)) {
1951 class DeviceStorageCursorRequest MOZ_FINAL
1952 : public nsIContentPermissionRequest
1955 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
1956 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageCursorRequest
,
1957 nsIContentPermissionRequest
)
1959 NS_FORWARD_NSICONTENTPERMISSIONREQUEST(mCursor
->);
1961 explicit DeviceStorageCursorRequest(nsDOMDeviceStorageCursor
* aCursor
)
1962 : mCursor(aCursor
) { }
1965 ~DeviceStorageCursorRequest() {}
1967 nsRefPtr
<nsDOMDeviceStorageCursor
> mCursor
;
1970 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageCursorRequest
)
1971 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIContentPermissionRequest
)
1972 NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest
)
1973 NS_INTERFACE_MAP_END
1975 NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageCursorRequest
)
1976 NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageCursorRequest
)
1978 NS_IMPL_CYCLE_COLLECTION(DeviceStorageCursorRequest
,
1982 class PostErrorEvent
: public nsRunnable
1985 PostErrorEvent(already_AddRefed
<DOMRequest
> aRequest
, const char* aMessage
)
1986 : mRequest(aRequest
)
1988 CopyASCIItoUTF16(aMessage
, mError
);
1991 PostErrorEvent(DOMRequest
* aRequest
, const char* aMessage
)
1992 : mRequest(aRequest
)
1994 CopyASCIItoUTF16(aMessage
, mError
);
1997 ~PostErrorEvent() {}
2001 MOZ_ASSERT(NS_IsMainThread());
2002 if (!mRequest
->GetOwner()) {
2005 mRequest
->FireError(mError
);
2011 nsRefPtr
<DOMRequest
> mRequest
;
2015 ContinueCursorEvent::ContinueCursorEvent(already_AddRefed
<DOMRequest
> aRequest
)
2016 : mRequest(aRequest
)
2020 ContinueCursorEvent::ContinueCursorEvent(DOMRequest
* aRequest
)
2021 : mRequest(aRequest
)
2025 already_AddRefed
<DeviceStorageFile
>
2026 ContinueCursorEvent::GetNextFile()
2028 MOZ_ASSERT(NS_IsMainThread());
2030 nsDOMDeviceStorageCursor
* cursor
2031 = static_cast<nsDOMDeviceStorageCursor
*>(mRequest
.get());
2032 nsString cursorStorageType
;
2033 cursor
->GetStorageType(cursorStorageType
);
2035 DeviceStorageTypeChecker
* typeChecker
2036 = DeviceStorageTypeChecker::CreateOrGet();
2041 while (cursor
->mFiles
.Length() > 0) {
2042 nsRefPtr
<DeviceStorageFile
> file
= cursor
->mFiles
[0];
2043 cursor
->mFiles
.RemoveElementAt(0);
2044 if (!typeChecker
->Check(cursorStorageType
, file
->mFile
)) {
2048 file
->CalculateMimeType();
2049 return file
.forget();
2055 ContinueCursorEvent::~ContinueCursorEvent() {}
2058 ContinueCursorEvent::Continue()
2060 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
2061 DebugOnly
<nsresult
> rv
= NS_DispatchToMainThread(this);
2062 MOZ_ASSERT(NS_SUCCEEDED(rv
));
2066 nsRefPtr
<DeviceStorageFile
> file
= GetNextFile();
2069 // done with enumeration.
2070 DebugOnly
<nsresult
> rv
= NS_DispatchToMainThread(this);
2071 MOZ_ASSERT(NS_SUCCEEDED(rv
));
2075 nsDOMDeviceStorageCursor
* cursor
2076 = static_cast<nsDOMDeviceStorageCursor
*>(mRequest
.get());
2077 nsString cursorStorageType
;
2078 cursor
->GetStorageType(cursorStorageType
);
2080 DeviceStorageRequestChild
* child
2081 = new DeviceStorageRequestChild(mRequest
, file
);
2082 child
->SetCallback(cursor
);
2083 DeviceStorageGetParams
params(cursorStorageType
,
2087 ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child
,
2093 ContinueCursorEvent::Run()
2095 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2100 nsRefPtr
<DeviceStorageFile
> file
= GetNextFile();
2102 nsDOMDeviceStorageCursor
* cursor
2103 = static_cast<nsDOMDeviceStorageCursor
*>(mRequest
.get());
2106 JS::Rooted
<JS::Value
> val(cx
, nsIFileToJsval(window
, file
));
2109 cursor
->mOkToCallContinue
= true;
2110 cursor
->FireSuccess(val
);
2118 class InitCursorEvent
: public nsRunnable
2121 InitCursorEvent(DOMRequest
* aRequest
, DeviceStorageFile
* aFile
)
2123 , mRequest(aRequest
)
2127 ~InitCursorEvent() {}
2130 MOZ_ASSERT(!NS_IsMainThread());
2134 mFile
->mFile
->IsDirectory(&check
);
2136 nsCOMPtr
<nsIRunnable
> event
=
2137 new PostErrorEvent(mRequest
.forget(),
2138 POST_ERROR_EVENT_FILE_NOT_ENUMERABLE
);
2139 return NS_DispatchToMainThread(event
);
2143 nsDOMDeviceStorageCursor
* cursor
2144 = static_cast<nsDOMDeviceStorageCursor
*>(mRequest
.get());
2145 mFile
->CollectFiles(cursor
->mFiles
, cursor
->mSince
);
2147 nsRefPtr
<ContinueCursorEvent
> event
2148 = new ContinueCursorEvent(mRequest
.forget());
2156 nsRefPtr
<DeviceStorageFile
> mFile
;
2157 nsRefPtr
<DOMRequest
> mRequest
;
2160 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDeviceStorageCursor
)
2161 NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest
)
2162 NS_INTERFACE_MAP_END_INHERITING(DOMCursor
)
2164 NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageCursor
, DOMCursor
)
2165 NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageCursor
, DOMCursor
)
2167 nsDOMDeviceStorageCursor::nsDOMDeviceStorageCursor(nsPIDOMWindow
* aWindow
,
2168 nsIPrincipal
* aPrincipal
,
2169 DeviceStorageFile
* aFile
,
2171 : DOMCursor(aWindow
, nullptr)
2172 , mOkToCallContinue(false)
2175 , mPrincipal(aPrincipal
)
2179 nsDOMDeviceStorageCursor::~nsDOMDeviceStorageCursor()
2184 nsDOMDeviceStorageCursor::GetStorageType(nsAString
& aType
)
2186 aType
= mFile
->mStorageType
;
2190 nsDOMDeviceStorageCursor::GetTypes(nsIArray
** aTypes
)
2194 DeviceStorageTypeChecker::GetPermissionForType(mFile
->mStorageType
, type
);
2195 NS_ENSURE_SUCCESS(rv
, rv
);
2197 nsTArray
<nsString
> emptyOptions
;
2198 return nsContentPermissionUtils::CreatePermissionArray(type
,
2199 NS_LITERAL_CSTRING("read"),
2205 nsDOMDeviceStorageCursor::GetPrincipal(nsIPrincipal
** aRequestingPrincipal
)
2207 NS_IF_ADDREF(*aRequestingPrincipal
= mPrincipal
);
2212 nsDOMDeviceStorageCursor::GetWindow(nsIDOMWindow
** aRequestingWindow
)
2214 NS_IF_ADDREF(*aRequestingWindow
= GetOwner());
2219 nsDOMDeviceStorageCursor::GetElement(nsIDOMElement
** aRequestingElement
)
2221 *aRequestingElement
= nullptr;
2226 nsDOMDeviceStorageCursor::Cancel()
2228 nsCOMPtr
<nsIRunnable
> event
2229 = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED
);
2230 return NS_DispatchToMainThread(event
);
2234 nsDOMDeviceStorageCursor::Allow(JS::HandleValue aChoices
)
2236 MOZ_ASSERT(aChoices
.isUndefined());
2238 if (!mFile
->IsSafePath()) {
2239 nsCOMPtr
<nsIRunnable
> r
2240 = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED
);
2241 return NS_DispatchToMainThread(r
);
2244 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
2245 PDeviceStorageRequestChild
* child
2246 = new DeviceStorageRequestChild(this, mFile
);
2247 DeviceStorageEnumerationParams
params(mFile
->mStorageType
,
2248 mFile
->mStorageName
,
2251 ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child
,
2256 nsCOMPtr
<nsIEventTarget
> target
2257 = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
2260 nsCOMPtr
<nsIRunnable
> event
= new InitCursorEvent(this, mFile
);
2261 target
->Dispatch(event
, NS_DISPATCH_NORMAL
);
2266 nsDOMDeviceStorageCursor::Continue(ErrorResult
& aRv
)
2268 if (!mOkToCallContinue
) {
2269 aRv
.Throw(NS_ERROR_UNEXPECTED
);
2273 if (mResult
!= JSVAL_VOID
) {
2274 // We call onsuccess multiple times. Clear the last
2276 mResult
= JSVAL_VOID
;
2280 nsRefPtr
<ContinueCursorEvent
> event
= new ContinueCursorEvent(this);
2283 mOkToCallContinue
= false;
2287 nsDOMDeviceStorageCursor::RequestComplete()
2289 MOZ_ASSERT(!mOkToCallContinue
);
2290 mOkToCallContinue
= true;
2293 class PostAvailableResultEvent
: public nsRunnable
2296 PostAvailableResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2298 , mRequest(aRequest
)
2300 MOZ_ASSERT(mRequest
);
2303 ~PostAvailableResultEvent() {}
2307 MOZ_ASSERT(NS_IsMainThread());
2308 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2313 nsString state
= NS_LITERAL_STRING("unavailable");
2315 mFile
->GetStatus(state
);
2319 JS::Rooted
<JS::Value
> result(cx
);
2320 StringToJsval(window
, state
, &result
);
2321 mRequest
->FireSuccess(result
);
2327 nsRefPtr
<DeviceStorageFile
> mFile
;
2328 nsRefPtr
<DOMRequest
> mRequest
;
2331 class PostStatusResultEvent
: public nsRunnable
2334 PostStatusResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2336 , mRequest(aRequest
)
2338 MOZ_ASSERT(mRequest
);
2341 ~PostStatusResultEvent() {}
2345 MOZ_ASSERT(NS_IsMainThread());
2346 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2351 nsString state
= NS_LITERAL_STRING("undefined");
2353 mFile
->GetStorageStatus(state
);
2357 JS::Rooted
<JS::Value
> result(cx
);
2358 StringToJsval(window
, state
, &result
);
2359 mRequest
->FireSuccess(result
);
2365 nsRefPtr
<DeviceStorageFile
> mFile
;
2366 nsRefPtr
<DOMRequest
> mRequest
;
2369 class PostFormatResultEvent
: public nsRunnable
2372 PostFormatResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2374 , mRequest(aRequest
)
2376 MOZ_ASSERT(mRequest
);
2379 ~PostFormatResultEvent() {}
2383 MOZ_ASSERT(NS_IsMainThread());
2384 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2389 nsString state
= NS_LITERAL_STRING("unavailable");
2391 mFile
->DoFormat(state
);
2395 JS::Rooted
<JS::Value
> result(cx
);
2396 StringToJsval(window
, state
, &result
);
2397 mRequest
->FireSuccess(result
);
2403 nsRefPtr
<DeviceStorageFile
> mFile
;
2404 nsRefPtr
<DOMRequest
> mRequest
;
2407 class PostMountResultEvent
: public nsRunnable
2410 PostMountResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2412 , mRequest(aRequest
)
2414 MOZ_ASSERT(mRequest
);
2417 ~PostMountResultEvent() {}
2421 MOZ_ASSERT(NS_IsMainThread());
2422 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2427 nsString state
= NS_LITERAL_STRING("unavailable");
2429 mFile
->DoMount(state
);
2433 JS::Rooted
<JS::Value
> result(cx
);
2434 StringToJsval(window
, state
, &result
);
2435 mRequest
->FireSuccess(result
);
2441 nsRefPtr
<DeviceStorageFile
> mFile
;
2442 nsRefPtr
<DOMRequest
> mRequest
;
2445 class PostUnmountResultEvent
: public nsRunnable
2448 PostUnmountResultEvent(DeviceStorageFile
*aFile
, DOMRequest
* aRequest
)
2450 , mRequest(aRequest
)
2452 MOZ_ASSERT(mRequest
);
2455 ~PostUnmountResultEvent() {}
2459 MOZ_ASSERT(NS_IsMainThread());
2460 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2465 nsString state
= NS_LITERAL_STRING("unavailable");
2467 mFile
->DoUnmount(state
);
2471 JS::Rooted
<JS::Value
> result(cx
);
2472 StringToJsval(window
, state
, &result
);
2473 mRequest
->FireSuccess(result
);
2479 nsRefPtr
<DeviceStorageFile
> mFile
;
2480 nsRefPtr
<DOMRequest
> mRequest
;
2483 class PostResultEvent
: public nsRunnable
2486 PostResultEvent(already_AddRefed
<DOMRequest
> aRequest
,
2487 DeviceStorageFile
* aFile
)
2489 , mRequest(aRequest
)
2491 MOZ_ASSERT(mRequest
);
2494 PostResultEvent(already_AddRefed
<DOMRequest
> aRequest
,
2495 const nsAString
& aPath
)
2497 , mRequest(aRequest
)
2499 MOZ_ASSERT(mRequest
);
2502 PostResultEvent(already_AddRefed
<DOMRequest
> aRequest
,
2503 const uint64_t aValue
)
2505 , mRequest(aRequest
)
2507 MOZ_ASSERT(mRequest
);
2510 ~PostResultEvent() {}
2514 MOZ_ASSERT(NS_IsMainThread());
2515 nsCOMPtr
<nsPIDOMWindow
> window
= mRequest
->GetOwner();
2521 JS::Rooted
<JS::Value
> result(cx
, JSVAL_NULL
);
2524 result
= nsIFileToJsval(window
, mFile
);
2525 } else if (mPath
.Length()) {
2526 StringToJsval(window
, mPath
, &result
);
2529 result
= JS_NumberValue(double(mValue
));
2532 mRequest
->FireSuccess(result
);
2538 nsRefPtr
<DeviceStorageFile
> mFile
;
2541 nsRefPtr
<DOMRequest
> mRequest
;
2544 class CreateFdEvent
: public nsRunnable
2547 CreateFdEvent(DeviceStorageFileDescriptor
* aDSFileDescriptor
,
2548 already_AddRefed
<DOMRequest
> aRequest
)
2549 : mDSFileDescriptor(aDSFileDescriptor
)
2550 , mRequest(aRequest
)
2552 MOZ_ASSERT(mDSFileDescriptor
);
2553 MOZ_ASSERT(mDSFileDescriptor
->mDSFile
);
2554 MOZ_ASSERT(mDSFileDescriptor
->mDSFile
->mFile
);
2555 MOZ_ASSERT(mRequest
);
2560 MOZ_ASSERT(!NS_IsMainThread());
2562 DeviceStorageFile
* dsFile
= mDSFileDescriptor
->mDSFile
;
2565 dsFile
->GetFullPath(fullPath
);
2566 MOZ_ASSERT(!fullPath
.IsEmpty());
2569 dsFile
->mFile
->Exists(&check
);
2571 nsCOMPtr
<nsIRunnable
> event
=
2572 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_FILE_EXISTS
);
2573 return NS_DispatchToMainThread(event
);
2576 nsresult rv
= dsFile
->CreateFileDescriptor(mDSFileDescriptor
->mFileDescriptor
);
2578 if (NS_FAILED(rv
)) {
2579 dsFile
->mFile
->Remove(false);
2581 nsCOMPtr
<nsIRunnable
> event
=
2582 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_UNKNOWN
);
2583 return NS_DispatchToMainThread(event
);
2586 nsCOMPtr
<nsIRunnable
> event
=
2587 new PostResultEvent(mRequest
.forget(), fullPath
);
2588 return NS_DispatchToMainThread(event
);
2592 nsRefPtr
<DeviceStorageFileDescriptor
> mDSFileDescriptor
;
2593 nsRefPtr
<DOMRequest
> mRequest
;
2596 class WriteFileEvent
: public nsRunnable
2599 WriteFileEvent(FileImpl
* aBlobImpl
,
2600 DeviceStorageFile
*aFile
,
2601 already_AddRefed
<DOMRequest
> aRequest
,
2602 int32_t aRequestType
)
2603 : mBlobImpl(aBlobImpl
)
2605 , mRequest(aRequest
)
2606 , mRequestType(aRequestType
)
2609 MOZ_ASSERT(mFile
->mFile
);
2610 MOZ_ASSERT(mRequest
);
2611 MOZ_ASSERT(mRequestType
);
2614 ~WriteFileEvent() {}
2618 MOZ_ASSERT(!NS_IsMainThread());
2620 nsCOMPtr
<nsIInputStream
> stream
;
2621 mBlobImpl
->GetInternalStream(getter_AddRefs(stream
));
2624 mFile
->mFile
->Exists(&check
);
2627 if (mRequestType
== DEVICE_STORAGE_REQUEST_APPEND
) {
2629 nsCOMPtr
<nsIRunnable
> event
=
2630 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_FILE_DOES_NOT_EXIST
);
2631 return NS_DispatchToMainThread(event
);
2633 rv
= mFile
->Append(stream
);
2635 else if (mRequestType
== DEVICE_STORAGE_REQUEST_CREATE
) {
2637 nsCOMPtr
<nsIRunnable
> event
=
2638 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_FILE_EXISTS
);
2639 return NS_DispatchToMainThread(event
);
2641 rv
= mFile
->Write(stream
);
2642 if (NS_FAILED(rv
)) {
2643 mFile
->mFile
->Remove(false);
2646 nsCOMPtr
<nsIRunnable
> event
=
2647 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_UNKNOWN
);
2648 return NS_DispatchToMainThread(event
);
2651 if (NS_FAILED(rv
)) {
2652 nsCOMPtr
<nsIRunnable
> event
=
2653 new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_UNKNOWN
);
2654 return NS_DispatchToMainThread(event
);
2658 mFile
->GetFullPath(fullPath
);
2659 nsCOMPtr
<nsIRunnable
> event
=
2660 new PostResultEvent(mRequest
.forget(), fullPath
);
2661 return NS_DispatchToMainThread(event
);
2665 nsRefPtr
<FileImpl
> mBlobImpl
;
2666 nsRefPtr
<DeviceStorageFile
> mFile
;
2667 nsRefPtr
<DOMRequest
> mRequest
;
2668 int32_t mRequestType
;
2672 class ReadFileEvent
: public nsRunnable
2675 ReadFileEvent(DeviceStorageFile
* aFile
,
2676 already_AddRefed
<DOMRequest
> aRequest
)
2678 , mRequest(aRequest
)
2681 MOZ_ASSERT(mRequest
);
2682 mFile
->CalculateMimeType();
2689 MOZ_ASSERT(!NS_IsMainThread());
2691 nsCOMPtr
<nsIRunnable
> r
;
2692 if (!mFile
->mEditable
) {
2694 mFile
->mFile
->Exists(&check
);
2696 r
= new PostErrorEvent(mRequest
.forget(),
2697 POST_ERROR_EVENT_FILE_DOES_NOT_EXIST
);
2702 nsresult rv
= mFile
->CalculateSizeAndModifiedDate();
2703 if (NS_FAILED(rv
)) {
2704 r
= new PostErrorEvent(mRequest
.forget(), POST_ERROR_EVENT_UNKNOWN
);
2709 r
= new PostResultEvent(mRequest
.forget(), mFile
);
2711 return NS_DispatchToMainThread(r
);
2715 nsRefPtr
<DeviceStorageFile
> mFile
;
2716 nsRefPtr
<DOMRequest
> mRequest
;
2719 class DeleteFileEvent
: public nsRunnable
2722 DeleteFileEvent(DeviceStorageFile
* aFile
,
2723 already_AddRefed
<DOMRequest
> aRequest
)
2725 , mRequest(aRequest
)
2728 MOZ_ASSERT(mRequest
);
2731 ~DeleteFileEvent() {}
2735 MOZ_ASSERT(!NS_IsMainThread());
2738 nsCOMPtr
<nsIRunnable
> r
;
2740 mFile
->mFile
->Exists(&check
);
2742 r
= new PostErrorEvent(mRequest
.forget(),
2743 POST_ERROR_EVENT_FILE_DOES_NOT_EXIST
);
2747 mFile
->GetFullPath(fullPath
);
2748 r
= new PostResultEvent(mRequest
.forget(), fullPath
);
2750 return NS_DispatchToMainThread(r
);
2754 nsRefPtr
<DeviceStorageFile
> mFile
;
2755 nsRefPtr
<DOMRequest
> mRequest
;
2758 class UsedSpaceFileEvent
: public nsRunnable
2761 UsedSpaceFileEvent(DeviceStorageFile
* aFile
,
2762 already_AddRefed
<DOMRequest
> aRequest
)
2764 , mRequest(aRequest
)
2767 MOZ_ASSERT(mRequest
);
2770 ~UsedSpaceFileEvent() {}
2774 MOZ_ASSERT(!NS_IsMainThread());
2776 uint64_t picturesUsage
= 0, videosUsage
= 0, musicUsage
= 0, totalUsage
= 0;
2777 mFile
->AccumDiskUsage(&picturesUsage
, &videosUsage
,
2778 &musicUsage
, &totalUsage
);
2779 nsCOMPtr
<nsIRunnable
> r
;
2780 if (mFile
->mStorageType
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
2781 r
= new PostResultEvent(mRequest
.forget(), picturesUsage
);
2783 else if (mFile
->mStorageType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
2784 r
= new PostResultEvent(mRequest
.forget(), videosUsage
);
2786 else if (mFile
->mStorageType
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
2787 r
= new PostResultEvent(mRequest
.forget(), musicUsage
);
2789 r
= new PostResultEvent(mRequest
.forget(), totalUsage
);
2791 return NS_DispatchToMainThread(r
);
2795 nsRefPtr
<DeviceStorageFile
> mFile
;
2796 nsRefPtr
<DOMRequest
> mRequest
;
2799 class FreeSpaceFileEvent
: public nsRunnable
2802 FreeSpaceFileEvent(DeviceStorageFile
* aFile
,
2803 already_AddRefed
<DOMRequest
> aRequest
)
2805 , mRequest(aRequest
)
2808 MOZ_ASSERT(mRequest
);
2811 ~FreeSpaceFileEvent() {}
2815 MOZ_ASSERT(!NS_IsMainThread());
2817 int64_t freeSpace
= 0;
2819 mFile
->GetDiskFreeSpace(&freeSpace
);
2822 nsCOMPtr
<nsIRunnable
> r
;
2823 r
= new PostResultEvent(mRequest
.forget(),
2824 static_cast<uint64_t>(freeSpace
));
2825 return NS_DispatchToMainThread(r
);
2829 nsRefPtr
<DeviceStorageFile
> mFile
;
2830 nsRefPtr
<DOMRequest
> mRequest
;
2833 class DeviceStorageRequest MOZ_FINAL
2834 : public nsIContentPermissionRequest
2835 , public nsIRunnable
2839 DeviceStorageRequest(const DeviceStorageRequestType aRequestType
,
2840 nsPIDOMWindow
* aWindow
,
2841 nsIPrincipal
* aPrincipal
,
2842 DeviceStorageFile
* aFile
,
2843 DOMRequest
* aRequest
,
2844 nsDOMDeviceStorage
* aDeviceStorage
)
2845 : mRequestType(aRequestType
)
2847 , mPrincipal(aPrincipal
)
2849 , mRequest(aRequest
)
2850 , mDeviceStorage(aDeviceStorage
)
2852 MOZ_ASSERT(mWindow
);
2853 MOZ_ASSERT(mPrincipal
);
2855 MOZ_ASSERT(mRequest
);
2856 MOZ_ASSERT(mDeviceStorage
);
2859 DeviceStorageRequest(const DeviceStorageRequestType aRequestType
,
2860 nsPIDOMWindow
* aWindow
,
2861 nsIPrincipal
* aPrincipal
,
2862 DeviceStorageFile
* aFile
,
2863 DOMRequest
* aRequest
,
2864 nsIDOMBlob
* aBlob
= nullptr)
2865 : mRequestType(aRequestType
)
2867 , mPrincipal(aPrincipal
)
2869 , mRequest(aRequest
)
2872 MOZ_ASSERT(mWindow
);
2873 MOZ_ASSERT(mPrincipal
);
2875 MOZ_ASSERT(mRequest
);
2878 DeviceStorageRequest(const DeviceStorageRequestType aRequestType
,
2879 nsPIDOMWindow
* aWindow
,
2880 nsIPrincipal
* aPrincipal
,
2881 DeviceStorageFile
* aFile
,
2882 DOMRequest
* aRequest
,
2883 DeviceStorageFileDescriptor
* aDSFileDescriptor
)
2884 : mRequestType(aRequestType
)
2886 , mPrincipal(aPrincipal
)
2888 , mRequest(aRequest
)
2889 , mDSFileDescriptor(aDSFileDescriptor
)
2891 MOZ_ASSERT(mRequestType
== DEVICE_STORAGE_REQUEST_CREATEFD
);
2892 MOZ_ASSERT(mWindow
);
2893 MOZ_ASSERT(mPrincipal
);
2895 MOZ_ASSERT(mRequest
);
2896 MOZ_ASSERT(mDSFileDescriptor
);
2899 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
2900 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageRequest
,
2901 nsIContentPermissionRequest
)
2903 NS_IMETHOD
Run() MOZ_OVERRIDE
2905 MOZ_ASSERT(NS_IsMainThread());
2907 if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
2908 Allow(JS::UndefinedHandleValue
);
2912 return nsContentPermissionUtils::AskPermission(this, mWindow
);
2915 NS_IMETHODIMP
GetTypes(nsIArray
** aTypes
) MOZ_OVERRIDE
2919 DeviceStorageTypeChecker::GetPermissionForType(mFile
->mStorageType
, type
);
2920 if (NS_FAILED(rv
)) {
2925 rv
= DeviceStorageTypeChecker::GetAccessForRequest(
2926 DeviceStorageRequestType(mRequestType
), access
);
2927 if (NS_FAILED(rv
)) {
2931 nsTArray
<nsString
> emptyOptions
;
2932 return nsContentPermissionUtils::CreatePermissionArray(type
, access
, emptyOptions
, aTypes
);
2935 NS_IMETHOD
GetPrincipal(nsIPrincipal
* *aRequestingPrincipal
) MOZ_OVERRIDE
2937 NS_IF_ADDREF(*aRequestingPrincipal
= mPrincipal
);
2941 NS_IMETHOD
GetWindow(nsIDOMWindow
* *aRequestingWindow
) MOZ_OVERRIDE
2943 NS_IF_ADDREF(*aRequestingWindow
= mWindow
);
2947 NS_IMETHOD
GetElement(nsIDOMElement
* *aRequestingElement
) MOZ_OVERRIDE
2949 *aRequestingElement
= nullptr;
2953 NS_IMETHOD
Cancel() MOZ_OVERRIDE
2955 nsCOMPtr
<nsIRunnable
> event
2956 = new PostErrorEvent(mRequest
.forget(),
2957 POST_ERROR_EVENT_PERMISSION_DENIED
);
2958 return NS_DispatchToMainThread(event
);
2961 NS_IMETHOD
Allow(JS::HandleValue aChoices
) MOZ_OVERRIDE
2963 MOZ_ASSERT(NS_IsMainThread());
2964 MOZ_ASSERT(aChoices
.isUndefined());
2967 return NS_ERROR_FAILURE
;
2970 nsCOMPtr
<nsIRunnable
> r
;
2972 switch(mRequestType
) {
2973 case DEVICE_STORAGE_REQUEST_CREATEFD
:
2975 if (!mFile
->mFile
) {
2976 return NS_ERROR_FAILURE
;
2979 DeviceStorageTypeChecker
* typeChecker
2980 = DeviceStorageTypeChecker::CreateOrGet();
2985 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
)) {
2986 r
= new PostErrorEvent(mRequest
.forget(),
2987 POST_ERROR_EVENT_ILLEGAL_TYPE
);
2988 return NS_DispatchToCurrentThread(r
);
2991 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
2993 DeviceStorageCreateFdParams params
;
2994 params
.type() = mFile
->mStorageType
;
2995 params
.storageName() = mFile
->mStorageName
;
2996 params
.relpath() = mFile
->mPath
;
2998 mFile
->Dump("DeviceStorageCreateFdParams");
3000 PDeviceStorageRequestChild
* child
3001 = new DeviceStorageRequestChild(mRequest
, mFile
,
3002 mDSFileDescriptor
.get());
3003 ContentChild::GetSingleton()
3004 ->SendPDeviceStorageRequestConstructor(child
, params
);
3007 mDSFileDescriptor
->mDSFile
= mFile
;
3008 r
= new CreateFdEvent(mDSFileDescriptor
.get(), mRequest
.forget());
3012 case DEVICE_STORAGE_REQUEST_CREATE
:
3014 if (!mBlob
|| !mFile
->mFile
) {
3015 return NS_ERROR_FAILURE
;
3018 DeviceStorageTypeChecker
* typeChecker
3019 = DeviceStorageTypeChecker::CreateOrGet();
3024 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
) ||
3025 !typeChecker
->Check(mFile
->mStorageType
, mBlob
)) {
3026 r
= new PostErrorEvent(mRequest
.forget(),
3027 POST_ERROR_EVENT_ILLEGAL_TYPE
);
3028 return NS_DispatchToCurrentThread(r
);
3031 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3033 = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
3034 static_cast<File
*>(mBlob
.get()));
3036 return NS_ERROR_FAILURE
;
3039 DeviceStorageAddParams params
;
3040 params
.blobChild() = actor
;
3041 params
.type() = mFile
->mStorageType
;
3042 params
.storageName() = mFile
->mStorageName
;
3043 params
.relpath() = mFile
->mPath
;
3045 PDeviceStorageRequestChild
* child
3046 = new DeviceStorageRequestChild(mRequest
, mFile
);
3047 ContentChild::GetSingleton()
3048 ->SendPDeviceStorageRequestConstructor(child
, params
);
3052 File
* blob
= static_cast<File
*>(mBlob
.get());
3053 r
= new WriteFileEvent(blob
->Impl(), mFile
, mRequest
.forget(),
3058 case DEVICE_STORAGE_REQUEST_APPEND
:
3060 if (!mBlob
|| !mFile
->mFile
) {
3061 return NS_ERROR_FAILURE
;
3064 DeviceStorageTypeChecker
* typeChecker
3065 = DeviceStorageTypeChecker::CreateOrGet();
3070 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
) ||
3071 !typeChecker
->Check(mFile
->mStorageType
, mBlob
)) {
3072 r
= new PostErrorEvent(mRequest
.forget(),
3073 POST_ERROR_EVENT_ILLEGAL_TYPE
);
3074 return NS_DispatchToCurrentThread(r
);
3077 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3079 = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
3080 static_cast<File
*>(mBlob
.get()));
3082 return NS_ERROR_FAILURE
;
3085 DeviceStorageAppendParams params
;
3086 params
.blobChild() = actor
;
3087 params
.type() = mFile
->mStorageType
;
3088 params
.storageName() = mFile
->mStorageName
;
3089 params
.relpath() = mFile
->mPath
;
3091 PDeviceStorageRequestChild
* child
3092 = new DeviceStorageRequestChild(mRequest
, mFile
);
3093 ContentChild::GetSingleton()
3094 ->SendPDeviceStorageRequestConstructor(child
, params
);
3098 File
* blob
= static_cast<File
*>(mBlob
.get());
3099 r
= new WriteFileEvent(blob
->Impl(), mFile
, mRequest
.forget(),
3104 case DEVICE_STORAGE_REQUEST_READ
:
3105 case DEVICE_STORAGE_REQUEST_WRITE
:
3107 if (!mFile
->mFile
) {
3108 return NS_ERROR_FAILURE
;
3111 DeviceStorageTypeChecker
* typeChecker
3112 = DeviceStorageTypeChecker::CreateOrGet();
3117 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
)) {
3118 r
= new PostErrorEvent(mRequest
.forget(),
3119 POST_ERROR_EVENT_ILLEGAL_TYPE
);
3120 return NS_DispatchToCurrentThread(r
);
3123 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3124 PDeviceStorageRequestChild
* child
3125 = new DeviceStorageRequestChild(mRequest
, mFile
);
3126 DeviceStorageGetParams
params(mFile
->mStorageType
,
3127 mFile
->mStorageName
,
3130 ContentChild::GetSingleton()
3131 ->SendPDeviceStorageRequestConstructor(child
, params
);
3135 r
= new ReadFileEvent(mFile
, mRequest
.forget());
3139 case DEVICE_STORAGE_REQUEST_DELETE
:
3141 if (!mFile
->mFile
) {
3142 return NS_ERROR_FAILURE
;
3145 DeviceStorageTypeChecker
* typeChecker
3146 = DeviceStorageTypeChecker::CreateOrGet();
3151 if (!typeChecker
->Check(mFile
->mStorageType
, mFile
->mFile
)) {
3152 r
= new PostErrorEvent(mRequest
.forget(),
3153 POST_ERROR_EVENT_ILLEGAL_TYPE
);
3154 return NS_DispatchToCurrentThread(r
);
3157 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3158 PDeviceStorageRequestChild
* child
3159 = new DeviceStorageRequestChild(mRequest
, mFile
);
3160 DeviceStorageDeleteParams
params(mFile
->mStorageType
,
3161 mFile
->mStorageName
,
3163 ContentChild::GetSingleton()
3164 ->SendPDeviceStorageRequestConstructor(child
, params
);
3167 r
= new DeleteFileEvent(mFile
, mRequest
.forget());
3171 case DEVICE_STORAGE_REQUEST_FREE_SPACE
:
3173 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3174 PDeviceStorageRequestChild
* child
3175 = new DeviceStorageRequestChild(mRequest
, mFile
);
3176 DeviceStorageFreeSpaceParams
params(mFile
->mStorageType
,
3177 mFile
->mStorageName
);
3178 ContentChild::GetSingleton()
3179 ->SendPDeviceStorageRequestConstructor(child
, params
);
3182 r
= new FreeSpaceFileEvent(mFile
, mRequest
.forget());
3186 case DEVICE_STORAGE_REQUEST_USED_SPACE
:
3188 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3189 PDeviceStorageRequestChild
* child
3190 = new DeviceStorageRequestChild(mRequest
, mFile
);
3191 DeviceStorageUsedSpaceParams
params(mFile
->mStorageType
,
3192 mFile
->mStorageName
);
3193 ContentChild::GetSingleton()
3194 ->SendPDeviceStorageRequestConstructor(child
, params
);
3197 // this needs to be dispatched to only one (1)
3198 // thread or we will do more work than required.
3199 DeviceStorageUsedSpaceCache
* usedSpaceCache
3200 = DeviceStorageUsedSpaceCache::CreateOrGet();
3201 MOZ_ASSERT(usedSpaceCache
);
3202 r
= new UsedSpaceFileEvent(mFile
, mRequest
.forget());
3203 usedSpaceCache
->Dispatch(r
);
3207 case DEVICE_STORAGE_REQUEST_AVAILABLE
:
3209 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3210 PDeviceStorageRequestChild
* child
3211 = new DeviceStorageRequestChild(mRequest
, mFile
);
3212 DeviceStorageAvailableParams
params(mFile
->mStorageType
,
3213 mFile
->mStorageName
);
3214 ContentChild::GetSingleton()
3215 ->SendPDeviceStorageRequestConstructor(child
, params
);
3218 r
= new PostAvailableResultEvent(mFile
, mRequest
);
3219 return NS_DispatchToCurrentThread(r
);
3222 case DEVICE_STORAGE_REQUEST_STATUS
:
3224 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3225 PDeviceStorageRequestChild
* child
3226 = new DeviceStorageRequestChild(mRequest
, mFile
);
3227 DeviceStorageStatusParams
params(mFile
->mStorageType
,
3228 mFile
->mStorageName
);
3229 ContentChild::GetSingleton()
3230 ->SendPDeviceStorageRequestConstructor(child
, params
);
3233 r
= new PostStatusResultEvent(mFile
, mRequest
);
3234 return NS_DispatchToCurrentThread(r
);
3237 case DEVICE_STORAGE_REQUEST_WATCH
:
3239 mDeviceStorage
->mAllowedToWatchFile
= true;
3243 case DEVICE_STORAGE_REQUEST_FORMAT
:
3245 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3246 PDeviceStorageRequestChild
* child
3247 = new DeviceStorageRequestChild(mRequest
, mFile
);
3248 DeviceStorageFormatParams
params(mFile
->mStorageType
,
3249 mFile
->mStorageName
);
3250 ContentChild::GetSingleton()
3251 ->SendPDeviceStorageRequestConstructor(child
, params
);
3254 r
= new PostFormatResultEvent(mFile
, mRequest
);
3255 return NS_DispatchToCurrentThread(r
);
3258 case DEVICE_STORAGE_REQUEST_MOUNT
:
3260 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3261 PDeviceStorageRequestChild
* child
3262 = new DeviceStorageRequestChild(mRequest
, mFile
);
3263 DeviceStorageMountParams
params(mFile
->mStorageType
,
3264 mFile
->mStorageName
);
3265 ContentChild::GetSingleton()
3266 ->SendPDeviceStorageRequestConstructor(child
, params
);
3269 r
= new PostMountResultEvent(mFile
, mRequest
);
3270 return NS_DispatchToCurrentThread(r
);
3273 case DEVICE_STORAGE_REQUEST_UNMOUNT
:
3275 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
3276 PDeviceStorageRequestChild
* child
3277 = new DeviceStorageRequestChild(mRequest
, mFile
);
3278 DeviceStorageUnmountParams
params(mFile
->mStorageType
,
3279 mFile
->mStorageName
);
3280 ContentChild::GetSingleton()
3281 ->SendPDeviceStorageRequestConstructor(child
, params
);
3284 r
= new PostUnmountResultEvent(mFile
, mRequest
);
3285 return NS_DispatchToCurrentThread(r
);
3290 nsCOMPtr
<nsIEventTarget
> target
3291 = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
3293 target
->Dispatch(r
, NS_DISPATCH_NORMAL
);
3300 ~DeviceStorageRequest() {}
3302 int32_t mRequestType
;
3303 nsCOMPtr
<nsPIDOMWindow
> mWindow
;
3304 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
3305 nsRefPtr
<DeviceStorageFile
> mFile
;
3307 nsRefPtr
<DOMRequest
> mRequest
;
3308 nsCOMPtr
<nsIDOMBlob
> mBlob
;
3309 nsRefPtr
<nsDOMDeviceStorage
> mDeviceStorage
;
3310 nsRefPtr
<DeviceStorageFileDescriptor
> mDSFileDescriptor
;
3313 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest
)
3314 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIContentPermissionRequest
)
3315 NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest
)
3316 NS_INTERFACE_MAP_ENTRY(nsIRunnable
)
3317 NS_INTERFACE_MAP_END
3319 NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageRequest
)
3320 NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageRequest
)
3322 NS_IMPL_CYCLE_COLLECTION(DeviceStorageRequest
,
3329 NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorage
)
3330 NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorage
)
3331 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
3332 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
3334 NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorage
, DOMEventTargetHelper
)
3335 NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorage
, DOMEventTargetHelper
)
3337 nsDOMDeviceStorage::nsDOMDeviceStorage(nsPIDOMWindow
* aWindow
)
3338 : DOMEventTargetHelper(aWindow
)
3339 , mIsShareable(false)
3340 , mIsRemovable(false)
3341 , mIsWatchingFile(false)
3342 , mAllowedToWatchFile(false)
3346 /* virtual */ JSObject
*
3347 nsDOMDeviceStorage::WrapObject(JSContext
* aCx
)
3349 return DeviceStorageBinding::Wrap(aCx
, this);
3353 nsDOMDeviceStorage::Init(nsPIDOMWindow
* aWindow
, const nsAString
&aType
,
3354 const nsAString
&aVolName
)
3356 DebugOnly
<FileUpdateDispatcher
*> observer
3357 = FileUpdateDispatcher::GetSingleton();
3358 MOZ_ASSERT(observer
);
3360 MOZ_ASSERT(aWindow
);
3362 SetRootDirectoryForType(aType
, aVolName
);
3363 if (!mRootDirectory
) {
3364 return NS_ERROR_NOT_AVAILABLE
;
3366 if (!mStorageName
.IsEmpty()) {
3367 RegisterForSDCardChanges(this);
3369 #ifdef MOZ_WIDGET_GONK
3370 if (DeviceStorageTypeChecker::IsVolumeBased(mStorageType
)) {
3371 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
3372 if (NS_WARN_IF(!vs
)) {
3373 return NS_ERROR_FAILURE
;
3376 nsCOMPtr
<nsIVolume
> vol
;
3377 rv
= vs
->GetVolumeByName(mStorageName
, getter_AddRefs(vol
));
3378 if (NS_WARN_IF(NS_FAILED(rv
))) {
3382 rv
= vol
->GetIsFake(&isFake
);
3383 if (NS_WARN_IF(NS_FAILED(rv
))) {
3386 mIsShareable
= !isFake
;
3388 rv
= vol
->GetIsHotSwappable(&isRemovable
);
3389 if (NS_WARN_IF(NS_FAILED(rv
))) {
3392 mIsRemovable
= isRemovable
;
3397 // Grab the principal of the document
3398 nsCOMPtr
<nsIDocument
> doc
= aWindow
->GetDoc();
3400 return NS_ERROR_FAILURE
;
3402 mPrincipal
= doc
->NodePrincipal();
3404 // the 'apps' type is special. We only want this exposed
3405 // if the caller has the "webapps-manage" permission.
3406 if (aType
.EqualsLiteral(DEVICESTORAGE_APPS
)) {
3407 nsCOMPtr
<nsIPermissionManager
> permissionManager
3408 = services::GetPermissionManager();
3409 NS_ENSURE_TRUE(permissionManager
, NS_ERROR_FAILURE
);
3411 uint32_t permission
;
3413 = permissionManager
->TestPermissionFromPrincipal(mPrincipal
,
3417 if (NS_FAILED(rv
) || permission
!= nsIPermissionManager::ALLOW_ACTION
) {
3418 return NS_ERROR_NOT_AVAILABLE
;
3425 nsDOMDeviceStorage::~nsDOMDeviceStorage()
3430 nsDOMDeviceStorage::Shutdown()
3432 MOZ_ASSERT(NS_IsMainThread());
3435 mFileSystem
->Shutdown();
3436 mFileSystem
= nullptr;
3439 if (!mStorageName
.IsEmpty()) {
3440 UnregisterForSDCardChanges(this);
3443 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
3444 obs
->RemoveObserver(this, kFileWatcherUpdate
);
3445 obs
->RemoveObserver(this, "disk-space-watcher");
3448 StaticAutoPtr
<nsTArray
<nsString
>> nsDOMDeviceStorage::sVolumeNameCache
;
3452 nsDOMDeviceStorage::GetOrderedVolumeNames(
3453 nsDOMDeviceStorage::VolumeNameArray
&aVolumeNames
)
3455 if (sVolumeNameCache
&& sVolumeNameCache
->Length() > 0) {
3456 aVolumeNames
.AppendElements(*sVolumeNameCache
);
3459 #ifdef MOZ_WIDGET_GONK
3460 nsCOMPtr
<nsIVolumeService
> vs
= do_GetService(NS_VOLUMESERVICE_CONTRACTID
);
3462 nsCOMPtr
<nsIArray
> volNames
;
3463 vs
->GetVolumeNames(getter_AddRefs(volNames
));
3464 uint32_t length
= -1;
3465 volNames
->GetLength(&length
);
3466 for (uint32_t i
= 0; i
< length
; i
++) {
3467 nsCOMPtr
<nsISupportsString
> str
= do_QueryElementAt(volNames
, i
);
3470 if (NS_SUCCEEDED(str
->GetData(s
)) && !s
.IsEmpty()) {
3471 aVolumeNames
.AppendElement(s
);
3476 // If the volume sdcard exists, then we want it to be first.
3478 VolumeNameArray::index_type sdcardIndex
;
3479 sdcardIndex
= aVolumeNames
.IndexOf(NS_LITERAL_STRING("sdcard"));
3480 if (sdcardIndex
!= VolumeNameArray::NoIndex
&& sdcardIndex
> 0) {
3481 aVolumeNames
.RemoveElementAt(sdcardIndex
);
3482 aVolumeNames
.InsertElementAt(0, NS_LITERAL_STRING("sdcard"));
3486 if (aVolumeNames
.IsEmpty()) {
3487 aVolumeNames
.AppendElement(EmptyString());
3489 sVolumeNameCache
= new nsTArray
<nsString
>;
3490 sVolumeNameCache
->AppendElements(aVolumeNames
);
3495 nsDOMDeviceStorage::CreateDeviceStorageFor(nsPIDOMWindow
* aWin
,
3496 const nsAString
&aType
,
3497 nsDOMDeviceStorage
** aStore
)
3499 nsString storageName
;
3500 if (!DeviceStorageTypeChecker::IsVolumeBased(aType
)) {
3501 // The storage name will be the empty string
3502 storageName
.Truncate();
3504 GetDefaultStorageName(aType
, storageName
);
3507 nsRefPtr
<nsDOMDeviceStorage
> ds
= new nsDOMDeviceStorage(aWin
);
3508 if (NS_FAILED(ds
->Init(aWin
, aType
, storageName
))) {
3512 NS_ADDREF(*aStore
= ds
.get());
3517 nsDOMDeviceStorage::CreateDeviceStoragesFor(
3518 nsPIDOMWindow
* aWin
,
3519 const nsAString
&aType
,
3520 nsTArray
<nsRefPtr
<nsDOMDeviceStorage
> > &aStores
)
3524 if (!DeviceStorageTypeChecker::IsVolumeBased(aType
)) {
3525 nsRefPtr
<nsDOMDeviceStorage
> storage
= new nsDOMDeviceStorage(aWin
);
3526 rv
= storage
->Init(aWin
, aType
, EmptyString());
3527 if (NS_SUCCEEDED(rv
)) {
3528 aStores
.AppendElement(storage
);
3532 VolumeNameArray volNames
;
3533 GetOrderedVolumeNames(volNames
);
3535 VolumeNameArray::size_type numVolumeNames
= volNames
.Length();
3536 for (VolumeNameArray::index_type i
= 0; i
< numVolumeNames
; i
++) {
3537 nsRefPtr
<nsDOMDeviceStorage
> storage
= new nsDOMDeviceStorage(aWin
);
3538 rv
= storage
->Init(aWin
, aType
, volNames
[i
]);
3539 if (NS_FAILED(rv
)) {
3542 aStores
.AppendElement(storage
);
3548 nsDOMDeviceStorage::ParseFullPath(const nsAString
& aFullPath
,
3549 nsAString
& aOutStorageName
,
3550 nsAString
& aOutStoragePath
)
3552 aOutStorageName
.Truncate();
3553 aOutStoragePath
.Truncate();
3555 NS_NAMED_LITERAL_STRING(slash
, "/");
3557 nsDependentSubstring storageName
;
3559 if (StringBeginsWith(aFullPath
, slash
)) {
3560 int32_t slashIndex
= aFullPath
.FindChar('/', 1);
3561 if (slashIndex
== kNotFound
) {
3562 // names of the form /filename are illegal
3565 storageName
.Rebind(aFullPath
, 1, slashIndex
- 1);
3566 aOutStoragePath
= Substring(aFullPath
, slashIndex
+ 1);
3568 aOutStoragePath
= aFullPath
;
3570 // If no volume name was specified in aFullPath, then aOutStorageName
3571 // will wind up being the empty string. It's up to the caller to figure
3572 // out which storage name to actually use.
3573 aOutStorageName
= storageName
;
3577 already_AddRefed
<nsDOMDeviceStorage
>
3578 nsDOMDeviceStorage::GetStorage(const nsAString
& aFullPath
,
3579 nsAString
& aOutStoragePath
)
3581 nsString storageName
;
3582 if (!ParseFullPath(aFullPath
, storageName
, aOutStoragePath
)) {
3585 nsRefPtr
<nsDOMDeviceStorage
> ds
;
3586 if (storageName
.IsEmpty()) {
3589 ds
= GetStorageByName(storageName
);
3594 already_AddRefed
<nsDOMDeviceStorage
>
3595 nsDOMDeviceStorage::GetStorageByName(const nsAString
& aStorageName
)
3597 MOZ_ASSERT(NS_IsMainThread());
3599 nsRefPtr
<nsDOMDeviceStorage
> ds
;
3601 if (mStorageName
.Equals(aStorageName
)) {
3605 VolumeNameArray volNames
;
3606 GetOrderedVolumeNames(volNames
);
3607 VolumeNameArray::size_type numVolumes
= volNames
.Length();
3608 VolumeNameArray::index_type i
;
3609 for (i
= 0; i
< numVolumes
; i
++) {
3610 if (volNames
[i
].Equals(aStorageName
)) {
3611 ds
= new nsDOMDeviceStorage(GetOwner());
3612 nsresult rv
= ds
->Init(GetOwner(), mStorageType
, aStorageName
);
3613 if (NS_FAILED(rv
)) {
3624 nsDOMDeviceStorage::GetDefaultStorageName(const nsAString
& aStorageType
,
3625 nsAString
& aStorageName
)
3627 // See if the preferred volume is available.
3628 nsRefPtr
<nsDOMDeviceStorage
> ds
;
3629 nsAdoptingString prefStorageName
=
3630 mozilla::Preferences::GetString("device.storage.writable.name");
3631 if (prefStorageName
) {
3632 aStorageName
= prefStorageName
;
3636 // No preferred storage, we'll use the first one (which should be sdcard).
3638 VolumeNameArray volNames
;
3639 GetOrderedVolumeNames(volNames
);
3640 if (volNames
.Length() > 0) {
3641 aStorageName
= volNames
[0];
3645 // No volumes available, return the empty string. This is normal for
3647 aStorageName
.Truncate();
3651 nsDOMDeviceStorage::IsAvailable()
3653 nsRefPtr
<DeviceStorageFile
> dsf(new DeviceStorageFile(mStorageType
, mStorageName
));
3654 return dsf
->IsAvailable();
3658 nsDOMDeviceStorage::Add(nsIDOMBlob
*aBlob
, nsIDOMDOMRequest
* *_retval
)
3661 nsRefPtr
<DOMRequest
> request
= Add(aBlob
, rv
);
3662 request
.forget(_retval
);
3663 return rv
.ErrorCode();
3666 already_AddRefed
<DOMRequest
>
3667 nsDOMDeviceStorage::Add(nsIDOMBlob
* aBlob
, ErrorResult
& aRv
)
3673 nsCOMPtr
<nsIMIMEService
> mimeSvc
= do_GetService(NS_MIMESERVICE_CONTRACTID
);
3675 aRv
.Throw(NS_ERROR_FAILURE
);
3679 // if mimeType isn't set, we will not get a correct
3680 // extension, and AddNamed() will fail. This will post an
3681 // onerror to the requestee.
3683 aBlob
->GetType(mimeType
);
3685 nsCString extension
;
3686 mimeSvc
->GetPrimaryExtension(NS_LossyConvertUTF16toASCII(mimeType
),
3687 EmptyCString(), extension
);
3688 // if extension is null here, we will ignore it for now.
3689 // AddNamed() will check the file path and fail. This
3690 // will post an onerror to the requestee.
3692 // possible race here w/ unique filename
3694 NS_MakeRandomString(buffer
, ArrayLength(buffer
) - 1);
3697 path
.Assign(nsDependentCString(buffer
));
3699 path
.Append(extension
);
3701 return AddNamed(aBlob
, NS_ConvertASCIItoUTF16(path
), aRv
);
3705 nsDOMDeviceStorage::AddNamed(nsIDOMBlob
*aBlob
,
3706 const nsAString
& aPath
,
3707 nsIDOMDOMRequest
* *_retval
)
3710 nsRefPtr
<DOMRequest
> request
= AddNamed(aBlob
, aPath
, rv
);
3711 request
.forget(_retval
);
3712 return rv
.ErrorCode();
3715 already_AddRefed
<DOMRequest
>
3716 nsDOMDeviceStorage::AddNamed(nsIDOMBlob
* aBlob
, const nsAString
& aPath
,
3719 return AddOrAppendNamed(aBlob
, aPath
,
3720 DEVICE_STORAGE_REQUEST_CREATE
, aRv
);
3723 already_AddRefed
<DOMRequest
>
3724 nsDOMDeviceStorage::AppendNamed(nsIDOMBlob
* aBlob
, const nsAString
& aPath
,
3727 return AddOrAppendNamed(aBlob
, aPath
,
3728 DEVICE_STORAGE_REQUEST_APPEND
, aRv
);
3732 already_AddRefed
<DOMRequest
>
3733 nsDOMDeviceStorage::AddOrAppendNamed(nsIDOMBlob
* aBlob
, const nsAString
& aPath
,
3734 const int32_t aRequestType
, ErrorResult
& aRv
)
3736 MOZ_ASSERT(NS_IsMainThread());
3738 // if the blob is null here, bail
3743 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3745 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3749 DeviceStorageTypeChecker
* typeChecker
3750 = DeviceStorageTypeChecker::CreateOrGet();
3752 aRv
.Throw(NS_ERROR_FAILURE
);
3756 nsCOMPtr
<nsIRunnable
> r
;
3759 if (IsFullPath(aPath
)) {
3760 nsString storagePath
;
3761 nsRefPtr
<nsDOMDeviceStorage
> ds
= GetStorage(aPath
, storagePath
);
3763 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3764 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_UNKNOWN
);
3765 rv
= NS_DispatchToCurrentThread(r
);
3766 if (NS_FAILED(rv
)) {
3769 return request
.forget();
3772 return ds
->AddOrAppendNamed(aBlob
, storagePath
,
3776 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3778 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3781 if (!dsf
->IsSafePath()) {
3782 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_PERMISSION_DENIED
);
3783 } else if (!typeChecker
->Check(mStorageType
, dsf
->mFile
) ||
3784 !typeChecker
->Check(mStorageType
, aBlob
)) {
3785 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_ILLEGAL_TYPE
);
3786 } else if (aRequestType
== DEVICE_STORAGE_REQUEST_APPEND
||
3787 aRequestType
== DEVICE_STORAGE_REQUEST_CREATE
) {
3788 r
= new DeviceStorageRequest(DeviceStorageRequestType(aRequestType
),
3789 win
, mPrincipal
, dsf
, request
, aBlob
);
3791 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3795 rv
= NS_DispatchToCurrentThread(r
);
3796 if (NS_FAILED(rv
)) {
3799 return request
.forget();
3803 nsDOMDeviceStorage::Get(const nsAString
& aPath
, nsIDOMDOMRequest
** aRetval
)
3806 nsRefPtr
<DOMRequest
> request
= Get(aPath
, rv
);
3807 request
.forget(aRetval
);
3808 return rv
.ErrorCode();
3812 nsDOMDeviceStorage::GetEditable(const nsAString
& aPath
,
3813 nsIDOMDOMRequest
** aRetval
)
3816 nsRefPtr
<DOMRequest
> request
= GetEditable(aPath
, rv
);
3817 request
.forget(aRetval
);
3818 return rv
.ErrorCode();
3821 already_AddRefed
<DOMRequest
>
3822 nsDOMDeviceStorage::GetInternal(const nsAString
& aPath
, bool aEditable
,
3825 MOZ_ASSERT(NS_IsMainThread());
3827 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3829 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3833 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3835 if (IsFullPath(aPath
)) {
3836 nsString storagePath
;
3837 nsRefPtr
<nsDOMDeviceStorage
> ds
= GetStorage(aPath
, storagePath
);
3839 nsCOMPtr
<nsIRunnable
> r
=
3840 new PostErrorEvent(request
, POST_ERROR_EVENT_UNKNOWN
);
3841 nsresult rv
= NS_DispatchToCurrentThread(r
);
3842 if (NS_FAILED(rv
)) {
3845 return request
.forget();
3847 ds
->GetInternal(win
, storagePath
, request
, aEditable
);
3848 return request
.forget();
3850 GetInternal(win
, aPath
, request
, aEditable
);
3851 return request
.forget();
3855 nsDOMDeviceStorage::GetInternal(nsPIDOMWindow
*aWin
,
3856 const nsAString
& aPath
,
3857 DOMRequest
* aRequest
,
3860 MOZ_ASSERT(NS_IsMainThread());
3862 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3865 dsf
->SetEditable(aEditable
);
3867 nsCOMPtr
<nsIRunnable
> r
;
3868 if (!dsf
->IsSafePath()) {
3869 r
= new PostErrorEvent(aRequest
, POST_ERROR_EVENT_PERMISSION_DENIED
);
3871 r
= new DeviceStorageRequest(aEditable
? DEVICE_STORAGE_REQUEST_WRITE
3872 : DEVICE_STORAGE_REQUEST_READ
,
3873 aWin
, mPrincipal
, dsf
, aRequest
);
3875 DebugOnly
<nsresult
> rv
= NS_DispatchToCurrentThread(r
);
3876 MOZ_ASSERT(NS_SUCCEEDED(rv
));
3880 nsDOMDeviceStorage::Delete(const nsAString
& aPath
, nsIDOMDOMRequest
** aRetval
)
3883 nsRefPtr
<DOMRequest
> request
= Delete(aPath
, rv
);
3884 request
.forget(aRetval
);
3885 return rv
.ErrorCode();
3888 already_AddRefed
<DOMRequest
>
3889 nsDOMDeviceStorage::Delete(const nsAString
& aPath
, ErrorResult
& aRv
)
3891 MOZ_ASSERT(NS_IsMainThread());
3893 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3895 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3899 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3901 if (IsFullPath(aPath
)) {
3902 nsString storagePath
;
3903 nsRefPtr
<nsDOMDeviceStorage
> ds
= GetStorage(aPath
, storagePath
);
3905 nsCOMPtr
<nsIRunnable
> r
=
3906 new PostErrorEvent(request
, POST_ERROR_EVENT_UNKNOWN
);
3907 nsresult rv
= NS_DispatchToCurrentThread(r
);
3908 if (NS_FAILED(rv
)) {
3911 return request
.forget();
3913 ds
->DeleteInternal(win
, storagePath
, request
);
3914 return request
.forget();
3916 DeleteInternal(win
, aPath
, request
);
3917 return request
.forget();
3921 nsDOMDeviceStorage::DeleteInternal(nsPIDOMWindow
*aWin
,
3922 const nsAString
& aPath
,
3923 DOMRequest
* aRequest
)
3925 MOZ_ASSERT(NS_IsMainThread());
3927 nsCOMPtr
<nsIRunnable
> r
;
3928 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3931 if (!dsf
->IsSafePath()) {
3932 r
= new PostErrorEvent(aRequest
, POST_ERROR_EVENT_PERMISSION_DENIED
);
3934 r
= new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_DELETE
,
3935 aWin
, mPrincipal
, dsf
, aRequest
);
3937 DebugOnly
<nsresult
> rv
= NS_DispatchToCurrentThread(r
);
3938 MOZ_ASSERT(NS_SUCCEEDED(rv
));
3942 nsDOMDeviceStorage::FreeSpace(nsIDOMDOMRequest
** aRetval
)
3945 nsRefPtr
<DOMRequest
> request
= FreeSpace(rv
);
3946 request
.forget(aRetval
);
3947 return rv
.ErrorCode();
3950 already_AddRefed
<DOMRequest
>
3951 nsDOMDeviceStorage::FreeSpace(ErrorResult
& aRv
)
3953 MOZ_ASSERT(NS_IsMainThread());
3955 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3957 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3961 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
3963 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
3965 nsCOMPtr
<nsIRunnable
> r
3966 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FREE_SPACE
,
3967 win
, mPrincipal
, dsf
, request
);
3968 nsresult rv
= NS_DispatchToCurrentThread(r
);
3969 if (NS_FAILED(rv
)) {
3972 return request
.forget();
3976 nsDOMDeviceStorage::UsedSpace(nsIDOMDOMRequest
** aRetval
)
3979 nsRefPtr
<DOMRequest
> request
= UsedSpace(rv
);
3980 request
.forget(aRetval
);
3981 return rv
.ErrorCode();
3984 already_AddRefed
<DOMRequest
>
3985 nsDOMDeviceStorage::UsedSpace(ErrorResult
& aRv
)
3987 MOZ_ASSERT(NS_IsMainThread());
3989 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
3991 aRv
.Throw(NS_ERROR_UNEXPECTED
);
3995 DebugOnly
<DeviceStorageUsedSpaceCache
*> usedSpaceCache
3996 = DeviceStorageUsedSpaceCache::CreateOrGet();
3997 MOZ_ASSERT(usedSpaceCache
);
3999 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4001 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4003 nsCOMPtr
<nsIRunnable
> r
4004 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_USED_SPACE
,
4005 win
, mPrincipal
, dsf
, request
);
4006 nsresult rv
= NS_DispatchToCurrentThread(r
);
4007 if (NS_FAILED(rv
)) {
4010 return request
.forget();
4014 nsDOMDeviceStorage::Available(nsIDOMDOMRequest
** aRetval
)
4017 nsRefPtr
<DOMRequest
> request
= Available(rv
);
4018 request
.forget(aRetval
);
4019 return rv
.ErrorCode();
4022 already_AddRefed
<DOMRequest
>
4023 nsDOMDeviceStorage::Available(ErrorResult
& aRv
)
4025 MOZ_ASSERT(NS_IsMainThread());
4027 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4029 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4033 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4035 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4037 nsCOMPtr
<nsIRunnable
> r
4038 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_AVAILABLE
,
4039 win
, mPrincipal
, dsf
, request
);
4040 nsresult rv
= NS_DispatchToCurrentThread(r
);
4041 if (NS_FAILED(rv
)) {
4044 return request
.forget();
4047 already_AddRefed
<DOMRequest
>
4048 nsDOMDeviceStorage::StorageStatus(ErrorResult
& aRv
)
4050 MOZ_ASSERT(NS_IsMainThread());
4052 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4054 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4058 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4060 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4062 nsCOMPtr
<nsIRunnable
> r
4063 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_STATUS
,
4064 win
, mPrincipal
, dsf
, request
);
4065 nsresult rv
= NS_DispatchToCurrentThread(r
);
4066 if (NS_FAILED(rv
)) {
4069 return request
.forget();
4072 already_AddRefed
<DOMRequest
>
4073 nsDOMDeviceStorage::Format(ErrorResult
& aRv
)
4075 MOZ_ASSERT(NS_IsMainThread());
4077 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4079 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4083 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4085 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4087 nsCOMPtr
<nsIRunnable
> r
4088 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FORMAT
,
4089 win
, mPrincipal
, dsf
, request
);
4090 nsresult rv
= NS_DispatchToCurrentThread(r
);
4091 if (NS_FAILED(rv
)) {
4094 return request
.forget();
4097 already_AddRefed
<DOMRequest
>
4098 nsDOMDeviceStorage::Mount(ErrorResult
& aRv
)
4100 MOZ_ASSERT(NS_IsMainThread());
4102 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4104 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4108 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4110 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4112 nsCOMPtr
<nsIRunnable
> r
4113 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_MOUNT
,
4114 win
, mPrincipal
, dsf
, request
);
4115 nsresult rv
= NS_DispatchToCurrentThread(r
);
4116 if (NS_FAILED(rv
)) {
4119 return request
.forget();
4122 already_AddRefed
<DOMRequest
>
4123 nsDOMDeviceStorage::Unmount(ErrorResult
& aRv
)
4125 MOZ_ASSERT(NS_IsMainThread());
4127 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4129 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4133 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4135 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4137 nsCOMPtr
<nsIRunnable
> r
4138 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_UNMOUNT
,
4139 win
, mPrincipal
, dsf
, request
);
4140 nsresult rv
= NS_DispatchToCurrentThread(r
);
4141 if (NS_FAILED(rv
)) {
4144 return request
.forget();
4148 nsDOMDeviceStorage::CreateFileDescriptor(const nsAString
& aPath
,
4149 DeviceStorageFileDescriptor
* aDSFileDescriptor
,
4150 nsIDOMDOMRequest
** aRequest
)
4152 MOZ_ASSERT(NS_IsMainThread());
4153 MOZ_ASSERT(aDSFileDescriptor
);
4155 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4157 return NS_ERROR_UNEXPECTED
;
4160 DeviceStorageTypeChecker
* typeChecker
4161 = DeviceStorageTypeChecker::CreateOrGet();
4163 return NS_ERROR_FAILURE
;
4166 nsCOMPtr
<nsIRunnable
> r
;
4169 if (IsFullPath(aPath
)) {
4170 nsString storagePath
;
4171 nsRefPtr
<nsDOMDeviceStorage
> ds
= GetStorage(aPath
, storagePath
);
4173 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4174 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_UNKNOWN
);
4175 rv
= NS_DispatchToCurrentThread(r
);
4176 if (NS_FAILED(rv
)) {
4179 request
.forget(aRequest
);
4182 return ds
->CreateFileDescriptor(storagePath
, aDSFileDescriptor
, aRequest
);
4185 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4187 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4190 if (!dsf
->IsSafePath()) {
4191 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_PERMISSION_DENIED
);
4192 } else if (!typeChecker
->Check(mStorageType
, dsf
->mFile
)) {
4193 r
= new PostErrorEvent(request
, POST_ERROR_EVENT_ILLEGAL_TYPE
);
4195 r
= new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_CREATEFD
,
4196 win
, mPrincipal
, dsf
, request
,
4200 rv
= NS_DispatchToCurrentThread(r
);
4201 if (NS_FAILED(rv
)) {
4204 request
.forget(aRequest
);
4209 nsDOMDeviceStorage::Default()
4211 nsString defaultStorageName
;
4212 GetDefaultStorageName(mStorageType
, defaultStorageName
);
4213 return mStorageName
.Equals(defaultStorageName
);
4217 nsDOMDeviceStorage::CanBeFormatted()
4219 // Currently, any volume which can be shared can also be formatted.
4220 return mIsShareable
;
4224 nsDOMDeviceStorage::CanBeMounted()
4226 // Currently, any volume which can be shared can also be mounted/unmounted.
4227 return mIsShareable
;
4231 nsDOMDeviceStorage::CanBeShared()
4233 return mIsShareable
;
4237 nsDOMDeviceStorage::IsRemovable()
4239 return mIsRemovable
;
4242 already_AddRefed
<Promise
>
4243 nsDOMDeviceStorage::GetRoot(ErrorResult
& aRv
)
4246 mFileSystem
= new DeviceStorageFileSystem(mStorageType
, mStorageName
);
4247 mFileSystem
->Init(this);
4249 return mozilla::dom::Directory::GetRoot(mFileSystem
, aRv
);
4253 nsDOMDeviceStorage::GetDefault(bool* aDefault
)
4255 *aDefault
= Default();
4260 nsDOMDeviceStorage::GetStorageName(nsAString
& aStorageName
)
4262 aStorageName
= mStorageName
;
4266 already_AddRefed
<DOMCursor
>
4267 nsDOMDeviceStorage::Enumerate(const nsAString
& aPath
,
4268 const EnumerationParameters
& aOptions
,
4271 return EnumerateInternal(aPath
, aOptions
, false, aRv
);
4274 already_AddRefed
<DOMCursor
>
4275 nsDOMDeviceStorage::EnumerateEditable(const nsAString
& aPath
,
4276 const EnumerationParameters
& aOptions
,
4279 return EnumerateInternal(aPath
, aOptions
, true, aRv
);
4283 already_AddRefed
<DOMCursor
>
4284 nsDOMDeviceStorage::EnumerateInternal(const nsAString
& aPath
,
4285 const EnumerationParameters
& aOptions
,
4286 bool aEditable
, ErrorResult
& aRv
)
4288 MOZ_ASSERT(NS_IsMainThread());
4290 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4292 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4297 if (aOptions
.mSince
.WasPassed() && !aOptions
.mSince
.Value().IsUndefined()) {
4298 since
= PRTime(aOptions
.mSince
.Value().TimeStamp());
4301 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4305 dsf
->SetEditable(aEditable
);
4307 nsRefPtr
<nsDOMDeviceStorageCursor
> cursor
4308 = new nsDOMDeviceStorageCursor(win
, mPrincipal
, dsf
, since
);
4309 nsRefPtr
<DeviceStorageCursorRequest
> r
4310 = new DeviceStorageCursorRequest(cursor
);
4312 if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
4313 r
->Allow(JS::UndefinedHandleValue
);
4314 return cursor
.forget();
4317 nsContentPermissionUtils::AskPermission(r
, win
);
4319 return cursor
.forget();
4322 #ifdef MOZ_WIDGET_GONK
4324 nsDOMDeviceStorage::DispatchStatusChangeEvent(nsAString
& aStatus
)
4326 if (aStatus
== mLastStatus
) {
4327 // We've already sent this status, don't bother sending it again.
4330 mLastStatus
= aStatus
;
4332 DeviceStorageChangeEventInit init
;
4333 init
.mBubbles
= true;
4334 init
.mCancelable
= false;
4335 init
.mPath
= mStorageName
;
4336 init
.mReason
= aStatus
;
4338 nsRefPtr
<DeviceStorageChangeEvent
> event
=
4339 DeviceStorageChangeEvent::Constructor(this, NS_LITERAL_STRING("change"),
4341 event
->SetTrusted(true);
4344 DispatchEvent(event
, &ignore
);
4348 nsDOMDeviceStorage::DispatchStorageStatusChangeEvent(nsAString
& aStorageStatus
)
4350 if (aStorageStatus
== mLastStorageStatus
) {
4351 // We've already sent this status, don't bother sending it again.
4354 mLastStorageStatus
= aStorageStatus
;
4356 DeviceStorageChangeEventInit init
;
4357 init
.mBubbles
= true;
4358 init
.mCancelable
= false;
4359 init
.mPath
= mStorageName
;
4360 init
.mReason
= aStorageStatus
;
4362 nsRefPtr
<DeviceStorageChangeEvent
> event
=
4363 DeviceStorageChangeEvent::Constructor(this, NS_LITERAL_STRING("storage-state-change"),
4365 event
->SetTrusted(true);
4368 DispatchEvent(event
, &ignore
);
4373 nsDOMDeviceStorage::Observe(nsISupports
*aSubject
,
4375 const char16_t
*aData
)
4377 MOZ_ASSERT(NS_IsMainThread());
4379 if (!strcmp(aTopic
, kFileWatcherUpdate
)) {
4381 DeviceStorageFile
* file
= static_cast<DeviceStorageFile
*>(aSubject
);
4382 Notify(NS_ConvertUTF16toUTF8(aData
).get(), file
);
4385 if (!strcmp(aTopic
, "disk-space-watcher")) {
4386 // 'disk-space-watcher' notifications are sent when there is a modification
4387 // of a file in a specific location while a low device storage situation
4388 // exists or after recovery of a low storage situation. For Firefox OS,
4389 // these notifications are specific for apps storage.
4390 nsRefPtr
<DeviceStorageFile
> file
=
4391 new DeviceStorageFile(mStorageType
, mStorageName
);
4392 if (!NS_strcmp(aData
, MOZ_UTF16("full"))) {
4393 Notify("low-disk-space", file
);
4394 } else if (!NS_strcmp(aData
, MOZ_UTF16("free"))) {
4395 Notify("available-disk-space", file
);
4400 #ifdef MOZ_WIDGET_GONK
4401 else if (!strcmp(aTopic
, NS_VOLUME_STATE_CHANGED
)) {
4402 // We invalidate the used space cache for the volume that actually changed
4404 nsCOMPtr
<nsIVolume
> vol
= do_QueryInterface(aSubject
);
4409 vol
->GetName(volName
);
4411 DeviceStorageUsedSpaceCache
* usedSpaceCache
4412 = DeviceStorageUsedSpaceCache::CreateOrGet();
4413 MOZ_ASSERT(usedSpaceCache
);
4414 usedSpaceCache
->Invalidate(volName
);
4416 if (!volName
.Equals(mStorageName
)) {
4417 // Not our volume - we can ignore.
4421 nsRefPtr
<DeviceStorageFile
> dsf(new DeviceStorageFile(mStorageType
, mStorageName
));
4422 nsString status
, storageStatus
;
4424 // Get Status (one of "available, unavailable, shared")
4425 dsf
->GetStatus(status
);
4426 DispatchStatusChangeEvent(status
);
4428 // Get real volume status (defined in dom/system/gonk/nsIVolume.idl)
4429 dsf
->GetStorageStatus(storageStatus
);
4430 DispatchStorageStatusChangeEvent(storageStatus
);
4438 nsDOMDeviceStorage::Notify(const char* aReason
, DeviceStorageFile
* aFile
)
4440 if (!mAllowedToWatchFile
) {
4444 if (!mStorageType
.Equals(aFile
->mStorageType
) ||
4445 !mStorageName
.Equals(aFile
->mStorageName
)) {
4450 DeviceStorageChangeEventInit init
;
4451 init
.mBubbles
= true;
4452 init
.mCancelable
= false;
4453 aFile
->GetFullPath(init
.mPath
);
4454 init
.mReason
.AssignWithConversion(aReason
);
4456 nsRefPtr
<DeviceStorageChangeEvent
> event
=
4457 DeviceStorageChangeEvent::Constructor(this, NS_LITERAL_STRING("change"),
4459 event
->SetTrusted(true);
4462 DispatchEvent(event
, &ignore
);
4467 nsDOMDeviceStorage::AddEventListener(const nsAString
& aType
,
4468 nsIDOMEventListener
*aListener
,
4470 bool aWantsUntrusted
,
4473 MOZ_ASSERT(NS_IsMainThread());
4475 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4477 return NS_ERROR_UNEXPECTED
;
4480 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4481 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4483 nsCOMPtr
<nsIRunnable
> r
4484 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH
,
4485 win
, mPrincipal
, dsf
, request
, this);
4486 nsresult rv
= NS_DispatchToCurrentThread(r
);
4487 if (NS_WARN_IF(NS_FAILED(rv
))) {
4491 return DOMEventTargetHelper::AddEventListener(aType
, aListener
, aUseCapture
,
4492 aWantsUntrusted
, aArgc
);
4496 nsDOMDeviceStorage::AddEventListener(const nsAString
& aType
,
4497 EventListener
*aListener
,
4499 const Nullable
<bool>& aWantsUntrusted
,
4502 MOZ_ASSERT(NS_IsMainThread());
4504 nsCOMPtr
<nsPIDOMWindow
> win
= GetOwner();
4506 aRv
.Throw(NS_ERROR_UNEXPECTED
);
4510 nsRefPtr
<DOMRequest
> request
= new DOMRequest(win
);
4511 nsRefPtr
<DeviceStorageFile
> dsf
= new DeviceStorageFile(mStorageType
,
4513 nsCOMPtr
<nsIRunnable
> r
4514 = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH
,
4515 win
, mPrincipal
, dsf
, request
, this);
4516 nsresult rv
= NS_DispatchToCurrentThread(r
);
4517 if (NS_WARN_IF(NS_FAILED(rv
))) {
4520 DOMEventTargetHelper::AddEventListener(aType
, aListener
, aUseCapture
,
4521 aWantsUntrusted
, aRv
);
4525 nsDOMDeviceStorage::AddSystemEventListener(const nsAString
& aType
,
4526 nsIDOMEventListener
*aListener
,
4528 bool aWantsUntrusted
,
4531 if (!mIsWatchingFile
) {
4532 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
4533 obs
->AddObserver(this, kFileWatcherUpdate
, false);
4534 mIsWatchingFile
= true;
4537 return nsDOMDeviceStorage::AddEventListener(aType
, aListener
, aUseCapture
,
4538 aWantsUntrusted
, aArgc
);
4542 nsDOMDeviceStorage::RemoveEventListener(const nsAString
& aType
,
4543 nsIDOMEventListener
*aListener
,
4546 DOMEventTargetHelper::RemoveEventListener(aType
, aListener
, false);
4548 if (mIsWatchingFile
&& !HasListenersFor(nsGkAtoms::onchange
)) {
4549 mIsWatchingFile
= false;
4550 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
4551 obs
->RemoveObserver(this, kFileWatcherUpdate
);
4557 nsDOMDeviceStorage::RemoveEventListener(const nsAString
& aType
,
4558 EventListener
* aListener
,
4562 DOMEventTargetHelper::RemoveEventListener(aType
, aListener
, aCapture
, aRv
);
4564 if (mIsWatchingFile
&& !HasListenersFor(nsGkAtoms::onchange
)) {
4565 mIsWatchingFile
= false;
4566 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
4567 obs
->RemoveObserver(this, kFileWatcherUpdate
);
4572 nsDOMDeviceStorage::RemoveSystemEventListener(const nsAString
& aType
,
4573 nsIDOMEventListener
*aListener
,
4576 return nsDOMDeviceStorage::RemoveEventListener(aType
, aListener
, aUseCapture
);
4580 nsDOMDeviceStorage::DispatchEvent(nsIDOMEvent
*aEvt
,
4583 return DOMEventTargetHelper::DispatchEvent(aEvt
, aRetval
);
4587 nsDOMDeviceStorage::GetTargetForDOMEvent()
4589 return DOMEventTargetHelper::GetTargetForDOMEvent();
4593 nsDOMDeviceStorage::GetTargetForEventTargetChain()
4595 return DOMEventTargetHelper::GetTargetForEventTargetChain();
4599 nsDOMDeviceStorage::PreHandleEvent(EventChainPreVisitor
& aVisitor
)
4601 return DOMEventTargetHelper::PreHandleEvent(aVisitor
);
4605 nsDOMDeviceStorage::WillHandleEvent(EventChainPostVisitor
& aVisitor
)
4607 return DOMEventTargetHelper::WillHandleEvent(aVisitor
);
4611 nsDOMDeviceStorage::PostHandleEvent(EventChainPostVisitor
& aVisitor
)
4613 return DOMEventTargetHelper::PostHandleEvent(aVisitor
);
4617 nsDOMDeviceStorage::DispatchDOMEvent(WidgetEvent
* aEvent
,
4618 nsIDOMEvent
* aDOMEvent
,
4619 nsPresContext
* aPresContext
,
4620 nsEventStatus
* aEventStatus
)
4622 return DOMEventTargetHelper::DispatchDOMEvent(aEvent
,
4628 EventListenerManager
*
4629 nsDOMDeviceStorage::GetOrCreateListenerManager()
4631 return DOMEventTargetHelper::GetOrCreateListenerManager();
4634 EventListenerManager
*
4635 nsDOMDeviceStorage::GetExistingListenerManager() const
4637 return DOMEventTargetHelper::GetExistingListenerManager();
4641 nsDOMDeviceStorage::GetContextForEventHandlers(nsresult
*aRv
)
4643 return DOMEventTargetHelper::GetContextForEventHandlers(aRv
);
4647 nsDOMDeviceStorage::GetJSContextForEventHandlers()
4649 return DOMEventTargetHelper::GetJSContextForEventHandlers();
4652 NS_IMPL_EVENT_HANDLER(nsDOMDeviceStorage
, change
)