Bug 1299500 - Get rid of DeviceStorage API - part 10 - DeviceStorage, r=ehsan, r=billm

This commit is contained in:
Andrea Marchesini 2017-03-08 20:15:45 +01:00
parent fb4c8780f3
commit 12b54aa0f5
75 changed files with 1 additions and 11992 deletions

View file

@ -89,38 +89,6 @@ var AdbController = {
updateState: function() {
this.umsActive = false;
this.storages = navigator.getDeviceStorages('sdcard');
this.updateStorageState(0);
},
updateStorageState: function(storageIndex) {
if (storageIndex >= this.storages.length) {
// We've iterated through all of the storage objects, now we can
// really do updateStateInternal.
this.updateStateInternal();
return;
}
let storage = this.storages[storageIndex];
DEBUG && debug("Checking availability of storage: '" + storage.storageName + "'");
let req = storage.available();
req.onsuccess = function(e) {
DEBUG && debug("Storage: '" + storage.storageName + "' is '" + e.target.result + "'");
if (e.target.result == 'shared') {
// We've found a storage area that's being shared with the PC.
// We can stop looking now.
this.umsActive = true;
this.updateStateInternal();
return;
}
this.updateStorageState(storageIndex + 1);
}.bind(this);
req.onerror = function(e) {
Cu.reportError("AdbController: error querying storage availability for '" +
this.storages[storageIndex].storageName + "' (ignoring)\n");
this.updateStorageState(storageIndex + 1);
}.bind(this);
},
updateStateInternal: function() {

View file

@ -307,11 +307,6 @@ DOMInterfaces = {
'headerFile': 'mozilla/dom/DeviceMotionEvent.h',
},
'DeviceStorage': {
'nativeType': 'nsDOMDeviceStorage',
'headerFile': 'DeviceStorage.h',
},
'Document': {
'nativeType': 'nsIDocument',
},

View file

@ -1,382 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DeviceStorage_h
#define DeviceStorage_h
#include "nsAutoPtr.h"
#include "nsIFile.h"
#include "nsIPrincipal.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/DOMRequest.h"
#include "nsWeakReference.h"
#define DEVICESTORAGE_PICTURES "pictures"
#define DEVICESTORAGE_VIDEOS "videos"
#define DEVICESTORAGE_MUSIC "music"
#define DEVICESTORAGE_APPS "apps"
#define DEVICESTORAGE_SDCARD "sdcard"
#define DEVICESTORAGE_CRASHES "crashes"
class nsIInputStream;
class nsIOutputStream;
struct DeviceStorageFileDescriptor;
#ifdef MOZ_WIDGET_GONK
class nsIVolume;
#endif
namespace mozilla {
class EventListenerManager;
namespace dom {
class Blob;
struct DeviceStorageEnumerationParameters;
class DOMCursor;
class DOMRequest;
class Promise;
class DeviceStorageFileSystem;
} // namespace dom
namespace ipc {
class FileDescriptor;
class PrincipalInfo;
} // namespace ipc
} // namespace mozilla
class DeviceStorageRequest;
class DeviceStorageCursorRequest;
class DeviceStorageRequestManager;
class nsDOMDeviceStorageCursor;
class DeviceStorageFile final
: public nsISupports {
public:
nsCOMPtr<nsIFile> mFile;
nsString mStorageType;
nsString mStorageName;
nsString mRootDir;
nsString mPath;
bool mEditable;
nsString mMimeType;
uint64_t mLength;
uint64_t mLastModifiedDate;
// Used when the path will be set later via SetPath.
DeviceStorageFile(const nsAString& aStorageType,
const nsAString& aStorageName);
// Used for non-enumeration purposes.
DeviceStorageFile(const nsAString& aStorageType,
const nsAString& aStorageName,
const nsAString& aPath);
// Used for enumerations. When you call Enumerate, you can pass in a
// directory to enumerate and the results that are returned are relative to
// that directory, files related to an enumeration need to know the "root of
// the enumeration" directory.
DeviceStorageFile(const nsAString& aStorageType,
const nsAString& aStorageName,
const nsAString& aRootDir,
const nsAString& aPath);
void SetPath(const nsAString& aPath);
void SetEditable(bool aEditable);
static already_AddRefed<DeviceStorageFile>
CreateUnique(nsAString& aFileName,
uint32_t aFileType,
uint32_t aFileAttributes);
static already_AddRefed<DeviceStorageFile>
CreateUnique(const nsAString& aStorageType,
const nsAString& aStorageName,
nsAString& aFileName,
uint32_t aFileType,
uint32_t aFileAttributes);
NS_DECL_THREADSAFE_ISUPPORTS
bool IsAvailable();
void GetFullPath(nsAString& aFullPath);
// we want to make sure that the names of file can't reach
// outside of the type of storage the user asked for.
bool IsSafePath() const;
bool ValidateAndSplitPath(const nsAString& aPath,
nsTArray<nsString>* aParts = nullptr) const;
void Dump(const char* label);
nsresult Remove();
nsresult Write(nsIInputStream* aInputStream);
nsresult Write(InfallibleTArray<uint8_t>& bits);
nsresult Append(nsIInputStream* aInputStream);
nsresult Append(nsIInputStream* aInputStream,
nsIOutputStream* aOutputStream);
void CollectFiles(nsTArray<RefPtr<DeviceStorageFile> >& aFiles,
PRTime aSince = 0);
void collectFilesInternal(nsTArray<RefPtr<DeviceStorageFile> >& aFiles,
PRTime aSince, nsAString& aRootPath);
void AccumDiskUsage(uint64_t* aPicturesSoFar, uint64_t* aVideosSoFar,
uint64_t* aMusicSoFar, uint64_t* aTotalSoFar);
void GetStorageFreeSpace(int64_t* aSoFar);
void GetStatus(nsAString& aStatus);
void GetStorageStatus(nsAString& aStatus);
void DoFormat(nsAString& aStatus);
void DoMount(nsAString& aStatus);
void DoUnmount(nsAString& aStatus);
static void GetRootDirectoryForType(const nsAString& aStorageType,
const nsAString& aStorageName,
nsIFile** aFile);
nsresult CalculateSizeAndModifiedDate();
nsresult CalculateMimeType();
nsresult CreateFileDescriptor(mozilla::ipc::FileDescriptor& aFileDescriptor);
private:
~DeviceStorageFile() {}
void Init();
void AppendRelativePath(const nsAString& aPath);
void AccumDirectoryUsage(nsIFile* aFile,
uint64_t* aPicturesSoFar,
uint64_t* aVideosSoFar,
uint64_t* aMusicSoFar,
uint64_t* aTotalSoFar);
};
#define NS_DOM_DEVICE_STORAGE_CID \
{ 0xe4a9b969, 0x81fe, 0x44f1, \
{ 0xaa, 0x0c, 0x9e, 0x16, 0x64, 0x86, 0x2a, 0xd5 } }
class nsDOMDeviceStorage final
: public mozilla::DOMEventTargetHelper
, public nsSupportsWeakReference
{
typedef mozilla::ErrorResult ErrorResult;
typedef mozilla::dom::DeviceStorageEnumerationParameters
EnumerationParameters;
typedef mozilla::dom::DOMCursor DOMCursor;
typedef mozilla::dom::DOMRequest DOMRequest;
typedef mozilla::dom::Promise Promise;
typedef mozilla::dom::DeviceStorageFileSystem DeviceStorageFileSystem;
public:
typedef nsTArray<nsString> VolumeNameArray;
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_DEVICE_STORAGE_CID)
NS_DECL_ISUPPORTS_INHERITED
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
void EventListenerWasAdded(const nsAString& aType,
ErrorResult& aRv,
JSCompartment* aCompartment) override;
explicit nsDOMDeviceStorage(nsPIDOMWindowInner* aWindow);
static int InstanceCount() { return sInstanceCount; }
static void InvalidateVolumeCaches();
nsresult Init(nsPIDOMWindowInner* aWindow, const nsAString& aType,
const nsAString& aVolName);
bool IsAvailable();
bool IsFullPath(const nsAString& aPath)
{
return aPath.Length() > 0 && aPath.CharAt(0) == '/';
}
void SetRootDirectoryForType(const nsAString& aType,
const nsAString& aVolName);
// WebIDL
nsPIDOMWindowInner*
GetParentObject() const
{
return GetOwner();
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
IMPL_EVENT_HANDLER(change)
already_AddRefed<DOMRequest>
Add(mozilla::dom::Blob* aBlob, ErrorResult& aRv);
already_AddRefed<DOMRequest>
AddNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath, ErrorResult& aRv);
already_AddRefed<DOMRequest>
AppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
ErrorResult& aRv);
already_AddRefed<DOMRequest>
Get(const nsAString& aPath, ErrorResult& aRv)
{
return GetInternal(aPath, false, aRv);
}
already_AddRefed<DOMRequest>
GetEditable(const nsAString& aPath, ErrorResult& aRv)
{
return GetInternal(aPath, true, aRv);
}
already_AddRefed<DOMRequest>
Delete(const nsAString& aPath, ErrorResult& aRv);
already_AddRefed<DOMCursor>
Enumerate(const EnumerationParameters& aOptions, ErrorResult& aRv)
{
return Enumerate(NullString(), aOptions, aRv);
}
already_AddRefed<DOMCursor>
Enumerate(const nsAString& aPath, const EnumerationParameters& aOptions,
ErrorResult& aRv);
already_AddRefed<DOMCursor>
EnumerateEditable(const EnumerationParameters& aOptions, ErrorResult& aRv)
{
return EnumerateEditable(NullString(), aOptions, aRv);
}
already_AddRefed<DOMCursor>
EnumerateEditable(const nsAString& aPath,
const EnumerationParameters& aOptions, ErrorResult& aRv);
already_AddRefed<DOMRequest> FreeSpace(ErrorResult& aRv);
already_AddRefed<DOMRequest> UsedSpace(ErrorResult& aRv);
already_AddRefed<DOMRequest> Available(ErrorResult& aRv);
already_AddRefed<DOMRequest> Format(ErrorResult& aRv);
already_AddRefed<DOMRequest> StorageStatus(ErrorResult& aRv);
already_AddRefed<DOMRequest> Mount(ErrorResult& aRv);
already_AddRefed<DOMRequest> Unmount(ErrorResult& aRv);
already_AddRefed<DOMRequest> CreateFileDescriptor(const nsAString& aPath,
DeviceStorageFileDescriptor* aDSFD,
ErrorResult& aRv);
bool CanBeMounted();
bool CanBeFormatted();
bool CanBeShared();
bool IsRemovable();
bool LowDiskSpace();
bool Default();
void GetStorageName(nsAString& aStorageName);
already_AddRefed<Promise>
GetRoot(ErrorResult& aRv);
static void
CreateDeviceStorageFor(nsPIDOMWindowInner* aWin,
const nsAString& aType,
nsDOMDeviceStorage** aStore);
static void
CreateDeviceStorageByNameAndType(nsPIDOMWindowInner* aWin,
const nsAString& aName,
const nsAString& aType,
nsDOMDeviceStorage** aStore);
bool Equals(nsPIDOMWindowInner* aWin,
const nsAString& aName,
const nsAString& aType);
void Shutdown();
static void GetOrderedVolumeNames(const nsAString& aType,
nsTArray<nsString>& aVolumeNames);
static void GetOrderedVolumeNames(nsTArray<nsString>& aVolumeNames);
static void GetDefaultStorageName(const nsAString& aStorageType,
nsAString& aStorageName);
static bool ParseFullPath(const nsAString& aFullPath,
nsAString& aOutStorageName,
nsAString& aOutStoragePath);
// DeviceStorageStatics callbacks
void OnFileWatcherUpdate(const nsCString& aData, DeviceStorageFile* aFile);
void OnDiskSpaceWatcher(bool aLowDiskSpace);
void OnWritableNameChanged();
#ifdef MOZ_WIDGET_GONK
void OnVolumeStateChanged(nsIVolume* aVolume);
#endif
uint32_t CreateDOMRequest(DOMRequest** aRequest, ErrorResult& aRv);
uint32_t CreateDOMCursor(DeviceStorageCursorRequest* aRequest,
nsDOMDeviceStorageCursor** aCursor,
ErrorResult& aRv);
already_AddRefed<DOMRequest> CreateAndRejectDOMRequest(const char *aReason,
ErrorResult& aRv);
nsresult CheckPermission(already_AddRefed<DeviceStorageRequest>&& aRequest);
bool IsOwningThread();
nsresult DispatchToOwningThread(already_AddRefed<nsIRunnable>&& aRunnable);
private:
~nsDOMDeviceStorage();
static nsresult CheckPrincipal(nsPIDOMWindowInner* aWindow,
bool aIsAppsStorage,
nsIPrincipal** aPrincipal);
already_AddRefed<DOMRequest>
AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
bool aCreate, ErrorResult& aRv);
already_AddRefed<DOMRequest>
GetInternal(const nsAString& aPath, bool aEditable, ErrorResult& aRv);
void
DeleteInternal(nsPIDOMWindowInner* aWin, const nsAString& aPath,
DOMRequest* aRequest);
already_AddRefed<DOMCursor>
EnumerateInternal(const nsAString& aName,
const EnumerationParameters& aOptions, bool aEditable,
ErrorResult& aRv);
static int sInstanceCount;
nsString mStorageType;
nsCOMPtr<nsIFile> mRootDirectory;
nsString mStorageName;
bool mIsShareable;
bool mIsRemovable;
already_AddRefed<nsDOMDeviceStorage> GetStorage(const nsAString& aFullPath,
nsAString& aOutStoragePath);
already_AddRefed<nsDOMDeviceStorage>
GetStorageByName(const nsAString &aStorageName);
static already_AddRefed<nsDOMDeviceStorage>
GetStorageByNameAndType(nsPIDOMWindowInner* aWin,
const nsAString& aStorageName,
const nsAString& aType);
bool mIsDefaultLocation;
nsresult Notify(const char* aReason, class DeviceStorageFile* aFile);
friend class WatchFileEvent;
friend class DeviceStorageRequest;
static mozilla::StaticAutoPtr<nsTArray<nsString>> sVolumeNameCache;
#ifdef MOZ_WIDGET_GONK
nsString mLastStatus;
nsString mLastStorageStatus;
void DispatchStatusChangeEvent(nsAString& aStatus);
void DispatchStorageStatusChangeEvent(nsAString& aStorageStatus);
#endif
uint64_t mInnerWindowID;
RefPtr<DeviceStorageFileSystem> mFileSystem;
RefPtr<DeviceStorageRequestManager> mManager;
nsAutoPtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
nsCOMPtr<nsIThread> mOwningThread;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMDeviceStorage, NS_DOM_DEVICE_STORAGE_CID)
#endif

View file

@ -1,21 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DeviceStorageFileDescriptor_h
#define DeviceStorageFileDescriptor_h
#include "mozilla/ipc/FileDescriptor.h"
struct DeviceStorageFileDescriptor final
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceStorageFileDescriptor)
RefPtr<DeviceStorageFile> mDSFile;
mozilla::ipc::FileDescriptor mFileDescriptor;
private:
~DeviceStorageFileDescriptor() {}
};
#endif

View file

@ -1,151 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DeviceStorageRequestChild.h"
#include "DeviceStorageFileDescriptor.h"
#include "nsDeviceStorage.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/ipc/BlobChild.h"
namespace mozilla {
namespace dom {
namespace devicestorage {
DeviceStorageRequestChild::DeviceStorageRequestChild()
{
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
}
DeviceStorageRequestChild::DeviceStorageRequestChild(DeviceStorageRequest* aRequest)
: mRequest(aRequest)
{
MOZ_ASSERT(aRequest);
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
}
DeviceStorageRequestChild::~DeviceStorageRequestChild() {
MOZ_COUNT_DTOR(DeviceStorageRequestChild);
}
mozilla::ipc::IPCResult
DeviceStorageRequestChild::
Recv__delete__(const DeviceStorageResponseValue& aValue)
{
switch (aValue.type()) {
case DeviceStorageResponseValue::TErrorResponse:
{
DS_LOG_INFO("error %u", mRequest->GetId());
ErrorResponse r = aValue;
mRequest->Reject(r.error());
break;
}
case DeviceStorageResponseValue::TSuccessResponse:
{
DS_LOG_INFO("success %u", mRequest->GetId());
nsString fullPath;
mRequest->GetFile()->GetFullPath(fullPath);
mRequest->Resolve(fullPath);
break;
}
case DeviceStorageResponseValue::TFileDescriptorResponse:
{
DS_LOG_INFO("fd %u", mRequest->GetId());
FileDescriptorResponse r = aValue;
DeviceStorageFile* file = mRequest->GetFile();
DeviceStorageFileDescriptor* descriptor = mRequest->GetFileDescriptor();
nsString fullPath;
file->GetFullPath(fullPath);
descriptor->mDSFile = file;
descriptor->mFileDescriptor = r.fileDescriptor();
mRequest->Resolve(fullPath);
break;
}
case DeviceStorageResponseValue::TBlobResponse:
{
DS_LOG_INFO("blob %u", mRequest->GetId());
BlobResponse r = aValue;
BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
RefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
mRequest->Resolve(blobImpl.get());
break;
}
case DeviceStorageResponseValue::TFreeSpaceStorageResponse:
{
DS_LOG_INFO("free %u", mRequest->GetId());
FreeSpaceStorageResponse r = aValue;
mRequest->Resolve(r.freeBytes());
break;
}
case DeviceStorageResponseValue::TUsedSpaceStorageResponse:
{
DS_LOG_INFO("used %u", mRequest->GetId());
UsedSpaceStorageResponse r = aValue;
mRequest->Resolve(r.usedBytes());
break;
}
case DeviceStorageResponseValue::TFormatStorageResponse:
{
DS_LOG_INFO("format %u", mRequest->GetId());
FormatStorageResponse r = aValue;
mRequest->Resolve(r.mountState());
break;
}
case DeviceStorageResponseValue::TMountStorageResponse:
{
DS_LOG_INFO("mount %u", mRequest->GetId());
MountStorageResponse r = aValue;
mRequest->Resolve(r.storageStatus());
break;
}
case DeviceStorageResponseValue::TUnmountStorageResponse:
{
DS_LOG_INFO("unmount %u", mRequest->GetId());
UnmountStorageResponse r = aValue;
mRequest->Resolve(r.storageStatus());
break;
}
case DeviceStorageResponseValue::TEnumerationResponse:
{
DS_LOG_INFO("enumerate %u", mRequest->GetId());
EnumerationResponse r = aValue;
auto request = static_cast<DeviceStorageCursorRequest*>(mRequest.get());
uint32_t count = r.paths().Length();
request->AddFiles(count);
for (uint32_t i = 0; i < count; i++) {
RefPtr<DeviceStorageFile> dsf
= new DeviceStorageFile(r.type(), r.paths()[i].storageName(),
r.rootdir(), r.paths()[i].name());
request->AddFile(dsf.forget());
}
request->Continue();
break;
}
default:
{
DS_LOG_ERROR("unknown %u", mRequest->GetId());
MOZ_CRASH("not reached");
break;
}
}
return IPC_OK();
}
} // namespace devicestorage
} // namespace dom
} // namespace mozilla

View file

@ -1,44 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_devicestorage_DeviceStorageRequestChild_h
#define mozilla_dom_devicestorage_DeviceStorageRequestChild_h
#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
class DeviceStorageFile;
class DeviceStorageRequest;
struct DeviceStorageFileDescriptor;
namespace mozilla {
namespace dom {
namespace devicestorage {
class DeviceStorageRequestChildCallback
{
public:
virtual void RequestComplete() = 0;
};
class DeviceStorageRequestChild : public PDeviceStorageRequestChild
{
public:
DeviceStorageRequestChild();
explicit DeviceStorageRequestChild(DeviceStorageRequest* aRequest);
~DeviceStorageRequestChild();
virtual mozilla::ipc::IPCResult Recv__delete__(const DeviceStorageResponseValue& value);
private:
RefPtr<DeviceStorageRequest> mRequest;
};
} // namespace devicestorage
} // namespace dom
} // namespace mozilla
#endif

View file

@ -1,595 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DeviceStorageRequestParent.h"
#include "nsIMIMEService.h"
#include "nsCExternalHandlerService.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/FileBlobImpl.h"
#include "mozilla/dom/ipc/BlobParent.h"
#include "ContentParent.h"
#include "nsProxyRelease.h"
#include "mozilla/Preferences.h"
#include "nsNetCID.h"
namespace mozilla {
namespace dom {
namespace devicestorage {
DeviceStorageRequestParent::DeviceStorageRequestParent(
const DeviceStorageParams& aParams)
: mParams(aParams)
, mMutex("DeviceStorageRequestParent::mMutex")
, mActorDestroyed(false)
{
MOZ_COUNT_CTOR(DeviceStorageRequestParent);
DebugOnly<DeviceStorageUsedSpaceCache*> usedSpaceCache
= DeviceStorageUsedSpaceCache::CreateOrGet();
MOZ_ASSERT(usedSpaceCache);
}
void
DeviceStorageRequestParent::Dispatch()
{
RefPtr<CancelableRunnable> r;
switch (mParams.type()) {
case DeviceStorageParams::TDeviceStorageAddParams:
{
DeviceStorageAddParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
ErrorResult rv;
nsCOMPtr<nsIInputStream> stream;
blobImpl->GetInternalStream(getter_AddRefs(stream), rv);
MOZ_ASSERT(!rv.Failed());
r = new WriteFileEvent(this, dsf.forget(), stream,
DEVICE_STORAGE_REQUEST_CREATE);
break;
}
case DeviceStorageParams::TDeviceStorageAppendParams:
{
DeviceStorageAppendParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
ErrorResult rv;
nsCOMPtr<nsIInputStream> stream;
blobImpl->GetInternalStream(getter_AddRefs(stream), rv);
MOZ_ASSERT(!rv.Failed());
r = new WriteFileEvent(this, dsf.forget(), stream,
DEVICE_STORAGE_REQUEST_APPEND);
break;
}
case DeviceStorageParams::TDeviceStorageCreateFdParams:
{
DeviceStorageCreateFdParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
r = new CreateFdEvent(this, dsf.forget());
break;
}
case DeviceStorageParams::TDeviceStorageGetParams:
{
DeviceStorageGetParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName(),
p.rootDir(), p.relpath());
r = new ReadFileEvent(this, dsf.forget());
break;
}
case DeviceStorageParams::TDeviceStorageDeleteParams:
{
DeviceStorageDeleteParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
r = new DeleteFileEvent(this, dsf.forget());
break;
}
case DeviceStorageParams::TDeviceStorageFreeSpaceParams:
{
DeviceStorageFreeSpaceParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName());
r = new FreeSpaceFileEvent(this, dsf.forget());
break;
}
case DeviceStorageParams::TDeviceStorageUsedSpaceParams:
{
DeviceStorageUsedSpaceCache* usedSpaceCache
= DeviceStorageUsedSpaceCache::CreateOrGet();
MOZ_ASSERT(usedSpaceCache);
DeviceStorageUsedSpaceParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName());
usedSpaceCache->Dispatch(
MakeAndAddRef<UsedSpaceFileEvent>(this, dsf.forget()));
return;
}
case DeviceStorageParams::TDeviceStorageFormatParams:
{
DeviceStorageFormatParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName());
DebugOnly<nsresult> rv = NS_DispatchToMainThread(
new PostFormatResultEvent(this, dsf.forget()));
MOZ_ASSERT(NS_SUCCEEDED(rv));
return;
}
case DeviceStorageParams::TDeviceStorageMountParams:
{
DeviceStorageMountParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName());
DebugOnly<nsresult> rv = NS_DispatchToMainThread(
new PostMountResultEvent(this, dsf.forget()));
MOZ_ASSERT(NS_SUCCEEDED(rv));
return;
}
case DeviceStorageParams::TDeviceStorageUnmountParams:
{
DeviceStorageUnmountParams p = mParams;
RefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName());
DebugOnly<nsresult> rv = NS_DispatchToMainThread(
new PostUnmountResultEvent(this, dsf.forget()));
MOZ_ASSERT(NS_SUCCEEDED(rv));
return;
}
case DeviceStorageParams::TDeviceStorageEnumerationParams:
{
DeviceStorageEnumerationParams p = mParams;
RefPtr<DeviceStorageFile> dsf
= new DeviceStorageFile(p.type(), p.storageName(),
p.rootdir(), NS_LITERAL_STRING(""));
r = new EnumerateFileEvent(this, dsf.forget(), p.since());
break;
}
default:
{
MOZ_CRASH("not reached");
return;
}
}
if (r) {
nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
}
DeviceStorageRequestParent::~DeviceStorageRequestParent()
{
MOZ_COUNT_DTOR(DeviceStorageRequestParent);
}
NS_IMPL_ADDREF(DeviceStorageRequestParent)
NS_IMPL_RELEASE(DeviceStorageRequestParent)
void
DeviceStorageRequestParent::ActorDestroy(ActorDestroyReason)
{
MutexAutoLock lock(mMutex);
mActorDestroyed = true;
for (auto& runnable : mRunnables) {
runnable->Cancel();
}
// Ensure we clear all references to the runnables so that there won't
// be leak due to cyclic reference. Note that it is safe to release
// the references here, since if a runnable is not cancelled yet, the
// corresponding thread should still hold a reference to it, and thus
// the runnable will end up being released in that thread, not here.
mRunnables.Clear();
}
DeviceStorageRequestParent::PostFreeSpaceResultEvent::PostFreeSpaceResultEvent(
DeviceStorageRequestParent* aParent,
uint64_t aFreeSpace)
: CancelableRunnable(aParent)
, mFreeSpace(aFreeSpace)
{
}
DeviceStorageRequestParent::PostFreeSpaceResultEvent::
~PostFreeSpaceResultEvent() {}
nsresult
DeviceStorageRequestParent::PostFreeSpaceResultEvent::CancelableRun() {
MOZ_ASSERT(NS_IsMainThread());
FreeSpaceStorageResponse response(mFreeSpace);
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
nsresult
DeviceStorageRequestParent::PostUsedSpaceResultEvent::CancelableRun() {
MOZ_ASSERT(NS_IsMainThread());
UsedSpaceStorageResponse response(mUsedSpace);
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
DeviceStorageRequestParent::PostErrorEvent::
PostErrorEvent(DeviceStorageRequestParent* aParent, const char* aError)
: CancelableRunnable(aParent)
{
CopyASCIItoUTF16(aError, mError);
}
nsresult
DeviceStorageRequestParent::PostErrorEvent::CancelableRun() {
MOZ_ASSERT(NS_IsMainThread());
ErrorResponse response(mError);
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
nsresult
DeviceStorageRequestParent::PostSuccessEvent::CancelableRun() {
MOZ_ASSERT(NS_IsMainThread());
SuccessResponse response;
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
nsresult
DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
MOZ_ASSERT(NS_IsMainThread());
nsString mime;
CopyASCIItoUTF16(mMimeType, mime);
nsString fullPath;
mFile->GetFullPath(fullPath);
RefPtr<BlobImpl> blob =
new FileBlobImpl(fullPath, mime, mLength, mFile->mFile,
mLastModificationDate);
ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
BlobParent* actor = cp->GetOrCreateActorForBlobImpl(blob);
if (!actor) {
ErrorResponse response(NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN));
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
BlobResponse response;
response.blobParent() = actor;
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
nsresult
DeviceStorageRequestParent::PostEnumerationSuccessEvent::CancelableRun() {
MOZ_ASSERT(NS_IsMainThread());
EnumerationResponse response(mStorageType, mRelPath, mPaths);
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
nsresult
DeviceStorageRequestParent::CreateFdEvent::CancelableRun()
{
MOZ_ASSERT(!NS_IsMainThread());
if (!mFile->mFile) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN));
}
bool check = false;
mFile->mFile->Exists(&check);
if (check) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_EXISTS));
}
nsCOMPtr<nsIRunnable> r;
FileDescriptor fileDescriptor;
nsresult rv = mFile->CreateFileDescriptor(fileDescriptor);
if (NS_FAILED(rv)) {
NS_WARNING("CreateFileDescriptor failed");
mFile->Dump("CreateFileDescriptor failed");
r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
}
else {
r = new PostFileDescriptorResultEvent(mParent, fileDescriptor);
}
return NS_DispatchToMainThread(r.forget());
}
nsresult
DeviceStorageRequestParent::WriteFileEvent::CancelableRun()
{
MOZ_ASSERT(!NS_IsMainThread());
if (!mInputStream || !mFile->mFile) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN));
}
bool check = false;
nsresult rv;
mFile->mFile->Exists(&check);
if (mRequestType == DEVICE_STORAGE_REQUEST_CREATE) {
if (check) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_EXISTS));
}
rv = mFile->Write(mInputStream);
} else if (mRequestType == DEVICE_STORAGE_REQUEST_APPEND) {
if (!check) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST));
}
rv = mFile->Append(mInputStream);
} else {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN));
}
nsCOMPtr<nsIRunnable> r;
if (NS_FAILED(rv)) {
r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
}
else {
r = new PostPathResultEvent(mParent, mFile->mPath);
}
return NS_DispatchToMainThread(r.forget());
}
nsresult
DeviceStorageRequestParent::DeleteFileEvent::CancelableRun()
{
MOZ_ASSERT(!NS_IsMainThread());
mFile->Remove();
if (!mFile->mFile) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN));
}
nsCOMPtr<nsIRunnable> r;
bool check = false;
mFile->mFile->Exists(&check);
if (check) {
r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
}
else {
r = new PostPathResultEvent(mParent, mFile->mPath);
}
return NS_DispatchToMainThread(r.forget());
}
nsresult
DeviceStorageRequestParent::FreeSpaceFileEvent::CancelableRun()
{
MOZ_ASSERT(!NS_IsMainThread());
int64_t freeSpace = 0;
if (mFile) {
mFile->GetStorageFreeSpace(&freeSpace);
}
return NS_DispatchToMainThread(
new PostFreeSpaceResultEvent(mParent, static_cast<uint64_t>(freeSpace)));
}
nsresult
DeviceStorageRequestParent::UsedSpaceFileEvent::CancelableRun()
{
MOZ_ASSERT(!NS_IsMainThread());
uint64_t picturesUsage = 0, videosUsage = 0, musicUsage = 0, totalUsage = 0;
mFile->AccumDiskUsage(&picturesUsage, &videosUsage,
&musicUsage, &totalUsage);
nsCOMPtr<nsIRunnable> r;
if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_PICTURES)) {
r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType,
picturesUsage);
}
else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) {
r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, videosUsage);
}
else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_MUSIC)) {
r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, musicUsage);
} else {
r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, totalUsage);
}
return NS_DispatchToMainThread(r.forget());
}
DeviceStorageRequestParent::ReadFileEvent::
ReadFileEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile)
: CancelableFileEvent(aParent, Move(aFile))
{
nsCOMPtr<nsIMIMEService> mimeService
= do_GetService(NS_MIMESERVICE_CONTRACTID);
if (mimeService) {
nsresult rv = mimeService->GetTypeFromFile(mFile->mFile, mMimeType);
if (NS_FAILED(rv)) {
mMimeType.Truncate();
}
}
}
nsresult
DeviceStorageRequestParent::ReadFileEvent::CancelableRun()
{
MOZ_ASSERT(!NS_IsMainThread());
if (!mFile->mFile) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN));
}
bool check = false;
mFile->mFile->Exists(&check);
if (!check) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST));
}
int64_t fileSize;
nsresult rv = mFile->mFile->GetFileSize(&fileSize);
if (NS_FAILED(rv)) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN));
}
PRTime modDate;
rv = mFile->mFile->GetLastModifiedTime(&modDate);
if (NS_FAILED(rv)) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN));
}
return NS_DispatchToMainThread(
new PostBlobSuccessEvent(mParent, mFile.forget(),
static_cast<uint64_t>(fileSize),
mMimeType, modDate));
}
nsresult
DeviceStorageRequestParent::EnumerateFileEvent::CancelableRun()
{
MOZ_ASSERT(!NS_IsMainThread());
if (mFile->mFile) {
bool check = false;
mFile->mFile->Exists(&check);
if (!check) {
return NS_DispatchToMainThread(
new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST));
}
}
nsTArray<RefPtr<DeviceStorageFile> > files;
mFile->CollectFiles(files, mSince);
InfallibleTArray<DeviceStorageFileValue> values;
uint32_t count = files.Length();
for (uint32_t i = 0; i < count; i++) {
DeviceStorageFileValue dsvf(files[i]->mStorageName, files[i]->mPath);
values.AppendElement(dsvf);
}
return NS_DispatchToMainThread(
new PostEnumerationSuccessEvent(mParent, mFile->mStorageType,
mFile->mRootDir, values));
}
nsresult
DeviceStorageRequestParent::PostPathResultEvent::CancelableRun()
{
MOZ_ASSERT(NS_IsMainThread());
SuccessResponse response;
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
nsresult
DeviceStorageRequestParent::PostFileDescriptorResultEvent::CancelableRun()
{
MOZ_ASSERT(NS_IsMainThread());
FileDescriptorResponse response(mFileDescriptor);
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
nsresult
DeviceStorageRequestParent::PostFormatResultEvent::CancelableRun()
{
MOZ_ASSERT(NS_IsMainThread());
nsString state = NS_LITERAL_STRING("unavailable");
if (mFile) {
mFile->DoFormat(state);
}
FormatStorageResponse response(state);
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
nsresult
DeviceStorageRequestParent::PostMountResultEvent::CancelableRun()
{
MOZ_ASSERT(NS_IsMainThread());
nsString state = NS_LITERAL_STRING("unavailable");
if (mFile) {
mFile->DoMount(state);
}
MountStorageResponse response(state);
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
nsresult
DeviceStorageRequestParent::PostUnmountResultEvent::CancelableRun()
{
MOZ_ASSERT(NS_IsMainThread());
nsString state = NS_LITERAL_STRING("unavailable");
if (mFile) {
mFile->DoUnmount(state);
}
UnmountStorageResponse response(state);
Unused << mParent->Send__delete__(mParent, response);
return NS_OK;
}
} // namespace devicestorage
} // namespace dom
} // namespace mozilla

View file

@ -1,333 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_devicestorage_DeviceStorageRequestParent_h
#define mozilla_dom_devicestorage_DeviceStorageRequestParent_h
#include "mozilla/Attributes.h"
#include "mozilla/dom/devicestorage/PDeviceStorageRequestParent.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "nsThreadUtils.h"
#include "nsDeviceStorage.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
namespace devicestorage {
class DeviceStorageRequestParent : public PDeviceStorageRequestParent
{
public:
explicit DeviceStorageRequestParent(const DeviceStorageParams& aParams);
NS_IMETHOD_(MozExternalRefCountType) AddRef();
NS_IMETHOD_(MozExternalRefCountType) Release();
void Dispatch();
virtual void ActorDestroy(ActorDestroyReason);
protected:
~DeviceStorageRequestParent();
private:
ThreadSafeAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
DeviceStorageParams mParams;
// XXXkhuey name collision :(
class CancelableRunnable : public Runnable
{
public:
explicit CancelableRunnable(DeviceStorageRequestParent* aParent)
: mParent(aParent)
{
mCanceled = !(mParent->AddRunnable(this));
}
virtual ~CancelableRunnable() {
}
NS_IMETHOD Run() override {
nsresult rv = NS_OK;
if (!mCanceled) {
rv = CancelableRun();
mParent->RemoveRunnable(this);
}
return rv;
}
void Cancel() {
mCanceled = true;
}
virtual nsresult CancelableRun() = 0;
protected:
RefPtr<DeviceStorageRequestParent> mParent;
private:
bool mCanceled;
};
class CancelableFileEvent : public CancelableRunnable
{
protected:
CancelableFileEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile)
: CancelableRunnable(aParent)
, mFile(Move(aFile)) {}
RefPtr<DeviceStorageFile> mFile;
};
class PostErrorEvent : public CancelableRunnable
{
public:
PostErrorEvent(DeviceStorageRequestParent* aParent, const char* aError);
virtual ~PostErrorEvent() {}
virtual nsresult CancelableRun();
private:
nsString mError;
};
class PostSuccessEvent : public CancelableRunnable
{
public:
explicit PostSuccessEvent(DeviceStorageRequestParent* aParent)
: CancelableRunnable(aParent) {}
virtual ~PostSuccessEvent() {}
virtual nsresult CancelableRun();
};
class PostBlobSuccessEvent : public CancelableFileEvent
{
public:
PostBlobSuccessEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile,
uint32_t aLength, nsACString& aMimeType,
uint64_t aLastModifiedDate)
: CancelableFileEvent(aParent, Move(aFile))
, mLength(aLength)
, mLastModificationDate(aLastModifiedDate)
, mMimeType(aMimeType) {}
virtual ~PostBlobSuccessEvent() {}
virtual nsresult CancelableRun();
private:
uint32_t mLength;
uint64_t mLastModificationDate;
nsCString mMimeType;
};
class PostEnumerationSuccessEvent : public CancelableRunnable
{
public:
PostEnumerationSuccessEvent(DeviceStorageRequestParent* aParent,
const nsAString& aStorageType,
const nsAString& aRelPath,
InfallibleTArray<DeviceStorageFileValue>& aPaths)
: CancelableRunnable(aParent)
, mStorageType(aStorageType)
, mRelPath(aRelPath)
, mPaths(aPaths) {}
virtual ~PostEnumerationSuccessEvent() {}
virtual nsresult CancelableRun();
private:
const nsString mStorageType;
const nsString mRelPath;
InfallibleTArray<DeviceStorageFileValue> mPaths;
};
class CreateFdEvent : public CancelableFileEvent
{
public:
CreateFdEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile)
: CancelableFileEvent(aParent, Move(aFile)) {}
virtual ~CreateFdEvent() {}
virtual nsresult CancelableRun();
};
class WriteFileEvent : public CancelableFileEvent
{
public:
WriteFileEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile,
nsIInputStream* aInputStream, int32_t aRequestType)
: CancelableFileEvent(aParent, Move(aFile))
, mInputStream(aInputStream)
, mRequestType(aRequestType) {}
virtual ~WriteFileEvent() {}
virtual nsresult CancelableRun();
private:
nsCOMPtr<nsIInputStream> mInputStream;
int32_t mRequestType;
};
class DeleteFileEvent : public CancelableFileEvent
{
public:
DeleteFileEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile)
: CancelableFileEvent(aParent, Move(aFile)) {}
virtual ~DeleteFileEvent() {}
virtual nsresult CancelableRun();
};
class FreeSpaceFileEvent : public CancelableFileEvent
{
public:
FreeSpaceFileEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile)
: CancelableFileEvent(aParent, Move(aFile)) {}
virtual ~FreeSpaceFileEvent() {}
virtual nsresult CancelableRun();
};
class UsedSpaceFileEvent : public CancelableFileEvent
{
public:
UsedSpaceFileEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile)
: CancelableFileEvent(aParent, Move(aFile)) {}
virtual ~UsedSpaceFileEvent() {}
virtual nsresult CancelableRun();
};
class ReadFileEvent : public CancelableFileEvent
{
public:
ReadFileEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile);
virtual ~ReadFileEvent() {}
virtual nsresult CancelableRun();
private:
nsCString mMimeType;
};
class EnumerateFileEvent : public CancelableFileEvent
{
public:
EnumerateFileEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile,
uint64_t aSince)
: CancelableFileEvent(aParent, Move(aFile))
, mSince(aSince) {}
virtual ~EnumerateFileEvent() {}
virtual nsresult CancelableRun();
private:
uint64_t mSince;
};
class PostPathResultEvent : public CancelableRunnable
{
public:
PostPathResultEvent(DeviceStorageRequestParent* aParent,
const nsAString& aPath)
: CancelableRunnable(aParent)
, mPath(aPath) {}
virtual ~PostPathResultEvent() {}
virtual nsresult CancelableRun();
private:
nsString mPath;
};
class PostFileDescriptorResultEvent : public CancelableRunnable
{
public:
PostFileDescriptorResultEvent(DeviceStorageRequestParent* aParent,
const FileDescriptor& aFileDescriptor)
: CancelableRunnable(aParent)
, mFileDescriptor(aFileDescriptor) {}
virtual ~PostFileDescriptorResultEvent() {}
virtual nsresult CancelableRun();
private:
FileDescriptor mFileDescriptor;
};
class PostFreeSpaceResultEvent : public CancelableRunnable
{
public:
PostFreeSpaceResultEvent(DeviceStorageRequestParent* aParent,
uint64_t aFreeSpace);
virtual ~PostFreeSpaceResultEvent();
virtual nsresult CancelableRun();
private:
uint64_t mFreeSpace;
};
class PostUsedSpaceResultEvent : public CancelableRunnable
{
public:
PostUsedSpaceResultEvent(DeviceStorageRequestParent* aParent,
const nsAString& aType,
uint64_t aUsedSpace)
: CancelableRunnable(aParent)
, mType(aType)
, mUsedSpace(aUsedSpace) {}
virtual ~PostUsedSpaceResultEvent() {}
virtual nsresult CancelableRun();
private:
nsString mType;
uint64_t mUsedSpace;
};
class PostFormatResultEvent : public CancelableFileEvent
{
public:
PostFormatResultEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile)
: CancelableFileEvent(aParent, Move(aFile)) {}
virtual ~PostFormatResultEvent() {}
virtual nsresult CancelableRun();
};
class PostMountResultEvent : public CancelableFileEvent
{
public:
PostMountResultEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile)
: CancelableFileEvent(aParent, Move(aFile)) {}
virtual ~PostMountResultEvent() {}
virtual nsresult CancelableRun();
};
class PostUnmountResultEvent : public CancelableFileEvent
{
public:
PostUnmountResultEvent(DeviceStorageRequestParent* aParent,
already_AddRefed<DeviceStorageFile>&& aFile)
: CancelableFileEvent(aParent, Move(aFile)) {}
virtual ~PostUnmountResultEvent() {}
virtual nsresult CancelableRun();
};
protected:
bool AddRunnable(CancelableRunnable* aRunnable) {
MutexAutoLock lock(mMutex);
if (mActorDestroyed)
return false;
mRunnables.AppendElement(aRunnable);
return true;
}
void RemoveRunnable(CancelableRunnable* aRunnable) {
MutexAutoLock lock(mMutex);
mRunnables.RemoveElement(aRunnable);
}
Mutex mMutex;
bool mActorDestroyed;
nsTArray<RefPtr<CancelableRunnable> > mRunnables;
};
} // namespace devicestorage
} // namespace dom
} // namespace mozilla
#endif

View file

@ -1,930 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DeviceStorageStatics.h"
#include "mozilla/Preferences.h"
#include "nsDeviceStorage.h"
#include "nsIObserverService.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceDefs.h"
#include "nsISupportsPrimitives.h"
#include "nsPrintfCString.h"
#ifdef MOZ_WIDGET_GONK
#include "nsIVolume.h"
#endif
#ifdef MOZ_WIDGET_ANDROID
#include "AndroidBridge.h"
#endif
namespace mozilla {
namespace dom {
namespace devicestorage {
static const char* kPrefOverrideRootDir = "device.storage.overrideRootDir";
static const char* kPrefTesting = "device.storage.testing";
static const char* kPrefPromptTesting = "device.storage.prompt.testing";
static const char* kPrefWritableName = "device.storage.writable.name";
// file-watcher-notify comes from some process (but not the MTP Server)
// to indicate that a file has changed. It eventually winds up in the
// parent process, and then gets broadcast out to all child listeners
// as a file-watcher-update and mtp-watcher-update.
//
// mtp-watcher-notify comes from the MTP Server whenever it detects a change
// and this gets rebroadcast as file-watcher-update to the device storage
// listeners.
//
// download-watcher-notify is treated similarly to file-watcher-notify,
// and gets converted into file-watcher-update and mtp-watcher-update.
//
// We need to make sure that the MTP server doesn't get notified about
// files which it told us it added, otherwise it confuses some clients
// (like the Android-File-Transfer program which runs under OS X).
static const char* kFileWatcherUpdate = "file-watcher-update";
static const char* kMtpWatcherUpdate = "mtp-watcher-update";
static const char* kDiskSpaceWatcher = "disk-space-watcher";
static const char* kFileWatcherNotify = "file-watcher-notify";
static const char* kMtpWatcherNotify = "mtp-watcher-notify";
static const char* kDownloadWatcherNotify = "download-watcher-notify";
StaticRefPtr<DeviceStorageStatics> DeviceStorageStatics::sInstance;
StaticMutex DeviceStorageStatics::sMutex;
NS_IMPL_ISUPPORTS(DeviceStorageStatics,
nsIObserver)
/* static */ void
DeviceStorageStatics::Initialize()
{
MOZ_ASSERT(!sInstance);
StaticMutexAutoLock lock(sMutex);
sInstance = new DeviceStorageStatics();
sInstance->Init();
}
/* static */ void
DeviceStorageStatics::InitializeDirs()
{
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return;
}
/* The actual initialization can only happen on the main thread. This will
either happen when device storage is first used on the main thread, or
(in the future) when a worker is created. */
if (!sInstance->mInitialized && NS_IsMainThread()) {
sInstance->InitDirs();
sInstance->mInitialized = true;
}
MOZ_ASSERT(sInstance->mInitialized);
}
DeviceStorageStatics::DeviceStorageStatics()
: mInitialized(false)
, mPromptTesting(false)
, mLowDiskSpace(false)
{
DS_LOG_INFO("");
}
DeviceStorageStatics::~DeviceStorageStatics()
{
DS_LOG_INFO("");
}
void
DeviceStorageStatics::Init()
{
MOZ_ASSERT(NS_IsMainThread());
sMutex.AssertCurrentThreadOwns();
DS_LOG_INFO("");
Preferences::AddStrongObserver(this, kPrefTesting);
Preferences::AddStrongObserver(this, kPrefPromptTesting);
Preferences::AddStrongObserver(this, kPrefWritableName);
mWritableName = Preferences::GetString(kPrefWritableName);
mPromptTesting = Preferences::GetBool(kPrefPromptTesting, false);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
obs->AddObserver(this, kFileWatcherNotify, false);
obs->AddObserver(this, kMtpWatcherNotify, false);
obs->AddObserver(this, kDownloadWatcherNotify, false);
}
DS_LOG_INFO("");
}
void
DeviceStorageStatics::InitDirs()
{
MOZ_ASSERT(NS_IsMainThread());
sMutex.AssertCurrentThreadOwns();
DS_LOG_INFO("");
#if !defined(MOZ_WIDGET_GONK)
if (!XRE_IsParentProcess()) {
// For gonk, we have the parent process forward the directory information
// to the child using ContentParent::ForwardKnownInfo. On desktop, this
// winds up slowing down the startup (in particular ts_paint), so rather
// than penalize all e10s processes, we do a synchronous IPC call here,
// which only penalizes child processes which actually use DeviceStorage.
dom::ContentChild* child = dom::ContentChild::GetSingleton();
DeviceStorageLocationInfo locationInfo;
child->SendGetDeviceStorageLocations(&locationInfo);
NS_NewLocalFile(locationInfo.apps(), true, getter_AddRefs(sInstance->mDirs[TYPE_APPS]));
NS_NewLocalFile(locationInfo.crashes(), true, getter_AddRefs(sInstance->mDirs[TYPE_CRASHES]));
NS_NewLocalFile(locationInfo.pictures(), true, getter_AddRefs(sInstance->mDirs[TYPE_PICTURES]));
NS_NewLocalFile(locationInfo.videos(), true, getter_AddRefs(sInstance->mDirs[TYPE_VIDEOS]));
NS_NewLocalFile(locationInfo.music(), true, getter_AddRefs(sInstance->mDirs[TYPE_MUSIC]));
NS_NewLocalFile(locationInfo.sdcard(), true, getter_AddRefs(sInstance->mDirs[TYPE_SDCARD]));
sInstance->mInitialized = true;
return;
}
#endif
nsCOMPtr<nsIProperties> dirService
= do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
MOZ_ASSERT(dirService);
#if !defined(MOZ_WIDGET_GONK)
// Keep MOZ_WIDGET_COCOA above XP_UNIX,
// because both are defined in Darwin builds.
#if defined (MOZ_WIDGET_COCOA)
dirService->Get(NS_OSX_PICTURE_DOCUMENTS_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_PICTURES]));
dirService->Get(NS_OSX_MOVIE_DOCUMENTS_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_VIDEOS]));
dirService->Get(NS_OSX_MUSIC_DOCUMENTS_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_MUSIC]));
// Keep MOZ_WIDGET_ANDROID above XP_UNIX,
// because both are defined in Android builds.
#elif defined (MOZ_WIDGET_ANDROID)
nsAutoString path;
if (NS_SUCCEEDED(mozilla::AndroidBridge::GetExternalPublicDirectory(
NS_LITERAL_STRING(DEVICESTORAGE_PICTURES), path))) {
NS_NewLocalFile(path, /* aFollowLinks */ true,
getter_AddRefs(mDirs[TYPE_PICTURES]));
}
if (NS_SUCCEEDED(mozilla::AndroidBridge::GetExternalPublicDirectory(
NS_LITERAL_STRING(DEVICESTORAGE_VIDEOS), path))) {
NS_NewLocalFile(path, /* aFollowLinks */ true,
getter_AddRefs(mDirs[TYPE_VIDEOS]));
}
if (NS_SUCCEEDED(mozilla::AndroidBridge::GetExternalPublicDirectory(
NS_LITERAL_STRING(DEVICESTORAGE_MUSIC), path))) {
NS_NewLocalFile(path, /* aFollowLinks */ true,
getter_AddRefs(mDirs[TYPE_MUSIC]));
}
if (NS_SUCCEEDED(mozilla::AndroidBridge::GetExternalPublicDirectory(
NS_LITERAL_STRING(DEVICESTORAGE_SDCARD), path))) {
NS_NewLocalFile(path, /* aFollowLinks */ true,
getter_AddRefs(mDirs[TYPE_SDCARD]));
}
#elif defined (XP_UNIX)
dirService->Get(NS_UNIX_XDG_PICTURES_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_PICTURES]));
dirService->Get(NS_UNIX_XDG_VIDEOS_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_VIDEOS]));
dirService->Get(NS_UNIX_XDG_MUSIC_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_MUSIC]));
#elif defined (XP_WIN)
dirService->Get(NS_WIN_PICTURES_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_PICTURES]));
dirService->Get(NS_WIN_VIDEOS_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_VIDEOS]));
dirService->Get(NS_WIN_MUSIC_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_MUSIC]));
#endif
#ifndef MOZ_WIDGET_ANDROID
// Eventually, on desktop, we want to do something smarter -- for example,
// detect when an sdcard is inserted, and use that instead of this.
dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_SDCARD]));
if (mDirs[TYPE_SDCARD]) {
mDirs[TYPE_SDCARD]->AppendRelativeNativePath(NS_LITERAL_CSTRING("fake-sdcard"));
}
#endif // !MOZ_WIDGET_ANDROID
dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_APPS]));
if (mDirs[TYPE_APPS]) {
mDirs[TYPE_APPS]->AppendRelativeNativePath(NS_LITERAL_CSTRING("webapps"));
}
#endif // !MOZ_WIDGET_GONK
#ifdef MOZ_WIDGET_GONK
NS_NewLocalFile(NS_LITERAL_STRING("/data"),
false,
getter_AddRefs(mDirs[TYPE_APPS]));
#endif
if (XRE_IsParentProcess()) {
NS_GetSpecialDirectory("UAppData", getter_AddRefs(mDirs[TYPE_CRASHES]));
if (mDirs[TYPE_CRASHES]) {
mDirs[TYPE_CRASHES]->Append(NS_LITERAL_STRING("Crash Reports"));
}
}
#ifdef MOZ_WIDGET_GONK
// NS_GetSpecialDirectory("UAppData") fails in content processes because
// gAppData from toolkit/xre/nsAppRunner.cpp is not initialized.
else {
NS_NewLocalFile(NS_LITERAL_STRING("/data/b2g/mozilla/Crash Reports"),
false,
getter_AddRefs(mDirs[TYPE_CRASHES]));
}
#endif
// Directories which don't depend on a volume should be calculated once
// here. Directories which depend on the root directory of a volume
// should be calculated in DeviceStorageFile::GetRootDirectoryForType.
Preferences::AddStrongObserver(this, kPrefOverrideRootDir);
ResetOverrideRootDir();
}
void
DeviceStorageStatics::DumpDirs()
{
#ifdef DS_LOGGING
sMutex.AssertCurrentThreadOwns();
static const char* storageTypes[] = {
"app",
"crashes",
"pictures",
"videos",
"music",
"sdcard",
"override",
nullptr
};
const char* ptStr;
if (XRE_IsParentProcess()) {
ptStr = "parent";
} else {
ptStr = "child";
}
for (uint32_t i = 0; i < TYPE_COUNT; ++i) {
MOZ_ASSERT(storageTypes[i]);
nsString path;
if (mDirs[i]) {
mDirs[i]->GetPath(path);
}
DS_LOG_INFO("(%s) %s: '%s'",
ptStr, storageTypes[i], NS_LossyConvertUTF16toASCII(path).get());
}
#endif
}
void
DeviceStorageStatics::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
sMutex.AssertCurrentThreadOwns();
DS_LOG_INFO("");
Preferences::RemoveObserver(this, kPrefOverrideRootDir);
Preferences::RemoveObserver(this, kPrefTesting);
Preferences::RemoveObserver(this, kPrefPromptTesting);
Preferences::RemoveObserver(this, kPrefWritableName);
}
/* static */ void
DeviceStorageStatics::GetDeviceStorageLocationsForIPC(
DeviceStorageLocationInfo* aLocationInfo)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
InitializeDirs();
GetDirPath(TYPE_APPS, aLocationInfo->apps());
GetDirPath(TYPE_CRASHES, aLocationInfo->crashes());
GetDirPath(TYPE_PICTURES, aLocationInfo->pictures());
GetDirPath(TYPE_VIDEOS, aLocationInfo->videos());
GetDirPath(TYPE_MUSIC, aLocationInfo->music());
GetDirPath(TYPE_SDCARD, aLocationInfo->sdcard());
}
/* static */ already_AddRefed<nsIFile>
DeviceStorageStatics::GetDir(DeviceStorageType aType)
{
MOZ_ASSERT(aType < TYPE_COUNT);
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return nullptr;
}
nsCOMPtr<nsIFile> file;
switch (aType) {
case TYPE_APPS:
case TYPE_CRASHES:
case TYPE_OVERRIDE:
file = sInstance->mDirs[aType];
return file.forget();
default:
break;
}
// In testing, we default all device storage types to a temp directory.
// This is only initialized if the preference device.storage.testing
// was set to true, or if device.storage.overrideRootDir is set.
file = sInstance->mDirs[TYPE_OVERRIDE];
if (!file) {
file = sInstance->mDirs[aType];
#ifdef MOZ_WIDGET_GONK
/* We should use volume mount points on B2G. */
MOZ_ASSERT(!file);
#endif
}
return file.forget();
}
/* static */ void
DeviceStorageStatics::GetDirPath(DeviceStorageType aType, nsString& aDirPath)
{
aDirPath.Truncate();
nsCOMPtr<nsIFile> file = GetDir(aType);
if (file) {
file->GetPath(aDirPath);
}
}
/* static */ bool
DeviceStorageStatics::HasOverrideRootDir()
{
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return false;
}
return sInstance->mDirs[TYPE_OVERRIDE];
}
/* static */ already_AddRefed<nsIFile>
DeviceStorageStatics::GetAppsDir()
{
return GetDir(TYPE_APPS);
}
/* static */ already_AddRefed<nsIFile>
DeviceStorageStatics::GetCrashesDir()
{
return GetDir(TYPE_CRASHES);
}
/* static */ already_AddRefed<nsIFile>
DeviceStorageStatics::GetPicturesDir()
{
return GetDir(TYPE_PICTURES);
}
/* static */ already_AddRefed<nsIFile>
DeviceStorageStatics::GetVideosDir()
{
return GetDir(TYPE_VIDEOS);
}
/* static */ already_AddRefed<nsIFile>
DeviceStorageStatics::GetMusicDir()
{
return GetDir(TYPE_MUSIC);
}
/* static */ already_AddRefed<nsIFile>
DeviceStorageStatics::GetSdcardDir()
{
return GetDir(TYPE_SDCARD);
}
/* static */ bool
DeviceStorageStatics::IsPromptTesting()
{
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return false;
}
return sInstance->mPromptTesting;
}
/* static */ bool
DeviceStorageStatics::LowDiskSpace()
{
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return false;
}
return sInstance->mLowDiskSpace;
}
/* static */ void
DeviceStorageStatics::GetWritableName(nsString& aName)
{
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
aName.Truncate();
return;
}
aName = sInstance->mWritableName;
}
/* static */ void
DeviceStorageStatics::SetWritableName(const nsAString& aName)
{
StaticMutexAutoLock lock(sMutex);
if (!NS_WARN_IF(!sInstance)) {
// Update inline although it will be updated again in case
// another thread comes in checking it before the update takes
sInstance->mWritableName = aName;
}
nsString name;
name.Assign(aName);
NS_DispatchToMainThread(NS_NewRunnableFunction([name] () -> void {
Preferences::SetString(kPrefWritableName, name);
}));
}
/* static */ void
DeviceStorageStatics::AddListener(nsDOMDeviceStorage* aListener)
{
DS_LOG_DEBUG("%p", aListener);
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return;
}
MOZ_ASSERT(sInstance->mInitialized);
if (sInstance->mListeners.IsEmpty()) {
NS_DispatchToMainThread(
NewRunnableMethod(sInstance.get(), &DeviceStorageStatics::Register));
}
RefPtr<ListenerWrapper> wrapper =
new ListenerWrapper(aListener);
sInstance->mListeners.AppendElement(wrapper.forget());
}
/* static */ void
DeviceStorageStatics::RemoveListener(nsDOMDeviceStorage* aListener)
{
DS_LOG_DEBUG("%p", aListener);
StaticMutexAutoLock lock(sMutex);
if (!sInstance) {
return;
}
bool removed = false;
uint32_t i = sInstance->mListeners.Length();
while (i > 0) {
--i;
if (sInstance->mListeners[i]->Equals(aListener)) {
sInstance->mListeners.RemoveElementAt(i);
removed = true;
break;
}
}
if (removed && sInstance->mListeners.IsEmpty()) {
NS_DispatchToMainThread(
NewRunnableMethod(sInstance.get(), &DeviceStorageStatics::Deregister));
}
}
void
DeviceStorageStatics::Register()
{
MOZ_ASSERT(NS_IsMainThread());
DS_LOG_INFO("");
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return;
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(this, kFileWatcherUpdate, false);
obs->AddObserver(this, kDiskSpaceWatcher, false);
#ifdef MOZ_WIDGET_GONK
obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false);
#endif
}
}
void
DeviceStorageStatics::Deregister()
{
MOZ_ASSERT(NS_IsMainThread());
DS_LOG_INFO("");
StaticMutexAutoLock lock(sMutex);
if (!sInstance) {
return;
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, kFileWatcherUpdate);
obs->RemoveObserver(this, kDiskSpaceWatcher);
#ifdef MOZ_WIDGET_GONK
obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED);
#endif
}
}
void
DeviceStorageStatics::ResetOverrideRootDir()
{
MOZ_ASSERT(NS_IsMainThread());
sMutex.AssertCurrentThreadOwns();
nsCOMPtr<nsIFile> f;
DS_LOG_INFO("");
// For users running on desktop, it's convenient to be able to override
// all of the directories to point to a single tree, much like what happens
// on a real device.
const nsAdoptingString& overrideRootDir =
mozilla::Preferences::GetString(kPrefOverrideRootDir);
if (overrideRootDir && !overrideRootDir.IsEmpty()) {
NS_NewLocalFile(overrideRootDir, false, getter_AddRefs(f));
}
if (!f && Preferences::GetBool(kPrefTesting, false)) {
DS_LOG_INFO("temp");
nsCOMPtr<nsIProperties> dirService
= do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
MOZ_ASSERT(dirService);
dirService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
if (f) {
f->AppendRelativeNativePath(
NS_LITERAL_CSTRING("device-storage-testing"));
}
}
if (f) {
if (XRE_IsParentProcess()) {
// Only the parent process can create directories. In testing, because
// the preference is updated after startup, its entirely possible that
// the preference updated notification will be received by a child
// prior to the parent.
nsresult rv = f->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
nsString path;
f->GetPath(path);
nsPrintfCString msg("DeviceStorage: Unable to create directory '%s'",
NS_LossyConvertUTF16toASCII(path).get());
NS_WARNING(msg.get());
}
}
f->Normalize();
}
mDirs[TYPE_OVERRIDE] = f.forget();
DumpDirs();
}
NS_IMETHODIMP
DeviceStorageStatics::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(NS_IsMainThread());
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
MOZ_ASSERT(aData);
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return NS_OK;
}
nsDependentString name(aData);
if (name.EqualsASCII(kPrefTesting) ||
name.EqualsASCII(kPrefOverrideRootDir)) {
ResetOverrideRootDir();
} else if(name.EqualsASCII(kPrefPromptTesting)) {
mPromptTesting = Preferences::GetBool(kPrefPromptTesting, false);
DS_LOG_INFO("prompt testing %d", mPromptTesting);
} else if(name.EqualsASCII(kPrefWritableName)) {
mWritableName = Preferences::GetString(kPrefWritableName);
uint32_t i = mListeners.Length();
DS_LOG_INFO("writable name '%s' (%u)",
NS_LossyConvertUTF16toASCII(mWritableName).get(), i);
while (i > 0) {
--i;
mListeners[i]->OnWritableNameChanged();
}
}
return NS_OK;
}
#ifdef MOZ_WIDGET_GONK
if (!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) {
nsCOMPtr<nsIVolume> volume = do_QueryInterface(aSubject);
if (NS_WARN_IF(!volume)) {
return NS_OK;
}
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return NS_OK;
}
uint32_t i = mListeners.Length();
DS_LOG_INFO("volume updated (%u)", i);
while (i > 0) {
--i;
mListeners[i]->OnVolumeStateChanged(volume);
}
return NS_OK;
}
#endif
if (!strcmp(aTopic, kFileWatcherUpdate)) {
DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject);
if (NS_WARN_IF(!file)) {
return NS_OK;
}
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return NS_OK;
}
auto data = NS_ConvertUTF16toUTF8(aData);
uint32_t i = mListeners.Length();
DS_LOG_INFO("file updated (%u)", i);
while (i > 0) {
--i;
mListeners[i]->OnFileWatcherUpdate(data, file);
}
return NS_OK;
}
if (!strcmp(aTopic, kDiskSpaceWatcher)) {
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return NS_OK;
}
// 'disk-space-watcher' notifications are sent when there is a modification
// of a file in a specific location while a low device storage situation
// exists or after recovery of a low storage situation. For Firefox OS,
// these notifications are specific for apps storage.
if (!NS_strcmp(aData, u"full")) {
sInstance->mLowDiskSpace = true;
} else if (!NS_strcmp(aData, u"free")) {
sInstance->mLowDiskSpace = false;
} else {
return NS_OK;
}
uint32_t i = mListeners.Length();
DS_LOG_INFO("disk space %d (%u)", sInstance->mLowDiskSpace, i);
while (i > 0) {
--i;
mListeners[i]->OnDiskSpaceWatcher(sInstance->mLowDiskSpace);
}
return NS_OK;
}
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return NS_OK;
}
Shutdown();
sInstance = nullptr;
return NS_OK;
}
/* Here we convert file-watcher-notify and download-watcher-notify observer
events to file-watcher-update events. This is used to be able to
broadcast events from one child to another child in B2G. (f.e., if one
child decides to add a file, we want to be able to able to send a onchange
notifications to every other child watching that device storage object).*/
RefPtr<DeviceStorageFile> dsf;
if (!strcmp(aTopic, kDownloadWatcherNotify)) {
// aSubject will be an nsISupportsString with the native path to the file
// in question.
nsCOMPtr<nsISupportsString> supportsString = do_QueryInterface(aSubject);
if (!supportsString) {
return NS_OK;
}
nsString path;
nsresult rv = supportsString->GetData(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_OK;
}
// The downloader uses the sdcard storage type.
nsString volName;
#ifdef MOZ_WIDGET_GONK
if (DeviceStorageTypeChecker::IsVolumeBased(NS_LITERAL_STRING(DEVICESTORAGE_SDCARD))) {
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
if (NS_WARN_IF(!vs)) {
return NS_OK;
}
nsCOMPtr<nsIVolume> vol;
rv = vs->GetVolumeByPath(path, getter_AddRefs(vol));
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_OK;
}
rv = vol->GetName(volName);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_OK;
}
nsString mountPoint;
rv = vol->GetMountPoint(mountPoint);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_OK;
}
if (!Substring(path, 0, mountPoint.Length()).Equals(mountPoint)) {
return NS_OK;
}
path = Substring(path, mountPoint.Length() + 1);
}
#endif
dsf = new DeviceStorageFile(NS_LITERAL_STRING(DEVICESTORAGE_SDCARD), volName, path);
} else if (!strcmp(aTopic, kFileWatcherNotify) ||
!strcmp(aTopic, kMtpWatcherNotify)) {
dsf = static_cast<DeviceStorageFile*>(aSubject);
} else {
DS_LOG_WARN("unhandled topic '%s'", aTopic);
return NS_OK;
}
if (NS_WARN_IF(!dsf || !dsf->mFile)) {
return NS_OK;
}
if (!XRE_IsParentProcess()) {
// Child process. Forward the notification to the parent.
ContentChild::GetSingleton()
->SendFilePathUpdateNotify(dsf->mStorageType,
dsf->mStorageName,
dsf->mPath,
NS_ConvertUTF16toUTF8(aData));
return NS_OK;
}
// Multiple storage types may match the same files. So walk through each of
// the storage types, and if the extension matches, tell them about it.
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (DeviceStorageTypeChecker::IsSharedMediaRoot(dsf->mStorageType)) {
DeviceStorageTypeChecker* typeChecker
= DeviceStorageTypeChecker::CreateOrGet();
MOZ_ASSERT(typeChecker);
static const nsLiteralString kMediaTypes[] = {
NS_LITERAL_STRING(DEVICESTORAGE_SDCARD),
NS_LITERAL_STRING(DEVICESTORAGE_PICTURES),
NS_LITERAL_STRING(DEVICESTORAGE_VIDEOS),
NS_LITERAL_STRING(DEVICESTORAGE_MUSIC),
};
for (size_t i = 0; i < MOZ_ARRAY_LENGTH(kMediaTypes); i++) {
RefPtr<DeviceStorageFile> dsf2;
if (typeChecker->Check(kMediaTypes[i], dsf->mPath)) {
if (dsf->mStorageType.Equals(kMediaTypes[i])) {
dsf2 = dsf;
} else {
dsf2 = new DeviceStorageFile(kMediaTypes[i],
dsf->mStorageName, dsf->mPath);
}
obs->NotifyObservers(dsf2, kFileWatcherUpdate, aData);
}
}
} else {
obs->NotifyObservers(dsf, kFileWatcherUpdate, aData);
}
if (strcmp(aTopic, kMtpWatcherNotify)) {
// Only send mtp-watcher-updates out if the MTP Server wasn't the one
// telling us about the change.
obs->NotifyObservers(dsf, kMtpWatcherUpdate, aData);
}
return NS_OK;
}
DeviceStorageStatics::ListenerWrapper::ListenerWrapper(nsDOMDeviceStorage* aListener)
: mListener(do_GetWeakReference(static_cast<DOMEventTargetHelper*>(aListener)))
, mOwningThread(NS_GetCurrentThread())
{
}
DeviceStorageStatics::ListenerWrapper::~ListenerWrapper()
{
// Even weak pointers are not thread safe
NS_ProxyRelease(mOwningThread, mListener.forget());
}
bool
DeviceStorageStatics::ListenerWrapper::Equals(nsDOMDeviceStorage* aListener)
{
bool current = false;
mOwningThread->IsOnCurrentThread(&current);
if (current) {
// It is only safe to acquire the reference on the owning thread
RefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(mListener);
return listener.get() == aListener;
}
return false;
}
void
DeviceStorageStatics::ListenerWrapper::OnFileWatcherUpdate(const nsCString& aData,
DeviceStorageFile* aFile)
{
RefPtr<ListenerWrapper> self = this;
nsCString data = aData;
RefPtr<DeviceStorageFile> file = aFile;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, data, file] () -> void {
RefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(self->mListener);
if (listener) {
listener->OnFileWatcherUpdate(data, file);
}
});
mOwningThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
void
DeviceStorageStatics::ListenerWrapper::OnDiskSpaceWatcher(bool aLowDiskSpace)
{
RefPtr<ListenerWrapper> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, aLowDiskSpace] () -> void {
RefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(self->mListener);
if (listener) {
listener->OnDiskSpaceWatcher(aLowDiskSpace);
}
});
mOwningThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
void
DeviceStorageStatics::ListenerWrapper::OnWritableNameChanged()
{
RefPtr<ListenerWrapper> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self] () -> void {
RefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(self->mListener);
if (listener) {
listener->OnWritableNameChanged();
}
});
mOwningThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
#ifdef MOZ_WIDGET_GONK
void
DeviceStorageStatics::ListenerWrapper::OnVolumeStateChanged(nsIVolume* aVolume)
{
RefPtr<ListenerWrapper> self = this;
nsCOMPtr<nsIVolume> volume = aVolume;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, volume] () -> void {
RefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(self->mListener);
if (listener) {
listener->OnVolumeStateChanged(volume);
}
});
mOwningThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
#endif
} // namespace devicestorage
} // namespace dom
} // namespace mozilla

View file

@ -1,115 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_devicestorage_DeviceStorageStatics_h
#define mozilla_dom_devicestorage_DeviceStorageStatics_h
#include "mozilla/Mutex.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
#include "nsArrayUtils.h"
class nsString;
class nsDOMDeviceStorage;
class DeviceStorageFile;
#ifdef MOZ_WIDGET_GONK
class nsIVolume;
#endif
namespace mozilla {
namespace dom {
namespace devicestorage {
class DeviceStorageStatics final : public nsIObserver
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
static void Initialize();
static void InitializeDirs();
static void AddListener(nsDOMDeviceStorage* aListener);
static void RemoveListener(nsDOMDeviceStorage* aListener);
static bool LowDiskSpace();
static bool IsPromptTesting();
static void GetWritableName(nsString& aName);
static void SetWritableName(const nsAString& aName);
static void GetDeviceStorageLocationsForIPC(DeviceStorageLocationInfo* aLocationInfo);
static bool HasOverrideRootDir();
static already_AddRefed<nsIFile> GetAppsDir();
static already_AddRefed<nsIFile> GetCrashesDir();
static already_AddRefed<nsIFile> GetPicturesDir();
static already_AddRefed<nsIFile> GetVideosDir();
static already_AddRefed<nsIFile> GetMusicDir();
static already_AddRefed<nsIFile> GetSdcardDir();
private:
enum DeviceStorageType {
TYPE_APPS,
TYPE_CRASHES,
TYPE_PICTURES,
TYPE_VIDEOS,
TYPE_MUSIC,
TYPE_SDCARD,
TYPE_OVERRIDE,
TYPE_COUNT
};
static already_AddRefed<nsIFile> GetDir(DeviceStorageType aType);
static void GetDirPath(DeviceStorageType aType, nsString& aString);
DeviceStorageStatics();
virtual ~DeviceStorageStatics();
void Init();
void InitDirs();
void DumpDirs();
void Shutdown();
void Register();
void Deregister();
void ResetOverrideRootDir();
class ListenerWrapper final {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ListenerWrapper)
explicit ListenerWrapper(nsDOMDeviceStorage* aListener);
bool Equals(nsDOMDeviceStorage* aListener);
void OnFileWatcherUpdate(const nsCString& aData, DeviceStorageFile* aFile);
void OnDiskSpaceWatcher(bool aLowDiskSpace);
void OnWritableNameChanged();
#ifdef MOZ_WIDGET_GONK
void OnVolumeStateChanged(nsIVolume* aVolume);
#endif
private:
virtual ~ListenerWrapper();
nsWeakPtr mListener;
nsCOMPtr<nsIThread> mOwningThread;
};
nsTArray<RefPtr<ListenerWrapper> > mListeners;
nsCOMPtr<nsIFile> mDirs[TYPE_COUNT];
bool mInitialized;
bool mPromptTesting;
bool mLowDiskSpace;
nsString mWritableName;
static StaticRefPtr<DeviceStorageStatics> sInstance;
static StaticMutex sMutex;
};
} // namespace devicestorage
} // namespace dom
} // namespace mozilla
#endif

View file

@ -1,93 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBlob;
include protocol PContent;
namespace mozilla {
namespace dom {
namespace devicestorage {
struct ErrorResponse
{
nsString error;
};
struct SuccessResponse
{
};
struct FileDescriptorResponse
{
FileDescriptor fileDescriptor;
};
struct BlobResponse
{
PBlob blob;
};
struct DeviceStorageFileValue
{
nsString storageName;
nsString name;
};
struct EnumerationResponse
{
nsString type;
nsString rootdir;
DeviceStorageFileValue[] paths;
};
struct FreeSpaceStorageResponse
{
uint64_t freeBytes;
};
struct UsedSpaceStorageResponse
{
uint64_t usedBytes;
};
struct FormatStorageResponse
{
nsString mountState;
};
struct MountStorageResponse
{
nsString storageStatus;
};
struct UnmountStorageResponse
{
nsString storageStatus;
};
union DeviceStorageResponseValue
{
ErrorResponse;
SuccessResponse;
FileDescriptorResponse;
BlobResponse;
EnumerationResponse;
FreeSpaceStorageResponse;
UsedSpaceStorageResponse;
FormatStorageResponse;
MountStorageResponse;
UnmountStorageResponse;
};
sync protocol PDeviceStorageRequest {
manager PContent;
child:
async __delete__(DeviceStorageResponseValue response);
};
} // namespace devicestorage
} // namespace dom
} // namespace mozilla

View file

@ -1,45 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
EXPORTS += [
'DeviceStorage.h',
'DeviceStorageFileDescriptor.h',
'nsDeviceStorage.h',
]
EXPORTS.mozilla.dom.devicestorage += [
'DeviceStorageRequestChild.h',
'DeviceStorageRequestParent.h',
'DeviceStorageStatics.h',
]
UNIFIED_SOURCES += [
'DeviceStorageRequestChild.cpp',
'DeviceStorageRequestParent.cpp',
'DeviceStorageStatics.cpp',
'nsDeviceStorage.cpp',
]
IPDL_SOURCES += [
'PDeviceStorageRequest.ipdl',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/base',
'/dom/ipc',
]
MOCHITEST_MANIFESTS += [
'test/mochitest.ini',
]
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']

File diff suppressed because it is too large Load diff

View file

@ -1,434 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsDeviceStorage_h
#define nsDeviceStorage_h
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
#include "DOMRequest.h"
#include "DOMCursor.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDOMClassInfoID.h"
#include "nsIClassInfo.h"
#include "nsIDOMWindow.h"
#include "nsIURI.h"
#include "nsIPrincipal.h"
#include "nsString.h"
#include "nsWeakPtr.h"
#include "nsIDOMEventListener.h"
#include "nsIObserver.h"
#include "nsIStringBundle.h"
#include "mozilla/Mutex.h"
#include "prtime.h"
#include "DeviceStorage.h"
#include "mozilla/StaticPtr.h"
namespace mozilla {
class ErrorResult;
namespace dom {
class BlobImpl;
class DeviceStorageParams;
} // namespace dom
} // namespace mozilla
class nsDOMDeviceStorage;
class DeviceStorageCursorRequest;
//#define DS_LOGGING 1
#ifdef DS_LOGGING
// FIXME -- use MOZ_LOG and set to warn by default
#define DS_LOG_DEBUG(msg, ...) printf_stderr("[%s:%d] " msg "\n", __func__, __LINE__, ##__VA_ARGS__)
#define DS_LOG_INFO DS_LOG_DEBUG
#define DS_LOG_WARN DS_LOG_DEBUG
#define DS_LOG_ERROR DS_LOG_DEBUG
#else
#define DS_LOG_DEBUG(msg, ...)
#define DS_LOG_INFO(msg, ...)
#define DS_LOG_WARN(msg, ...)
#define DS_LOG_ERROR(msg, ...)
#endif
#define POST_ERROR_EVENT_FILE_EXISTS "NoModificationAllowedError"
#define POST_ERROR_EVENT_FILE_DOES_NOT_EXIST "NotFoundError"
#define POST_ERROR_EVENT_FILE_NOT_ENUMERABLE "TypeMismatchError"
#define POST_ERROR_EVENT_PERMISSION_DENIED "SecurityError"
#define POST_ERROR_EVENT_ILLEGAL_TYPE "TypeMismatchError"
#define POST_ERROR_EVENT_UNKNOWN "Unknown"
enum DeviceStorageRequestType {
DEVICE_STORAGE_REQUEST_READ,
DEVICE_STORAGE_REQUEST_WRITE,
DEVICE_STORAGE_REQUEST_APPEND,
DEVICE_STORAGE_REQUEST_CREATE,
DEVICE_STORAGE_REQUEST_DELETE,
DEVICE_STORAGE_REQUEST_WATCH,
DEVICE_STORAGE_REQUEST_FREE_SPACE,
DEVICE_STORAGE_REQUEST_USED_SPACE,
DEVICE_STORAGE_REQUEST_AVAILABLE,
DEVICE_STORAGE_REQUEST_STATUS,
DEVICE_STORAGE_REQUEST_FORMAT,
DEVICE_STORAGE_REQUEST_MOUNT,
DEVICE_STORAGE_REQUEST_UNMOUNT,
DEVICE_STORAGE_REQUEST_CREATEFD,
DEVICE_STORAGE_REQUEST_CURSOR
};
enum DeviceStorageAccessType {
DEVICE_STORAGE_ACCESS_READ,
DEVICE_STORAGE_ACCESS_WRITE,
DEVICE_STORAGE_ACCESS_CREATE,
DEVICE_STORAGE_ACCESS_UNDEFINED,
DEVICE_STORAGE_ACCESS_COUNT
};
class DeviceStorageUsedSpaceCache final
{
public:
static DeviceStorageUsedSpaceCache* CreateOrGet();
DeviceStorageUsedSpaceCache();
~DeviceStorageUsedSpaceCache();
class InvalidateRunnable final : public mozilla::Runnable
{
public:
InvalidateRunnable(DeviceStorageUsedSpaceCache* aCache,
const nsAString& aStorageName)
: mCache(aCache)
, mStorageName(aStorageName) {}
~InvalidateRunnable() {}
NS_IMETHOD Run() override
{
RefPtr<DeviceStorageUsedSpaceCache::CacheEntry> cacheEntry;
cacheEntry = mCache->GetCacheEntry(mStorageName);
if (cacheEntry) {
cacheEntry->mDirty = true;
}
return NS_OK;
}
private:
DeviceStorageUsedSpaceCache* mCache;
nsString mStorageName;
};
void Invalidate(const nsAString& aStorageName)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mIOThread);
mIOThread->Dispatch(new InvalidateRunnable(this, aStorageName),
NS_DISPATCH_NORMAL);
}
void Dispatch(already_AddRefed<nsIRunnable>&& aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mIOThread);
mIOThread->Dispatch(mozilla::Move(aRunnable), NS_DISPATCH_NORMAL);
}
nsresult AccumUsedSizes(const nsAString& aStorageName,
uint64_t* aPictureSize, uint64_t* aVideosSize,
uint64_t* aMusicSize, uint64_t* aTotalSize);
void SetUsedSizes(const nsAString& aStorageName,
uint64_t aPictureSize, uint64_t aVideosSize,
uint64_t aMusicSize, uint64_t aTotalSize);
private:
friend class InvalidateRunnable;
struct CacheEntry
{
// Technically, this doesn't need to be threadsafe, but the implementation
// of the non-thread safe one causes ASSERTS due to the underlying thread
// associated with a LazyIdleThread changing from time to time.
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheEntry)
bool mDirty;
nsString mStorageName;
int64_t mFreeBytes;
uint64_t mPicturesUsedSize;
uint64_t mVideosUsedSize;
uint64_t mMusicUsedSize;
uint64_t mTotalUsedSize;
private:
~CacheEntry() {}
};
already_AddRefed<CacheEntry> GetCacheEntry(const nsAString& aStorageName);
nsTArray<RefPtr<CacheEntry>> mCacheEntries;
nsCOMPtr<nsIThread> mIOThread;
static mozilla::StaticAutoPtr<DeviceStorageUsedSpaceCache> sDeviceStorageUsedSpaceCache;
};
class DeviceStorageTypeChecker final
{
public:
static DeviceStorageTypeChecker* CreateOrGet();
DeviceStorageTypeChecker();
~DeviceStorageTypeChecker();
void InitFromBundle(nsIStringBundle* aBundle);
bool Check(const nsAString& aType, mozilla::dom::BlobImpl* aBlob);
bool Check(const nsAString& aType, nsIFile* aFile);
bool Check(const nsAString& aType, const nsString& aPath);
void GetTypeFromFile(nsIFile* aFile, nsAString& aType);
void GetTypeFromFileName(const nsAString& aFileName, nsAString& aType);
static nsresult GetPermissionForType(const nsAString& aType,
nsACString& aPermissionResult);
static nsresult GetAccessForRequest(const DeviceStorageRequestType aRequestType,
nsACString& aAccessResult);
static nsresult GetAccessForIndex(size_t aAccessIndex, nsACString& aAccessResult);
static size_t GetAccessIndexForRequest(const DeviceStorageRequestType aRequestType);
static bool IsVolumeBased(const nsAString& aType);
static bool IsSharedMediaRoot(const nsAString& aType);
private:
nsString mPicturesExtensions;
nsString mVideosExtensions;
nsString mMusicExtensions;
static mozilla::StaticAutoPtr<DeviceStorageTypeChecker> sDeviceStorageTypeChecker;
};
class nsDOMDeviceStorageCursor final
: public mozilla::dom::DOMCursor
{
public:
NS_FORWARD_NSIDOMDOMCURSOR(mozilla::dom::DOMCursor::)
// DOMCursor
virtual void Continue(mozilla::ErrorResult& aRv) override;
nsDOMDeviceStorageCursor(nsIGlobalObject* aGlobal,
DeviceStorageCursorRequest* aRequest);
void FireSuccess(JS::Handle<JS::Value> aResult);
void FireError(const nsString& aReason);
void FireDone();
private:
virtual ~nsDOMDeviceStorageCursor();
bool mOkToCallContinue;
RefPtr<DeviceStorageCursorRequest> mRequest;
};
class DeviceStorageRequestManager final
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceStorageRequestManager)
static const uint32_t INVALID_ID = 0;
DeviceStorageRequestManager();
bool IsOwningThread();
nsresult DispatchToOwningThread(already_AddRefed<nsIRunnable>&& aRunnable);
void StorePermission(size_t aAccess, bool aAllow);
uint32_t CheckPermission(size_t aAccess);
/* These must be called on the owning thread context of the device
storage object. It will hold onto a device storage reference until
all of the pending requests are completed or shutdown is called. */
uint32_t Create(nsDOMDeviceStorage* aDeviceStorage,
mozilla::dom::DOMRequest** aRequest);
uint32_t Create(nsDOMDeviceStorage* aDeviceStorage,
DeviceStorageCursorRequest* aRequest,
nsDOMDeviceStorageCursor** aCursor);
/* These may be called from any thread context and post a request
to the owning thread to resolve the underlying DOMRequest or
DOMCursor. In order to trigger FireDone for a DOMCursor, one
should call Resolve with only the request ID. */
nsresult Resolve(uint32_t aId, bool aForceDispatch);
nsresult Resolve(uint32_t aId, const nsString& aValue, bool aForceDispatch);
nsresult Resolve(uint32_t aId, uint64_t aValue, bool aForceDispatch);
nsresult Resolve(uint32_t aId, DeviceStorageFile* aValue, bool aForceDispatch);
nsresult Resolve(uint32_t aId, mozilla::dom::BlobImpl* aValue, bool aForceDispatch);
nsresult Reject(uint32_t aId, const nsString& aReason);
nsresult Reject(uint32_t aId, const char* aReason);
void Shutdown();
private:
DeviceStorageRequestManager(const DeviceStorageRequestManager&) = delete;
DeviceStorageRequestManager& operator=(const DeviceStorageRequestManager&) = delete;
struct ListEntry {
RefPtr<mozilla::dom::DOMRequest> mRequest;
uint32_t mId;
bool mCursor;
};
typedef nsTArray<ListEntry> ListType;
typedef ListType::index_type ListIndex;
virtual ~DeviceStorageRequestManager();
uint32_t CreateInternal(mozilla::dom::DOMRequest* aRequest, bool aCursor);
nsresult ResolveInternal(ListIndex aIndex, JS::HandleValue aResult);
nsresult RejectInternal(ListIndex aIndex, const nsString& aReason);
nsresult DispatchOrAbandon(uint32_t aId,
already_AddRefed<nsIRunnable>&& aRunnable);
ListType::index_type Find(uint32_t aId);
nsCOMPtr<nsIThread> mOwningThread;
ListType mPending; // owning thread or destructor only
mozilla::Mutex mMutex;
uint32_t mPermissionCache[DEVICE_STORAGE_ACCESS_COUNT];
bool mShutdown;
static mozilla::Atomic<uint32_t> sLastRequestId;
};
class DeviceStorageRequest
: public mozilla::Runnable
{
protected:
DeviceStorageRequest();
public:
virtual void Initialize(DeviceStorageRequestManager* aManager,
already_AddRefed<DeviceStorageFile>&& aFile,
uint32_t aRequest);
virtual void Initialize(DeviceStorageRequestManager* aManager,
already_AddRefed<DeviceStorageFile>&& aFile,
uint32_t aRequest,
mozilla::dom::BlobImpl* aBlob);
virtual void Initialize(DeviceStorageRequestManager* aManager,
already_AddRefed<DeviceStorageFile>&& aFile,
uint32_t aRequest,
DeviceStorageFileDescriptor* aDSFileDescriptor);
DeviceStorageAccessType GetAccess() const;
void GetStorageType(nsAString& aType) const;
DeviceStorageFile* GetFile() const;
DeviceStorageFileDescriptor* GetFileDescriptor() const;
DeviceStorageRequestManager* GetManager() const;
uint32_t GetId() const
{
return mId;
}
void PermissionCacheMissed()
{
mPermissionCached = false;
}
nsresult Cancel();
nsresult Allow();
nsresult Resolve()
{
/* Always dispatch an empty resolve because that signals a cursor end
and should not be executed directly from the caller's context due
to the object potentially getting freed before we return. */
uint32_t id = mId;
mId = DeviceStorageRequestManager::INVALID_ID;
return mManager->Resolve(id, true);
}
template<class T>
nsresult Resolve(T aValue)
{
uint32_t id = mId;
if (!mMultipleResolve) {
mId = DeviceStorageRequestManager::INVALID_ID;
}
return mManager->Resolve(id, aValue, ForceDispatch());
}
template<class T>
nsresult Reject(T aReason)
{
uint32_t id = mId;
mId = DeviceStorageRequestManager::INVALID_ID;
return mManager->Reject(id, aReason);
}
protected:
bool ForceDispatch() const
{
return !mSendToParent && mPermissionCached;
}
virtual ~DeviceStorageRequest();
virtual nsresult Prepare();
virtual nsresult CreateSendParams(mozilla::dom::DeviceStorageParams& aParams);
nsresult AllowInternal();
nsresult SendToParentProcess();
RefPtr<DeviceStorageRequestManager> mManager;
RefPtr<DeviceStorageFile> mFile;
uint32_t mId;
RefPtr<mozilla::dom::BlobImpl> mBlob;
RefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
DeviceStorageAccessType mAccess;
bool mSendToParent;
bool mUseMainThread;
bool mUseStreamTransport;
bool mCheckFile;
bool mCheckBlob;
bool mMultipleResolve;
bool mPermissionCached;
private:
DeviceStorageRequest(const DeviceStorageRequest&) = delete;
DeviceStorageRequest& operator=(const DeviceStorageRequest&) = delete;
};
class DeviceStorageCursorRequest final
: public DeviceStorageRequest
{
public:
DeviceStorageCursorRequest();
using DeviceStorageRequest::Initialize;
virtual void Initialize(DeviceStorageRequestManager* aManager,
already_AddRefed<DeviceStorageFile>&& aFile,
uint32_t aRequest,
PRTime aSince);
void AddFiles(size_t aSize);
void AddFile(already_AddRefed<DeviceStorageFile> aFile);
nsresult Continue();
NS_IMETHOD Run() override;
protected:
virtual ~DeviceStorageCursorRequest()
{ };
nsresult SendContinueToParentProcess();
nsresult CreateSendParams(mozilla::dom::DeviceStorageParams& aParams) override;
size_t mIndex;
PRTime mSince;
nsString mStorageType;
nsTArray<RefPtr<DeviceStorageFile> > mFiles;
};
#endif

View file

@ -1,5 +0,0 @@
[DEFAULT]
skip-if = os == 'android'
[test_app_permissions.html]
[test_fs_app_permissions.html]

View file

@ -1,110 +0,0 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var oldVal = false;
Object.defineProperty(Array.prototype, "remove", {
enumerable: false,
configurable: false,
writable: false,
value: function(from, to) {
// Array Remove - By John Resig (MIT Licensed)
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
}
});
function devicestorage_setup(callback) {
SimpleTest.waitForExplicitFinish();
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
var directoryService = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
let script = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('remove_testing_directory.js'));
script.addMessageListener('directory-removed', function listener () {
script.removeMessageListener('directory-removed', listener);
var prefs = [["device.storage.enabled", true],
["device.storage.testing", true],
["device.storage.overrideRootDir", f.path],
["device.storage.prompt.testing", true]];
SpecialPowers.pushPrefEnv({"set": prefs}, callback);
});
}
function getRandomBuffer() {
var size = 1024;
var buffer = new ArrayBuffer(size);
var view = new Uint8Array(buffer);
for (var i = 0; i < size; i++) {
view[i] = parseInt(Math.random() * 255);
}
return buffer;
}
function createRandomBlob(mime) {
return blob = new Blob([getRandomBuffer()], {type: mime});
}
function randomFilename(l) {
var set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
var result = "";
for (var i=0; i<l; i++) {
var r = Math.floor(set.length * Math.random());
result += set.substring(r, r + 1);
}
return result;
}
function reportErrorAndQuit(e) {
ok(false, "handleError was called : " + e.target.error.name);
SimpleTest.finish();
}
function createTestFiles(storage, paths) {
function createTestFile(path) {
return new Promise(function(resolve, reject) {
function addNamed() {
var req = storage.addNamed(createRandomBlob("image/png"), path);
req.onsuccess = function() {
ok(true, path + " was created.");
resolve();
};
req.onerror = function(e) {
ok(false, "Failed to create " + path + ': ' + e.target.error.name);
reject();
};
}
// Bug 980136. Check if the file exists before we create.
var req = storage.get(path);
req.onsuccess = function() {
ok(true, path + " exists. Do not need to create.");
resolve();
};
req.onerror = function(e) {
ok(true, path + " does not exists: " + e.target.error.name);
addNamed();
};
});
}
var arr = [];
paths.forEach(function(path) {
arr.push(createTestFile(path));
});
return Promise.all(arr);
}

View file

@ -1,35 +0,0 @@
[DEFAULT]
support-files = devicestorage_common.js
remove_testing_directory.js
[test_823965.html]
# [test_add.html]
# man, our mime database sucks hard. followup bug # 788273
[test_addCorrectType.html]
[test_available.html]
[test_basic.html]
[test_dirs.html]
# [test_diskSpace.html]
# Possible race between the time we write a file, and the
# time it takes to be reflected by statfs(). Bug # 791287
[test_dotdot.html]
[test_enumerate.html]
[test_enumerateMultipleContinue.html]
[test_enumerateOptions.html]
[test_freeSpace.html]
# FileSystem API tests start
[test_fs_basic.html]
[test_fs_createDirectory.html]
[test_fs_get.html]
[test_fs_getFilesAndDirectories.html]
[test_fs_remove.html]
[test_fs_createFile.html]
[test_fs_appendFile.html]
# FileSystem API tests end
[test_lastModificationFilter.html]
[test_overrideDir.html]
[test_overwrite.html]
[test_sanity.html]
[test_usedSpace.html]
[test_watch.html]
[test_watchOther.html]

View file

@ -1,11 +0,0 @@
// ensure that the directory we are writing into is empty
try {
var Cc = Components.classes;
var Ci = Components.interfaces;
var directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
f.remove(true);
} catch(e) {}
sendAsyncMessage('directory-removed', {});

View file

@ -1,107 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=823965
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=823965">Mozilla Bug 823965</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
var gFileName = "devicestorage/" + randomFilename(12) + "/hi.png";
var gData = "My name is Doug Turner (?!?). My IRC nick is DougT. I like Maple cookies."
var gDataBlob = new Blob([gData], {type: 'image/png'});
function getSuccess(e) {
var storage = navigator.getDeviceStorage("pictures");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(e.target.result.name == gFileName, "File name should match");
ok(e.target.result.size > 0, "File size be greater than zero");
ok(e.target.result.type, "File should have a mime type");
ok(e.target.result.lastModifiedDate, "File should have a last modified date");
var mreq = storage.enumerate();
mreq.onsuccess = function() {
var storage2 = navigator.getDeviceStorage('music');
var dreq = storage2.delete(mreq.result.name);
dreq.onerror = function () {
ok(true, "The bug has been fixed");
SimpleTest.finish();
};
dreq.onsuccess = function () {
ok(false, "The bug has been fixed");
SimpleTest.finish();
};
};
mreq.onerror = getError;
}
function getError(e) {
ok(false, "getError was called : " + e.target.error.name);
SimpleTest.finish();
}
function addSuccess(e) {
var filename = e.target.result;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
// Remove the storageName (this shows up on FirefoxOS)
filename = filename.substring(1); // Remove leading slash
var slashIndex = filename.indexOf("/");
if (slashIndex >= 0) {
filename = filename.substring(slashIndex + 1); // Remove storageName
}
}
ok(filename == gFileName, "File name should match");
// Since we now have the fully qualified name, change gFileName to that.
gFileName = e.target.result;
var storage = navigator.getDeviceStorage("pictures");
request = storage.get(gFileName);
request.onsuccess = getSuccess;
request.onerror = getError;
ok(true, "addSuccess was called");
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage");
request = storage.addNamed(gDataBlob, gFileName);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>

View file

@ -1,70 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=786922
-->
<head>
<title>Test for basic sanity of the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=786922">Mozilla Bug 786922</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
function add(storage, mime) {
dump("adding: " + mime + "\n");
return navigator.getDeviceStorage(storage).add(createRandomBlob(mime));
}
var tests = [
function () { return add("pictures", "image/png")},
function () { return add("videos", "video/webm")},
function () { return add("music", "audio/wav")},
function () { return add("sdcard", "maple/cookies")},
];
function fail(e) {
ok(false, "onerror was called");
SimpleTest.finish();
}
function next(e) {
if (e != undefined)
ok(true, "addError was called");
var f = tests.pop();
if (f == undefined) {
SimpleTest.finish();
return;
}
request = f();
request.onsuccess = next;
request.onerror = fail;
}
next();
});
</script>
</pre>
</body>
</html>

View file

@ -1,75 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=786922
-->
<head>
<title>Test for basic sanity of the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=786922">Mozilla Bug 786922</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
function addNamed(storage, mime, fileExtension) {
dump("adding: " + mime + " " + fileExtension + "\n");
return navigator.getDeviceStorage(storage).addNamed(createRandomBlob(mime), randomFilename(40) + "." + fileExtension);
}
// These tests must all fail
var tests = [
function () { return addNamed("pictures", "kyle/smash", ".png")},
function () { return addNamed("pictures", "image/png", ".poo")},
function () { return addNamed("music", "kyle/smash", ".mp3")},
function () { return addNamed("music", "music/mp3", ".poo")},
function () { return addNamed("videos", "kyle/smash", ".ogv")},
function () { return addNamed("videos", "video/ogv", ".poo")},
];
function fail(e) {
ok(false, "addSuccess was called");
ok(e.target.error.name == "TypeMismatchError", "Error must be TypeMismatchError");
SimpleTest.finish();
}
function next(e) {
if (e != undefined)
ok(true, "addError was called");
var f = tests.pop();
if (f == undefined) {
SimpleTest.finish();
return;
}
request = f();
request.onsuccess = fail;
request.onerror = next;
}
next();
});
</script>
</pre>
</body>
</html>

View file

@ -1,481 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=805322
-->
<head>
<meta charset="utf-8">
<title>Permission test for Device Storage</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=805322">Mozilla Bug 805322</a>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script type="application/javascript">
function randomFilename(l) {
var set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
var result = "";
for (var i=0; i<l; i++) {
var r = Math.floor(set.length * Math.random());
result += set.substring(r, r + 1);
}
return result;
}
var MockPermissionPrompt = SpecialPowers.MockPermissionPrompt;
MockPermissionPrompt.init();
SimpleTest.waitForExplicitFinish();
function TestAdd(iframe, data) {
var storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "Should be able to get storage object for " + data.type);
var blob = new Blob(["Kyle Huey is not a helicopter."], {type: data.mimeType});
request = storage.addNamed(blob, randomFilename(100) + "hi" + data.fileExtension);
isnot(request, null, "Should be able to get request");
request.onsuccess = function() {
is(data.shouldPass, true, "onsuccess was called for type " + data.type);
testComplete(iframe, data);
};
request.onerror = function(e) {
isnot(data.shouldPass, true, "onfailure was called for type " + data.type + " Error: " + e.target.error.name);
is(e.target.error.name, "SecurityError", "onerror should fire a SecurityError");
testComplete(iframe, data);
};
}
function TestGet(iframe, data) {
createTestFile(data.fileExtension);
var storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "Should be able to get storage object for " + data.type);
request = storage.get("testfile" + data.fileExtension);
isnot(request, null, "Should be able to get request");
request.onsuccess = function() {
is(data.shouldPass, true, "onsuccess was called for type " + data.type);
testComplete(iframe, data);
};
request.onerror = function(e) {
isnot(data.shouldPass, true, "onfailure was called for type " + data.type + " Error: " + e.target.error.name);
testComplete(iframe, data);
};
}
function TestDelete(iframe, data) {
createTestFile(data.fileExtension);
var storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "Should be able to get storage object for " + data.type);
request = storage.delete("testfile" + data.fileExtension);
isnot(request, null, "Should be able to get request");
request.onsuccess = function() {
is(data.shouldPass, true, "onsuccess was called for type " + data.type);
testComplete(iframe, data);
};
request.onerror = function(e) {
isnot(data.shouldPass, true, "onfailure was called for type " + data.type + " Error: " + e.target.error.name);
is(e.target.error.name, "SecurityError", "onerror should fire a SecurityError");
testComplete(iframe, data);
};
}
function TestEnumerate(iframe, data) {
createTestFile(data.fileExtension);
var storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "Should be able to get storage object for " + data.type);
request = storage.enumerate();
isnot(request, null, "Should be able to get request");
request.onsuccess = function(e) {
is(data.shouldPass, true, "onsuccess was called for type " + data.type);
if (e.target.result == null) {
testComplete(iframe, data);
return;
}
e.target.continue();
};
request.onerror = function(e) {
isnot(data.shouldPass, true, "onfailure was called for type " + data.type + " Error: " + e.target.error.name);
is(e.target.error.name, "SecurityError", "onerror should fire a SecurityError");
testComplete(iframe, data);
};
}
var gTestUri = "https://example.com/chrome/dom/devicestorage/test/test_app_permissions.html"
var gData = [
// Get
// Web applications with no permissions
{
type: 'pictures',
shouldPass: false,
fileExtension: '.png',
test: TestGet
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogv',
test: TestGet
},
{
type: 'music',
shouldPass: false,
fileExtension: '.ogg',
test: TestGet
},
{
type: 'sdcard',
shouldPass: false,
fileExtension: '.txt',
test: TestGet
},
// Web applications with permission granted
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
permissions: ["device-storage:pictures"],
test: TestGet
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
permissions: ["device-storage:videos"],
test: TestGet
},
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:music"],
test: TestGet
},
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
permissions: ["device-storage:sdcard"],
test: TestGet
},
// Add
// Web applications with no permissions
{
type: 'pictures',
mimeType: 'image/png',
fileExtension: '.png',
shouldPass: false,
test: TestAdd
},
{
type: 'videos',
mimeType: 'video/ogv',
fileExtension: '.ogv',
shouldPass: false,
test: TestAdd
},
{
type: 'music',
mimeType: 'audio/ogg',
fileExtension: '.ogg',
shouldPass: false,
test: TestAdd
},
{
type: 'sdcard',
mimeType: 'text/plain',
fileExtension: '.txt',
shouldPass: false,
test: TestAdd
},
// Web applications with permission granted
{
type: 'pictures',
mimeType: 'image/png',
fileExtension: '.png',
shouldPass: true,
permissions: ["device-storage:pictures"],
test: TestAdd
},
{
type: 'videos',
mimeType: 'video/ogv',
fileExtension: '.ogv',
shouldPass: true,
permissions: ["device-storage:videos"],
test: TestAdd
},
{
type: 'music',
mimeType: 'audio/ogg',
fileExtension: '.ogg',
shouldPass: true,
permissions: ["device-storage:music"],
test: TestAdd
},
{
type: 'sdcard',
mimeType: 'text/plain',
fileExtension: '.txt',
shouldPass: true,
permissions: ["device-storage:sdcard"],
test: TestAdd
},
// Delete
// Web applications with no permissions
{
type: 'pictures',
shouldPass: false,
fileExtension: '.png',
test: TestDelete
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogv',
test: TestDelete
},
{
type: 'music',
shouldPass: false,
fileExtension: '.ogg',
test: TestDelete
},
{
type: 'sdcard',
shouldPass: false,
fileExtension: '.txt',
test: TestDelete
},
// Web applications with permission granted
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
permissions: ["device-storage:pictures"],
test: TestDelete
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
permissions: ["device-storage:videos"],
test: TestDelete
},
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:music"],
test: TestDelete
},
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
permissions: ["device-storage:sdcard"],
test: TestDelete
},
// Enumeration
// Web applications with no permissions
{
type: 'pictures',
shouldPass: false,
fileExtension: '.png',
test: TestEnumerate
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogv',
test: TestEnumerate
},
{
type: 'music',
shouldPass: false,
fileExtension: '.ogg',
test: TestEnumerate
},
{
type: 'sdcard',
shouldPass: false,
fileExtension: '.txt',
test: TestEnumerate
},
// Web applications with permission granted
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
permissions: ["device-storage:pictures"],
test: TestEnumerate
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
permissions: ["device-storage:videos"],
test: TestEnumerate
},
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:music"],
test: TestEnumerate
},
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
permissions: ["device-storage:sdcard"],
test: TestEnumerate
},
];
function setupTest(iframe,data) {
if (data.permissions) {
for (var j in data.permissions) {
SpecialPowers.addPermission(data.permissions[j], true, iframe.contentDocument);
}
}
}
function testComplete(iframe, data) {
if (data.permissions) {
for (var j in data.permissions) {
SpecialPowers.removePermission(data.permissions[j], iframe.contentDocument);
}
}
document.getElementById('content').removeChild(iframe);
if (gData.length == 0) {
SimpleTest.finish();
} else {
gTestRunner.next();
}
}
function* runTest() {
while (gData.length > 0) {
var iframe = document.createElement('iframe');
var data = gData.pop();
iframe.setAttribute('mozbrowser', '');
iframe.src = gTestUri;
iframe.addEventListener('load', function(e) {
setupTest(iframe, data)
data.test(iframe, data);
});
document.getElementById('content').appendChild(iframe);
yield undefined;
}
}
function createTestFile(extension) {
try {
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
var directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
f.remove(true);
f.appendRelativePath("testfile" + extension);
f.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
} catch(e) {}
}
createTestFile('.txt');
var gTestRunner = runTest();
SpecialPowers.addPermission("browser", true, gTestUri);
SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["device.storage.enabled", true],
["device.storage.testing", true],
["device.storage.prompt.testing", false]]},
function() { gTestRunner.next(); });
</script>
</pre>
</body>
</html>

View file

@ -1,50 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=834595
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=834595">Mozilla Bug 834595</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
function availableSuccess(e) {
isnot(e.target.result, null, "result should not be null");
SimpleTest.finish();
}
function availableError(e) {
ok(false, "availableError was called");
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
request = storage.available();
ok(request, "Should have a non-null request");
request.onsuccess = availableSuccess;
request.onerror = availableError;
});
</script>
</pre>
</body>
</html>

View file

@ -1,141 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function() {
var gFileName = "devicestorage/" + randomFilename(12) + "/hi.png";
var gData = "My name is Doug Turner. My IRC nick is DougT. I like Maple cookies."
var gDataBlob = new Blob([gData], {type: 'image/png'});
var gFileReader = new FileReader();
function getAfterDeleteSuccess(e) {
ok(false, "file was deleted not successfully");
SimpleTest.finish();
}
function getAfterDeleteError(e) {
ok(true, "file was deleted successfully");
SimpleTest.finish();
}
function deleteSuccess(e) {
ok(e.target.result == gFileName, "File name should match");
dump(e.target.result + "\n")
var storage = navigator.getDeviceStorage("pictures");
request = storage.get(e.target.result);
request.onsuccess = getAfterDeleteSuccess;
request.onerror = getAfterDeleteError;
}
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
SimpleTest.finish();
}
function getSuccess(e) {
var storage = navigator.getDeviceStorage("pictures");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(e.target.result.name == gFileName, "File name should match");
ok(e.target.result.size > 0, "File size be greater than zero");
ok(e.target.result.type, "File should have a mime type");
ok(e.target.result.lastModifiedDate, "File should have a last modified date");
var name = e.target.result.name;
gFileReader.readAsArrayBuffer(gDataBlob);
gFileReader.onload = function(e) {
readerCallback(e);
request = storage.delete(name)
request.onsuccess = deleteSuccess;
request.onerror = deleteError;
}
}
function readerCallback(e) {
ab = e.target.result;
is(ab.byteLength, gData.length, "wrong arraybuffer byteLength");
var u8v = new Uint8Array(ab);
is(String.fromCharCode.apply(String, u8v), gData, "wrong values");
}
function getError(e) {
ok(false, "getError was called : " + e.target.error.name);
SimpleTest.finish();
}
function addSuccess(e) {
var filename = e.target.result;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
// Remove the storageName (this shows up on FirefoxOS)
filename = filename.substring(1); // Remove leading slash
var slashIndex = filename.indexOf("/");
if (slashIndex >= 0) {
filename = filename.substring(slashIndex + 1); // Remove storageName
}
}
ok(filename == gFileName, "File name should match");
// Update gFileName to be the fully qualified name so that
// further checks will pass.
gFileName = e.target.result;
var storage = navigator.getDeviceStorage("pictures");
request = storage.get(gFileName);
request.onsuccess = getSuccess;
request.onerror = getError;
ok(true, "addSuccess was called");
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage");
request = storage.addNamed(gDataBlob, gFileName);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>

View file

@ -1,80 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=886627
-->
<head>
<title>Test for the device storage API</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=886627">
Mozilla Bug 886627
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script class="testbody" type="text/javascript">
/**
* Test that common device storage directories are available.
*
* This test differs from other device storage tests in that other tests use a
* "testing mode", which relocates the device storage directories to a testing
* directory. On the other hand, this test turns off testing mode to makes sure
* that the normal, non-testing directories also work properly.
*/
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
'set': [
["device.storage.enabled", true],
["device.storage.testing", false],
["device.storage.prompt.testing", true],
]
}, function() {
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(!navigator.getDeviceStorage("nonexistent-type"), "Should not have nonexistent storage");
ok(navigator.getDeviceStorage("pictures"), "Should have pictures storage");
ok(navigator.getDeviceStorage("videos"), "Should have videos storage");
ok(navigator.getDeviceStorage("music"), "Should have music storage");
// Need special permission to access "apps". We always have the permission in B2G
// mochitests, but on other platforms, we need to manually add the permission.
var needAppsPermission = false;;
if (!SpecialPowers.testPermission(
"webapps-manage", SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document)) {
ok(!navigator.getDeviceStorage("apps"), "Should not have apps storage without permission");
needAppsPermission = true;
}
var testFunction = function() {
ok(navigator.getDeviceStorage("apps"), "Should have apps storage with permission");
ok(navigator.getDeviceStorage("sdcard"), "Should have sdcard storage");
ok(navigator.getDeviceStorage("crashes"), "Should have crashes storage");
// The test harness reverts our pref changes automatically.
SimpleTest.finish();
}
if (needAppsPermission) {
SpecialPowers.pushPermissions(
[{ "type":"webapps-manage", "allow": true, "context": document }],
testFunction);
} else {
testFunction();
}
});
</script>
</pre>
</body>
</html>

View file

@ -1,101 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
var freeBytes = -1;
var stats = 0;
function stat(s, file_list_length) {
if (freeBytes == -1) {
freeBytes = s.target.result.freeBytes;
}
ok(freeBytes == s.target.result.freeBytes, "Free bytes should be the same");
ok(file_list_length * 1024 == s.target.result.totalBytes, "space taken up by files should match")
stats = stats + 1;
if (stats == 2) {
SimpleTest.finish();
}
}
function addSuccess(e) {
added = added - 1;
if (added == 0) {
request = pictures.stat();
request.onsuccess = function(s) {stat(s, picture_files.length)};
request = videos.stat();
request.onsuccess = function(s) {stat(s, video_files.length)};
request = music.stat();
request.onsuccess = function(s) {stat(s, music_files.length)};
}
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
ok(true, "hi");
var pictures = navigator.getDeviceStorage("pictures");
var picture_files = [ "a.png", "b.png", "c.png", "d.png", "e.png" ];
var videos = navigator.getDeviceStorage("videos");
var video_files = [ "a.ogv", "b.ogv" ];
var music = navigator.getDeviceStorage("music");
var music_files = [ "a.mp3", "b.mp3", "c.mp3" ];
var added = picture_files.length + video_files.length + music_files.length;
for (var i=0; i < picture_files.length; i++) {
request = pictures.addNamed(createRandomBlob('image/png'), picture_files[i]);
request.onsuccess = addSuccess;
request.onerror = addError;
}
for (var i=0; i < video_files.length; i++) {
request = videos.addNamed(createRandomBlob('video/ogv'), video_files[i]);
request.onsuccess = addSuccess;
request.onerror = addError;
}
for (var i=0; i < music_files.length; i++) {
request = music.addNamed(createRandomBlob('audio/mp3'), music_files[i]);
request.onsuccess = addSuccess;
request.onerror = addError;
}
});
</script>
</pre>
</body>
</html>

View file

@ -1,72 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
function testingStorage() {
return navigator.getDeviceStorage("pictures");
}
var tests = [
function () { return testingStorage().addNamed(createRandomBlob('image/png'), gFileName); },
function () { return testingStorage().delete(gFileName); },
function () { return testingStorage().get(gFileName); },
function () { var r = testingStorage().enumerate("../"); return r; }
];
var gFileName = "../owned.png";
function fail(e) {
ok(false, "addSuccess was called");
dump(request);
SimpleTest.finish();
}
function next(e) {
if (e != undefined) {
ok(true, "addError was called");
ok(e.target.error.name == "SecurityError", "Error must be SecurityError");
}
var f = tests.pop();
if (f == undefined) {
SimpleTest.finish();
return;
}
request = f();
request.onsuccess = fail;
request.onerror = next;
}
next();
});
</script>
</pre>
</body>
</html>

View file

@ -1,104 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
function enumerateSuccess(e) {
if (e.target.result == null) {
ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
dump("We still have length = " + files.length + "\n");
SimpleTest.finish();
return;
}
var filename = e.target.result.name;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
// Remove the storageName (this shows up on FirefoxOS)
filename = filename.substring(1); // Remove leading slash
var slashIndex = filename.indexOf("/");
if (slashIndex >= 0) {
filename = filename.substring(slashIndex + 1); // Remove storageName
}
}
if (filename.startsWith(prefix)) {
filename = filename.substring(prefix.length + 1); // Remove prefix
}
var index = files.indexOf(filename);
files.remove(index);
ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
// clean up
var cleanup = storage.delete(e.target.result.name);
cleanup.onsuccess = function(e) {} // todo - can i remove this?
e.target.continue();
}
function handleError(e) {
ok(false, "handleError was called : " + e.target.error.name);
SimpleTest.finish();
}
function addSuccess(e) {
addedSoFar = addedSoFar + 1;
if (addedSoFar == files.length) {
var cursor = storage.enumerate(prefix);
cursor.onsuccess = enumerateSuccess;
cursor.onerror = handleError;
}
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var prefix = "devicestorage/" + randomFilename(12) + ".png"
var files = [ "a.PNG", "b.pnG", "c.png", "d/a.png", "d/b.png", "d/c.png", "d/d.png", "The/quick/brown/fox/jumps/over/the/lazy/dog.png"]
var addedSoFar = 0;
for (var i=0; i<files.length; i++) {
request = storage.addNamed(createRandomBlob('image/png'), prefix + '/' + files[i]);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
}
});
</script>
</pre>
</body>
</html>

View file

@ -1,50 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
function enumerateSuccess(e) {
}
function enumerateFailure(e) {
}
var cursor = navigator.getDeviceStorage("pictures").enumerate();
cursor.onsuccess = enumerateSuccess;
cursor.onerror = enumerateFailure;
try {
cursor.continue();
}
catch (e) {
ok(true, "Calling continue before enumerateSuccess fires should throw");
SimpleTest.finish();
}
});
</script>
</pre>
</body>
</html>

View file

@ -1,109 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
devicestorage_setup();
function enumerateSuccess(e) {
if (e.target.result == null) {
ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
SimpleTest.finish();
return;
}
var filename = e.target.result.name;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
// Remove the storageName (this shows up on FirefoxOS)
filename = filename.substring(1); // Remove leading slash
var slashIndex = filename.indexOf("/");
if (slashIndex >= 0) {
filename = filename.substring(slashIndex + 1); // Remove storageName
}
}
if (filename.startsWith(prefix)) {
filename = filename.substring(prefix.length + 1); // Remove prefix
}
var index = files.indexOf(enumFilename);
files.remove(index);
ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
// clean up
var cleanup = storage.delete(e.target.result.name);
cleanup.onsuccess = function(e) {} // todo - can i remove this?
e.target.continue();
}
function handleError(e) {
ok(false, "handleError was called : " + e.target.error.name);
SimpleTest.finish();
}
function addSuccess(e) {
addedSoFar = addedSoFar + 1;
if (addedSoFar == files.length) {
var cursor = storage.enumerate();
cursor.onsuccess = enumerateSuccess;
cursor.onerror = handleError;
}
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var prefix = "devicestorage/" + randomFilename(12)
var files = [ "a.png", "b.png", "c.png" ]
var addedSoFar = 0;
for (var i=0; i<files.length; i++) {
request = storage.addNamed(createRandomBlob('image/png'), prefix + '/' + files[i]);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
}
</script>
</pre>
</body>
</html>

View file

@ -1,80 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for basic sanity of the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
storage = navigator.getDeviceStorage("pictures");
throws = false;
try {
var cursor = storage.enumerate();
} catch(e) {throws = true}
ok(!throws, "enumerate no parameter");
throws = false;
try {
var cursor = storage.enumerate("string");
} catch(e) {throws = true}
ok(!throws, "enumerate one string parameter");
throws = false;
try {
var cursor = storage.enumerate("string", "string2");
} catch(e) {throws = true}
ok(throws, "enumerate two string parameter");
throws = false;
try {
var cursor = storage.enumerate("string", {"since": new Date(1)});
} catch(e) {throws = true}
ok(!throws, "enumerate a string and object parameter");
throws = false;
try {
var cursor = storage.enumerate({"path": "a"});
} catch(e) {throws = true}
ok(!throws, "enumerate object parameter with path");
throws = false;
try {
var cursor = storage.enumerate({}, "string");
} catch(e) {throws = true}
ok(throws, "enumerate object then a string");
throws = false;
try {
var cursor = storage.enumerate({"path": "a", "since": new Date(0) });
} catch(e) {throws = true}
ok(!throws, "enumerate object parameter with path");
SimpleTest.finish()
});
</script>
</pre>
</body>
</html>

View file

@ -1,62 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
function freeSpaceSuccess(e) {
ok(e.target.result > 0, "free bytes should exist and be greater than zero");
SimpleTest.finish();
}
function freeSpaceError(e) {
ok(false, "freeSpaceError was called");
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
function addSuccess(e) {
request = storage.freeSpace();
ok(request, "Should have a non-null request");
request.onsuccess = freeSpaceSuccess;
request.onerror = freeSpaceError;
}
var prefix = "devicestorage/" + randomFilename(12);
request = storage.addNamed(createRandomBlob('image/png'), prefix + "/a/b.png");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>

View file

@ -1,598 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=910412
-->
<head>
<meta charset="utf-8">
<title>Permission test of FileSystem API for Device Storage</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=910412">Mozilla Bug 910412</a>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script type="application/javascript">
function randomFilename(l) {
let set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
let result = "";
for (let i=0; i<l; i++) {
let r = Math.floor(set.length * Math.random());
result += set.substring(r, r + 1);
}
return result;
}
function getRandomBuffer() {
var size = 1024;
var buffer = new ArrayBuffer(size);
var view = new Uint8Array(buffer);
for (var i = 0; i < size; i++) {
view[i] = parseInt(Math.random() * 255);
}
return buffer;
}
function createRandomBlob(mime) {
let size = 1024;
let buffer = new ArrayBuffer(size);
let view = new Uint8Array(buffer);
for (let i = 0; i < size; i++) {
view[i] = parseInt(Math.random() * 255);
}
return blob = new Blob([buffer], {type: mime});
}
let MockPermissionPrompt = SpecialPowers.MockPermissionPrompt;
MockPermissionPrompt.init();
SimpleTest.waitForExplicitFinish();
function TestCreateDirectory(iframe, data) {
function cbError(e) {
is(e.name, "SecurityError", "[TestCreateDirectory] Should fire a SecurityError for type " + data.type);
is(data.shouldPass, false, "[TestCreateDirectory] Error callback was called for type " + data.type + '. Error: ' + e.name);
testComplete(iframe, data);
}
let storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "[TestCreateDirectory] Should be able to get storage object for " + data.type);
if (!storage) {
testComplete(iframe, data);
return;
}
storage.getRoot().then(function(root) {
is(data.shouldPass, true, "[TestCreateDirectory] Success callback was called for type " + data.type);
let filename = randomFilename(100);
root.createDirectory(filename).then(function(d) {
let passed = d && (d.name === filename);
is(data.shouldPass, passed, "[TestCreateDirectory] Success callback was called for type " + data.type);
testComplete(iframe, data);
}, cbError);
}, cbError);
}
function TestGet(iframe, data) {
function cbError(e) {
is(e.name, "SecurityError", "[TestGet] Should fire a SecurityError for type " + data.type);
is(data.shouldPass, false, "[TestGet] Error callback was called for type " + data.type + '. Error: ' + e.name);
testComplete(iframe, data);
}
createTestFile(data.fileExtension);
let storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "[TestGet] Should be able to get storage object for " + data.type);
if (!storage) {
testComplete(iframe, data);
return;
}
storage.getRoot().then(function(root) {
ok(true, "[TestGet] Success callback of getRoot was called for type " + data.type);
root.get("testfile" + data.fileExtension).then(function() {
is(data.shouldPass, true, "[TestGet] Success callback was called for type " + data.type);
testComplete(iframe, data);
}, cbError);
}, cbError);
}
function TestCreateFile(iframe, data) {
function cbError(e) {
is(e.name, "SecurityError", "[TestCreateFile] Should fire a SecurityError for type " + data.type);
is(data.shouldPass, false, "[TestCreateFile] Error callback was called for type " + data.type + '. Error: ' + e.name);
testComplete(iframe, data);
}
let storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "[TestCreateFile] Should be able to get storage object for " + data.type);
if (!storage) {
testComplete(iframe, data);
return;
}
storage.getRoot().then(function(root) {
ok(true, "[TestCreateFile] Success callback of getRoot was called for type " + data.type);
let filename = randomFilename(100) + data.fileExtension;
root.createFile(filename, {
data: createRandomBlob(data.mimeType),
ifExists: "replace"
}).then(function() {
is(data.shouldPass, true, "[TestCreateFile] Success callback was called for type " + data.type);
testComplete(iframe, data);
}, cbError);
}, cbError);
}
function TestRemove(iframe, data) {
function cbError(e) {
is(e.name, "SecurityError", "[TestRemove] Should fire a SecurityError for type " + data.type);
is(data.shouldPass, false, "[TestRemove] Error callback was called for type " + data.type + '. Error: ' + e.name);
testComplete(iframe, data);
}
createTestFile(data.fileExtension);
let storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "[TestRemove] Should be able to get storage object for " + data.type);
if (!storage) {
testComplete(iframe, data);
return;
}
storage.getRoot().then(function(root) {
ok(true, "[TestRemove] Success callback of getRoot was called for type " + data.type);
root.remove("testfile" + data.fileExtension).then(function() {
is(data.shouldPass, true, "[TestRemove] Success callback was called for type " + data.type);
testComplete(iframe, data);
}, cbError);
}, cbError);
}
let gTestUri = "https://example.com/tests/dom/devicestorage/test/test_fs_app_permissions.html"
let gData = [
// Directory#get
// Web applications with no permissions
{
type: 'pictures',
shouldPass: false,
fileExtension: '.png',
test: TestGet
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogv',
test: TestGet
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogg',
test: TestGet
},
{
type: 'music',
shouldPass: false,
fileExtension: '.ogg',
test: TestGet
},
{
type: 'music',
shouldPass: false,
fileExtension: '.txt',
test: TestGet
},
{
type: 'sdcard',
shouldPass: false,
fileExtension: '.txt',
test: TestGet
},
// Web applications with permission granted
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
permissions: ["device-storage:pictures"],
test: TestGet
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
permissions: ["device-storage:videos"],
test: TestGet
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:videos"],
test: TestGet
},
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:music"],
test: TestGet
},
{
type: 'music',
shouldPass: false,
fileExtension: '.txt',
permissions: ["device-storage:music"],
test: TestGet
},
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
permissions: ["device-storage:sdcard"],
test: TestGet
},
// Directory#createDirectory
// Web applications with no permissions
{
type: 'pictures',
shouldPass: false,
test: TestCreateDirectory
},
{
type: 'videos',
shouldPass: false,
test: TestCreateDirectory
},
{
type: 'music',
shouldPass: false,
test: TestCreateDirectory
},
{
type: 'sdcard',
shouldPass: false,
test: TestCreateDirectory
},
// Web applications with permission granted
{
type: 'pictures',
shouldPass: true,
permissions: ["device-storage:pictures"],
test: TestCreateDirectory
},
{
type: 'videos',
shouldPass: true,
permissions: ["device-storage:videos"],
test: TestCreateDirectory
},
{
type: 'music',
shouldPass: true,
permissions: ["device-storage:music"],
test: TestCreateDirectory
},
{
type: 'sdcard',
shouldPass: true,
permissions: ["device-storage:sdcard"],
test: TestCreateDirectory
},
// Directory#createFile
// Web applications with no permissions
{
type: 'pictures',
mimeType: 'image/png',
shouldPass: false,
fileExtension: '.png',
test: TestCreateFile
},
{
type: 'videos',
mimeType: 'video/ogv',
shouldPass: false,
fileExtension: '.ogv',
test: TestCreateFile
},
{
type: 'videos',
mimeType: 'video/ogg',
shouldPass: false,
fileExtension: '.ogg',
test: TestCreateFile
},
{
type: 'music',
mimeType: 'audio/ogg',
shouldPass: false,
fileExtension: '.ogg',
test: TestCreateFile
},
{
type: 'music',
mimeType: 'audio/ogg',
shouldPass: false,
fileExtension: '.txt',
test: TestCreateFile
},
{
type: 'sdcard',
mimeType: 'text/plain',
shouldPass: false,
fileExtension: '.txt',
test: TestCreateFile
},
// Web applications with permission granted
{
type: 'pictures',
mimeType: 'image/png',
shouldPass: true,
fileExtension: '.png',
permissions: ["device-storage:pictures"],
test: TestCreateFile
},
{
type: 'videos',
mimeType: 'video/ogv',
shouldPass: true,
fileExtension: '.ogv',
permissions: ["device-storage:videos"],
test: TestCreateFile
},
{
type: 'videos',
mimeType: 'video/ogg',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:videos"],
test: TestCreateFile
},
{
type: 'music',
mimeType: 'audio/ogg',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:music"],
test: TestCreateFile
},
{
type: 'music',
mimeType: 'audio/ogg',
shouldPass: false,
fileExtension: '.txt',
permissions: ["device-storage:music"],
test: TestCreateFile
},
{
type: 'sdcard',
mimeType: 'text/plain',
shouldPass: true,
fileExtension: '.txt',
permissions: ["device-storage:sdcard"],
test: TestCreateFile
},
// Directory#remove
// Web applications with no permissions
{
type: 'pictures',
shouldPass: false,
fileExtension: '.png',
test: TestRemove
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogv',
test: TestRemove
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogg',
test: TestRemove
},
{
type: 'music',
shouldPass: false,
fileExtension: '.ogg',
test: TestRemove
},
{
type: 'music',
shouldPass: false,
fileExtension: '.txt',
test: TestRemove
},
{
type: 'sdcard',
shouldPass: false,
fileExtension: '.txt',
test: TestRemove
},
// Web applications with permission granted
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
permissions: ["device-storage:pictures"],
test: TestRemove
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
permissions: ["device-storage:videos"],
test: TestRemove
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:videos"],
test: TestRemove
},
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:music"],
test: TestRemove
},
{
type: 'music',
shouldPass: false,
fileExtension: '.txt',
permissions: ["device-storage:music"],
test: TestRemove
},
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
permissions: ["device-storage:sdcard"],
test: TestRemove
},
];
function setupTest(iframe,data) {
if (data.permissions) {
for (let j in data.permissions) {
SpecialPowers.addPermission(data.permissions[j], true, iframe.contentDocument);
}
}
}
function testComplete(iframe, data) {
if (data.permissions) {
for (let j in data.permissions) {
SpecialPowers.removePermission(data.permissions[j], iframe.contentDocument);
}
}
document.getElementById('content').removeChild(iframe);
if (gData.length == 0) {
SimpleTest.finish();
} else {
gTestRunner.next();
}
}
function* runTest() {
while (gData.length > 0) {
let iframe = document.createElement('iframe');
let data = gData.shift();
iframe.setAttribute('mozbrowser', '');
iframe.src = gTestUri;
iframe.addEventListener('load', function(e) {
setupTest(iframe, data)
data.test(iframe, data);
});
document.getElementById('content').appendChild(iframe);
yield undefined;
}
}
function createTestFile(extension) {
try {
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
let directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
let f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
f.remove(true);
f.appendRelativePath("testfile" + extension);
f.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
} catch(e) {}
}
let gTestRunner = runTest();
SpecialPowers.addPermission("browser", true, gTestUri);
SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["device.storage.enabled", true],
["device.storage.testing", true],
["device.storage.prompt.testing", false]]},
function() { gTestRunner.next(); });
</script>
</pre>
</body>
</html>

View file

@ -1,91 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=855952
-->
<head>
<title>Test for basic sanity of the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=855952">Mozilla Bug 855952</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
var file = new Blob(["This is a text file."], {type: "text/plain"});
var appendFile = new Blob([" Another text file."], {type: "text/plain"});
devicestorage_setup(function () {
function deleteSuccess(e) {
SimpleTest.finish();
}
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
SimpleTest.finish();
}
function appendSuccess(e) {
ok(true, "appendSuccess was called.");
request = gStorage.delete(e.target.result)
request.onsuccess = deleteSuccess;
request.onerror = deleteError;
}
function appendError(e) {
ok(false, "appendError was called.");
SimpleTest.finish();
}
function addSuccess(e) {
ok(true, "addSuccess was called");
request = gStorage.appendNamed(appendFile, e.target.result);
ok(request, "Should have a non-null request");
request.onsuccess = appendSuccess;
request.onerror = appendError;
}
function addError(e) {
// test file is already exists. clean it up and try again..
request = gStorage.delete(e.target.result)
request.onsuccess = addFile;
}
function addFile() {
// Add a file first
request = gStorage.addNamed(file, "devicestorage/append.asc");
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
}
function runtest() {
addFile();
}
var gStorage = navigator.getDeviceStorage("sdcard");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(gStorage, "Should get storage from sdcard");
runtest();
});
</script>
</pre>
</body>
</html>

View file

@ -1,72 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=910412
-->
<head>
<title>Test for the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=910412">Mozilla Bug 910412</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
var gFileName = randomFilename(12);
// The root directory object.
var gRoot;
function getRootSuccess(r) {
ok(r && r.name === storage.storageName, "Failed to get the root directory.");
gRoot = r;
// Create a new directory under the root.
gRoot.createDirectory(gFileName).then(createDirectorySuccess, cbError);
}
function createDirectorySuccess(d) {
ok(d.name === gFileName, "Failed to create directory: name mismatch.");
// Get the new created directory from the root.
gRoot.get(gFileName).then(getSuccess, cbError);
}
function getSuccess(d) {
ok(d.name === gFileName, "Should get directory - " + gFileName + ".");
SimpleTest.finish();
}
function cbError(e) {
ok(false, "Should not arrive here! Error: " + e.name);
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage");
var promise = storage.getRoot();
ok(promise, "Should have a non-null promise");
promise.then(getRootSuccess, cbError);
});
</script>
</pre>
</body>
</html>

View file

@ -1,107 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=910412
-->
<head>
<title>Test createDirectory of the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=910412">Mozilla Bug 910412</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
// The root directory object.
var gRoot;
var gTestCount = 0;
var gPath = '';
var gName = '';
function testCreateDirectory(rootDir, path) {
rootDir.createDirectory(path).then(createDirectorySuccess, cbError);
}
function createDirectorySuccess(d) {
is(d.name, gName, "Failed to create directory: name mismatch.");
// Get the new created directory from the root.
gRoot.get(gPath).then(getSuccess, cbError);
}
function getSuccess(d) {
is(d.name, gName, "Should get directory - " + (gPath || "[root]") + ".");
switch (gTestCount) {
case 0:
gRoot = d;
// Create a new directory under the root.
gName = gPath = randomFilename(12);
testCreateDirectory(gRoot, gName);
break;
case 1:
// Create a sub-directory under current directory.
gName = randomFilename(12);
gPath = gPath + '/' + gName;
testCreateDirectory(d, gName);
break;
case 2:
// Create directory with an existing path.
gRoot.createDirectory(gPath).then(function(what) {
ok(false, "Should not overwrite an existing directory.");
SimpleTest.finish();
}, function(e) {
ok(true, "Creating directory should fail if it already exists.");
// Create a directory whose intermediate directory doesn't exit.
gName = randomFilename(12);
gPath = 'sub1/sub2/' + gName;
testCreateDirectory(gRoot, gPath);
});
break;
default:
// Create the parent directory.
d.createDirectory('..').then(function(what) {
ok(false, "Should not overwrite an existing directory.");
SimpleTest.finish();
}, function(e) {
ok(true, "Accessing parent directory with '..' is not allowed.");
SimpleTest.finish();
});
break;
}
gTestCount++;
}
function cbError(e) {
ok(false, e.name + " error should not arrive here!");
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage.");
var promise = storage.getRoot();
ok(promise, "Should have a non-null promise for getRoot.");
gName = storage.storageName;
promise.then(getSuccess, cbError);
});
</script>
</pre>
</body>
</html>

View file

@ -1,133 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=910412
-->
<head>
<title>Test createDirectory of the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=910412">Mozilla Bug 910412</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript">
devicestorage_setup(function () {
let gTestCount = 0;
let gFileReader = new FileReader();
let gRoot;
function str2array(str) {
let strlen = str.length;
let buf = new ArrayBuffer(strlen);
let bufView = new Uint8Array(buf);
for (let i=0; i < strlen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function array2str(data) {
return String.fromCharCode.apply(String, new Uint8Array(data));
}
let gTestCases = [
// Create with string data.
{
text: "My name is Yuan.",
get data() { return this.text; },
shouldPass: true,
mode: "replace"
},
// Create with array buffer data.
{
text: "I'm from Kunming.",
get data() { return str2array(this.text); },
shouldPass: true,
mode: "replace"
},
// Create with array buffer view data.
{
text: "Kunming is in Yunnan province of China.",
get data() { return new Uint8Array(str2array(this.text)); },
shouldPass: true,
mode: "replace"
},
// Create with blob data.
{
text: "Kunming is in Yunnan province of China.",
get data() { return new Blob([this.text], {type: 'image/png'}); },
shouldPass: true,
mode: "replace"
},
// Don't overwrite existing file.
{
data: null,
shouldPass: false,
mode: "fail"
}
];
function next() {
if (gTestCount >= gTestCases.length) {
SimpleTest.finish();
return;
}
let c = gTestCases[gTestCount++];
gRoot.createFile("text.png", {
data: c.data,
ifExists: c.mode
}).then(function(file) {
is(c.shouldPass, true, "[" + gTestCount + "] Success callback was called for createFile.");
if (!c.shouldPass) {
SimpleTest.executeSoon(next);
return;
}
// Check the file content.
gFileReader.readAsArrayBuffer(file);
gFileReader.onload = function(e) {
ab = e.target.result;
is(array2str(e.target.result), c.text, "[" + gTestCount + "] Wrong values.");
SimpleTest.executeSoon(next);
};
}, function(e) {
is(c.shouldPass, false, "[" + gTestCount + "] Error callback was called for createFile.");
SimpleTest.executeSoon(next);
});
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
let storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage.");
// Get the root directory
storage.getRoot().then(function(dir) {
ok(dir, "Should have gotten the root directory.");
gRoot = dir;
next();
}, function(e) {
ok(false, e.name + " error should not arrive here!");
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>

View file

@ -1,206 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=910412
-->
<head>
<title>Test Directory#get of the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=910412">Mozilla Bug 910412</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
SimpleTest.requestCompleteLog();
// The root directory object.
var gRoot = null;
var gSub1 = null;
var gSub2 = null;
var gTestCount = 0;
var gPath = "/";
function testGetSuccess(dir, path) {
dir.get(path).then(getSuccess, cbError);
}
function testGetFailure(dir, path) {
dir.get(path).then(cbSuccess, getFailure);
}
function getSuccess(r) {
ok(r, "[" + gTestCount +"] Should get the file - " + gPath + ".");
switch (gTestCount) {
case 0:
gRoot = r;
// Get sub1/sub2/text.png from root.
gPath = "sub1/sub2/test.png";
testGetSuccess(gRoot, "sub1/sub2/test.png");
break;
case 1:
// Get sub1 from root.
gPath = "sub1";
testGetSuccess(gRoot, "sub1");
break;
case 2:
// Get sub1/sub2 from root.
gSub1 = r;
gPath = "sub1/sub2";
testGetSuccess(gRoot, "sub1/sub2");
break;
case 3:
// Get sub1/sub2 from sub2.
gSub2 = r;
gPath = "sub1/sub2";
testGetSuccess(gSub1, "sub2");
break;
case 4:
// Test path with leading and trailing white spaces.
gPath = "sub1/sub2";
testGetSuccess(gSub1, "\t sub2 ");
break;
case 5:
// Get sub1 from sub1/sub2 with "..".
gPath = "sub1/sub2/..";
testGetFailure(gSub2, "..");
break;
default:
ok(false, "Should not arrive at getSuccess!");
SimpleTest.finish();
break;
}
gTestCount++;
}
function getFailure(e) {
ok(true, "[" + gTestCount +"] Should not get the file - " + gPath + ". Error: " + e.name);
switch (gTestCount) {
case 6:
// Test special path "..".
gPath = "sub1/sub2/../sub2";
testGetFailure(gSub2, "../sub2");
break;
case 7:
gPath = "sub1/sub2/../sub2";
testGetFailure(gRoot, "sub1/sub2/../sub2");
break;
case 8:
// Test special path ".".
gPath = "sub1/./sub2";
testGetFailure(gRoot, "sub1/./sub2");
break;
case 9:
gPath = "./sub1/sub2";
testGetFailure(gRoot, "./sub1/sub2");
break;
case 10:
gPath = "././sub1/sub2";
testGetFailure(gRoot, "././sub1/sub2");
break;
case 11:
gPath = "sub1/sub2/.";
testGetFailure(gRoot, "sub1/sub2/.");
break;
case 12:
gPath = "sub1/.";
testGetFailure(gSub1, "./");
break;
case 13:
// Test path starting with "/".
gPath = "sub1/";
testGetFailure(gSub1, "/");
break;
case 14:
// Test path ending with "/".
gPath = "sub1/";
testGetFailure(gSub1, "sub2/");
break;
case 15:
// Test empty path.
gPath = "sub2";
testGetFailure(gSub2, "");
break;
case 16:
// Test special path "//".
gPath = "sub1//sub2";
testGetFailure(gRoot, "sub1//sub2");
break;
case 17:
SimpleTest.finish();
break;
default:
ok(false, "Should not arrive here!");
SimpleTest.finish();
break;
}
gTestCount++;
}
function cbError(e) {
ok(false, "Should not arrive at cbError! Error: " + e.name);
SimpleTest.finish();
}
function cbSuccess(e) {
ok(false, "Should not arrive at cbSuccess!");
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
var gStorage = navigator.getDeviceStorage("pictures");
ok(gStorage, "Should have gotten a storage.");
function createTestFile(path, callback) {
function addNamed() {
var req = gStorage.addNamed(createRandomBlob("image/png"), path);
req.onsuccess = function() {
ok(true, path + " was created.");
callback();
};
req.onerror = function(e) {
ok(false, "Failed to create " + path + ": " + e.target.error.name);
SimpleTest.finish();
};
}
// Bug 980136. Check if the file exists before we create.
var req = gStorage.get(path);
req.onsuccess = function() {
ok(true, path + " exists. Do not need to create.");
callback();
};
req.onerror = function(e) {
ok(true, path + " does not exists: " + e.target.error.name);
addNamed();
};
}
createTestFile("sub1/sub2/test.png", function() {
var promise = gStorage.getRoot();
ok(promise, "Should have a non-null promise for getRoot.");
promise.then(getSuccess, cbError);
});
});
</script>
</pre>
</body>
</html>

View file

@ -1,98 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=XXX
-->
<head>
<title>Test Directory#getFilesAndDirectories of the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=XXX">Mozilla Bug XXX</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
SimpleTest.requestCompleteLog();
// The root directory object.
var gRoot = null;
function checkContents1(contents) {
var expected = {
"sub2": "/sub",
"sub3": "/sub",
"a.png": "/sub",
"b.png": "/sub",
};
is(contents.length, Object.keys(expected).length,
"The sub-directory should contain four children");
var sub2;
for (var child of contents) {
if (child.name in expected) {
ok(true, "Found '" + child.name + "' in /sub");
if (child.name == "sub2") {
sub2 = child;
}
} else {
ok(false, "Did not expect '" + child.name + "' in /sub");
}
delete expected[child.name];
}
// 'expected' should now be "empty"
for (var missing in Object.keys(expected)) {
ok(false, "Expected '" + missing.name + "' in /sub");
}
sub2.getFilesAndDirectories().then(checkContents2, handleError);
}
function checkContents2(contents) {
is(contents[0].name, "c.png", "'sub2' should contain 'c.png'");
SimpleTest.finish();
}
function handleError(e) {
ok(false, "Should not arrive at handleError! Error: " + e.name);
SimpleTest.finish();
}
var gStorage = navigator.getDeviceStorage("pictures");
ok(gStorage, "Should have gotten a storage.");
function runTests() {
gStorage.getRoot().then(function(rootDir) {
gRoot = rootDir;
return rootDir.get("sub");
}).then(function(subDir) {
return subDir.getFilesAndDirectories();
}).then(checkContents1).catch(handleError);
}
createTestFiles(gStorage, ["sub/a.png", "sub/b.png", "sub/sub2/c.png", "sub/sub3/d.png"]).then(function() {
runTests();
}, function() {
ok(false, "Failed to created test files.");
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>

View file

@ -1,176 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=934368
-->
<head>
<title>Test Directory#remove and #removeDeep of the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=934368">Mozilla Bug 934368</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript">
devicestorage_setup(function () {
let gStorage = null;
let gTestCount = 0;
let gFileMap = {};
let gRemoveDeep = true;
let gTestCases = [
// Remove a non-existent file should return false.
{
dir: "/",
path: "non-existent.png",
ret: false,
shouldPass: true
},
// Remove parent directory should fail.
{
dir: "sub1/sub2",
target: "sub1",
ret: true,
shouldPass: false
},
// Remove root directory should fail.
{
dir: "/",
target: "/",
ret: true,
shouldPass: false
},
// Remove non-descendant file should fail.
{
dir: "sub1",
target: "sub/b.png",
ret: true,
shouldPass: false
},
// Remove descendant file should return true.
{
dir: "sub1",
target: "sub1/sub2/a.png",
ret: true,
shouldPass: true
},
// Remove empty directory should return true.
{
dir: "sub1",
path: "sub2",
ret: true,
shouldPass: true
},
// Remove non-empty directory should return true for "removeDeep" and fail
// for "remove".
{
dir: "/",
path: "sub",
ret: true,
get shouldPass() { return gRemoveDeep; }
}
];
function runNextTests() {
gTestCount = 0;
function runTests() {
function cbError(e) {
ok(false, "Should not arrive at cbError! Error: " + e.name);
SimpleTest.finish();
}
function cbSuccess(r) {
ok(r, "Should get the file - " + this);
gFileMap[this] = r;
}
// Get directory and file objects.
gStorage.getRoot().then(function(root) {
ok(root, "Should get root directory.");
gFileMap["/"] = root;
let arr = [];
["sub1", "sub1/sub2", "sub1/sub2/a.png", "sub/b.png"].forEach(function(path) {
arr.push(root.get(path).then(cbSuccess.bind(path), cbError));
});
Promise.all(arr).then(function() {
testNextRemove();
}, function() {
ok(false, "Failed to get test files.");
SimpleTest.finish();
});
}, cbError);
};
createTestFiles(gStorage, ["sub1/sub2/a.png", "sub/b.png"]).then(function() {
runTests();
}, function() {
ok(false, "Failed to created test files.");
SimpleTest.finish();
});
}
function testNextRemove() {
if (gTestCount < gTestCases.length) {
let data = gTestCases[gTestCount++];
let dir = gFileMap[data.dir];
let path = data.path || gFileMap[data.target];
let targetPath = data.path || data.target;
let promise = gRemoveDeep ? dir.removeDeep(path) : dir.remove(path);
promise.then(function(result) {
ok(data.shouldPass, "Success callback was called to remove " +
targetPath + " from " + data.dir);
is(result, data.ret, "Return value should match to remove " +
targetPath + " from " + data.dir);
SimpleTest.executeSoon(testNextRemove);
}, function(err) {
ok(!data.shouldPass, "Error callback was called to remove " +
targetPath + " from " + data.dir + '. Error: ' + err.name);
SimpleTest.executeSoon(testNextRemove);
});
return;
}
if (gRemoveDeep) {
// Test "remove" after "removeDeep".
gRemoveDeep = false;
runNextTests();
return;
}
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
gStorage = navigator.getDeviceStorage("pictures");
ok(gStorage, "Should have gotten a storage.");
// Test "removeDeep" first.
gRemoveDeep = true;
runNextTests();
});
</script>
</pre>
</body>
</html>

View file

@ -1,176 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.requestFlakyTimeout("untriaged");
devicestorage_setup(function () {
// We put the old files in 2 levels deep. When you add a file to a directory
// it will modify the parents last modification time, but not the parents
// parents. So we want to make sure that even though x's timestamp is earlier
// than the since parameter, we still pick up the later files.
var oldFiles = ["x/y/aa.png", "x/y/ab.png", "x/y/ac.png"];
var timeFile = "t.png";
var newFiles = ["x/y/ad.png", "x/y/ae.png", "x/y/af.png", // new files in old dir
"z/bd.png", "z/be.png", "z/bf.png"]; // new files in new dir
var storage = navigator.getDeviceStorage('pictures');
var prefix = "devicestorage/" + randomFilename(12);
var i;
var timestamp;
var lastFileAddedTimestamp;
function verifyAndDelete(prefix, files, e) {
if (e.target.result == null) {
ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
dump("We still have length = " + files.length + "\n");
dump(files + "\n");
SimpleTest.finish();
return;
}
var filename = e.target.result.name;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
// Remove the storageName (this shows up on FirefoxOS)
filename = filename.substring(1); // Remove leading slash
var slashIndex = filename.indexOf("/");
if (slashIndex >= 0) {
filename = filename.substring(slashIndex + 1); // Remove storageName
}
}
if (filename.startsWith(prefix)) {
filename = filename.substring(prefix.length + 1); // Remove prefix
}
var index = files.indexOf(filename);
ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
if (index == -1)
return;
files.splice(index, 1);
// clean up
var cleanup = storage.delete(e.target.result.name);
cleanup.onsuccess = function(e) {}
}
function addFile(filename, callback) {
var addReq = storage.addNamed(createRandomBlob('image/png'), prefix + '/' + filename);
addReq.onsuccess = function(e) {
// After adding the file, we go ahead and grab the timestamp of the file
// that we just added
var getReq = storage.get(prefix + '/' + filename);
getReq.onsuccess = function(e) {
lastFileAddedTimestamp = e.target.result.lastModifiedDate;
callback();
}
getReq.onerror = function(e) {
ok(false, "getError was called : " + e.target.error.name);
SimpleTest.finish();
};
}
addReq.onerror = function(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
}
function addFileArray(fileArray, callback) {
var i = 0;
function addNextFile() {
i = i + 1;
if (i == fileArray.length) {
callback();
return;
}
addFile(fileArray[i], addNextFile);
}
addFile(fileArray[0], addNextFile);
}
function delFile(filename, callback) {
var req = storage.delete(prefix + '/' + filename);
req.onsuccess = function(e) {
callback();
};
req.onerror = function(e) {
ok(false, "delError was called : " + e.target.error.name);
SimpleTest.finish();
};
}
function afterNewFiles() {
var cursor = storage.enumerate(prefix, {"since": timestamp});
cursor.onsuccess = function(e) {
verifyAndDelete(prefix, newFiles, e);
if (e.target.result) {
e.target.continue();
}
};
cursor.onerror = function (e) {
ok(false, "handleError was called : " + e.target.error.name);
SimpleTest.finish();
};
}
function waitForTimestampChange() {
// We've added a new file. See if the timestamp differs from
// oldFileAddedTimestamp, and if it's the same wait for a bit
// and try again.
if (lastFileAddedTimestamp.valueOf() === timestamp.valueOf()) {
delFile(timeFile, function() {
setTimeout(function() {
addFile(timeFile, waitForTimestampChange);
}, 1000);
});
} else {
timestamp = lastFileAddedTimestamp;
// The timestamp has changed. Go ahead and add the rest of the new files
delFile(timeFile, function() {
addFileArray(newFiles, afterNewFiles);
});
}
}
function afterOldFiles() {
timestamp = lastFileAddedTimestamp;
setTimeout(function() {
// We've added our old files and waited for a second.
// Add a new file until the timestamp changes
addFile(timeFile, waitForTimestampChange);
}, 1000);
}
function addOldFiles() {
addFileArray(oldFiles, afterOldFiles);
}
addOldFiles();
});
</script>
</pre>
</body>
</html>

View file

@ -1,163 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
var gFileName = "devicestorage/" + randomFilename(12) + "/hi.png";
var gData = "My name is Doug Turner. My IRC nick is DougT. I like Maple cookies."
var gDataBlob = new Blob([gData], {type: 'image/png'});
var gFileReader = new FileReader();
function getAfterDeleteSuccess(e) {
ok(false, "file was deleted not successfully");
SimpleTest.finish();
}
function getAfterDeleteError(e) {
ok(true, "file was deleted successfully");
SimpleTest.finish();
}
function deleteSuccess(e) {
ok(e.target.result == gFileName, "File name should match");
dump(e.target.result + "\n")
// File was deleted using the sdcard stoage area. It should be gone
// from the pictures as well.
var storage = navigator.getDeviceStorage("pictures");
request = storage.get(e.target.result);
request.onsuccess = getAfterDeleteSuccess;
request.onerror = getAfterDeleteError;
}
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
SimpleTest.finish();
}
function getSuccess(e) {
// We wrote the file out using pictures type. Since we've over-ridden the
// root directory, we should be able to read it back using the sdcard
// storage area.
var storage = navigator.getDeviceStorage("sdcard");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(e.target.result.name == gFileName, "File name should match");
ok(e.target.result.size > 0, "File size be greater than zero");
ok(e.target.result.type, "File should have a mime type");
ok(e.target.result.lastModifiedDate, "File should have a last modified date");
var name = e.target.result.name;
gFileReader.readAsArrayBuffer(gDataBlob);
gFileReader.onload = function(e) {
readerCallback(e);
request = storage.delete(name)
request.onsuccess = deleteSuccess;
request.onerror = deleteError;
}
}
function readerCallback(e) {
ab = e.target.result;
is(ab.byteLength, gData.length, "wrong arraybuffer byteLength");
var u8v = new Uint8Array(ab);
is(String.fromCharCode.apply(String, u8v), gData, "wrong values");
}
function getError(e) {
ok(false, "getError was called : " + e.target.error.name);
SimpleTest.finish();
}
function addSuccess(e) {
var filename = e.target.result;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
// Remove the storageName (this shows up on FirefoxOS)
filename = filename.substring(1); // Remove leading slash
var slashIndex = filename.indexOf("/");
if (slashIndex >= 0) {
filename = filename.substring(slashIndex + 1); // Remove storageName
}
}
ok(filename == gFileName, "File name should match");
// Update gFileName to be the fully qualified name so that
// further checks will pass.
gFileName = e.target.result;
var storage = navigator.getDeviceStorage("pictures");
request = storage.get(gFileName);
request.onsuccess = getSuccess;
request.onerror = getError;
ok(true, "addSuccess was called");
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
function startTest() {
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage");
request = storage.addNamed(gDataBlob, gFileName);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
}
try {
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
var directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-sdcard");
try {
// The remove will fail if the directory doesn't exist, which is fine.
f.remove(true);
} catch (e) {}
SpecialPowers.pushPrefEnv({'set': [["device.storage.overrideRootDir", f.path]]},
function() {
startTest();
});
} catch(e) {}
});
</script>
</pre>
</body>
</html>

View file

@ -1,93 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for basic sanity of the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
var filename = "devicestorage/aaaa.png"
devicestorage_setup(function () {
function deleteSuccess(e) {
SimpleTest.finish();
}
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
SimpleTest.finish();
}
function addOverwritingSuccess(e) {
ok(false, "addOverwritingSuccess was called.");
SimpleTest.finish();
}
function addOverwritingError(e) {
ok(true, "Adding to the same location should fail");
ok(e.target.error.name == "NoModificationAllowedError", "Error must be NoModificationAllowedError");
var storage = navigator.getDeviceStorage("pictures");
request = storage.delete(filename)
request.onsuccess = deleteSuccess;
request.onerror = deleteError;
}
function addSuccess(e) {
ok(true, "addSuccess was called");
var storage = navigator.getDeviceStorage("pictures");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
request = storage.addNamed(createRandomBlob('image/png'), filename);
ok(request, "Should have a non-null request");
request.onsuccess = addOverwritingSuccess;
request.onerror = addOverwritingError;
}
function addError(e) {
// test file is already exists. clean it up and try again..
var storage = navigator.getDeviceStorage("pictures");
request = storage.delete(filename)
request.onsuccess = runtest;
}
function runtest() {
var storage = navigator.getDeviceStorage("pictures");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
request = storage.addNamed(createRandomBlob('image/png'), filename);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
}
runtest();
});
</script>
</pre>
</body>
</html>

View file

@ -1,60 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for basic sanity of the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var storage;
var throws = false;
try {
storage = navigator.getDeviceStorage();
} catch(e) {throws = true}
ok(throws, "getDeviceStorage takes one arg");
storage = navigator.getDeviceStorage("kilimanjaro");
ok(!storage, "kilimanjaro - Should not have this type of storage");
storage = navigator.getDeviceStorage("pictures");
ok(storage, "pictures - Should have getDeviceStorage");
storage = navigator.getDeviceStorage("music");
ok(storage, "music - Should have getDeviceStorage");
storage = navigator.getDeviceStorage("videos");
ok(storage, "videos - Should have getDeviceStorage");
var cursor = storage.enumerate();
ok(cursor, "Should have a non-null cursor");
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View file

@ -1,63 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
function usedSpaceSuccess(e) {
ok(e.target.result > 0, "total bytes should exist and be greater than zero");
SimpleTest.finish();
}
function usedSpaceError(e) {
ok(false, "usedSpaceError was called");
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
function addSuccess(e) {
request = storage.usedSpace();
ok(request, "Should have a non-null request");
request.onsuccess = usedSpaceSuccess;
request.onerror = usedSpaceError;
}
var prefix = "devicestorage/" + randomFilename(12);
request = storage.addNamed(createRandomBlob('image/png'), prefix + "/a/b.png");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>

View file

@ -1,77 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
var gFileName = randomFilename(20) + ".png"
function addSuccess(e) {
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
function onChange(e) {
dump("we saw: " + e.path + " " + e.reason + "\n");
var filename = e.path;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
// Remove the storageName (this shows up on FirefoxOS)
filename = filename.substring(1); // Remove leading slash
var slashIndex = filename.indexOf("/");
if (slashIndex >= 0) {
filename = filename.substring(slashIndex + 1); // Remove storageName
}
}
if (filename == gFileName) {
ok(true, "we saw the file get created");
storage.removeEventListener("change", onChange);
SimpleTest.finish();
}
else {
// we may see other file changes during the test, and
// that is completely ok
}
}
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have storage");
storage.addEventListener("change", onChange);
request = storage.addNamed(createRandomBlob('image/png'), gFileName);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>

View file

@ -1,86 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717103
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup(function () {
var gFileName = randomFilename(20) + ".png"
function addSuccess(e) {
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
SimpleTest.finish();
}
function onChange(e) {
dump("we saw: " + e.path + " " + e.reason + "\n");
var filename = e.path;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
// Remove the storageName (this shows up on FirefoxOS)
filename = filename.substring(1); // Remove leading slash
var slashIndex = filename.indexOf("/");
if (slashIndex >= 0) {
filename = filename.substring(slashIndex + 1); // Remove storageName
}
}
if (filename == gFileName) {
ok(true, "we saw the file get created");
storage.removeEventListener("change", onChange);
SimpleTest.finish();
}
else {
// we may see other file changes during the test, and
// that is completely ok
}
}
function onChangeFail(e) {
dump("onChangeFail: " + e.path + " " + e.reason + "\n");
ok(false, "We should never see any changes");
}
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have storage");
storage.addEventListener("change", onChange);
var storageOther = navigator.getDeviceStorage("music");
ok(storageOther, "Should have storage");
storageOther.addEventListener("change", onChangeFail);
request = storage.addNamed(createRandomBlob('image/png'), gFileName);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>

View file

@ -6,7 +6,6 @@
#include "mozilla/dom/DeviceStorageFileSystem.h"
#include "DeviceStorage.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/File.h"
@ -15,7 +14,6 @@
#include "mozilla/Unused.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "nsDeviceStorage.h"
#include "nsIFile.h"
#include "nsPIDOMWindow.h"
#include "nsGlobalWindow.h"
@ -42,34 +40,6 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
} else {
AssertIsOnBackgroundThread();
}
// Get the permission name required to access the file system.
DebugOnly<nsresult> rv =
DeviceStorageTypeChecker::GetPermissionForType(mStorageType, mPermission);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetPermissionForType failed");
// Get the local path of the file system root.
nsCOMPtr<nsIFile> rootFile;
DeviceStorageFile::GetRootDirectoryForType(aStorageType,
aStorageName,
getter_AddRefs(rootFile));
Unused <<
NS_WARN_IF(!rootFile ||
NS_FAILED(rootFile->GetPath(mLocalOrDeviceStorageRootPath)));
if (!XRE_IsParentProcess()) {
return;
}
// DeviceStorageTypeChecker is a singleton object and must be initialized on
// the main thread. We initialize it here so that we can use it on the worker
// thread.
if (NS_IsMainThread()) {
DebugOnly<DeviceStorageTypeChecker*> typeChecker =
DeviceStorageTypeChecker::CreateOrGet();
MOZ_ASSERT(typeChecker);
}
}
DeviceStorageFileSystem::~DeviceStorageFileSystem()

View file

@ -175,7 +175,6 @@
#endif
#include "mozilla/dom/File.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
#include "mozilla/dom/PPresentationChild.h"
#include "mozilla/dom/PresentationIPCService.h"
#include "mozilla/ipc/InputStreamUtils.h"
@ -188,7 +187,6 @@
#include "URIUtils.h"
#include "nsContentUtils.h"
#include "nsIPrincipal.h"
#include "nsDeviceStorage.h"
#include "DomainPolicy.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
#include "mozilla/dom/time/DateCacheCleaner.h"
@ -211,7 +209,6 @@
using namespace mozilla;
using namespace mozilla::docshell;
using namespace mozilla::dom::devicestorage;
using namespace mozilla::dom::ipc;
using namespace mozilla::dom::workers;
using namespace mozilla::media;
@ -1679,19 +1676,6 @@ ContentChild::RecvPTestShellConstructor(PTestShellChild* actor)
return IPC_OK();
}
PDeviceStorageRequestChild*
ContentChild::AllocPDeviceStorageRequestChild(const DeviceStorageParams& aParams)
{
return new DeviceStorageRequestChild();
}
bool
ContentChild::DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild* aDeviceStorage)
{
delete aDeviceStorage;
return true;
}
PNeckoChild*
ContentChild::AllocPNeckoChild()
{
@ -2371,28 +2355,6 @@ ContentChild::RecvLastPrivateDocShellDestroyed()
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvFilePathUpdate(const nsString& aStorageType,
const nsString& aStorageName,
const nsString& aPath,
const nsCString& aReason)
{
if (nsDOMDeviceStorage::InstanceCount() == 0) {
// No device storage instances in this process. Don't try and
// and create a DeviceStorageFile since it will fail.
return IPC_OK();
}
RefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(aStorageType, aStorageName, aPath);
nsString reason;
CopyASCIItoUTF16(aReason, reason);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->NotifyObservers(dsf, "file-watcher-update", reason.get());
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvNotifyProcessPriorityChanged(
const hal::ProcessPriority& aPriority)

View file

@ -177,12 +177,6 @@ public:
virtual bool DeallocPBrowserChild(PBrowserChild*) override;
virtual PDeviceStorageRequestChild*
AllocPDeviceStorageRequestChild(const DeviceStorageParams&) override;
virtual bool
DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*) override;
virtual PBlobChild*
AllocPBlobChild(const BlobConstructorParams& aParams) override;
@ -401,11 +395,6 @@ public:
virtual mozilla::ipc::IPCResult RecvLastPrivateDocShellDestroyed() override;
virtual mozilla::ipc::IPCResult RecvFilePathUpdate(const nsString& aStorageType,
const nsString& aStorageName,
const nsString& aPath,
const nsCString& aReason) override;
virtual mozilla::ipc::IPCResult
RecvNotifyProcessPriorityChanged(const hal::ProcessPriority& aPriority) override;

View file

@ -25,7 +25,6 @@
#include "mozilla/a11y/PDocAccessible.h"
#include "AudioChannelService.h"
#include "DeviceStorageStatics.h"
#include "GMPServiceParent.h"
#include "HandlerServiceParent.h"
#include "IHistory.h"
@ -53,7 +52,6 @@
#include "mozilla/dom/ServiceWorkerRegistrar.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/StorageIPC.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
#include "mozilla/dom/power/PowerManagerService.h"
#include "mozilla/dom/Permissions.h"
#include "mozilla/dom/PresentationParent.h"
@ -270,7 +268,6 @@ using base::KillProcess;
#ifdef MOZ_CRASHREPORTER
using namespace CrashReporter;
#endif
using namespace mozilla::dom::devicestorage;
using namespace mozilla::dom::power;
using namespace mozilla::media;
using namespace mozilla::embedding;
@ -2800,12 +2797,6 @@ ContentParent::Observe(nsISupports* aSubject,
else if (!strcmp(aTopic, "last-pb-context-exited")) {
Unused << SendLastPrivateDocShellDestroyed();
}
else if (!strcmp(aTopic, "file-watcher-update")) {
nsCString creason;
CopyUTF16toUTF8(aData, creason);
DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject);
Unused << SendFilePathUpdate(file->mStorageType, file->mStorageName, file->mPath, creason);
}
#ifdef ACCESSIBILITY
else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) {
if (*aData == '1') {
@ -2889,22 +2880,6 @@ ContentParent::DeallocPBrowserParent(PBrowserParent* frame)
return nsIContentParent::DeallocPBrowserParent(frame);
}
PDeviceStorageRequestParent*
ContentParent::AllocPDeviceStorageRequestParent(const DeviceStorageParams& aParams)
{
RefPtr<DeviceStorageRequestParent> result = new DeviceStorageRequestParent(aParams);
result->Dispatch();
return result.forget().take();
}
bool
ContentParent::DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent* doomed)
{
DeviceStorageRequestParent *parent = static_cast<DeviceStorageRequestParent*>(doomed);
NS_RELEASE(parent);
return true;
}
PBlobParent*
ContentParent::AllocPBlobParent(const BlobConstructorParams& aParams)
{
@ -3719,25 +3694,6 @@ ContentParent::RecvAsyncMessage(const nsString& aMsg,
aData);
}
mozilla::ipc::IPCResult
ContentParent::RecvFilePathUpdateNotify(const nsString& aType,
const nsString& aStorageName,
const nsString& aFilePath,
const nsCString& aReason)
{
RefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(aType,
aStorageName,
aFilePath);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (!obs) {
return IPC_FAIL_NO_REASON(this);
}
obs->NotifyObservers(dsf, "file-watcher-update",
NS_ConvertASCIItoUTF16(aReason).get());
return IPC_OK();
}
static int32_t
AddGeolocationListener(nsIDOMGeoPositionCallback* watcher,
nsIDOMGeoPositionErrorCallback* errorCallBack,
@ -4770,25 +4726,6 @@ ContentParent::RecvEndDriverCrashGuard(const uint32_t& aGuardType)
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvGetDeviceStorageLocation(const nsString& aType,
nsString* aPath)
{
#ifdef MOZ_WIDGET_ANDROID
mozilla::AndroidBridge::GetExternalPublicDirectory(aType, *aPath);
return IPC_OK();
#else
return IPC_FAIL_NO_REASON(this);
#endif
}
mozilla::ipc::IPCResult
ContentParent::RecvGetDeviceStorageLocations(DeviceStorageLocationInfo* info)
{
DeviceStorageStatics::GetDeviceStorageLocationsForIPC(info);
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvGetAndroidSystemInfo(AndroidSystemInfo* aInfo)
{

View file

@ -782,12 +782,6 @@ private:
virtual bool DeallocPBrowserParent(PBrowserParent* frame) override;
virtual PDeviceStorageRequestParent*
AllocPDeviceStorageRequestParent(const DeviceStorageParams&) override;
virtual bool
DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent*) override;
virtual PBlobParent*
AllocPBlobParent(const BlobConstructorParams& aParams) override;
@ -973,11 +967,6 @@ private:
const IPC::Principal& aPrincipal,
const ClonedMessageData& aData) override;
virtual mozilla::ipc::IPCResult RecvFilePathUpdateNotify(const nsString& aType,
const nsString& aStorageName,
const nsString& aFilePath,
const nsCString& aReason) override;
virtual mozilla::ipc::IPCResult RecvAddGeolocationListener(const IPC::Principal& aPrincipal,
const bool& aHighAccuracy) override;
virtual mozilla::ipc::IPCResult RecvRemoveGeolocationListener() override;
@ -1074,11 +1063,6 @@ private:
void StartProfiler(nsIProfilerStartParams* aParams);
virtual mozilla::ipc::IPCResult RecvGetDeviceStorageLocation(const nsString& aType,
nsString* aPath) override;
virtual mozilla::ipc::IPCResult RecvGetDeviceStorageLocations(DeviceStorageLocationInfo* info) override;
virtual mozilla::ipc::IPCResult RecvGetAndroidSystemInfo(AndroidSystemInfo* aInfo) override;
virtual mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsString& aCodecName,

View file

@ -14,7 +14,6 @@ include protocol PCycleCollectWithLogs;
include protocol PPSMContentDownloader;
include protocol PExternalHelperApp;
include protocol PHandlerService;
include protocol PDeviceStorageRequest;
include protocol PFileDescriptorSet;
include protocol PHal;
include protocol PHeapSnapshotTempFileHelper;
@ -124,120 +123,6 @@ struct FontFamilyListEntry {
uint8_t entryType;
};
struct DeviceStorageFreeSpaceParams
{
nsString type;
nsString storageName;
};
struct DeviceStorageUsedSpaceParams
{
nsString type;
nsString storageName;
};
struct DeviceStorageAvailableParams
{
nsString type;
nsString storageName;
};
struct DeviceStorageStatusParams
{
nsString type;
nsString storageName;
};
struct DeviceStorageFormatParams
{
nsString type;
nsString storageName;
};
struct DeviceStorageMountParams
{
nsString type;
nsString storageName;
};
struct DeviceStorageUnmountParams
{
nsString type;
nsString storageName;
};
struct DeviceStorageAddParams
{
nsString type;
nsString storageName;
nsString relpath;
PBlob blob;
};
struct DeviceStorageAppendParams
{
nsString type;
nsString storageName;
nsString relpath;
PBlob blob;
};
struct DeviceStorageCreateFdParams
{
nsString type;
nsString storageName;
nsString relpath;
};
struct DeviceStorageGetParams
{
nsString type;
nsString storageName;
nsString rootDir;
nsString relpath;
};
struct DeviceStorageDeleteParams
{
nsString type;
nsString storageName;
nsString relpath;
};
struct DeviceStorageEnumerationParams
{
nsString type;
nsString storageName;
nsString rootdir;
uint64_t since;
};
union DeviceStorageParams
{
DeviceStorageAddParams;
DeviceStorageAppendParams;
DeviceStorageCreateFdParams;
DeviceStorageGetParams;
DeviceStorageDeleteParams;
DeviceStorageEnumerationParams;
DeviceStorageFreeSpaceParams;
DeviceStorageUsedSpaceParams;
DeviceStorageAvailableParams;
DeviceStorageStatusParams;
DeviceStorageFormatParams;
DeviceStorageMountParams;
DeviceStorageUnmountParams;
};
struct DeviceStorageLocationInfo {
nsString music;
nsString pictures;
nsString videos;
nsString sdcard;
nsString apps;
nsString crashes;
};
union PrefValue {
nsCString;
int32_t;
@ -385,7 +270,6 @@ nested(upto inside_cpow) sync protocol PContent
manages PBrowser;
manages PContentPermissionRequest;
manages PCycleCollectWithLogs;
manages PDeviceStorageRequest;
manages PPSMContentDownloader;
manages PExternalHelperApp;
manages PFileDescriptorSet;
@ -564,9 +448,6 @@ child:
// Notify child that last-pb-context-exited notification was observed
async LastPrivateDocShellDestroyed();
async FilePathUpdate(nsString storageType, nsString storageName, nsString filepath,
nsCString reasons);
async NotifyProcessPriorityChanged(ProcessPriority priority);
async MinimizeMemoryUsage();
@ -750,7 +631,6 @@ parent:
async PJavaScript();
async PRemoteSpellcheckEngine();
async PDeviceStorageRequest(DeviceStorageParams params);
async InitCrashReporter(Shmem shmem, NativeThreadId tid);
@ -936,11 +816,6 @@ parent:
async AudioChannelChangeDefVolChannel(int32_t aChannel, bool aHidden);
async FilePathUpdateNotify(nsString aType,
nsString aStorageName,
nsString aFilepath,
nsCString aReason);
sync KeywordToURI(nsCString keyword)
returns (nsString providerName, OptionalInputStreamParams postData, OptionalURIParams uri);
@ -1125,12 +1000,6 @@ parent:
OriginAttributes aOpenerOriginAttributes,
float aFullZoom);
sync GetDeviceStorageLocation(nsString type)
returns (nsString path);
sync GetDeviceStorageLocations()
returns (DeviceStorageLocationInfo info);
sync GetAndroidSystemInfo()
returns (AndroidSystemInfo info);

View file

@ -123,7 +123,6 @@ LOCAL_INCLUDES += [
'/chrome',
'/docshell/base',
'/dom/base',
'/dom/devicestorage',
'/dom/events',
'/dom/filesystem',
'/dom/geolocation',

View file

@ -50,7 +50,6 @@ DIRS += [
'canvas',
'commandhandler',
'crypto',
'devicestorage',
'encoding',
'events',
'fetch',

View file

@ -281,10 +281,6 @@ var interfaceNamesInGlobalScope =
"DeviceOrientationEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"DeviceProximityEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "DeviceStorageAreaListener", desktop: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "DeviceStorage", desktop: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
"Directory",
// IMPORTANT: Do not change this list without review from a DOM peer!

View file

@ -1,95 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
dictionary DeviceStorageEnumerationParameters {
Date since;
};
[Pref="device.storage.enabled"]
interface DeviceStorage : EventTarget {
attribute EventHandler onchange;
[Throws]
DOMRequest? add(Blob? aBlob);
[Throws]
DOMRequest? addNamed(Blob? aBlob, DOMString aName);
/**
* Append data to a given file.
* If the file doesn't exist, a "NotFoundError" event will be dispatched.
* In the same time, it is a request.onerror case.
* If the file exists, it will be opened with the following permission:
* "PR_WRONLY|PR_CREATE_FILE|PR_APPEND".
* The function will return null when blob file is null and other unexpected situations.
* @parameter aBlob: A Blob object representing the data to append
* @parameter aName: A string representing the full name (path + file name) of the file
* to append data to.
*/
[Throws]
DOMRequest? appendNamed(Blob? aBlob, DOMString aName);
[Throws]
DOMRequest get(DOMString aName);
[Throws]
DOMRequest getEditable(DOMString aName);
[Throws]
DOMRequest delete(DOMString aName);
[Throws]
DOMCursor enumerate(optional DeviceStorageEnumerationParameters options);
[Throws]
DOMCursor enumerate(DOMString path,
optional DeviceStorageEnumerationParameters options);
[Throws]
DOMCursor enumerateEditable(optional DeviceStorageEnumerationParameters options);
[Throws]
DOMCursor enumerateEditable(DOMString path,
optional DeviceStorageEnumerationParameters options);
[Throws]
DOMRequest freeSpace();
[Throws]
DOMRequest usedSpace();
[Throws]
DOMRequest available();
[Throws]
DOMRequest storageStatus();
[Throws]
DOMRequest format();
[Throws]
DOMRequest mount();
[Throws]
DOMRequest unmount();
// Note that the storageName is just a name (like sdcard), and doesn't
// include any path information.
readonly attribute DOMString storageName;
// Indicates if the storage area denoted by storageName is capable of
// being mounted and unmounted.
readonly attribute boolean canBeMounted;
// Indicates if the storage area denoted by storageName is capable of
// being shared and unshared.
readonly attribute boolean canBeShared;
// Indicates if the storage area denoted by storageName is capable of
// being formatted.
readonly attribute boolean canBeFormatted;
// Determines if this storage area is the one which will be used by default
// for storing new files.
readonly attribute boolean default;
// Indicates if the storage area denoted by storageName is removable
readonly attribute boolean isRemovable;
// True if the storage area is close to being full
readonly attribute boolean lowDiskSpace;
[NewObject]
// XXXbz what type does this really return?
Promise<any> getRoot();
};

View file

@ -484,7 +484,6 @@ WEBIDL_FILES = [
'DelayNode.webidl',
'DesktopNotification.webidl',
'DeviceMotionEvent.webidl',
'DeviceStorage.webidl',
'Directory.webidl',
'Document.webidl',
'DocumentFragment.webidl',

View file

@ -819,10 +819,6 @@ description =
description =
[PContent::CreateWindow]
description =
[PContent::GetDeviceStorageLocation]
description =
[PContent::GetDeviceStorageLocations]
description =
[PContent::GetAndroidSystemInfo]
description =
[PContent::UngrabPointer]

View file

@ -129,7 +129,6 @@ using namespace mozilla::system;
#include "TouchManager.h"
#include "MediaDecoder.h"
#include "MediaPrefs.h"
#include "mozilla/dom/devicestorage/DeviceStorageStatics.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/StaticPresData.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
@ -310,8 +309,6 @@ nsLayoutStatics::Initialize()
PromiseDebugging::Init();
mozilla::dom::devicestorage::DeviceStorageStatics::Initialize();
mozilla::dom::WebCryptoThreadPool::Initialize();
#ifdef MOZ_STYLO

View file

@ -13,10 +13,6 @@ Cu.import("resource://gre/modules/Services.jsm");
const kEntities = {
"contacts": "contacts",
"desktop-notification": "desktopNotification2",
"device-storage:music": "deviceStorageMusic",
"device-storage:pictures": "deviceStoragePictures",
"device-storage:sdcard": "deviceStorageSdcard",
"device-storage:videos": "deviceStorageVideos",
"geolocation": "geolocation",
"flyweb-publish-server": "flyWebPublishServer",
};

View file

@ -2189,44 +2189,6 @@ public class GeckoAppShell
return connection.getContentType();
}
/**
* Retrieve the absolute path of an external storage directory.
*
* @param type The type of directory to return
* @return Absolute path of the specified directory or null on failure
*/
@WrapForJNI(calledFrom = "gecko")
private static String getExternalPublicDirectory(final String type) {
final String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state) &&
!Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// External storage is not available.
return null;
}
if ("sdcard".equals(type)) {
// SD card has a separate path.
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
final String systemType;
if ("downloads".equals(type)) {
systemType = Environment.DIRECTORY_DOWNLOADS;
} else if ("pictures".equals(type)) {
systemType = Environment.DIRECTORY_PICTURES;
} else if ("videos".equals(type)) {
systemType = Environment.DIRECTORY_MOVIES;
} else if ("music".equals(type)) {
systemType = Environment.DIRECTORY_MUSIC;
} else if ("apps".equals(type)) {
File appInternalStorageDirectory = getApplicationContext().getFilesDir();
return new File(appInternalStorageDirectory, "mozilla").getAbsolutePath();
} else {
return null;
}
return Environment.getExternalStoragePublicDirectory(systemType).getAbsolutePath();
}
@WrapForJNI(calledFrom = "gecko")
private static int getMaxTouchPoints() {
PackageManager pm = getApplicationContext().getPackageManager();

View file

@ -145,35 +145,6 @@ flyWebPublishServer.publishServer=Publish Server
imageblocking.downloadedImage=Image unblocked
imageblocking.showAllImages=Show All
# Device Storage API
deviceStorageMusic.allow=Allow
deviceStorageMusic.dontAllow=Don't allow
deviceStorageMusic.ask=Allow %S access to your music?
# LOCALIZATION NOTE (deviceStorageMusic.dontAskAgain): This label appears next to a
# checkbox to indicate whether or not the user wants to make a permanent decision.
deviceStorageMusic.dontAskAgain=Don't ask again for this site
deviceStoragePictures.allow=Allow
deviceStoragePictures.dontAllow=Don't allow
deviceStoragePictures.ask=Allow %S access to your images?
# LOCALIZATION NOTE (deviceStoragePictures.dontAskAgain): This label appears next to a
# checkbox to indicate whether or not the user wants to make a permanent decision.
deviceStoragePictures.dontAskAgain=Don't ask again for this site
deviceStorageSdcard.allow=Allow
deviceStorageSdcard.dontAllow=Don't allow
deviceStorageSdcard.ask=Allow %S access to external storage?
# LOCALIZATION NOTE (deviceStorageSdcard.dontAskAgain): This label appears next to a
# checkbox to indicate whether or not the user wants to make a permanent decision.
deviceStorageSdcard.dontAskAgain=Don't ask again for this site
deviceStorageVideos.allow=Allow
deviceStorageVideos.dontAllow=Don't allow
deviceStorageVideos.ask=Allow %S access to your videos?
# LOCALIZATION NOTE (deviceStorageVideos.dontAskAgain): This label appears next to a
# checkbox to indicate whether or not the user wants to make a permanent decision.
deviceStorageVideos.dontAskAgain=Don't ask again for this site
# New Tab Popup
# LOCALIZATION NOTE (newtabpopup, newprivatetabpopup): Semicolon-separated list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals

View file

@ -40,9 +40,6 @@ Content-Type: application/x-web-app-manifest+json\r
{
"systemXHR": {
"description": "Needed to download stuff"
},
"devicestorage:pictures": {
"description": "Need to load pictures"
}
}
],

View file

@ -273,43 +273,6 @@ this.DownloadIntegration = {
yield new DownloadAutoSaveView(list, this._store).initialize();
}),
#ifdef MOZ_WIDGET_GONK
/**
* Finds the default download directory which can be either in the
* internal storage or on the sdcard.
*
* @return {Promise}
* @resolves The downloads directory string path.
*/
_getDefaultDownloadDirectory: Task.async(function* () {
let directoryPath;
let win = Services.wm.getMostRecentWindow("navigator:browser");
let storages = win.navigator.getDeviceStorages("sdcard");
let preferredStorageName;
// Use the first one or the default storage.
storages.forEach((aStorage) => {
if (aStorage.default || !preferredStorageName) {
preferredStorageName = aStorage.storageName;
}
});
// Now get the path for this storage area.
if (preferredStorageName) {
let volume = volumeService.getVolumeByName(preferredStorageName);
if (volume && volume.state === Ci.nsIVolume.STATE_MOUNTED){
directoryPath = OS.Path.join(volume.mountPoint, "downloads");
yield OS.File.makeDir(directoryPath, { ignoreExisting: true });
}
}
if (directoryPath) {
return directoryPath;
} else {
throw new Components.Exception("No suitable storage for downloads.",
Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH);
}
}),
#endif
/**
* Determines if a Download object from the list of persistent downloads
* should be saved into a file, so that it can be restored across sessions.
@ -382,8 +345,6 @@ this.DownloadIntegration = {
throw new Components.Exception("DOWNLOADS_DIRECTORY is not set.",
Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH);
}
#elifdef MOZ_WIDGET_GONK
directoryPath = this._getDefaultDownloadDirectory();
#else
// For Linux, use XDG download dir, with a fallback to Home/Downloads
// if the XDG user dirs are disabled.
@ -410,9 +371,6 @@ this.DownloadIntegration = {
*/
getPreferredDownloadsDirectory: Task.async(function* () {
let directoryPath = null;
#ifdef MOZ_WIDGET_GONK
directoryPath = this._getDefaultDownloadDirectory();
#else
let prefValue = Services.prefs.getIntPref("browser.download.folderList", 1);
switch(prefValue) {
@ -436,7 +394,6 @@ this.DownloadIntegration = {
default:
directoryPath = yield this.getSystemDownloadsDirectory();
}
#endif
return directoryPath;
}),

View file

@ -190,18 +190,6 @@ nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIURI* aReferrer, nsIF
}
}
#endif
if (mozilla::Preferences::GetBool("device.storage.enabled", true)) {
// Tell DeviceStorage that a new file may have been added.
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
nsCOMPtr<nsISupportsString> pathString
= do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
if (obs && pathString) {
if (NS_SUCCEEDED(pathString->SetData(path))) {
(void)obs->NotifyObservers(pathString, "download-watcher-notify",
u"modified");
}
}
}
}
#endif

View file

@ -2273,86 +2273,6 @@ add_task(function* test_toSerializable_startTime() {
do_check_eq(download1.startTime.toJSON(), download2.startTime.toJSON());
});
/**
* This test will call the platform specific operations within
* DownloadPlatform::DownloadDone. While there is no test to verify the
* specific behaviours, this at least ensures that there is no error or crash.
*/
add_task(function* test_platform_integration() {
let downloadFiles = [];
let oldDeviceStorageEnabled = Services.prefs.getBoolPref("device.storage.enabled", false);
let downloadWatcherNotified = false;
let observer = {
observe(subject, topic, data) {
do_check_eq(topic, "download-watcher-notify");
do_check_eq(data, "modified");
downloadWatcherNotified = true;
}
}
Services.obs.addObserver(observer, "download-watcher-notify", false);
Services.prefs.setBoolPref("device.storage.enabled", true);
let downloadDoneCalled = false;
let monitorFn = base => ({
__proto__: base,
downloadDone() {
return super.downloadDone(...arguments).then(() => {
downloadDoneCalled = true;
});
},
});
Integration.downloads.register(monitorFn);
DownloadIntegration.allowDirectories = true;
function cleanup() {
for (let file of downloadFiles) {
file.remove(true);
}
Services.obs.removeObserver(observer, "download-watcher-notify");
Services.prefs.setBoolPref("device.storage.enabled", oldDeviceStorageEnabled);
Integration.downloads.unregister(monitorFn);
DownloadIntegration.allowDirectories = false;
}
for (let isPrivate of [false, true]) {
downloadDoneCalled = false;
// Some platform specific operations only operate on files outside the
// temporary directory or in the Downloads directory (such as setting
// the Windows searchable attribute, and the Mac Downloads icon bouncing),
// so use the system Downloads directory for the target file.
let targetFilePath = yield DownloadIntegration.getSystemDownloadsDirectory();
targetFilePath = OS.Path.join(targetFilePath,
"test" + (Math.floor(Math.random() * 1000000)));
let targetFile = new FileUtils.File(targetFilePath);
downloadFiles.push(targetFile);
let download;
if (gUseLegacySaver) {
download = yield promiseStartLegacyDownload(httpUrl("source.txt"),
{ isPrivate, targetFile });
} else {
download = yield Downloads.createDownload({
source: { url: httpUrl("source.txt"), isPrivate },
target: targetFile,
});
download.start().catch(() => {});
}
// Wait for the whenSucceeded promise to be resolved first.
// downloadDone should be called before the whenSucceeded promise is resolved.
yield download.whenSucceeded().then(function() {
do_check_true(downloadDoneCalled);
do_check_true(downloadWatcherNotified);
});
// Then, wait for the promise returned by "start" to be resolved.
yield promiseDownloadStopped(download);
yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
}
cleanup();
});
/**
* Checks that downloads are added to browsing history when they start.
*/

View file

@ -1,4 +0,0 @@
# Extensions we recognize for DeviceStorage storage areas
pictures=*.jpe; *.jpg; *.jpeg; *.gif; *.png; *.bmp;
music=*.mp3; *.oga; *.ogg; *.m4a; *.m4b; *.m4p; *.m4r; *.3gp; *.3gpp; *.mp4; *.m3u; *.pls; *.opus; *.amr; *.wav; *.lcka; *.mka; *.flac;
videos=*.mp4; *.mpeg; *.mpg; *.ogv; *.ogx; *.webm; *.3gp; *.3gpp; *.3g2; *.ogg; *.m4v; *.ts; *.m2ts; *.avi; *.divx; *.mkv;

View file

@ -46,7 +46,6 @@ toolkit.jar:
content/global/customizeToolbar.xul
#endif
content/global/datepicker.xhtml
content/global/devicestorage.properties
#ifndef MOZ_FENNEC
content/global/editMenuOverlay.js
* content/global/editMenuOverlay.xul
@ -119,4 +118,4 @@ toolkit.jar:
content/global/macWindowMenu.js
#endif
content/global/gmp-sources/openh264.json (gmp-sources/openh264.json)
content/global/gmp-sources/widevinecdm.json (gmp-sources/widevinecdm.json)
content/global/gmp-sources/widevinecdm.json (gmp-sources/widevinecdm.json)

View file

@ -107,10 +107,6 @@
#include "mozilla/Preferences.h"
#include "mozilla/ipc/URIUtils.h"
#ifdef MOZ_WIDGET_GONK
#include "nsDeviceStorage.h"
#endif
using namespace mozilla;
using namespace mozilla::ipc;
@ -327,55 +323,6 @@ static nsresult GetDownloadDirectory(nsIFile **_directory,
getter_AddRefs(dir));
NS_ENSURE_SUCCESS(rv, rv);
}
#elif defined(MOZ_WIDGET_GONK)
// On Gonk, store the files on the sdcard in the downloads directory.
// We need to check with the volume manager which storage point is
// available.
// Pick the default storage in case multiple (internal and external) ones
// are available.
nsString storageName;
nsDOMDeviceStorage::GetDefaultStorageName(NS_LITERAL_STRING("sdcard"),
storageName);
RefPtr<DeviceStorageFile> dsf(
new DeviceStorageFile(NS_LITERAL_STRING("sdcard"),
storageName,
NS_LITERAL_STRING("downloads")));
NS_ENSURE_TRUE(dsf->mFile, NS_ERROR_FILE_ACCESS_DENIED);
// If we're not checking for availability we're done.
if (aSkipChecks) {
dsf->mFile.forget(_directory);
return NS_OK;
}
// Check device storage status before continuing.
nsString storageStatus;
dsf->GetStatus(storageStatus);
// If we get an "unavailable" status, it means the sd card is not present.
// We'll also catch internal errors by looking for an empty string and assume
// the SD card isn't present when this occurs.
if (storageStatus.EqualsLiteral("unavailable") ||
storageStatus.IsEmpty()) {
return NS_ERROR_FILE_NOT_FOUND;
}
// If we get a status other than 'available' here it means the card is busy
// because it's mounted via USB or it is being formatted.
if (!storageStatus.EqualsLiteral("available")) {
return NS_ERROR_FILE_ACCESS_DENIED;
}
bool alreadyThere;
nsresult rv = dsf->mFile->Exists(&alreadyThere);
NS_ENSURE_SUCCESS(rv, rv);
if (!alreadyThere) {
rv = dsf->mFile->Create(nsIFile::DIRECTORY_TYPE, 0770);
NS_ENSURE_SUCCESS(rv, rv);
}
dir = dsf->mFile;
#elif defined(ANDROID)
// We ask Java for the temporary download directory. The directory will be
// different depending on whether we have the permission to write to the

View file

@ -1130,37 +1130,3 @@ nsresult AndroidBridge::InputStreamRead(Object::Param obj, char *aBuf, uint32_t
*aRead = read;
return NS_OK;
}
nsresult AndroidBridge::GetExternalPublicDirectory(const nsAString& aType, nsAString& aPath) {
if (XRE_IsContentProcess()) {
nsString key(aType);
nsAutoString path;
if (AndroidBridge::sStoragePaths.Get(key, &path)) {
aPath = path;
return NS_OK;
}
// Lazily get the value from the parent.
dom::ContentChild* child = dom::ContentChild::GetSingleton();
if (child) {
nsAutoString type(aType);
child->SendGetDeviceStorageLocation(type, &path);
if (!path.IsEmpty()) {
AndroidBridge::sStoragePaths.Put(key, path);
aPath = path;
return NS_OK;
}
}
ALOG_BRIDGE("AndroidBridge::GetExternalPublicDirectory no cache for %s",
NS_ConvertUTF16toUTF8(aType).get());
return NS_ERROR_NOT_AVAILABLE;
}
auto path = GeckoAppShell::GetExternalPublicDirectory(aType);
if (!path) {
return NS_ERROR_NOT_AVAILABLE;
}
aPath = path->ToString();
return NS_OK;
}

View file

@ -196,8 +196,6 @@ public:
static uint32_t InputStreamAvailable(jni::Object::Param obj);
static nsresult InputStreamRead(jni::Object::Param obj, char *aBuf, uint32_t aCount, uint32_t *aRead);
static nsresult GetExternalPublicDirectory(const nsAString& aType, nsAString& aPath);
protected:
static nsDataHashtable<nsStringHashKey, nsString> sStoragePaths;

View file

@ -335,14 +335,6 @@ auto GeckoAppShell::GetExtensionFromMimeType(mozilla::jni::String::Param a0) ->
return mozilla::jni::Method<GetExtensionFromMimeType_t>::Call(GeckoAppShell::Context(), nullptr, a0);
}
constexpr char GeckoAppShell::GetExternalPublicDirectory_t::name[];
constexpr char GeckoAppShell::GetExternalPublicDirectory_t::signature[];
auto GeckoAppShell::GetExternalPublicDirectory(mozilla::jni::String::Param a0) -> mozilla::jni::String::LocalRef
{
return mozilla::jni::Method<GetExternalPublicDirectory_t>::Call(GeckoAppShell::Context(), nullptr, a0);
}
constexpr char GeckoAppShell::GetHWDecoderCapability_t::name[];
constexpr char GeckoAppShell::GetHWDecoderCapability_t::signature[];

View file

@ -951,26 +951,6 @@ public:
static auto GetExtensionFromMimeType(mozilla::jni::String::Param) -> mozilla::jni::String::LocalRef;
struct GetExternalPublicDirectory_t {
typedef GeckoAppShell Owner;
typedef mozilla::jni::String::LocalRef ReturnType;
typedef mozilla::jni::String::Param SetterType;
typedef mozilla::jni::Args<
mozilla::jni::String::Param> Args;
static constexpr char name[] = "getExternalPublicDirectory";
static constexpr char signature[] =
"(Ljava/lang/String;)Ljava/lang/String;";
static const bool isStatic = true;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::GECKO;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};
static auto GetExternalPublicDirectory(mozilla::jni::String::Param) -> mozilla::jni::String::LocalRef;
struct GetHWDecoderCapability_t {
typedef GeckoAppShell Owner;
typedef bool ReturnType;

View file

@ -160,7 +160,6 @@
#endif
#include "mozilla/dom/DataContainerEventBinding.h"
#include "mozilla/dom/DataTransferBinding.h"
#include "mozilla/dom/DeviceStorageBinding.h"
#include "mozilla/dom/DOMCursorBinding.h"
#include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/dom/DOMParserBinding.h"