Bug 1173320 - patch 1/8 - Implement Directory object as string and not as BlobImpl, r=smaug

This commit is contained in:
Andrea Marchesini 2016-03-19 14:32:18 +01:00
Родитель 1f36475812
Коммит f1f32823dd
42 изменённых файлов: 1579 добавлений и 883 удалений

Просмотреть файл

@ -227,12 +227,6 @@ Blob::IsFile() const
return mImpl->IsFile();
}
bool
Blob::IsDirectory() const
{
return mImpl->IsDirectory();
}
const nsTArray<RefPtr<BlobImpl>>*
Blob::GetSubBlobImpls() const
{
@ -420,11 +414,10 @@ File::Create(nsISupports* aParent, BlobImpl* aImpl)
/* static */ already_AddRefed<File>
File::Create(nsISupports* aParent, const nsAString& aName,
const nsAString& aContentType, uint64_t aLength,
int64_t aLastModifiedDate, BlobDirState aDirState)
int64_t aLastModifiedDate)
{
RefPtr<File> file = new File(aParent,
new BlobImplBase(aName, aContentType, aLength, aLastModifiedDate,
aDirState));
new BlobImplBase(aName, aContentType, aLength, aLastModifiedDate));
return file.forget();
}
@ -946,17 +939,6 @@ BlobImplFile::SetPath(const nsAString& aPath)
mPath = aPath;
}
void
BlobImplFile::LookupAndCacheIsDirectory()
{
MOZ_ASSERT(mIsFile,
"This should only be called when this object has been created "
"from an nsIFile to note that the nsIFile is a directory");
bool isDir;
mFile->IsDirectory(&isDir);
mDirState = isDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir;
}
////////////////////////////////////////////////////////////////////////////
// EmptyBlobImpl implementation

Просмотреть файл

@ -44,18 +44,6 @@ class BlobImpl;
class File;
class OwningArrayBufferOrArrayBufferViewOrBlobOrString;
/**
* Used to indicate when a Blob/BlobImpl that was created from an nsIFile
* (when IsFile() will return true) was from an nsIFile for which
* nsIFile::IsDirectory() returned true. This is a tri-state to enable us to
* assert that the state is always set when callers request it.
*/
enum BlobDirState : uint32_t {
eIsDir,
eIsNotDir,
eUnknownIfDir
};
class Blob : public nsIDOMBlob
, public nsIXHRSendable
, public nsIMutable
@ -101,12 +89,6 @@ public:
bool IsFile() const;
/**
* This may return true if the Blob was created from an nsIFile that is a
* directory.
*/
bool IsDirectory() const;
const nsTArray<RefPtr<BlobImpl>>* GetSubBlobImpls() const;
// This method returns null if this Blob is not a File; it returns
@ -114,9 +96,6 @@ public:
// otherwise it returns a new File object with the same BlobImpl.
already_AddRefed<File> ToFile();
// XXXjwatt Consider having a ToDirectory() method. The need for a FileSystem
// object complicates that though.
// This method creates a new File object with the given name and the same
// BlobImpl.
already_AddRefed<File> ToFile(const nsAString& aName,
@ -194,7 +173,7 @@ public:
static already_AddRefed<File>
Create(nsISupports* aParent, const nsAString& aName,
const nsAString& aContentType, uint64_t aLength,
int64_t aLastModifiedDate, BlobDirState aDirState);
int64_t aLastModifiedDate);
// The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
// freed by free so it must be allocated by malloc or something
@ -339,28 +318,6 @@ public:
virtual bool IsFile() const = 0;
/**
* Called when this BlobImpl was created from an nsIFile in order to call
* nsIFile::IsDirectory() and cache the result so that when the BlobImpl is
* copied to another process that informaton is available.
* nsIFile::IsDirectory() does synchronous I/O, and BlobImpl objects may be
* created on the main thread or in a non-chrome process (where I/O is not
* allowed). Do not call this on a non-chrome process, and preferably do not
* call it on the main thread.
*
* Not all creators of BlobImplFile will call this method, in which case
* calling IsDirectory will MOZ_ASSERT.
*/
virtual void LookupAndCacheIsDirectory() = 0;
virtual void SetIsDirectory(bool aIsDir) = 0;
virtual bool IsDirectory() const = 0;
/**
* Prefer IsDirectory(). This exists to help consumer code pass on state from
* one BlobImpl when creating another.
*/
virtual BlobDirState GetDirState() const = 0;
// True if this implementation can be sent to other threads.
virtual bool MayBeClonedToOtherThreads() const
{
@ -377,11 +334,9 @@ class BlobImplBase : public BlobImpl
{
public:
BlobImplBase(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength, int64_t aLastModifiedDate,
BlobDirState aDirState = BlobDirState::eUnknownIfDir)
uint64_t aLength, int64_t aLastModifiedDate)
: mIsFile(true)
, mImmutable(false)
, mDirState(aDirState)
, mContentType(aContentType)
, mName(aName)
, mStart(0)
@ -397,7 +352,6 @@ public:
uint64_t aLength)
: mIsFile(true)
, mImmutable(false)
, mDirState(BlobDirState::eUnknownIfDir)
, mContentType(aContentType)
, mName(aName)
, mStart(0)
@ -412,7 +366,6 @@ public:
BlobImplBase(const nsAString& aContentType, uint64_t aLength)
: mIsFile(false)
, mImmutable(false)
, mDirState(BlobDirState::eUnknownIfDir)
, mContentType(aContentType)
, mStart(0)
, mLength(aLength)
@ -427,7 +380,6 @@ public:
uint64_t aLength)
: mIsFile(false)
, mImmutable(false)
, mDirState(BlobDirState::eUnknownIfDir)
, mContentType(aContentType)
, mStart(aStart)
, mLength(aLength)
@ -518,36 +470,6 @@ public:
return mIsFile;
}
virtual void LookupAndCacheIsDirectory() override
{
MOZ_ASSERT(false, "Why is this being called on a non-BlobImplFile?");
}
virtual void SetIsDirectory(bool aIsDir) override
{
MOZ_ASSERT(mIsFile,
"This should only be called when this object has been created "
"from an nsIFile to note that the nsIFile is a directory");
mDirState = aIsDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir;
}
/**
* Returns true if the nsIFile that this object wraps is a directory.
*/
virtual bool IsDirectory() const override
{
MOZ_ASSERT(mDirState != BlobDirState::eUnknownIfDir,
"Must only be used by callers for whom the code paths are "
"know to call LookupAndCacheIsDirectory() or "
"SetIsDirectory()");
return mDirState == BlobDirState::eIsDir;
}
virtual BlobDirState GetDirState() const override
{
return mDirState;
}
virtual bool IsSizeUnknown() const override
{
return mLength == UINT64_MAX;
@ -565,7 +487,6 @@ protected:
bool mIsFile;
bool mImmutable;
BlobDirState mDirState;
nsString mContentType;
nsString mName;
@ -590,8 +511,7 @@ public:
BlobImplMemory(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
const nsAString& aContentType, int64_t aLastModifiedDate)
: BlobImplBase(aName, aContentType, aLength, aLastModifiedDate,
BlobDirState::eIsNotDir)
: BlobImplBase(aName, aContentType, aLength, aLastModifiedDate)
, mDataOwner(new DataOwner(aMemoryBuffer, aLength))
{
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
@ -792,8 +712,6 @@ public:
void SetPath(const nsAString& aFullPath);
virtual void LookupAndCacheIsDirectory() override;
// We always have size and date for this kind of blob.
virtual bool IsSizeUnknown() const override { return false; }
virtual bool IsDateUnknown() const override { return false; }

Просмотреть файл

@ -7625,7 +7625,6 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
// has this data available to it when passed over:
blobImpl->GetSize(rv);
blobImpl->GetLastModified(rv);
blobImpl->LookupAndCacheIsDirectory();
} else {
if (aInSyncMessage) {
// Can't do anything.

Просмотреть файл

@ -49,7 +49,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mItems)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage)
@ -57,7 +57,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mItems)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage)
@ -281,11 +281,12 @@ DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
FileList*
DataTransfer::GetFiles(ErrorResult& aRv)
{
return GetFilesInternal(aRv, nsContentUtils::SubjectPrincipal());
return GetFileListInternal(aRv, nsContentUtils::SubjectPrincipal());
}
FileList*
DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal)
DataTransfer::GetFileListInternal(ErrorResult& aRv,
nsIPrincipal* aSubjectPrincipal)
{
if (mEventMessage != eDrop &&
mEventMessage != eLegacyDragDrop &&
@ -293,14 +294,15 @@ DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal
return nullptr;
}
if (!mFiles) {
mFiles = new FileList(static_cast<nsIDOMDataTransfer*>(this));
if (!mFileList) {
mFileList = new FileList(static_cast<nsIDOMDataTransfer*>(this));
uint32_t count = mItems.Length();
for (uint32_t i = 0; i < count; i++) {
nsCOMPtr<nsIVariant> variant;
aRv = GetDataAtInternal(NS_ConvertUTF8toUTF16(kFileMime), i, aSubjectPrincipal, getter_AddRefs(variant));
aRv = GetDataAtInternal(NS_ConvertUTF8toUTF16(kFileMime), i,
aSubjectPrincipal, getter_AddRefs(variant));
if (aRv.Failed()) {
return nullptr;
}
@ -338,21 +340,21 @@ DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal
MOZ_ASSERT(domFile);
}
if (!mFiles->Append(domFile)) {
if (!mFileList->Append(domFile)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
}
}
return mFiles;
return mFileList;
}
NS_IMETHODIMP
DataTransfer::GetFiles(nsIDOMFileList** aFileList)
{
ErrorResult rv;
NS_IF_ADDREF(*aFileList = GetFilesInternal(rv, nsContentUtils::GetSystemPrincipal()));
NS_IF_ADDREF(*aFileList = GetFileListInternal(rv, nsContentUtils::GetSystemPrincipal()));
return rv.StealNSResult();
}
@ -854,7 +856,7 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
return nullptr;
}
if (!mFiles) {
if (!mFileList) {
GetFiles(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@ -863,38 +865,14 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
Sequence<OwningFileOrDirectory> filesAndDirsSeq;
if (mFiles && mFiles->Length()) {
if (!filesAndDirsSeq.SetLength(mFiles->Length(), mozilla::fallible_t())) {
if (mFileList && mFileList->Length()) {
if (!filesAndDirsSeq.SetLength(mFileList->Length(), mozilla::fallible_t())) {
p->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
return p.forget();
}
for (uint32_t i = 0; i < mFiles->Length(); ++i) {
if (mFiles->Item(i)->Impl()->IsDirectory()) {
#if defined(ANDROID) || defined(MOZ_B2G)
MOZ_ASSERT(false,
"Directory picking should have been redirected to normal "
"file picking for platforms that don't have a directory "
"picker");
#endif
nsAutoString path;
mFiles->Item(i)->GetMozFullPathInternal(path, aRv);
if (aRv.Failed()) {
return nullptr;
}
int32_t leafSeparatorIndex = path.RFind(FILE_PATH_SEPARATOR);
nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex);
nsDependentSubstring basename = Substring(path, leafSeparatorIndex);
RefPtr<OSFileSystem> fs = new OSFileSystem(dirname);
fs->Init(parentNode->OwnerDoc()->GetInnerWindow());
RefPtr<Directory> directory = new Directory(fs, basename);
directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive"));
filesAndDirsSeq[i].SetAsDirectory() = directory;
} else {
filesAndDirsSeq[i].SetAsFile() = mFiles->Item(i);
}
for (uint32_t i = 0; i < mFileList->Length(); ++i) {
filesAndDirsSeq[i].SetAsFile() = mFileList->Item(i);
}
}

Просмотреть файл

@ -252,7 +252,7 @@ protected:
void FillInExternalData(TransferItem& aItem, uint32_t aIndex);
FileList* GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal);
FileList* GetFileListInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal);
nsresult GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
nsIPrincipal* aSubjectPrincipal, nsIVariant** aData);
nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex,
@ -300,8 +300,9 @@ protected:
// array of items, each containing an array of format->data pairs
nsTArray<nsTArray<TransferItem> > mItems;
// array of files, containing only the files present in the dataTransfer
RefPtr<FileList> mFiles;
// array of files and directories, containing only the files present in the
// dataTransfer
RefPtr<FileList> mFileList;
// the target of the drag. The drag and dragend events will fire at this.
nsCOMPtr<mozilla::dom::Element> mDragTarget;

Просмотреть файл

@ -318,8 +318,7 @@ ConvertActorToFile(FileHandleBase* aFileHandle,
actor->SetMysteryBlobInfo(mutableFile->Name(),
mutableFile->Type(),
size.get_uint64_t(),
lastModified.get_int64_t(),
BlobDirState::eUnknownIfDir);
lastModified.get_int64_t());
RefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
MOZ_ASSERT(blobImpl);

Просмотреть файл

@ -16,33 +16,73 @@
namespace mozilla {
namespace dom {
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
const nsAString& aPath,
ErrorResult& aRv)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aPath)
/* static */ already_AddRefed<CreateDirectoryTask>
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<CreateDirectoryTask> task =
new CreateDirectoryTask(aFileSystem, aTargetPath);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mPromise = Promise::Create(globalObject, aRv);
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
CreateDirectoryTask::CreateDirectoryTask(
FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
/* static */ already_AddRefed<CreateDirectoryTask>
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<CreateDirectoryTask> task =
new CreateDirectoryTask(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath)
: FileSystemTaskBase(aFileSystem)
, mTargetPath(aTargetPath)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
mTargetRealPath = aParam.realPath();
}
CreateDirectoryTask::~CreateDirectoryTask()
@ -59,25 +99,44 @@ CreateDirectoryTask::GetPromise()
}
FileSystemParams
CreateDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
CreateDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemCreateDirectoryParams(aFileSystem, mTargetRealPath);
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemCreateDirectoryParams();
}
return FileSystemCreateDirectoryParams(aSerializedDOMPath, path);
}
FileSystemResponseValue
CreateDirectoryTask::GetSuccessRequestResult() const
CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemDirectoryResponse(mTargetRealPath);
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemDirectoryResponse();
}
return FileSystemDirectoryResponse(path);
}
void
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemDirectoryResponse r = aValue;
mTargetRealPath = r.realPath();
NS_ConvertUTF16toUTF8 path(r.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
NS_WARN_IF(aRv.Failed());
}
nsresult
@ -91,13 +150,8 @@ CreateDirectoryTask::Work()
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
if (!file) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
bool fileExists;
nsresult rv = file->Exists(&fileExists);
nsresult rv = mTargetPath->Exists(&fileExists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -106,8 +160,12 @@ CreateDirectoryTask::Work()
return NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
}
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0770);
return rv;
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0770);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
void
@ -124,7 +182,12 @@ CreateDirectoryTask::HandlerCallback()
mPromise = nullptr;
return;
}
RefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetWindow(),
mTargetPath,
Directory::eNotDOMRootDirectory,
mFileSystem);
MOZ_ASSERT(dir);
mPromise->MaybeResolve(dir);
mPromise = nullptr;
}

Просмотреть файл

@ -16,16 +16,19 @@ namespace dom {
class Promise;
class CreateDirectoryTask final
: public FileSystemTaskBase
class CreateDirectoryTask final : public FileSystemTaskBase
{
public:
CreateDirectoryTask(FileSystemBase* aFileSystem,
const nsAString& aPath,
ErrorResult& aRv);
CreateDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<CreateDirectoryTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
ErrorResult& aRv);
static already_AddRefed<CreateDirectoryTask>
Create(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~CreateDirectoryTask();
@ -38,13 +41,15 @@ public:
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@ -53,8 +58,15 @@ protected:
HandlerCallback() override;
private:
CreateDirectoryTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath);
CreateDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent);
RefPtr<Promise> mPromise;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
};
} // namespace dom

Просмотреть файл

@ -25,34 +25,104 @@ namespace dom {
uint32_t CreateFileTask::sOutputBufferSize = 0;
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
const nsAString& aPath,
Blob* aBlobData,
InfallibleTArray<uint8_t>& aArrayData,
bool replace,
ErrorResult& aRv)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aPath)
, mReplace(replace)
/* static */ already_AddRefed<CreateFileTask>
CreateFileTask::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Blob* aBlobData,
InfallibleTArray<uint8_t>& aArrayData,
bool aReplace,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
GetOutputBufferSize();
RefPtr<CreateFileTask> task =
new CreateFileTask(aFileSystem, aTargetPath, aReplace);
// aTargetPath can be null. In this case SetError will be called.
task->GetOutputBufferSize();
if (aBlobData) {
if (XRE_IsParentProcess()) {
aBlobData->GetInternalStream(getter_AddRefs(mBlobStream), aRv);
NS_WARN_IF(aRv.Failed());
aBlobData->GetInternalStream(getter_AddRefs(task->mBlobStream), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
} else {
mBlobData = aBlobData;
task->mBlobData = aBlobData;
}
}
mArrayData.SwapElements(aArrayData);
task->mArrayData.SwapElements(aArrayData);
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mPromise = Promise::Create(globalObject, aRv);
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
/* static */ already_AddRefed<CreateFileTask>
CreateFileTask::Create(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<CreateFileTask> task =
new CreateFileTask(aFileSystem, aParam, aParent);
task->GetOutputBufferSize();
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->mReplace = aParam.replace();
auto& data = aParam.data();
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
task->mArrayData = data;
return task.forget();
}
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
MOZ_ASSERT(blobImpl, "blobData should not be null.");
ErrorResult rv;
blobImpl->GetInternalStream(getter_AddRefs(task->mBlobStream), rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
return task.forget();
}
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
bool aReplace)
: FileSystemTaskBase(aFileSystem)
, mTargetPath(aTargetPath)
, mReplace(aReplace)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
@ -61,32 +131,9 @@ CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mReplace(false)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
GetOutputBufferSize();
mTargetRealPath = aParam.realPath();
mReplace = aParam.replace();
auto& data = aParam.data();
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
mArrayData = data;
return;
}
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
MOZ_ASSERT(blobImpl, "blobData should not be null.");
ErrorResult rv;
blobImpl->GetInternalStream(getter_AddRefs(mBlobStream), rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
}
CreateFileTask::~CreateFileTask()
@ -107,12 +154,18 @@ CreateFileTask::GetPromise()
}
FileSystemParams
CreateFileTask::GetRequestParams(const nsString& aFileSystem) const
CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemCreateFileParams param;
param.filesystem() = aFileSystem;
param.realPath() = mTargetRealPath;
param.filesystem() = aSerializedDOMPath;
aRv = mTargetPath->GetPath(param.realPath());
if (NS_WARN_IF(aRv.Failed())) {
return param;
}
param.replace() = mReplace;
if (mBlobData) {
BlobChild* actor
@ -127,7 +180,7 @@ CreateFileTask::GetRequestParams(const nsString& aFileSystem) const
}
FileSystemResponseValue
CreateFileTask::GetSuccessRequestResult() const
CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
BlobParent* actor = GetBlobParent(mTargetBlobImpl);
@ -140,7 +193,8 @@ CreateFileTask::GetSuccessRequestResult() const
}
void
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemFileResponse r = aValue;
@ -176,24 +230,19 @@ CreateFileTask::Work()
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
if (!file) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
if (!mFileSystem->IsSafeFile(file)) {
if (!mFileSystem->IsSafeFile(mTargetPath)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
bool exists = false;
nsresult rv = file->Exists(&exists);
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (exists) {
bool isFile = false;
rv = file->IsFile(&isFile);
rv = mTargetPath->IsFile(&isFile);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -207,19 +256,19 @@ CreateFileTask::Work()
}
// Remove the old file before creating.
rv = file->Remove(false);
rv = mTargetPath->Remove(false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
rv = mTargetPath->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIOutputStream> outputStream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mTargetPath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -262,7 +311,7 @@ CreateFileTask::Work()
return NS_ERROR_FAILURE;
}
mTargetBlobImpl = new BlobImplFile(file);
mTargetBlobImpl = new BlobImplFile(mTargetPath);
return NS_OK;
}
@ -281,7 +330,7 @@ CreateFileTask::Work()
return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
}
mTargetBlobImpl = new BlobImplFile(file);
mTargetBlobImpl = new BlobImplFile(mTargetPath);
return NS_OK;
}

Просмотреть файл

@ -20,19 +20,22 @@ class Blob;
class BlobImpl;
class Promise;
class CreateFileTask final
: public FileSystemTaskBase
class CreateFileTask final : public FileSystemTaskBase
{
public:
CreateFileTask(FileSystemBase* aFileSystem,
const nsAString& aPath,
Blob* aBlobData,
InfallibleTArray<uint8_t>& aArrayData,
bool replace,
ErrorResult& aRv);
CreateFileTask(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<CreateFileTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aFile,
Blob* aBlobData,
InfallibleTArray<uint8_t>& aArrayData,
bool replace,
ErrorResult& aRv);
static already_AddRefed<CreateFileTask>
Create(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~CreateFileTask();
@ -45,13 +48,15 @@ public:
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@ -60,12 +65,20 @@ protected:
HandlerCallback() override;
private:
CreateFileTask(FileSystemBase* aFileSystem,
nsIFile* aFile,
bool aReplace);
CreateFileTask(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent);
void
GetOutputBufferSize() const;
static uint32_t sOutputBufferSize;
RefPtr<Promise> mPromise;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
// Not thread-safe and should be released on main thread.
RefPtr<Blob> mBlobData;

Просмотреть файл

@ -46,17 +46,17 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(
NS_WARN_IF(NS_FAILED(rv));
// Get the local path of the file system root.
// Since the child process is not allowed to access the file system, we only
// do this from the parent process.
if (!XRE_IsParentProcess()) {
return;
}
nsCOMPtr<nsIFile> rootFile;
DeviceStorageFile::GetRootDirectoryForType(aStorageType,
aStorageName,
getter_AddRefs(rootFile));
NS_WARN_IF(!rootFile || NS_FAILED(rootFile->GetPath(mLocalRootPath)));
if (!XRE_IsParentProcess()) {
return;
}
FileSystemUtils::LocalPathToNormalizedPath(mLocalRootPath,
mNormalizedLocalRootPath);
@ -132,8 +132,14 @@ DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aDir);
RefPtr<FileSystemBase> fs = aDir->GetFileSystem();
MOZ_ASSERT(fs);
ErrorResult rv;
RefPtr<FileSystemBase> fs = aDir->GetFileSystem(rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return false;
}
// Check if the given directory is from this storage.
return fs->ToString() == mString;
}

Просмотреть файл

@ -18,6 +18,7 @@
#include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/OSFileSystem.h"
// Resolve the name collision of Microsoft's API name with macros defined in
// Windows header files. Undefine the macro of CreateDirectory to avoid
@ -37,12 +38,19 @@ namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(Directory)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Directory)
tmp->mFileSystem->Unlink();
if (tmp->mFileSystem) {
tmp->mFileSystem->Unlink();
tmp->mFileSystem = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Directory)
tmp->mFileSystem->Traverse(cb);
if (tmp->mFileSystem) {
tmp->mFileSystem->Traverse(cb);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -59,23 +67,57 @@ NS_INTERFACE_MAP_END
already_AddRefed<Promise>
Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
{
RefPtr<GetFileOrDirectoryTask> task = new GetFileOrDirectoryTask(
aFileSystem, EmptyString(), true, aRv);
if (aRv.Failed()) {
MOZ_ASSERT(aFileSystem);
nsCOMPtr<nsIFile> path;
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aFileSystem->GetLocalRootPath()),
true, getter_AddRefs(path));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<GetFileOrDirectoryTask> task =
GetFileOrDirectoryTask::Create(aFileSystem, path, eDOMRootDirectory, true, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
}
Directory::Directory(FileSystemBase* aFileSystem,
const nsAString& aPath)
: mFileSystem(aFileSystem)
, mPath(aPath)
/* static */ already_AddRefed<Directory>
Directory::Create(nsPIDOMWindowInner* aWindow, nsIFile* aFile,
DirectoryType aType, FileSystemBase* aFileSystem)
{
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
// Remove the trailing "/".
mPath.Trim(FILESYSTEM_DOM_PATH_SEPARATOR, false, true);
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aFile);
#ifdef DEBUG
bool isDir;
nsresult rv = aFile->IsDirectory(&isDir);
MOZ_ASSERT(NS_SUCCEEDED(rv) && isDir);
#endif
RefPtr<Directory> directory =
new Directory(aWindow, aFile, aType, aFileSystem);
return directory.forget();
}
Directory::Directory(nsPIDOMWindowInner* aWindow,
nsIFile* aFile,
DirectoryType aType,
FileSystemBase* aFileSystem)
: mWindow(aWindow)
, mFileSystem(aFileSystem)
, mFile(aFile)
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aFile);
// aFileSystem can be null. In this case we create a OSFileSystem when needed.
}
Directory::~Directory()
@ -85,7 +127,7 @@ Directory::~Directory()
nsPIDOMWindowInner*
Directory::GetParentObject() const
{
return mFileSystem->GetWindow();
return mWindow;
}
JSObject*
@ -95,25 +137,28 @@ Directory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
}
void
Directory::GetName(nsAString& aRetval) const
Directory::GetName(nsAString& aRetval, ErrorResult& aRv)
{
aRetval.Truncate();
if (mPath.IsEmpty()) {
mFileSystem->GetRootName(aRetval);
if (mType == eDOMRootDirectory) {
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
fs->GetRootName(aRetval);
return;
}
aRetval = Substring(mPath,
mPath.RFindChar(FileSystemUtils::kSeparatorChar) + 1);
aRv = mFile->GetLeafName(aRetval);
NS_WARN_IF(aRv.Failed());
}
already_AddRefed<Promise>
Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
ErrorResult& aRv)
{
nsresult error = NS_OK;
nsAutoString realPath;
RefPtr<Blob> blobData;
InfallibleTArray<uint8_t> arrayData;
bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace);
@ -138,15 +183,20 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
}
}
if (!DOMPathToRealPath(aPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
nsCOMPtr<nsIFile> realPath;
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<CreateFileTask> task =
new CreateFileTask(mFileSystem, realPath, blobData, arrayData, replace, aRv);
if (aRv.Failed()) {
CreateFileTask::Create(fs, realPath, blobData, arrayData, replace, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->SetError(error);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
@ -155,16 +205,20 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
already_AddRefed<Promise>
Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
{
nsresult error = NS_OK;
nsAutoString realPath;
if (!DOMPathToRealPath(aPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
RefPtr<CreateDirectoryTask> task = new CreateDirectoryTask(
mFileSystem, realPath, aRv);
if (aRv.Failed()) {
nsCOMPtr<nsIFile> realPath;
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<CreateDirectoryTask> task =
CreateDirectoryTask::Create(fs, realPath, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->SetError(error);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
@ -173,16 +227,21 @@ Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
already_AddRefed<Promise>
Directory::Get(const nsAString& aPath, ErrorResult& aRv)
{
nsresult error = NS_OK;
nsAutoString realPath;
if (!DOMPathToRealPath(aPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
RefPtr<GetFileOrDirectoryTask> task = new GetFileOrDirectoryTask(
mFileSystem, realPath, false, aRv);
if (aRv.Failed()) {
nsCOMPtr<nsIFile> realPath;
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<GetFileOrDirectoryTask> task =
GetFileOrDirectoryTask::Create(fs, realPath, eNotDOMRootDirectory, false,
aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->SetError(error);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
@ -205,30 +264,33 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
ErrorResult& aRv)
{
nsresult error = NS_OK;
nsAutoString realPath;
nsCOMPtr<nsIFile> realPath;
RefPtr<BlobImpl> blob;
// Check and get the target path.
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (aPath.IsFile()) {
blob = aPath.GetAsFile().Impl();
} else if (aPath.IsString()) {
if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
} else if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) {
error = DOMPathToRealPath(aPath.GetAsString(), getter_AddRefs(realPath));
} else if (!fs->IsSafeDirectory(&aPath.GetAsDirectory())) {
error = NS_ERROR_DOM_SECURITY_ERR;
} else {
realPath = aPath.GetAsDirectory().mPath;
realPath = aPath.GetAsDirectory().mFile;
// The target must be a descendant of this directory.
if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) {
if (!FileSystemUtils::IsDescendantPath(mFile, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
}
}
RefPtr<RemoveTask> task = new RemoveTask(mFileSystem, mPath, blob, realPath,
aRecursive, aRv);
if (aRv.Failed()) {
RefPtr<RemoveTask> task =
RemoveTask::Create(fs, mFile, blob, realPath, aRecursive, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->SetError(error);
@ -237,23 +299,38 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
}
void
Directory::GetPath(nsAString& aRetval) const
Directory::GetPath(nsAString& aRetval, ErrorResult& aRv)
{
if (mPath.IsEmpty()) {
// The Directory ctor removes any trailing '/'; this is the root directory.
if (mType == eDOMRootDirectory) {
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
} else {
aRetval = mPath;
// TODO: this should be a bit different...
GetName(aRetval, aRv);
}
}
already_AddRefed<Promise>
Directory::GetFilesAndDirectories()
nsresult
Directory::GetFullRealPath(nsAString& aPath)
{
ErrorResult rv;
nsresult rv = mFile->GetPath(aPath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
already_AddRefed<Promise>
Directory::GetFilesAndDirectories(ErrorResult& aRv)
{
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<GetDirectoryListingTask> task =
new GetDirectoryListingTask(mFileSystem, mPath, mFilters, rv);
if (NS_WARN_IF(rv.Failed())) {
GetDirectoryListingTask::Create(fs, mFile, mType, mFilters, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -268,16 +345,38 @@ Directory::SetContentFilters(const nsAString& aFilters)
}
FileSystemBase*
Directory::GetFileSystem() const
Directory::GetFileSystem(ErrorResult& aRv)
{
return mFileSystem.get();
if (!mFileSystem) {
nsCOMPtr<nsIFile> parent;
aRv = mFile->GetParent(getter_AddRefs(parent));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// Parent can be null if mFile is pointing to the top directory.
if (!parent) {
parent = mFile;
}
nsAutoString path;
aRv = parent->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<OSFileSystem> fs = new OSFileSystem(path);
fs->Init(mWindow);
mFileSystem = fs;
}
return mFileSystem;
}
bool
Directory::DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const
nsresult
Directory::DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const
{
aRealPath.Truncate();
nsString relativePath;
relativePath = aPath;
@ -286,13 +385,22 @@ Directory::DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const
relativePath.Trim(kWhitespace);
if (!IsValidRelativePath(relativePath)) {
return false;
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
aRealPath = mPath + NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR) +
relativePath;
nsCOMPtr<nsIFile> file;
nsresult rv = mFile->Clone(getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return true;
rv = file->AppendRelativePath(relativePath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
file.forget(aFile);
return NS_OK;
}
// static

Просмотреть файл

@ -41,14 +41,37 @@ class Directory final
, public nsWrapperCache
{
public:
struct BlobImplOrDirectoryPath
{
RefPtr<BlobImpl> mBlobImpl;
nsString mDirectoryPath;
enum {
eBlobImpl,
eDirectoryPath
} mType;
};
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
public:
static already_AddRefed<Promise>
GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
Directory(FileSystemBase* aFileSystem, const nsAString& aPath);
enum DirectoryType {
// When a directory is selected using a HTMLInputElement, that will be the
// DOM root directory and its name will be '/'. All the sub directory will
// be called with they real name. We use this enum to mark what we must
// consider the '/' of this DOM filesystem.
eDOMRootDirectory,
// All the sub directories of the '/' will be marked using this other value.
eNotDOMRootDirectory
};
static already_AddRefed<Directory>
Create(nsPIDOMWindowInner* aWindow, nsIFile* aDirectory,
DirectoryType aType, FileSystemBase* aFileSystem = 0);
// ========= Begin WebIDL bindings. ===========
@ -59,7 +82,7 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void
GetName(nsAString& aRetval) const;
GetName(nsAString& aRetval, ErrorResult& aRv);
already_AddRefed<Promise>
CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
@ -80,10 +103,13 @@ public:
// From https://microsoftedge.github.io/directory-upload/proposal.html#directory-interface :
void
GetPath(nsAString& aRetval) const;
GetPath(nsAString& aRetval, ErrorResult& aRv);
nsresult
GetFullRealPath(nsAString& aPath);
already_AddRefed<Promise>
GetFilesAndDirectories();
GetFilesAndDirectories(ErrorResult& aRv);
// =========== End WebIDL bindings.============
@ -113,8 +139,12 @@ public:
SetContentFilters(const nsAString& aFilters);
FileSystemBase*
GetFileSystem() const;
GetFileSystem(ErrorResult& aRv);
private:
Directory(nsPIDOMWindowInner* aWindow,
nsIFile* aFile, DirectoryType aType,
FileSystemBase* aFileSystem = nullptr);
~Directory();
static bool
@ -122,17 +152,19 @@ private:
/*
* Convert relative DOM path to the absolute real path.
* @return true if succeed. false if the DOM path is invalid.
*/
bool
DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const;
nsresult
DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const;
already_AddRefed<Promise>
RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
ErrorResult& aRv);
nsCOMPtr<nsPIDOMWindowInner> mWindow;
RefPtr<FileSystemBase> mFileSystem;
nsString mPath;
nsCOMPtr<nsIFile> mFile;
DirectoryType mType;
nsString mFilters;
};

Просмотреть файл

@ -68,26 +68,41 @@ FileSystemBase::GetLocalFile(const nsAString& aRealPath) const
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Should be on parent process!");
// Let's convert the input path to /path
nsAutoString localPath;
FileSystemUtils::NormalizedPathToLocalPath(aRealPath, localPath);
localPath = mLocalRootPath + localPath;
if (!aRealPath.IsEmpty() &&
!StringBeginsWith(aRealPath,
NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR))) {
localPath.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
}
localPath.Append(aRealPath);
// We have to normalize the path string in order to follow the separator
// schema of this OS.
nsAutoString normalizedPath;
FileSystemUtils::NormalizedPathToLocalPath(localPath, normalizedPath);
// The full path is mLocalRootPath + normalizedPath.
nsAutoString path(mLocalRootPath);
path.Append(normalizedPath);
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewLocalFile(localPath, false, getter_AddRefs(file));
nsresult rv = NS_NewLocalFile(path, false, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return file.forget();
}
bool
FileSystemBase::GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const
FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Should be on parent process!");
MOZ_ASSERT(aFile, "aFile Should not be null.");
aRealPath.Truncate();
nsAutoString filePath;
ErrorResult rv;
aFile->GetMozFullPathInternal(filePath, rv);
@ -95,7 +110,13 @@ FileSystemBase::GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const
return false;
}
return LocalPathToRealPath(filePath, aRealPath);
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(filePath),
true, aPath);
if (NS_WARN_IF(rv.Failed())) {
return false;
}
return true;
}
bool
@ -120,6 +141,7 @@ FileSystemBase::LocalPathToRealPath(const nsAString& aLocalPath,
aRealPath.Truncate();
return false;
}
aRealPath = Substring(path, mNormalizedLocalRootPath.Length());
return true;
}

Просмотреть файл

@ -73,13 +73,8 @@ public:
virtual bool
IsSafeDirectory(Directory* aDir) const;
/*
* Get the real path (absolute DOM path) of the DOM file in the file system.
* If succeeded, returns true. Otherwise, returns false and set aRealPath to
* empty string.
*/
bool
GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const;
GetRealPath(BlobImpl* aFile, nsIFile** aPath) const;
/*
* Get the permission name required to access this file system.

Просмотреть файл

@ -29,7 +29,10 @@ FileSystemRequestParent::~FileSystemRequestParent()
case FileSystemParams::TFileSystem##name##Params: { \
const FileSystem##name##Params& p = aParams; \
mFileSystem = FileSystemBase::FromString(p.filesystem()); \
task = new name##Task(mFileSystem, p, this); \
task = name##Task::Create(mFileSystem, p, this, rv); \
if (NS_WARN_IF(rv.Failed())) { \
return false; \
} \
break; \
}
@ -39,6 +42,8 @@ FileSystemRequestParent::Dispatch(ContentParent* aParent,
{
MOZ_ASSERT(aParent, "aParent should not be null.");
RefPtr<FileSystemTaskBase> task;
ErrorResult rv;
switch (aParams.type()) {
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(CreateDirectory)

Просмотреть файл

@ -106,12 +106,19 @@ FileSystemTaskBase::Start()
return;
}
ErrorResult rv;
FileSystemParams params = GetRequestParams(mFileSystem->ToString(), rv);
if (NS_WARN_IF(rv.Failed())) {
return;
}
// Retain a reference so the task object isn't deleted without IPDL's
// knowledge. The reference will be released by
// mozilla::dom::ContentChild::DeallocPFileSystemRequestChild.
NS_ADDREF_THIS();
ContentChild::GetSingleton()->SendPFileSystemRequestConstructor(this,
GetRequestParams(mFileSystem->ToString()));
params);
}
NS_IMETHODIMP
@ -154,11 +161,17 @@ FileSystemTaskBase::GetRequestResult() const
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (HasError()) {
return FileSystemErrorResponse(mErrorValue);
} else {
return GetSuccessRequestResult();
if (!HasError()) {
ErrorResult rv;
FileSystemResponseValue value = GetSuccessRequestResult(rv);
if (NS_WARN_IF(rv.Failed())) {
return FileSystemErrorResponse(rv.StealNSResult());
}
return value;
}
return FileSystemErrorResponse(mErrorValue);
}
void
@ -171,7 +184,9 @@ FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
FileSystemErrorResponse r = aValue;
mErrorValue = r.error();
} else {
SetSuccessRequestResult(aValue);
ErrorResult rv;
SetSuccessRequestResult(aValue, rv);
mErrorValue = rv.StealNSResult();
}
}

Просмотреть файл

@ -176,7 +176,8 @@ protected:
* @param filesystem The string representation of the file system.
*/
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const = 0;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const = 0;
/*
* Wrap the task success result to FileSystemResponseValue for sending it
@ -185,7 +186,7 @@ protected:
* send the task success result back to the child process.
*/
virtual FileSystemResponseValue
GetSuccessRequestResult() const = 0;
GetSuccessRequestResult(ErrorResult& aRv) const = 0;
/*
* Unwrap the IPC message to get the task success result.
@ -194,7 +195,8 @@ protected:
* success result.
*/
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) = 0;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) = 0;
bool
HasError() const { return mErrorValue != NS_OK; }

Просмотреть файл

@ -65,5 +65,31 @@ FileSystemUtils::IsDescendantPath(const nsAString& aPath,
return true;
}
// static
bool
FileSystemUtils::IsDescendantPath(nsIFile* aFile,
nsIFile* aDescendantFile)
{
nsAutoString path;
nsresult rv = aFile->GetPath(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
nsAutoString descendantPath;
rv = aDescendantFile->GetPath(descendantPath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
// Check the sub-directory path to see if it has the parent path as prefix.
if (descendantPath.Length() <= path.Length() ||
!StringBeginsWith(descendantPath, path)) {
return false;
}
return true;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -34,6 +34,12 @@ public:
static void
NormalizedPathToLocalPath(const nsAString& aNorm, nsAString& aLocal);
/*
* Return true if aDescendantPath is a descendant of aPath.
*/
static bool
IsDescendantPath(nsIFile* aPath, nsIFile* aDescendantPath);
/*
* Return true if aDescendantPath is a descendant of aPath. Both aPath and
* aDescendantPath are absolute DOM path.

Просмотреть файл

@ -8,7 +8,6 @@
#include "HTMLSplitOnSpacesTokenizer.h"
#include "js/Value.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
@ -21,33 +20,80 @@
namespace mozilla {
namespace dom {
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
const nsAString& aFilters,
ErrorResult& aRv)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aTargetPath)
, mFilters(aFilters)
/* static */ already_AddRefed<GetDirectoryListingTask>
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetDirectoryListingTask> task =
new GetDirectoryListingTask(aFileSystem, aTargetPath, aType, aFilters);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mPromise = Promise::Create(globalObject, aRv);
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
/* static */ already_AddRefed<GetDirectoryListingTask>
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetDirectoryListingTask> task =
new GetDirectoryListingTask(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->mType = aParam.isRoot()
? Directory::eDOMRootDirectory : Directory::eNotRootDirectory;
return task.forget();
}
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters)
: FileSystemTaskBase(aFileSystem)
, mTargetPath(aTargetPath)
, mFilters(aFilters)
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mTargetRealPath(aParam.realPath())
, mFilters(aParam.filters())
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
@ -66,43 +112,88 @@ GetDirectoryListingTask::GetPromise()
}
FileSystemParams
GetDirectoryListingTask::GetRequestParams(const nsString& aFileSystem) const
GetDirectoryListingTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemGetDirectoryListingParams(aFileSystem, mTargetRealPath,
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemGetDirectoryListingParams();
}
return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
mType == Directory::eDOMRootDirectory,
mFilters);
}
void
GetDirectoryListingTask::CreateNormalizedRelativePath(const nsAString& aPath,
nsAString& aRelativePath) const
{
uint32_t rootPathLen = mFileSystem->GetLocalRootPath().Length();
FileSystemUtils::LocalPathToNormalizedPath(
Substring(aPath, rootPathLen, aPath.Length() - rootPathLen), aRelativePath);
}
FileSystemResponseValue
GetDirectoryListingTask::GetSuccessRequestResult() const
GetDirectoryListingTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
InfallibleTArray<PBlobParent*> blobs;
for (unsigned i = 0; i < mTargetBlobImpls.Length(); i++) {
BlobParent* blobParent = GetBlobParent(mTargetBlobImpls[i]);
if (blobParent) {
blobs.AppendElement(blobParent);
nsTArray<FileSystemDirectoryListingResponseData> inputs;
for (unsigned i = 0; i < mTargetData.Length(); i++) {
if (mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl) {
BlobParent* blobParent = GetBlobParent(mTargetData[i].mBlobImpl);
if (!blobParent) {
continue;
}
FileSystemDirectoryListingResponseBlob blobData;
blobData.blobParent() = blobParent;
inputs.AppendElement(blobData);
} else {
MOZ_ASSERT(mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath);
FileSystemDirectoryListingResponseDirectory directoryData;
directoryData.directoryRealPath() = mTargetData[i].mDirectoryPath;
inputs.AppendElement(directoryData);
}
}
FileSystemDirectoryListingResponse response;
response.blobsParent().SwapElements(blobs);
response.data().SwapElements(inputs);
return response;
}
void
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aValue.type() ==
FileSystemResponseValue::TFileSystemDirectoryListingResponse);
FileSystemDirectoryListingResponse r = aValue;
nsTArray<PBlobChild*>& blobs = r.blobsChild();
for (uint32_t i = 0; i < r.data().Length(); ++i) {
const FileSystemDirectoryListingResponseData& data = r.data()[i];
for (unsigned i = 0; i < blobs.Length(); i++) {
mTargetBlobImpls.AppendElement(static_cast<BlobChild*>(blobs[i])->GetBlobImpl());
if (data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseBlob) {
PBlobChild* blob = data.get_FileSystemDirectoryListingResponseBlob().blobChild();
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
element->mType = Directory::BlobImplOrDirectoryPath::eBlobImpl;
element->mBlobImpl = static_cast<BlobChild*>(blob)->GetBlobImpl();
} else {
MOZ_ASSERT(data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseDirectory);
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
element->mType = Directory::BlobImplOrDirectoryPath::eDirectoryPath;
element->mDirectoryPath = data.get_FileSystemDirectoryListingResponseDirectory().directoryRealPath();
}
}
}
@ -117,27 +208,19 @@ GetDirectoryListingTask::Work()
return NS_ERROR_FAILURE;
}
// Whether we want to get the root directory.
bool getRoot = mTargetRealPath.IsEmpty();
nsCOMPtr<nsIFile> dir = mFileSystem->GetLocalFile(mTargetRealPath);
if (!dir) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
bool exists;
nsresult rv = dir->Exists(&exists);
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!exists) {
if (!getRoot) {
if (mType == Directory::eNotRootDirectory) {
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
}
// If the root directory doesn't exit, create it.
rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0777);
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -145,7 +228,7 @@ GetDirectoryListingTask::Work()
// Get isDirectory.
bool isDir;
rv = dir->IsDirectory(&isDir);
rv = mTargetPath->IsDirectory(&isDir);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -155,7 +238,7 @@ GetDirectoryListingTask::Work()
}
nsCOMPtr<nsISimpleEnumerator> entries;
rv = dir->GetDirectoryEntries(getter_AddRefs(entries));
rv = mTargetPath->GetDirectoryEntries(getter_AddRefs(entries));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -186,7 +269,7 @@ GetDirectoryListingTask::Work()
nsCOMPtr<nsIFile> currFile = do_QueryInterface(supp);
MOZ_ASSERT(currFile);
bool isLink, isSpecial, isFile;
if (NS_WARN_IF(NS_FAILED(currFile->IsSymlink(&isLink)) ||
NS_FAILED(currFile->IsSpecial(&isSpecial))) ||
@ -213,9 +296,22 @@ GetDirectoryListingTask::Work()
}
}
BlobImplFile* impl = new BlobImplFile(currFile);
impl->LookupAndCacheIsDirectory();
mTargetBlobImpls.AppendElement(impl);
if (isDir) {
nsAutoString path;
if (NS_WARN_IF(NS_FAILED(currFile->GetPath(path)))) {
continue;
}
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
element->mType = Directory::BlobImplOrDirectoryPath::eDirectoryPath;
element->mDirectoryPath = path;
} else {
BlobImplFile* impl = new BlobImplFile(currFile);
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
element->mType = Directory::BlobImplOrDirectoryPath::eBlobImpl;
element->mBlobImpl = impl;
}
}
return NS_OK;
}
@ -235,7 +331,7 @@ GetDirectoryListingTask::HandlerCallback()
return;
}
size_t count = mTargetBlobImpls.Length();
size_t count = mTargetData.Length();
Sequence<OwningFileOrDirectory> listing;
@ -246,26 +342,65 @@ GetDirectoryListingTask::HandlerCallback()
}
for (unsigned i = 0; i < count; i++) {
if (mTargetBlobImpls[i]->IsDirectory()) {
nsAutoString name;
mTargetBlobImpls[i]->GetName(name);
nsAutoString path(mTargetRealPath);
path.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
path.Append(name);
if (mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath) {
#ifdef DEBUG
if (XRE_IsParentProcess()) {
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(path);
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewLocalFile(mTargetData[i].mDirectoryPath, false,
getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(rv);
mPromise = nullptr;
return;
}
bool exist;
file->Exists(&exist);
MOZ_ASSERT(exist);
rv = file->Exists(&exist);
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(rv);
mPromise = nullptr;
return;
}
// We cannot assert here because the file can be done in the meantime.
NS_ASSERTION(exist, "The file doesn't exist anymore?!?");
nsAutoString normalizedLocalRootPath;
FileSystemUtils::NormalizedPathToLocalPath(mFileSystem->GetLocalRootPath(),
normalizedLocalRootPath);
nsAutoString directoryPath;
FileSystemUtils::NormalizedPathToLocalPath(mTargetData[i].mDirectoryPath,
directoryPath);
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(normalizedLocalRootPath,
directoryPath));
}
#endif
RefPtr<Directory> directory = new Directory(mFileSystem, path);
nsCOMPtr<nsIFile> directoryPath;
NS_ConvertUTF16toUTF8 path(mTargetData[i].mDirectoryPath);
nsresult rv = NS_NewNativeLocalFile(path, true,
getter_AddRefs(directoryPath));
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(rv);
mPromise = nullptr;
return;
}
RefPtr<Directory> directory = Directory::Create(mFileSystem->GetWindow(),
directoryPath,
Directory::eNotRootDirectory,
mFileSystem);
MOZ_ASSERT(directory);
// Propogate mFilter onto sub-Directory object:
directory->SetContentFilters(mFilters);
listing[i].SetAsDirectory() = directory;
} else {
listing[i].SetAsFile() = File::Create(mFileSystem->GetWindow(), mTargetBlobImpls[i]);
MOZ_ASSERT(mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl);
listing[i].SetAsFile() =
File::Create(mFileSystem->GetWindow(), mTargetData[i].mBlobImpl);
}
}

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef mozilla_dom_GetDirectoryListing_h
#define mozilla_dom_GetDirectoryListing_h
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemTaskBase.h"
#include "mozilla/ErrorResult.h"
#include "nsAutoPtr.h"
@ -16,18 +17,21 @@ namespace dom {
class BlobImpl;
class GetDirectoryListingTask final
: public FileSystemTaskBase
class GetDirectoryListingTask final : public FileSystemTaskBase
{
public:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetDirectoryListingTask(FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
const nsAString& aFilters,
ErrorResult& aRv);
GetDirectoryListingTask(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<GetDirectoryListingTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters,
ErrorResult& aRv);
static already_AddRefed<GetDirectoryListingTask>
Create(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~GetDirectoryListingTask();
@ -37,15 +41,28 @@ public:
virtual void
GetPermissionAccessType(nsCString& aAccess) const override;
protected:
private:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetDirectoryListingTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters);
GetDirectoryListingTask(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent);
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@ -53,14 +70,18 @@ protected:
virtual void
HandlerCallback() override;
private:
void
CreateNormalizedRelativePath(const nsAString& aPath,
nsAString& aRelativePath) const;
RefPtr<Promise> mPromise;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
nsString mFilters;
Directory::DirectoryType mType;
// We cannot store File or Directory objects bacause this object is created
// on a different thread and File and Directory are not thread-safe.
nsTArray<RefPtr<BlobImpl>> mTargetBlobImpls;
nsTArray<Directory::BlobImplOrDirectoryPath> mTargetData;
};
} // namespace dom

Просмотреть файл

@ -7,7 +7,6 @@
#include "GetFileOrDirectoryTask.h"
#include "js/Value.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
@ -20,37 +19,82 @@
namespace mozilla {
namespace dom {
GetFileOrDirectoryTask::GetFileOrDirectoryTask(
FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
bool aDirectoryOnly,
ErrorResult& aRv)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aTargetPath)
, mIsDirectory(aDirectoryOnly)
/* static */ already_AddRefed<GetFileOrDirectoryTask>
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetFileOrDirectoryTask> task =
new GetFileOrDirectoryTask(aFileSystem, aTargetPath, aType, aDirectoryOnly);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mPromise = Promise::Create(globalObject, aRv);
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
GetFileOrDirectoryTask::GetFileOrDirectoryTask(
FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent)
/* static */ already_AddRefed<GetFileOrDirectoryTask>
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetFileOrDirectoryTask> task =
new GetFileOrDirectoryTask(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->mType = aParam.isRoot()
? Directory::eDOMRootDirectory : Directory::eNotRootDirectory;
return task.forget();
}
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly)
: FileSystemTaskBase(aFileSystem)
, mTargetPath(aTargetPath)
, mIsDirectory(aDirectoryOnly)
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mIsDirectory(false)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
mTargetRealPath = aParam.realPath();
}
GetFileOrDirectoryTask::~GetFileOrDirectoryTask()
@ -67,18 +111,33 @@ GetFileOrDirectoryTask::GetPromise()
}
FileSystemParams
GetFileOrDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
GetFileOrDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemGetFileOrDirectoryParams(aFileSystem, mTargetRealPath);
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemGetFileOrDirectoryParams();
}
return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path,
mType == Directory::eDOMRootDirectory);
}
FileSystemResponseValue
GetFileOrDirectoryTask::GetSuccessRequestResult() const
GetFileOrDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (mIsDirectory) {
return FileSystemDirectoryResponse(mTargetRealPath);
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemDirectoryResponse();
}
return FileSystemDirectoryResponse(path);
}
BlobParent* actor = GetBlobParent(mTargetBlobImpl);
@ -91,7 +150,8 @@ GetFileOrDirectoryTask::GetSuccessRequestResult() const
}
void
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
switch (aValue.type()) {
@ -104,7 +164,13 @@ GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& a
}
case FileSystemResponseValue::TFileSystemDirectoryResponse: {
FileSystemDirectoryResponse r = aValue;
mTargetRealPath = r.realPath();
NS_ConvertUTF16toUTF8 path(r.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
mIsDirectory = true;
break;
}
@ -127,33 +193,26 @@ GetFileOrDirectoryTask::Work()
}
// Whether we want to get the root directory.
bool getRoot = mTargetRealPath.IsEmpty();
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
if (!file) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
bool exists;
nsresult rv = file->Exists(&exists);
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!exists) {
if (!getRoot) {
if (mType == Directory::eNotRootDirectory) {
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
}
// If the root directory doesn't exit, create it.
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777);
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// Get isDirectory.
rv = file->IsDirectory(&mIsDirectory);
rv = mTargetPath->IsDirectory(&mIsDirectory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -163,13 +222,13 @@ GetFileOrDirectoryTask::Work()
}
// Check if the root is a directory.
if (getRoot) {
if (mType == Directory::eDOMRootDirectory) {
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
}
bool isFile;
// Get isFile
rv = file->IsFile(&isFile);
rv = mTargetPath->IsFile(&isFile);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -179,11 +238,11 @@ GetFileOrDirectoryTask::Work()
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
}
if (!mFileSystem->IsSafeFile(file)) {
if (!mFileSystem->IsSafeFile(mTargetPath)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
mTargetBlobImpl = new BlobImplFile(file);
mTargetBlobImpl = new BlobImplFile(mTargetPath);
return NS_OK;
}
@ -204,7 +263,12 @@ GetFileOrDirectoryTask::HandlerCallback()
}
if (mIsDirectory) {
RefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetWindow(),
mTargetPath,
mType,
mFileSystem);
MOZ_ASSERT(dir);
mPromise->MaybeResolve(dir);
mPromise = nullptr;
return;

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef mozilla_dom_GetFileOrDirectory_h
#define mozilla_dom_GetFileOrDirectory_h
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemTaskBase.h"
#include "nsAutoPtr.h"
#include "mozilla/ErrorResult.h"
@ -16,18 +17,21 @@ namespace dom {
class BlobImpl;
class GetFileOrDirectoryTask final
: public FileSystemTaskBase
class GetFileOrDirectoryTask final : public FileSystemTaskBase
{
public:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
bool aDirectoryOnly,
ErrorResult& aRv);
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<GetFileOrDirectoryTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly,
ErrorResult& aRv);
static already_AddRefed<GetFileOrDirectoryTask>
Create(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~GetFileOrDirectoryTask();
@ -39,13 +43,15 @@ public:
GetPermissionAccessType(nsCString& aAccess) const override;
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@ -54,10 +60,22 @@ protected:
HandlerCallback() override;
private:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly);
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent);
RefPtr<Promise> mPromise;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
// Whether we get a directory.
bool mIsDirectory;
Directory::DirectoryType mType;
// This cannot be a File bacause this object is created on a different
// thread and File is not thread-safe. Let's use the BlobImpl instead.

Просмотреть файл

@ -20,9 +20,26 @@ struct FileSystemDirectoryResponse
nsString realPath;
};
struct FileSystemDirectoryListingResponseBlob
{
PBlob blob;
};
struct FileSystemDirectoryListingResponseDirectory
{
// This is the full real path for the directory that we are sending via IPC.
nsString directoryRealPath;
};
union FileSystemDirectoryListingResponseData
{
FileSystemDirectoryListingResponseBlob;
FileSystemDirectoryListingResponseDirectory;
};
struct FileSystemDirectoryListingResponse
{
PBlob[] blobs;
FileSystemDirectoryListingResponseData[] data;
};
struct FileSystemErrorResponse

Просмотреть файл

@ -18,27 +18,94 @@
namespace mozilla {
namespace dom {
/* static */ already_AddRefed<RemoveTask>
RemoveTask::Create(FileSystemBase* aFileSystem,
nsIFile* aDirPath,
BlobImpl* aTargetBlob,
nsIFile* aTargetPath,
bool aRecursive,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
MOZ_ASSERT(aDirPath);
RefPtr<RemoveTask> task =
new RemoveTask(aFileSystem, aDirPath, aTargetBlob, aTargetPath, aRecursive);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
/* static */ already_AddRefed<RemoveTask>
RemoveTask::Create(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<RemoveTask> task =
new RemoveTask(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 directoryPath(aParam.directory());
aRv = NS_NewNativeLocalFile(directoryPath, true,
getter_AddRefs(task->mDirPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->mRecursive = aParam.recursive();
const FileSystemPathOrFileValue& target = aParam.target();
if (target.type() == FileSystemPathOrFileValue::TnsString) {
NS_ConvertUTF16toUTF8 path(target);
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
task->mTargetBlobImpl = bp->GetBlobImpl();
MOZ_ASSERT(task->mTargetBlobImpl);
return task.forget();
}
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
const nsAString& aDirPath,
nsIFile* aDirPath,
BlobImpl* aTargetBlob,
const nsAString& aTargetPath,
bool aRecursive,
ErrorResult& aRv)
nsIFile* aTargetPath,
bool aRecursive)
: FileSystemTaskBase(aFileSystem)
, mDirRealPath(aDirPath)
, mDirPath(aDirPath)
, mTargetBlobImpl(aTargetBlob)
, mTargetRealPath(aTargetPath)
, mTargetPath(aTargetPath)
, mRecursive(aRecursive)
, mReturnValue(false)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
}
mPromise = Promise::Create(globalObject, aRv);
MOZ_ASSERT(aDirPath);
}
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
@ -48,25 +115,9 @@ RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
, mRecursive(false)
, mReturnValue(false)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
mDirRealPath = aParam.directory();
mRecursive = aParam.recursive();
const FileSystemPathOrFileValue& target = aParam.target();
if (target.type() == FileSystemPathOrFileValue::TnsString) {
mTargetRealPath = target;
return;
}
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
mTargetBlobImpl = bp->GetBlobImpl();
MOZ_ASSERT(mTargetBlobImpl);
}
RemoveTask::~RemoveTask()
@ -83,36 +134,49 @@ RemoveTask::GetPromise()
}
FileSystemParams
RemoveTask::GetRequestParams(const nsString& aFileSystem) const
RemoveTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemRemoveParams param;
param.filesystem() = aFileSystem;
param.directory() = mDirRealPath;
param.filesystem() = aSerializedDOMPath;
aRv = mDirPath->GetPath(param.directory());
if (NS_WARN_IF(aRv.Failed())) {
return param;
}
param.recursive() = mRecursive;
if (mTargetBlobImpl) {
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(),
mTargetBlobImpl);
mTargetBlobImpl);
BlobChild* actor
= ContentChild::GetSingleton()->GetOrCreateActorForBlob(blob);
if (actor) {
param.target() = actor;
}
} else {
param.target() = mTargetRealPath;
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return param;
}
param.target() = path;
}
return param;
}
FileSystemResponseValue
RemoveTask::GetSuccessRequestResult() const
RemoveTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemBooleanResponse(mReturnValue);
}
void
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemBooleanResponse r = aValue;
@ -130,23 +194,19 @@ RemoveTask::Work()
return NS_ERROR_FAILURE;
}
// Get the DOM path if a File is passed as the target.
// Get the path if a File is passed as the target.
if (mTargetBlobImpl) {
if (!mFileSystem->GetRealPath(mTargetBlobImpl, mTargetRealPath)) {
if (!mFileSystem->GetRealPath(mTargetBlobImpl,
getter_AddRefs(mTargetPath))) {
return NS_ERROR_DOM_SECURITY_ERR;
}
if (!FileSystemUtils::IsDescendantPath(mDirRealPath, mTargetRealPath)) {
if (!FileSystemUtils::IsDescendantPath(mDirPath, mTargetPath)) {
return NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
}
}
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
if (!file) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
bool exists = false;
nsresult rv = file->Exists(&exists);
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -157,16 +217,16 @@ RemoveTask::Work()
}
bool isFile = false;
rv = file->IsFile(&isFile);
rv = mTargetPath->IsFile(&isFile);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (isFile && !mFileSystem->IsSafeFile(file)) {
if (isFile && !mFileSystem->IsSafeFile(mTargetPath)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
rv = file->Remove(mRecursive);
rv = mTargetPath->Remove(mRecursive);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

Просмотреть файл

@ -17,19 +17,22 @@ namespace dom {
class BlobImpl;
class Promise;
class RemoveTask final
: public FileSystemTaskBase
class RemoveTask final : public FileSystemTaskBase
{
public:
RemoveTask(FileSystemBase* aFileSystem,
const nsAString& aDirPath,
BlobImpl* aTargetBlob,
const nsAString& aTargetPath,
bool aRecursive,
ErrorResult& aRv);
RemoveTask(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<RemoveTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aDirPath,
BlobImpl* aTargetBlob,
nsIFile* aTargetPath,
bool aRecursive,
ErrorResult& aRv);
static already_AddRefed<RemoveTask>
Create(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~RemoveTask();
@ -42,13 +45,15 @@ public:
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@ -57,12 +62,23 @@ protected:
HandlerCallback() override;
private:
RemoveTask(FileSystemBase* aFileSystem,
nsIFile* aDirPath,
BlobImpl* aTargetBlob,
nsIFile* aTargetPath,
bool aRecursive);
RemoveTask(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent);
RefPtr<Promise> mPromise;
nsString mDirRealPath;
nsCOMPtr<nsIFile> mDirPath;
// This cannot be a File because this object will be used on a different
// thread and File is not thread-safe. Let's use the BlobImpl instead.
RefPtr<BlobImpl> mTargetBlobImpl;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
bool mRecursive;
bool mReturnValue;
};

Просмотреть файл

@ -251,16 +251,63 @@ class HTMLInputElementState final : public nsISupports
mValue = aValue;
}
const nsTArray<RefPtr<BlobImpl>>& GetBlobImpls()
void
GetFilesOrDirectories(nsPIDOMWindowInner* aWindow,
nsTArray<OwningFileOrDirectory>& aResult) const
{
return mBlobImpls;
for (uint32_t i = 0; i < mBlobImplsOrDirectoryPaths.Length(); ++i) {
if (mBlobImplsOrDirectoryPaths[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl) {
RefPtr<File> file =
File::Create(aWindow,
mBlobImplsOrDirectoryPaths[i].mBlobImpl);
MOZ_ASSERT(file);
OwningFileOrDirectory* element = aResult.AppendElement();
element->SetAsFile() = file;
} else {
MOZ_ASSERT(mBlobImplsOrDirectoryPaths[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath);
nsCOMPtr<nsIFile> file;
NS_ConvertUTF16toUTF8 path(mBlobImplsOrDirectoryPaths[i].mDirectoryPath);
nsresult rv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
RefPtr<Directory> directory = Directory::Create(aWindow, file,
Directory::eDOMRootDirectory);
MOZ_ASSERT(directory);
OwningFileOrDirectory* element = aResult.AppendElement();
element->SetAsDirectory() = directory;
}
}
}
void SetBlobImpls(const nsTArray<RefPtr<File>>& aFile)
void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aArray)
{
mBlobImpls.Clear();
for (uint32_t i = 0, len = aFile.Length(); i < len; ++i) {
mBlobImpls.AppendElement(aFile[i]->Impl());
mBlobImplsOrDirectoryPaths.Clear();
for (uint32_t i = 0; i < aArray.Length(); ++i) {
if (aArray[i].IsFile()) {
Directory::BlobImplOrDirectoryPath* data =
mBlobImplsOrDirectoryPaths.AppendElement();
data->mBlobImpl = aArray[i].GetAsFile()->Impl();
data->mType = Directory::BlobImplOrDirectoryPath::eBlobImpl;
} else {
MOZ_ASSERT(aArray[i].IsDirectory());
nsAutoString fullPath;
nsresult rv = aArray[i].GetAsDirectory()->GetFullRealPath(fullPath);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
Directory::BlobImplOrDirectoryPath* data =
mBlobImplsOrDirectoryPaths.AppendElement();
data->mDirectoryPath = fullPath;
data->mType = Directory::BlobImplOrDirectoryPath::eDirectoryPath;
}
}
}
@ -274,7 +321,9 @@ class HTMLInputElementState final : public nsISupports
~HTMLInputElementState() {}
nsString mValue;
nsTArray<RefPtr<BlobImpl>> mBlobImpls;
nsTArray<Directory::BlobImplOrDirectoryPath> mBlobImplsOrDirectoryPaths;
bool mChecked;
bool mCheckedSet;
};
@ -340,33 +389,65 @@ UploadLastDir::ContentPrefCallback::HandleError(nsresult error)
namespace {
/**
* This may return nullptr if aDomFile's implementation of
* This may return nullptr if the DOM File's implementation of
* File::mozFullPathInternal does not successfully return a non-empty
* string that is a valid path. This can happen on Firefox OS, for example,
* where the file picker can create Blobs.
*/
static already_AddRefed<nsIFile>
DOMFileToLocalFile(File* aDomFile)
DOMFileOrDirectoryToLocalFile(const OwningFileOrDirectory& aData)
{
nsString path;
ErrorResult rv;
aDomFile->GetMozFullPathInternal(path, rv);
if (rv.Failed() || path.IsEmpty()) {
rv.SuppressException();
return nullptr;
if (aData.IsFile()) {
ErrorResult rv;
aData.GetAsFile()->GetMozFullPathInternal(path, rv);
if (rv.Failed() || path.IsEmpty()) {
rv.SuppressException();
return nullptr;
}
} else {
MOZ_ASSERT(aData.IsDirectory());
aData.GetAsDirectory()->GetFullRealPath(path);
}
nsCOMPtr<nsIFile> localFile;
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
getter_AddRefs(localFile));
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
getter_AddRefs(localFile));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return localFile.forget();
}
void
GetDOMFileOrDirectoryName(const OwningFileOrDirectory& aData,
nsAString& aName)
{
if (aData.IsFile()) {
aData.GetAsFile()->GetName(aName);
} else {
MOZ_ASSERT(aData.IsDirectory());
ErrorResult rv;
aData.GetAsDirectory()->GetName(aName, rv);
NS_WARN_IF(rv.Failed());
}
}
void
GetDOMFileOrDirectoryPath(const OwningFileOrDirectory& aData,
nsAString& aPath,
ErrorResult& aRv)
{
if (aData.IsFile()) {
aData.GetAsFile()->GetMozFullPathInternal(aPath, aRv);
} else {
MOZ_ASSERT(aData.IsDirectory());
aData.GetAsDirectory()->GetFullRealPath(aPath);
}
}
} // namespace
@ -383,7 +464,7 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
mFilePicker->GetMode(&mode);
// Collect new selected filenames
nsTArray<RefPtr<File>> newFiles;
nsTArray<OwningFileOrDirectory> newFilesOrDirectories;
if (mode == static_cast<int16_t>(nsIFilePicker::modeOpenMultiple)) {
nsCOMPtr<nsISimpleEnumerator> iter;
nsresult rv =
@ -402,9 +483,12 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(tmp);
MOZ_ASSERT(domBlob,
"Null file object from FilePicker's file enumerator?");
if (domBlob) {
newFiles.AppendElement(static_cast<File*>(domBlob.get()));
if (!domBlob) {
continue;
}
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
element->SetAsFile() = static_cast<File*>(domBlob.get());
}
} else {
MOZ_ASSERT(mode == static_cast<int16_t>(nsIFilePicker::modeOpen) ||
@ -416,16 +500,25 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(tmp);
if (blob) {
RefPtr<File> file = static_cast<Blob*>(blob.get())->ToFile();
newFiles.AppendElement(file);
MOZ_ASSERT(file);
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
element->SetAsFile() = file;
} else if (tmp) {
RefPtr<Directory> directory = static_cast<Directory*>(tmp.get());
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
element->SetAsDirectory() = directory;
}
}
if (newFiles.IsEmpty()) {
if (newFilesOrDirectories.IsEmpty()) {
return NS_OK;
}
// Store the last used directory using the content pref service:
nsCOMPtr<nsIFile> file = DOMFileToLocalFile(newFiles[0]);
nsCOMPtr<nsIFile> file =
DOMFileOrDirectoryToLocalFile(newFilesOrDirectories[0]);
if (file) {
nsCOMPtr<nsIFile> lastUsedDir;
file->GetParent(getter_AddRefs(lastUsedDir));
@ -436,7 +529,7 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
// The text control frame (if there is one) isn't going to send a change
// event because it will think this is done by a script.
// So, we can safely send one by ourself.
mInput->SetFiles(newFiles, true);
mInput->SetFilesOrDirectories(newFilesOrDirectories, true);
return nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
NS_LITERAL_STRING("change"), true,
@ -672,7 +765,8 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
// Set default directry and filename
nsAutoString defaultName;
const nsTArray<RefPtr<File>>& oldFiles = GetFilesInternal();
const nsTArray<OwningFileOrDirectory>& oldFiles =
GetFilesOrDirectoriesInternal();
nsCOMPtr<nsIFilePickerShownCallback> callback =
new HTMLInputElement::nsFilePickerShownCallback(this, filePicker);
@ -681,18 +775,10 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
aType != FILE_PICKER_DIRECTORY) {
nsString path;
ErrorResult error;
oldFiles[0]->GetMozFullPathInternal(path, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
nsCOMPtr<nsIFile> localFile;
rv = NS_NewLocalFile(path, false, getter_AddRefs(localFile));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIFile> localFile = DOMFileOrDirectoryToLocalFile(oldFiles[0]);
if (localFile) {
nsCOMPtr<nsIFile> parentFile;
rv = localFile->GetParent(getter_AddRefs(parentFile));
nsresult rv = localFile->GetParent(getter_AddRefs(parentFile));
if (NS_SUCCEEDED(rv)) {
filePicker->SetDisplayDirectory(parentFile);
}
@ -703,7 +789,8 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
// one file was selected before.
if (oldFiles.Length() == 1) {
nsAutoString leafName;
oldFiles[0]->GetName(leafName);
GetDOMFileOrDirectoryName(oldFiles[0], leafName);
if (!leafName.IsEmpty()) {
filePicker->SetDefaultString(leafName);
}
@ -756,7 +843,7 @@ UploadLastDir::FetchDirectoryAndDisplayPicker(nsIDocument* aDoc,
NS_PRECONDITION(docURI, "docURI is null");
nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
nsCOMPtr<nsIContentPrefCallback2> prefCallback =
nsCOMPtr<nsIContentPrefCallback2> prefCallback =
new UploadLastDir::ContentPrefCallback(aFilePicker, aFpCallback);
#ifdef MOZ_B2G
@ -935,7 +1022,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement,
if (tmp->IsSingleLineTextControl(false)) {
tmp->mInputData.mState->Traverse(cb);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesOrDirectories)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesAndDirectoriesPromise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -944,7 +1031,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
nsGenericHTMLFormElementWithState)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesOrDirectories)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesAndDirectoriesPromise)
if (tmp->IsSingleLineTextControl(false)) {
@ -1003,8 +1090,8 @@ HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) co
// we can just grab the pretty string and use it as wallpaper
GetDisplayFileName(it->mStaticDocFileList);
} else {
it->mFiles.Clear();
it->mFiles.AppendElements(mFiles);
it->mFilesOrDirectories.Clear();
it->mFilesOrDirectories.AppendElements(mFilesOrDirectories);
}
break;
case VALUE_MODE_DEFAULT_ON:
@ -1442,9 +1529,9 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const
#else
// XXX We'd love to assert that this can't happen, but some mochitests
// use SpecialPowers to circumvent our more sane security model.
if (!mFiles.IsEmpty()) {
if (!mFilesOrDirectories.IsEmpty()) {
ErrorResult rv;
mFiles[0]->GetMozFullPath(aValue, rv);
GetDOMFileOrDirectoryPath(mFilesOrDirectories[0], aValue, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
@ -1456,10 +1543,10 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const
#endif
} else {
// Just return the leaf name
if (mFiles.IsEmpty()) {
if (mFilesOrDirectories.IsEmpty()) {
aValue.Truncate();
} else {
mFiles[0]->GetName(aValue);
GetDOMFileOrDirectoryName(mFilesOrDirectories[0], aValue);
}
}
@ -1494,8 +1581,8 @@ HTMLInputElement::IsValueEmpty() const
void
HTMLInputElement::ClearFiles(bool aSetValueChanged)
{
nsTArray<RefPtr<File>> files;
SetFiles(files, aSetValueChanged);
nsTArray<OwningFileOrDirectory> data;
SetFilesOrDirectories(data, aSetValueChanged);
}
/* static */ Decimal
@ -2065,9 +2152,9 @@ void
HTMLInputElement::MozGetFileNameArray(nsTArray<nsString>& aArray,
ErrorResult& aRv)
{
for (uint32_t i = 0; i < mFiles.Length(); i++) {
nsString str;
mFiles[i]->GetMozFullPathInternal(str, aRv);
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); i++) {
nsAutoString str;
GetDOMFileOrDirectoryPath(mFilesOrDirectories[i], str, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@ -2117,25 +2204,29 @@ HTMLInputElement::MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles)
if (!global) {
return;
}
nsTArray<RefPtr<File>> files;
nsTArray<OwningFileOrDirectory> files;
for (uint32_t i = 0; i < aFiles.Length(); ++i) {
RefPtr<File> file = File::Create(global, aFiles[i].get()->Impl());
MOZ_ASSERT(file);
files.AppendElement(file);
OwningFileOrDirectory* element = files.AppendElement();
element->SetAsFile() = file;
}
SetFiles(files, true);
SetFilesOrDirectories(files, true);
}
void
HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv)
HTMLInputElement::MozSetFileNameArray(const Sequence<nsString>& aFileNames,
ErrorResult& aRv)
{
if (XRE_IsContentProcess()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
nsTArray<RefPtr<File>> files;
nsTArray<OwningFileOrDirectory> files;
for (uint32_t i = 0; i < aFileNames.Length(); ++i) {
nsCOMPtr<nsIFile> file;
@ -2152,21 +2243,28 @@ HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames, Er
NS_NewLocalFile(aFileNames[i], false, getter_AddRefs(file));
}
if (file) {
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
RefPtr<File> domFile = File::CreateFromFile(global, file);
files.AppendElement(domFile);
} else {
if (!file) {
continue; // Not much we can do if the file doesn't exist
}
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
if (!global) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
RefPtr<File> domFile = File::CreateFromFile(global, file);
OwningFileOrDirectory* element = files.AppendElement();
element->SetAsFile() = domFile;
}
SetFiles(files, true);
SetFilesOrDirectories(files, true);
}
NS_IMETHODIMP
HTMLInputElement::MozSetFileNameArray(const char16_t** aFileNames, uint32_t aLength)
HTMLInputElement::MozSetFileNameArray(const char16_t** aFileNames,
uint32_t aLength)
{
if (!nsContentUtils::IsCallerChrome()) {
// setting the value of a "FILE" input widget requires chrome privilege
@ -2379,14 +2477,14 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
return;
}
if (mFiles.Length() == 1) {
mFiles[0]->GetName(aValue);
if (mFilesOrDirectories.Length() == 1) {
GetDOMFileOrDirectoryName(mFilesOrDirectories[0], aValue);
return;
}
nsXPIDLString value;
if (mFiles.IsEmpty()) {
if (mFilesOrDirectories.IsEmpty()) {
if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
"NoFilesSelected", value);
@ -2396,7 +2494,7 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
}
} else {
nsString count;
count.AppendInt(int(mFiles.Length()));
count.AppendInt(int(mFilesOrDirectories.Length()));
const char16_t* params[] = { count.get() };
nsContentUtils::FormatLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
@ -2407,13 +2505,13 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
}
void
HTMLInputElement::SetFiles(const nsTArray<RefPtr<File>>& aFiles,
bool aSetValueChanged)
HTMLInputElement::SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories,
bool aSetValueChanged)
{
mFiles.Clear();
mFiles.AppendElements(aFiles);
mFilesOrDirectories.Clear();
mFilesOrDirectories.AppendElements(aFilesOrDirectories);
AfterSetFiles(aSetValueChanged);
AfterSetFilesOrDirectories(aSetValueChanged);
}
void
@ -2421,22 +2519,24 @@ HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
bool aSetValueChanged)
{
RefPtr<FileList> files = static_cast<FileList*>(aFiles);
mFiles.Clear();
mFilesOrDirectories.Clear();
if (aFiles) {
uint32_t listLength;
aFiles->GetLength(&listLength);
for (uint32_t i = 0; i < listLength; i++) {
RefPtr<File> file = files->Item(i);
mFiles.AppendElement(file);
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
element->SetAsFile() = file;
}
}
AfterSetFiles(aSetValueChanged);
AfterSetFilesOrDirectories(aSetValueChanged);
}
void
HTMLInputElement::AfterSetFiles(bool aSetValueChanged)
HTMLInputElement::AfterSetFilesOrDirectories(bool aSetValueChanged)
{
// No need to flush here, if there's no frame at this point we
// don't need to force creation of one just to tell it about this
@ -2454,11 +2554,11 @@ HTMLInputElement::AfterSetFiles(bool aSetValueChanged)
// call under GetMozFullPath won't be rejected for not being urgent.
// XXX Protected by the ifndef because the blob code doesn't allow us to send
// this message in b2g.
if (mFiles.IsEmpty()) {
if (mFilesOrDirectories.IsEmpty()) {
mFirstFilePath.Truncate();
} else {
ErrorResult rv;
mFiles[0]->GetMozFullPath(mFirstFilePath, rv);
GetDOMFileOrDirectoryPath(mFilesOrDirectories[0], mFirstFilePath, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
@ -2538,9 +2638,11 @@ HTMLInputElement::UpdateFileList()
if (mFileList) {
mFileList->Clear();
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
for (uint32_t i = 0; i < files.Length(); ++i) {
if (!mFileList->Append(files[i])) {
const nsTArray<OwningFileOrDirectory>& array =
GetFilesOrDirectoriesInternal();
for (uint32_t i = 0; i < array.Length(); ++i) {
if (array[i].IsFile() && !mFileList->Append(array[i].GetAsFile())) {
return NS_ERROR_FAILURE;
}
}
@ -3988,7 +4090,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
nsNumberControlFrame* numberControlFrame =
do_QueryFrame(GetPrimaryFrame());
if (numberControlFrame) {
if (aVisitor.mEvent->mMessage == eMouseDown &&
if (aVisitor.mEvent->mMessage == eMouseDown &&
IsMutable()) {
switch (numberControlFrame->GetSpinButtonForPointerEvent(
aVisitor.mEvent->AsMouseEvent())) {
@ -4539,7 +4641,7 @@ HTMLInputElement::GetValueAsDate(const nsAString& aValue,
}
uint32_t endOfYearOffset = aValue.Length() - 6;
if (aValue[endOfYearOffset] != '-' ||
aValue[endOfYearOffset + 3] != '-') {
return false;
@ -4907,45 +5009,38 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
return nullptr;
}
const nsTArray<RefPtr<File>>& filesAndDirs = GetFilesInternal();
const nsTArray<OwningFileOrDirectory>& filesAndDirs =
GetFilesOrDirectoriesInternal();
Sequence<OwningFileOrDirectory> filesAndDirsSeq;
if (!filesAndDirsSeq.SetLength(filesAndDirs.Length(), mozilla::fallible_t())) {
if (!filesAndDirsSeq.SetLength(filesAndDirs.Length(),
mozilla::fallible_t())) {
p->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
return p.forget();
}
for (uint32_t i = 0; i < filesAndDirs.Length(); ++i) {
if (filesAndDirs[i]->IsDirectory()) {
if (filesAndDirs[i].IsDirectory()) {
#if defined(ANDROID) || defined(MOZ_B2G)
MOZ_ASSERT(false,
"Directory picking should have been redirected to normal "
"file picking for platforms that don't have a directory "
"picker");
#endif
nsAutoString path;
filesAndDirs[i]->GetMozFullPathInternal(path, aRv);
if (aRv.Failed()) {
return nullptr;
}
int32_t leafSeparatorIndex = path.RFind(FILE_PATH_SEPARATOR);
nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex);
RefPtr<OSFileSystem> fs = new OSFileSystem(dirname);
fs->Init(OwnerDoc()->GetInnerWindow());
RefPtr<Directory> directory = filesAndDirs[i].GetAsDirectory();
nsAutoString dompath(NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR));
dompath.Append(Substring(path, leafSeparatorIndex + 1));
RefPtr<Directory> directory = new Directory(fs, dompath);
// In future we could refactor SetFilePickerFiltersFromAccept to return a
// semicolon separated list of file extensions and include that in the
// filter string passed here.
directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive"));
filesAndDirsSeq[i].SetAsDirectory() = directory;
} else {
MOZ_ASSERT(filesAndDirs[i].IsFile());
// This file was directly selected by the user, so don't filter it.
filesAndDirsSeq[i].SetAsFile() = filesAndDirs[i];
filesAndDirsSeq[i].SetAsFile() = filesAndDirs[i].GetAsFile();
}
}
@ -5579,13 +5674,18 @@ HTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
if (mType == NS_FORM_INPUT_FILE) {
// Submit files
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
const nsTArray<OwningFileOrDirectory>& files =
GetFilesOrDirectoriesInternal();
bool hasBlobs = false;
for (uint32_t i = 0; i < files.Length(); ++i) {
aFormSubmission->AddNameBlobOrNullPair(name, files[i]);
if (files[i].IsFile()) {
hasBlobs = true;
aFormSubmission->AddNameBlobOrNullPair(name, files[i].GetAsFile());
}
}
if (files.IsEmpty()) {
if (!hasBlobs) {
aFormSubmission->AddNameBlobOrNullPair(name, nullptr);
}
@ -5619,9 +5719,9 @@ HTMLInputElement::SaveState()
}
break;
case VALUE_MODE_FILENAME:
if (!mFiles.IsEmpty()) {
if (!mFilesOrDirectories.IsEmpty()) {
inputState = new HTMLInputElementState();
inputState->SetBlobImpls(mFiles);
inputState->SetFilesOrDirectories(mFilesOrDirectories);
}
break;
case VALUE_MODE_VALUE:
@ -5790,7 +5890,7 @@ HTMLInputElement::AddStates(EventStates aStates)
}
}
}
nsGenericHTMLFormElementWithState::AddStates(aStates);
nsGenericHTMLFormElementWithState::AddStates(aStates);
}
void
@ -5827,20 +5927,13 @@ HTMLInputElement::RestoreState(nsPresState* aState)
break;
case VALUE_MODE_FILENAME:
{
const nsTArray<RefPtr<BlobImpl>>& blobImpls = inputState->GetBlobImpls();
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
if (window) {
nsTArray<OwningFileOrDirectory> array;
inputState->GetFilesOrDirectories(window, array);
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
MOZ_ASSERT(global);
nsTArray<RefPtr<File>> files;
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
RefPtr<File> file = File::Create(global, blobImpls[i]);
MOZ_ASSERT(file);
files.AppendElement(file);
SetFilesOrDirectories(array, true);
}
SetFiles(files, true);
}
break;
case VALUE_MODE_VALUE:
@ -6350,15 +6443,15 @@ HTMLInputElement::IsValueMissing() const
switch (GetValueMode()) {
case VALUE_MODE_VALUE:
return IsValueEmpty();
case VALUE_MODE_FILENAME:
{
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
return files.IsEmpty();
}
return GetFilesOrDirectoriesInternal().IsEmpty();
case VALUE_MODE_DEFAULT_ON:
// This should not be used for type radio.
// See the MOZ_ASSERT at the beginning of the method.
return !mChecked;
case VALUE_MODE_DEFAULT:
default:
return false;

Просмотреть файл

@ -20,6 +20,7 @@
#include "mozilla/dom/HTMLFormElement.h" // for HasEverTriedInvalidSubmit()
#include "mozilla/dom/HTMLInputElementBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/UnionTypes.h"
#include "nsIFilePicker.h"
#include "nsIContentPrefService2.h"
#include "mozilla/Decimal.h"
@ -220,12 +221,13 @@ public:
void GetDisplayFileName(nsAString& aFileName) const;
const nsTArray<RefPtr<File>>& GetFilesInternal() const
const nsTArray<OwningFileOrDirectory>& GetFilesOrDirectoriesInternal() const
{
return mFiles;
return mFilesOrDirectories;
}
void SetFiles(const nsTArray<RefPtr<File>>& aFiles, bool aSetValueChanged);
void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories,
bool aSetValueChanged);
void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
// Called when a nsIFilePicker or a nsIColorPicker terminate.
@ -925,9 +927,9 @@ protected:
nsresult UpdateFileList();
/**
* Called after calling one of the SetFiles() functions.
* Called after calling one of the SetFilesOrDirectories() functions.
*/
void AfterSetFiles(bool aSetValueChanged);
void AfterSetFilesOrDirectories(bool aSetValueChanged);
/**
* Determine whether the editor needs to be initialized explicitly for
@ -1266,16 +1268,16 @@ protected:
} mInputData;
/**
* The value of the input if it is a file input. This is the list of filenames
* used when uploading a file. It is vital that this is kept separate from
* mValue so that it won't be possible to 'leak' the value from a text-input
* to a file-input. Additionally, the logic for this value is kept as simple
* as possible to avoid accidental errors where the wrong filename is used.
* Therefor the list of filenames is always owned by this member, never by
* the frame. Whenever the frame wants to change the filename it has to call
* SetFileNames to update this member.
* The value of the input if it is a file input. This is the list of files or
* directories DOM objects used when uploading a file. It is vital that this
* is kept separate from mValue so that it won't be possible to 'leak' the
* value from a text-input to a file-input. Additionally, the logic for this
* value is kept as simple as possible to avoid accidental errors where the
* wrong filename is used. Therefor the list of filenames is always owned by
* this member, never by the frame. Whenever the frame wants to change the
* filename it has to call SetFilesOrDirectories to update this member.
*/
nsTArray<RefPtr<File>> mFiles;
nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
#ifndef MOZ_CHILD_PERMISSIONS
/**

Просмотреть файл

@ -187,30 +187,6 @@ private:
return mBlobImpl->IsFile();
}
virtual void
LookupAndCacheIsDirectory() override
{
mBlobImpl->LookupAndCacheIsDirectory();
}
virtual void
SetIsDirectory(bool aIsDir) override
{
return mBlobImpl->SetIsDirectory(aIsDir);
}
virtual bool
IsDirectory() const override
{
return mBlobImpl->IsDirectory();
}
virtual BlobDirState
GetDirState() const override
{
return mBlobImpl->GetDirState();
}
virtual bool
MayBeClonedToOtherThreads() const override
{

Просмотреть файл

@ -444,8 +444,7 @@ ResolveMysteryFile(BlobImpl* aImpl,
BlobChild* actor = ActorFromRemoteBlobImpl(aImpl);
if (actor) {
return actor->SetMysteryBlobInfo(aName, aContentType,
aSize, aLastModifiedDate,
BlobDirState::eUnknownIfDir);
aSize, aLastModifiedDate);
}
return true;
}

Просмотреть файл

@ -670,8 +670,7 @@ public:
EmptyBlobImpl(const nsAString& aName,
const nsAString& aContentType,
int64_t aLastModifiedDate)
: BlobImplBase(aName, aContentType, 0, aLastModifiedDate,
BlobDirState::eIsNotDir)
: BlobImplBase(aName, aContentType, 0, aLastModifiedDate)
{
mImmutable = true;
}
@ -716,14 +715,12 @@ struct MOZ_STACK_CLASS CreateBlobImplMetadata final
nsString mName;
uint64_t mLength;
int64_t mLastModifiedDate;
BlobDirState mDirState;
bool mHasRecursed;
const bool mIsSameProcessActor;
explicit CreateBlobImplMetadata(bool aIsSameProcessActor)
: mLength(0)
, mLastModifiedDate(0)
, mDirState(BlobDirState::eUnknownIfDir)
, mHasRecursed(false)
, mIsSameProcessActor(aIsSameProcessActor)
{
@ -965,7 +962,6 @@ CreateBlobImpl(const ParentBlobConstructorParams& aParams,
metadata.mName = params.name();
metadata.mLength = params.length();
metadata.mLastModifiedDate = params.modDate();
metadata.mDirState = BlobDirState(params.dirState());
}
RefPtr<BlobImpl> blobImpl =
@ -1775,7 +1771,6 @@ public:
const nsAString& aContentType,
uint64_t aLength,
int64_t aModDate,
BlobDirState aDirState,
bool aIsSameProcessBlob);
// For Blob.
@ -2053,18 +2048,6 @@ public:
virtual bool
IsFile() const override;
virtual void
LookupAndCacheIsDirectory() override;
virtual void
SetIsDirectory(bool aIsDir) override;
virtual bool
IsDirectory() const override;
virtual BlobDirState
GetDirState() const override;
virtual bool
MayBeClonedToOtherThreads() const override;
@ -2096,9 +2079,8 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
const nsAString& aContentType,
uint64_t aLength,
int64_t aModDate,
BlobDirState aDirState,
bool aIsSameProcessBlob)
: BlobImplBase(aName, aContentType, aLength, aModDate, aDirState)
: BlobImplBase(aName, aContentType, aLength, aModDate)
, mIsSlice(false)
{
if (aIsSameProcessBlob) {
@ -2814,34 +2796,6 @@ RemoteBlobImpl::IsFile() const
return mBlobImpl->IsFile();
}
void
BlobParent::
RemoteBlobImpl::LookupAndCacheIsDirectory()
{
return mBlobImpl->LookupAndCacheIsDirectory();
}
void
BlobParent::
RemoteBlobImpl::SetIsDirectory(bool aIsDir)
{
return mBlobImpl->SetIsDirectory(aIsDir);
}
bool
BlobParent::
RemoteBlobImpl::IsDirectory() const
{
return mBlobImpl->IsDirectory();
}
BlobDirState
BlobParent::
RemoteBlobImpl::GetDirState() const
{
return mBlobImpl->GetDirState();
}
bool
BlobParent::
RemoteBlobImpl::MayBeClonedToOtherThreads() const
@ -3033,8 +2987,7 @@ BlobChild::CommonInit(BlobChild* aOther, BlobImpl* aBlobImpl)
MOZ_ASSERT(!rv.Failed());
remoteBlob = new RemoteBlobImpl(this, otherImpl, name, contentType, length,
modDate, otherImpl->GetDirState(),
false /* SameProcessBlobImpl */);
modDate, false /* SameProcessBlobImpl */);
} else {
remoteBlob = new RemoteBlobImpl(this, otherImpl, contentType, length,
false /* SameProcessBlobImpl */);
@ -3086,7 +3039,6 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
params.contentType(),
params.length(),
params.modDate(),
BlobDirState(params.dirState()),
false /* SameProcessBlobImpl */);
break;
}
@ -3122,7 +3074,6 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
contentType,
size,
lastModifiedDate,
blobImpl->GetDirState(),
true /* SameProcessBlobImpl */);
} else {
remoteBlob = new RemoteBlobImpl(this, blobImpl, contentType, size,
@ -3303,8 +3254,7 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
MOZ_ASSERT(!rv.Failed());
blobParams =
FileBlobConstructorParams(name, contentType, length, modDate,
aBlobImpl->GetDirState(), blobData);
FileBlobConstructorParams(name, contentType, length, modDate, blobData);
} else {
blobParams = NormalBlobConstructorParams(contentType, length, blobData);
}
@ -3477,8 +3427,7 @@ bool
BlobChild::SetMysteryBlobInfo(const nsString& aName,
const nsString& aContentType,
uint64_t aLength,
int64_t aLastModifiedDate,
BlobDirState aDirState)
int64_t aLastModifiedDate)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mBlobImpl);
@ -3491,7 +3440,6 @@ BlobChild::SetMysteryBlobInfo(const nsString& aName,
aContentType,
aLength,
aLastModifiedDate,
aDirState,
void_t() /* optionalBlobData */);
return SendResolveMystery(params);
}
@ -3854,7 +3802,7 @@ BlobParent::GetOrCreateFromImpl(ParentManagerType* aManager,
blobParams =
FileBlobConstructorParams(name, contentType, length, modDate,
aBlobImpl->GetDirState(), void_t());
void_t());
} else {
blobParams = NormalBlobConstructorParams(contentType, length, void_t());
}

Просмотреть файл

@ -31,8 +31,6 @@ class ContentChild;
class nsIContentChild;
class PBlobStreamChild;
enum BlobDirState : uint32_t;
class BlobChild final
: public PBlobChild
{
@ -117,8 +115,7 @@ public:
SetMysteryBlobInfo(const nsString& aName,
const nsString& aContentType,
uint64_t aLength,
int64_t aLastModifiedDate,
BlobDirState aDirState);
int64_t aLastModifiedDate);
// Use this for non-file blobs.
bool

Просмотреть файл

@ -73,7 +73,6 @@ struct FileBlobConstructorParams
nsString contentType;
uint64_t length;
int64_t modDate;
uint32_t dirState;
// This must be of type BlobData in a child->parent message, and will always
// be of type void_t in a parent->child message.

Просмотреть файл

@ -53,15 +53,18 @@ FilePickerParent::~FilePickerParent()
// 2. The stream transport thread stat()s the file in Run() and then dispatches
// the same runnable on the main thread.
// 3. The main thread sends the results over IPC.
FilePickerParent::FileSizeAndDateRunnable::FileSizeAndDateRunnable(FilePickerParent *aFPParent,
nsTArray<RefPtr<BlobImpl>>& aBlobs)
FilePickerParent::IORunnable::IORunnable(FilePickerParent *aFPParent,
nsTArray<nsCOMPtr<nsIFile>>& aFiles,
bool aIsDirectory)
: mFilePickerParent(aFPParent)
, mIsDirectory(aIsDirectory)
{
mBlobs.SwapElements(aBlobs);
mFiles.SwapElements(aFiles);
MOZ_ASSERT_IF(aIsDirectory, mFiles.Length() == 1);
}
bool
FilePickerParent::FileSizeAndDateRunnable::Dispatch()
FilePickerParent::IORunnable::Dispatch()
{
MOZ_ASSERT(NS_IsMainThread());
@ -75,23 +78,49 @@ FilePickerParent::FileSizeAndDateRunnable::Dispatch()
}
NS_IMETHODIMP
FilePickerParent::FileSizeAndDateRunnable::Run()
FilePickerParent::IORunnable::Run()
{
// If we're on the main thread, then that means we're done. Just send the
// results.
if (NS_IsMainThread()) {
if (mFilePickerParent) {
mFilePickerParent->SendFiles(mBlobs);
mFilePickerParent->SendFilesOrDirectories(mResults);
}
return NS_OK;
}
// We're not on the main thread, so do the stat().
for (unsigned i = 0; i < mBlobs.Length(); i++) {
ErrorResult rv;
mBlobs[i]->GetSize(rv);
mBlobs[i]->GetLastModified(rv);
mBlobs[i]->LookupAndCacheIsDirectory();
// We're not on the main thread, so do the IO.
for (uint32_t i = 0; i < mFiles.Length(); ++i) {
if (mIsDirectory) {
nsAutoString path;
nsresult rv = mFiles[i]->GetPath(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
BlobImplOrString* data = mResults.AppendElement();
data->mType = BlobImplOrString::eDirectoryPath;
data->mDirectoryPath = path;
continue;
}
RefPtr<BlobImpl> blobImpl = new BlobImplFile(mFiles[i]);
ErrorResult error;
blobImpl->GetSize(error);
if (NS_WARN_IF(error.Failed())) {
continue;
}
blobImpl->GetLastModified(error);
if (NS_WARN_IF(error.Failed())) {
continue;
}
BlobImplOrString* data = mResults.AppendElement();
data->mType = BlobImplOrString::eBlobImpl;
data->mBlobImpl = blobImpl;
}
// Dispatch ourselves back on the main thread.
@ -101,29 +130,46 @@ FilePickerParent::FileSizeAndDateRunnable::Run()
// thread.
MOZ_CRASH();
}
return NS_OK;
}
void
FilePickerParent::FileSizeAndDateRunnable::Destroy()
FilePickerParent::IORunnable::Destroy()
{
mFilePickerParent = nullptr;
}
void
FilePickerParent::SendFiles(const nsTArray<RefPtr<BlobImpl>>& aBlobs)
FilePickerParent::SendFilesOrDirectories(const nsTArray<BlobImplOrString>& aData)
{
if (mMode == nsIFilePicker::modeGetFolder) {
MOZ_ASSERT(aData.Length() <= 1);
if (aData.IsEmpty()) {
Unused << Send__delete__(this, void_t(), mResult);
return;
}
MOZ_ASSERT(aData[0].mType == BlobImplOrString::eDirectoryPath);
InputDirectory input;
input.directoryPath() = aData[0].mDirectoryPath;
Unused << Send__delete__(this, input, mResult);
return;
}
nsIContentParent* parent = TabParent::GetFrom(Manager())->Manager();
InfallibleTArray<PBlobParent*> blobs;
for (unsigned i = 0; i < aBlobs.Length(); i++) {
BlobParent* blobParent = parent->GetOrCreateActorForBlobImpl(aBlobs[i]);
for (unsigned i = 0; i < aData.Length(); i++) {
MOZ_ASSERT(aData[i].mType == BlobImplOrString::eBlobImpl);
BlobParent* blobParent = parent->GetOrCreateActorForBlobImpl(aData[i].mBlobImpl);
if (blobParent) {
blobs.AppendElement(blobParent);
}
}
InputFiles inblobs;
InputBlobs inblobs;
inblobs.blobsParent().SwapElements(blobs);
Unused << Send__delete__(this, inblobs, mResult);
}
@ -138,7 +184,7 @@ FilePickerParent::Done(int16_t aResult)
return;
}
nsTArray<RefPtr<BlobImpl>> blobs;
nsTArray<nsCOMPtr<nsIFile>> files;
if (mMode == nsIFilePicker::modeOpenMultiple) {
nsCOMPtr<nsISimpleEnumerator> iter;
NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
@ -149,22 +195,26 @@ FilePickerParent::Done(int16_t aResult)
iter->GetNext(getter_AddRefs(supports));
if (supports) {
nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
RefPtr<BlobImpl> blobimpl = new BlobImplFile(file);
blobs.AppendElement(blobimpl);
MOZ_ASSERT(file);
files.AppendElement(file);
}
}
} else {
nsCOMPtr<nsIFile> file;
mFilePicker->GetFile(getter_AddRefs(file));
if (file) {
RefPtr<BlobImpl> blobimpl = new BlobImplFile(file);
blobs.AppendElement(blobimpl);
files.AppendElement(file);
}
}
if (files.IsEmpty()) {
Unused << Send__delete__(this, void_t(), mResult);
return;
}
MOZ_ASSERT(!mRunnable);
mRunnable = new FileSizeAndDateRunnable(this, blobs);
mRunnable = new IORunnable(this, files, mMode == nsIFilePicker::modeGetFolder);
// Dispatch to background thread to do I/O:
if (!mRunnable->Dispatch()) {
Unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);

Просмотреть файл

@ -14,6 +14,8 @@
#include "mozilla/dom/File.h"
#include "mozilla/dom/PFilePickerParent.h"
class nsIFile;
namespace mozilla {
namespace dom {
@ -29,7 +31,19 @@ class FilePickerParent : public PFilePickerParent
virtual ~FilePickerParent();
void Done(int16_t aResult);
void SendFiles(const nsTArray<RefPtr<BlobImpl>>& aDomBlobs);
struct BlobImplOrString
{
RefPtr<BlobImpl> mBlobImpl;
nsString mDirectoryPath;
enum {
eBlobImpl,
eDirectoryPath
} mType;
};
void SendFilesOrDirectories(const nsTArray<BlobImplOrString>& aData);
virtual bool RecvOpen(const int16_t& aSelectedType,
const bool& aAddToRecentDocs,
@ -61,21 +75,26 @@ class FilePickerParent : public PFilePickerParent
private:
bool CreateFilePicker();
class FileSizeAndDateRunnable : public nsRunnable
// This runnable is used to do some I/O operation on a separate thread.
class IORunnable : public nsRunnable
{
FilePickerParent* mFilePickerParent;
nsTArray<RefPtr<BlobImpl>> mBlobs;
nsTArray<nsCOMPtr<nsIFile>> mFiles;
nsTArray<BlobImplOrString> mResults;
nsCOMPtr<nsIEventTarget> mEventTarget;
bool mIsDirectory;
public:
FileSizeAndDateRunnable(FilePickerParent *aFPParent,
nsTArray<RefPtr<BlobImpl>>& aBlobs);
IORunnable(FilePickerParent *aFPParent,
nsTArray<nsCOMPtr<nsIFile>>& aFiles,
bool aIsDirectory);
bool Dispatch();
NS_IMETHOD Run();
void Destroy();
};
RefPtr<FileSizeAndDateRunnable> mRunnable;
RefPtr<IORunnable> mRunnable;
RefPtr<FilePickerShownCallback> mCallback;
nsCOMPtr<nsIFilePicker> mFilePicker;

Просмотреть файл

@ -289,6 +289,7 @@ struct FileSystemGetDirectoryListingParams
{
nsString filesystem;
nsString realPath;
bool isRoot;
// 'filters' could be an array rather than a semicolon separated string
// (we'd then use InfallibleTArray<nsString> internally), but that is
// wasteful. E10s requires us to pass the filters over as a string anyway,
@ -305,6 +306,7 @@ struct FileSystemGetFileOrDirectoryParams
{
nsString filesystem;
nsString realPath;
bool isRoot;
};
union FileSystemPathOrFileValue

Просмотреть файл

@ -12,14 +12,20 @@ using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace dom {
struct InputFiles
struct InputBlobs
{
PBlob[] blobs;
};
union MaybeInputFiles
struct InputDirectory
{
InputFiles;
nsString directoryPath;
};
union MaybeInputData
{
InputBlobs;
InputDirectory;
void_t;
};
@ -33,7 +39,7 @@ parent:
nsString displayDirectory);
child:
async __delete__(MaybeInputFiles files, int16_t result);
async __delete__(MaybeInputData data, int16_t result);
};
} // namespace dom

Просмотреть файл

@ -20,6 +20,7 @@ interface Directory {
/*
* The leaf name of the directory.
*/
[Throws]
readonly attribute DOMString name;
/*
@ -105,11 +106,13 @@ partial interface Directory {
* to obtain this Directory. Full filesystem paths are not exposed to
* unprivilaged content.
*/
[Throws]
readonly attribute DOMString path;
/*
* Getter for the immediate children of this directory.
*/
[Throws]
Promise<sequence<(File or Directory)>> getFilesAndDirectories();
};

Просмотреть файл

@ -17,6 +17,7 @@
#include "nsCOMArray.h"
#include "nsIFile.h"
#include "nsEnumeratorUtils.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/File.h"
#include "mozilla/Services.h"
#include "WidgetUtils.h"
@ -30,6 +31,36 @@ using namespace mozilla::dom;
#define FILEPICKER_TITLES "chrome://global/locale/filepicker.properties"
#define FILEPICKER_FILTERS "chrome://global/content/filepicker.properties"
namespace {
nsresult
LocalFileToDirectoryOrBlob(nsPIDOMWindowInner* aWindow,
bool aIsDirectory,
nsIFile* aFile,
nsISupports** aResult)
{
if (aIsDirectory) {
#ifdef DEBUG
bool isDir;
aFile->IsDirectory(&isDir);
MOZ_ASSERT(isDir);
#endif
RefPtr<Directory> directory =
Directory::Create(aWindow, aFile, Directory::eDOMRootDirectory);
MOZ_ASSERT(directory);
directory.forget(aResult);
return NS_OK;
}
nsCOMPtr<nsIDOMBlob> blob = File::CreateFromFile(aWindow, aFile);
blob.forget(aResult);
return NS_OK;
}
} // anonymous namespace
/**
* A runnable to dispatch from the main thread to the main thread to display
* the file picker while letting the showAsync method return right away.
@ -74,9 +105,9 @@ class nsBaseFilePickerEnumerator : public nsISimpleEnumerator
public:
NS_DECL_ISUPPORTS
explicit nsBaseFilePickerEnumerator(nsPIDOMWindowOuter* aParent,
nsISimpleEnumerator* iterator,
int16_t aMode)
nsBaseFilePickerEnumerator(nsPIDOMWindowOuter* aParent,
nsISimpleEnumerator* iterator,
int16_t aMode)
: mIterator(iterator)
, mParent(aParent->GetCurrentInnerWindow())
, mMode(aMode)
@ -98,32 +129,10 @@ public:
return NS_ERROR_FAILURE;
}
RefPtr<File> domFile = File::CreateFromFile(mParent, localFile);
// Right now we're on the main thread of the chrome process. We need
// to call SetIsDirectory on the BlobImpl, but it's preferable not to
// call nsIFile::IsDirectory to determine what argument to pass since
// IsDirectory does synchronous I/O. It's true that since we've just
// been called synchronously directly after nsIFilePicker::Show blocked
// the main thread while the picker was being shown and the OS did file
// system access, doing more I/O to stat the selected files probably
// wouldn't be the end of the world. However, we can simply check
// mMode and avoid calling IsDirectory.
//
// In future we may take advantage of OS X's ability to allow both
// files and directories to be picked at the same time, so we do assert
// in debug builds that the mMode trick produces the correct results.
// If we do add that support maybe it's better to use IsDirectory
// directly, but in an nsRunnable punted off to a background thread.
#ifdef DEBUG
bool isDir;
localFile->IsDirectory(&isDir);
MOZ_ASSERT(isDir == (mMode == nsIFilePicker::modeGetFolder));
#endif
domFile->Impl()->SetIsDirectory(mMode == nsIFilePicker::modeGetFolder);
nsCOMPtr<nsIDOMBlob>(domFile).forget(aResult);
return NS_OK;
return LocalFileToDirectoryOrBlob(mParent,
mMode == nsIFilePicker::modeGetFolder,
localFile,
aResult);
}
NS_IMETHOD
@ -349,10 +358,10 @@ nsBaseFilePicker::GetDomFileOrDirectory(nsISupports** aValue)
auto* innerParent = mParent ? mParent->GetCurrentInnerWindow() : nullptr;
RefPtr<File> domFile = File::CreateFromFile(innerParent, localFile);
domFile->Impl()->SetIsDirectory(mMode == nsIFilePicker::modeGetFolder);
nsCOMPtr<nsIDOMBlob>(domFile).forget(aValue);
return NS_OK;
return LocalFileToDirectoryOrBlob(innerParent,
mMode == nsIFilePicker::modeGetFolder,
localFile,
aValue);
}
NS_IMETHODIMP

Просмотреть файл

@ -7,6 +7,7 @@
#include "nsFilePickerProxy.h"
#include "nsComponentManagerUtils.h"
#include "nsIFile.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/ipc/BlobChild.h"
@ -142,11 +143,11 @@ nsFilePickerProxy::Open(nsIFilePickerShownCallback* aCallback)
}
bool
nsFilePickerProxy::Recv__delete__(const MaybeInputFiles& aFiles,
nsFilePickerProxy::Recv__delete__(const MaybeInputData& aData,
const int16_t& aResult)
{
if (aFiles.type() == MaybeInputFiles::TInputFiles) {
const InfallibleTArray<PBlobChild*>& blobs = aFiles.get_InputFiles().blobsChild();
if (aData.type() == MaybeInputData::TInputBlobs) {
const InfallibleTArray<PBlobChild*>& blobs = aData.get_InputBlobs().blobsChild();
for (uint32_t i = 0; i < blobs.Length(); ++i) {
BlobChild* actor = static_cast<BlobChild*>(blobs[i]);
RefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
@ -161,8 +162,24 @@ nsFilePickerProxy::Recv__delete__(const MaybeInputFiles& aFiles,
RefPtr<File> file = File::Create(inner, blobImpl);
MOZ_ASSERT(file);
mFilesOrDirectories.AppendElement(file);
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
element->SetAsFile() = file;
}
} else if (aData.type() == MaybeInputData::TInputDirectory) {
nsCOMPtr<nsIFile> file;
NS_ConvertUTF16toUTF8 path(aData.get_InputDirectory().directoryPath());
nsresult rv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
RefPtr<Directory> directory =
Directory::Create(mParent->GetCurrentInnerWindow(), file,
Directory::eDOMRootDirectory);
MOZ_ASSERT(directory);
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
element->SetAsDirectory() = directory;
}
if (mCallback) {
@ -182,8 +199,16 @@ nsFilePickerProxy::GetDomFileOrDirectory(nsISupports** aValue)
}
MOZ_ASSERT(mFilesOrDirectories.Length() == 1);
nsCOMPtr<nsIDOMBlob> blob = mFilesOrDirectories[0].get();
blob.forget(aValue);
if (mFilesOrDirectories[0].IsFile()) {
nsCOMPtr<nsIDOMBlob> blob = mFilesOrDirectories[0].GetAsFile().get();
blob.forget(aValue);
return NS_OK;
}
MOZ_ASSERT(mFilesOrDirectories[0].IsDirectory());
RefPtr<Directory> directory = mFilesOrDirectories[0].GetAsDirectory();
directory.forget(aValue);
return NS_OK;
}
@ -194,8 +219,9 @@ class SimpleEnumerator final : public nsISimpleEnumerator
public:
NS_DECL_ISUPPORTS
explicit SimpleEnumerator(const nsTArray<RefPtr<File>>& aFiles)
: mFiles(aFiles)
explicit
SimpleEnumerator(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories)
: mFilesOrDirectories(aFilesOrDirectories)
, mIndex(0)
{}
@ -203,17 +229,26 @@ public:
HasMoreElements(bool* aRetvalue) override
{
MOZ_ASSERT(aRetvalue);
*aRetvalue = mIndex < mFiles.Length();
*aRetvalue = mIndex < mFilesOrDirectories.Length();
return NS_OK;
}
NS_IMETHOD
GetNext(nsISupports** aSupports) override
GetNext(nsISupports** aValue) override
{
NS_ENSURE_TRUE(mIndex < mFiles.Length(), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(mIndex < mFilesOrDirectories.Length(), NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMBlob> blob = mFiles[mIndex++].get();
blob.forget(aSupports);
uint32_t index = mIndex++;
if (mFilesOrDirectories[index].IsFile()) {
nsCOMPtr<nsIDOMBlob> blob = mFilesOrDirectories[index].GetAsFile().get();
blob.forget(aValue);
return NS_OK;
}
MOZ_ASSERT(mFilesOrDirectories[index].IsDirectory());
RefPtr<Directory> directory = mFilesOrDirectories[index].GetAsDirectory();
directory.forget(aValue);
return NS_OK;
}
@ -221,7 +256,7 @@ private:
~SimpleEnumerator()
{}
nsTArray<RefPtr<File>> mFiles;
nsTArray<mozilla::dom::OwningFileOrDirectory> mFilesOrDirectories;
uint32_t mIndex;
};
@ -232,7 +267,8 @@ NS_IMPL_ISUPPORTS(SimpleEnumerator, nsISimpleEnumerator)
NS_IMETHODIMP
nsFilePickerProxy::GetDomFileOrDirectoryEnumerator(nsISimpleEnumerator** aDomfiles)
{
RefPtr<SimpleEnumerator> enumerator = new SimpleEnumerator(mFilesOrDirectories);
RefPtr<SimpleEnumerator> enumerator =
new SimpleEnumerator(mFilesOrDirectories);
enumerator.forget(aDomfiles);
return NS_OK;
}

Просмотреть файл

@ -13,17 +13,12 @@
#include "nsCOMArray.h"
#include "mozilla/dom/PFilePickerChild.h"
#include "mozilla/dom/UnionTypes.h"
class nsIWidget;
class nsIFile;
class nsPIDOMWindowInner;
namespace mozilla {
namespace dom {
class File;
} // namespace dom
} // namespace mozilla
/**
This class creates a proxy file picker to be used in content processes.
The file picker just collects the initialization data and when Show() is
@ -59,13 +54,13 @@ public:
// PFilePickerChild
virtual bool
Recv__delete__(const MaybeInputFiles& aFiles, const int16_t& aResult) override;
Recv__delete__(const MaybeInputData& aData, const int16_t& aResult) override;
private:
~nsFilePickerProxy();
void InitNative(nsIWidget*, const nsAString&) override;
nsTArray<RefPtr<mozilla::dom::File>> mFilesOrDirectories;
nsTArray<mozilla::dom::OwningFileOrDirectory> mFilesOrDirectories;
nsCOMPtr<nsIFilePickerShownCallback> mCallback;
int16_t mSelectedType;