зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 8 changesets (bug 1173320) for bustage.
Backed out changeset e5c224d964bc (bug 1173320) Backed out changeset db971ba7c26d (bug 1173320) Backed out changeset cd7e79d9a750 (bug 1173320) Backed out changeset 56bbea4fe199 (bug 1173320) Backed out changeset e94ced2f8e3c (bug 1173320) Backed out changeset 401c1e7df8ea (bug 1173320) Backed out changeset bf65b38f759e (bug 1173320) Backed out changeset ac58a56021ac (bug 1173320) DONTBUILD CLOSED TREE
This commit is contained in:
Родитель
613f13dae7
Коммит
ac97cbbe14
|
@ -227,6 +227,12 @@ Blob::IsFile() const
|
|||
return mImpl->IsFile();
|
||||
}
|
||||
|
||||
bool
|
||||
Blob::IsDirectory() const
|
||||
{
|
||||
return mImpl->IsDirectory();
|
||||
}
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>*
|
||||
Blob::GetSubBlobImpls() const
|
||||
{
|
||||
|
@ -414,10 +420,11 @@ 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)
|
||||
int64_t aLastModifiedDate, BlobDirState aDirState)
|
||||
{
|
||||
RefPtr<File> file = new File(aParent,
|
||||
new BlobImplBase(aName, aContentType, aLength, aLastModifiedDate));
|
||||
new BlobImplBase(aName, aContentType, aLength, aLastModifiedDate,
|
||||
aDirState));
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
|
@ -939,6 +946,17 @@ 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,6 +44,18 @@ 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
|
||||
|
@ -89,6 +101,12 @@ 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
|
||||
|
@ -96,6 +114,9 @@ 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,
|
||||
|
@ -173,7 +194,7 @@ public:
|
|||
static already_AddRefed<File>
|
||||
Create(nsISupports* aParent, const nsAString& aName,
|
||||
const nsAString& aContentType, uint64_t aLength,
|
||||
int64_t aLastModifiedDate);
|
||||
int64_t aLastModifiedDate, BlobDirState aDirState);
|
||||
|
||||
// The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
|
||||
// freed by free so it must be allocated by malloc or something
|
||||
|
@ -318,6 +339,28 @@ 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
|
||||
{
|
||||
|
@ -334,9 +377,11 @@ class BlobImplBase : public BlobImpl
|
|||
{
|
||||
public:
|
||||
BlobImplBase(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, int64_t aLastModifiedDate)
|
||||
uint64_t aLength, int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState = BlobDirState::eUnknownIfDir)
|
||||
: mIsFile(true)
|
||||
, mImmutable(false)
|
||||
, mDirState(aDirState)
|
||||
, mContentType(aContentType)
|
||||
, mName(aName)
|
||||
, mStart(0)
|
||||
|
@ -352,6 +397,7 @@ public:
|
|||
uint64_t aLength)
|
||||
: mIsFile(true)
|
||||
, mImmutable(false)
|
||||
, mDirState(BlobDirState::eUnknownIfDir)
|
||||
, mContentType(aContentType)
|
||||
, mName(aName)
|
||||
, mStart(0)
|
||||
|
@ -366,6 +412,7 @@ public:
|
|||
BlobImplBase(const nsAString& aContentType, uint64_t aLength)
|
||||
: mIsFile(false)
|
||||
, mImmutable(false)
|
||||
, mDirState(BlobDirState::eUnknownIfDir)
|
||||
, mContentType(aContentType)
|
||||
, mStart(0)
|
||||
, mLength(aLength)
|
||||
|
@ -380,6 +427,7 @@ public:
|
|||
uint64_t aLength)
|
||||
: mIsFile(false)
|
||||
, mImmutable(false)
|
||||
, mDirState(BlobDirState::eUnknownIfDir)
|
||||
, mContentType(aContentType)
|
||||
, mStart(aStart)
|
||||
, mLength(aLength)
|
||||
|
@ -470,6 +518,36 @@ 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;
|
||||
|
@ -487,6 +565,7 @@ protected:
|
|||
|
||||
bool mIsFile;
|
||||
bool mImmutable;
|
||||
BlobDirState mDirState;
|
||||
|
||||
nsString mContentType;
|
||||
nsString mName;
|
||||
|
@ -511,7 +590,8 @@ public:
|
|||
|
||||
BlobImplMemory(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
|
||||
const nsAString& aContentType, int64_t aLastModifiedDate)
|
||||
: BlobImplBase(aName, aContentType, aLength, aLastModifiedDate)
|
||||
: BlobImplBase(aName, aContentType, aLength, aLastModifiedDate,
|
||||
BlobDirState::eIsNotDir)
|
||||
, mDataOwner(new DataOwner(aMemoryBuffer, aLength))
|
||||
{
|
||||
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
|
||||
|
@ -712,6 +792,8 @@ 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; }
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileList.h"
|
||||
#include "mozilla/dom/FileListBinding.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
@ -12,7 +11,7 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFilesOrDirectories, mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFiles, mParent)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileList)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
|
@ -29,20 +28,6 @@ FileList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
return mozilla::dom::FileListBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
FileList::Append(File* aFile)
|
||||
{
|
||||
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
|
||||
element->SetAsFile() = aFile;
|
||||
}
|
||||
|
||||
void
|
||||
FileList::Append(Directory* aDirectory)
|
||||
{
|
||||
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
|
||||
element->SetAsDirectory() = aDirectory;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileList::GetLength(uint32_t* aLength)
|
||||
{
|
||||
|
@ -52,76 +37,12 @@ FileList::GetLength(uint32_t* aLength)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileList::Item(uint32_t aIndex, nsISupports** aValue)
|
||||
FileList::Item(uint32_t aIndex, nsISupports** aFile)
|
||||
{
|
||||
if (aIndex >= mFilesOrDirectories.Length()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mFilesOrDirectories[aIndex].IsFile()) {
|
||||
nsCOMPtr<nsIDOMBlob> file = mFilesOrDirectories[aIndex].GetAsFile();
|
||||
file.forget(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mFilesOrDirectories[aIndex].IsDirectory());
|
||||
RefPtr<Directory> directory = mFilesOrDirectories[aIndex].GetAsDirectory();
|
||||
directory.forget(aValue);
|
||||
nsCOMPtr<nsIDOMBlob> file = Item(aIndex);
|
||||
file.forget(aFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FileList::Item(uint32_t aIndex, Nullable<OwningFileOrDirectory>& aValue,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
if (aIndex >= mFilesOrDirectories.Length()) {
|
||||
aValue.SetNull();
|
||||
return;
|
||||
}
|
||||
|
||||
aValue.SetValue(mFilesOrDirectories[aIndex]);
|
||||
}
|
||||
|
||||
void
|
||||
FileList::IndexedGetter(uint32_t aIndex, bool& aFound,
|
||||
Nullable<OwningFileOrDirectory>& aFileOrDirectory,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
aFound = aIndex < mFilesOrDirectories.Length();
|
||||
Item(aIndex, aFileOrDirectory, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
FileList::ToSequence(Sequence<OwningFileOrDirectory>& aSequence,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(aSequence.IsEmpty());
|
||||
if (mFilesOrDirectories.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aSequence.SetLength(mFilesOrDirectories.Length(),
|
||||
mozilla::fallible_t())) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
|
||||
aSequence[i] = mFilesOrDirectories[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FileList::ClonableToDifferentThreadOrProcess() const
|
||||
{
|
||||
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
|
||||
if (mFilesOrDirectories[i].IsDirectory()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#define mozilla_dom_FileList_h
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
@ -40,13 +39,15 @@ public:
|
|||
return mParent;
|
||||
}
|
||||
|
||||
void Append(File* aFile);
|
||||
void Append(Directory* aDirectory);
|
||||
bool Append(File* aFile)
|
||||
{
|
||||
return mFiles.AppendElement(aFile);
|
||||
}
|
||||
|
||||
bool Remove(uint32_t aIndex)
|
||||
{
|
||||
if (aIndex < mFilesOrDirectories.Length()) {
|
||||
mFilesOrDirectories.RemoveElementAt(aIndex);
|
||||
if (aIndex < mFiles.Length()) {
|
||||
mFiles.RemoveElementAt(aIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -55,7 +56,7 @@ public:
|
|||
|
||||
void Clear()
|
||||
{
|
||||
return mFilesOrDirectories.Clear();
|
||||
return mFiles.Clear();
|
||||
}
|
||||
|
||||
static FileList* FromSupports(nsISupports* aSupports)
|
||||
|
@ -75,34 +76,29 @@ public:
|
|||
return static_cast<FileList*>(aSupports);
|
||||
}
|
||||
|
||||
const OwningFileOrDirectory& UnsafeItem(uint32_t aIndex) const
|
||||
File* Item(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(aIndex < Length());
|
||||
return mFilesOrDirectories[aIndex];
|
||||
return mFiles.SafeElementAt(aIndex);
|
||||
}
|
||||
|
||||
void Item(uint32_t aIndex,
|
||||
Nullable<OwningFileOrDirectory>& aFileOrDirectory,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
void IndexedGetter(uint32_t aIndex, bool& aFound,
|
||||
Nullable<OwningFileOrDirectory>& aFileOrDirectory,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
uint32_t Length() const
|
||||
File* IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
return mFilesOrDirectories.Length();
|
||||
aFound = aIndex < mFiles.Length();
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
return mFiles.ElementAt(aIndex);
|
||||
}
|
||||
|
||||
void ToSequence(Sequence<OwningFileOrDirectory>& aSequence,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
bool ClonableToDifferentThreadOrProcess() const;
|
||||
uint32_t Length()
|
||||
{
|
||||
return mFiles.Length();
|
||||
}
|
||||
|
||||
private:
|
||||
~FileList() {}
|
||||
|
||||
nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
|
||||
nsTArray<RefPtr<File>> mFiles;
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/dom/BlobBinding.h"
|
||||
#include "mozilla/dom/CryptoKey.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileList.h"
|
||||
#include "mozilla/dom/FileListBinding.h"
|
||||
|
@ -724,59 +723,36 @@ ReadFileList(JSContext* aCx,
|
|||
{
|
||||
RefPtr<FileList> fileList = new FileList(aHolder->ParentDuringRead());
|
||||
|
||||
// |aCount| is the number of Files or Directory for this FileList.
|
||||
uint32_t tag, offset;
|
||||
// Offset is the index of the blobImpl from which we can find the blobImpl
|
||||
// for this FileList.
|
||||
if (!JS_ReadUint32Pair(aReader, &tag, &offset)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(tag == 0);
|
||||
|
||||
// |aCount| is the number of BlobImpls to use from the |offset|.
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
uint32_t tagOrDirectoryType, indexOrLengthOfString;
|
||||
if (!JS_ReadUint32Pair(aReader, &tagOrDirectoryType,
|
||||
&indexOrLengthOfString)) {
|
||||
uint32_t index = offset + i;
|
||||
MOZ_ASSERT(index < aHolder->BlobImpls().Length());
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[index];
|
||||
MOZ_ASSERT(blobImpl->IsFile());
|
||||
|
||||
ErrorResult rv;
|
||||
blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(tagOrDirectoryType == SCTAG_DOM_BLOB ||
|
||||
tagOrDirectoryType == Directory::eDOMRootDirectory ||
|
||||
tagOrDirectoryType == Directory::eNotDOMRootDirectory);
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
if (tagOrDirectoryType == SCTAG_DOM_BLOB) {
|
||||
MOZ_ASSERT(indexOrLengthOfString < aHolder->BlobImpls().Length());
|
||||
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
aHolder->BlobImpls()[indexOrLengthOfString];
|
||||
MOZ_ASSERT(blobImpl->IsFile());
|
||||
|
||||
ErrorResult rv;
|
||||
blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<File> file =
|
||||
File::Create(aHolder->ParentDuringRead(), blobImpl);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
fileList->Append(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString path;
|
||||
path.SetLength(indexOrLengthOfString);
|
||||
size_t charSize = sizeof(nsString::char_type);
|
||||
if (!JS_ReadBytes(aReader, (void*) path.BeginWriting(),
|
||||
indexOrLengthOfString * charSize)) {
|
||||
RefPtr<File> file = File::Create(aHolder->ParentDuringRead(), blobImpl);
|
||||
if (!fileList->Append(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
|
||||
getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(aHolder->ParentDuringRead(), file,
|
||||
(Directory::DirectoryType) tagOrDirectoryType);
|
||||
fileList->Append(directory);
|
||||
}
|
||||
|
||||
if (!ToJSValue(aCx, fileList, &val)) {
|
||||
|
@ -789,13 +765,7 @@ ReadFileList(JSContext* aCx,
|
|||
|
||||
// The format of the FileList serialization is:
|
||||
// - pair of ints: SCTAG_DOM_FILELIST, Length of the FileList
|
||||
// - for each element of the FileList:
|
||||
// - if it's a blob:
|
||||
// - pair of ints: SCTAG_DOM_BLOB, index of the BlobImpl in the array
|
||||
// mBlobImplArray.
|
||||
// - else:
|
||||
// - pair of ints: 0/1 is root, string length
|
||||
// - value string
|
||||
// - pair of ints: 0, The offset of the BlobImpl array
|
||||
bool
|
||||
WriteFileList(JSStructuredCloneWriter* aWriter,
|
||||
FileList* aFileList,
|
||||
|
@ -805,8 +775,13 @@ WriteFileList(JSStructuredCloneWriter* aWriter,
|
|||
MOZ_ASSERT(aFileList);
|
||||
MOZ_ASSERT(aHolder);
|
||||
|
||||
// A FileList is serialized writing the X number of elements and the offset
|
||||
// from mBlobImplArray. The Read will take X elements from mBlobImplArray
|
||||
// starting from the offset.
|
||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
|
||||
aFileList->Length())) {
|
||||
aFileList->Length()) ||
|
||||
!JS_WriteUint32Pair(aWriter, 0,
|
||||
aHolder->BlobImpls().Length())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -814,39 +789,18 @@ WriteFileList(JSStructuredCloneWriter* aWriter,
|
|||
nsTArray<RefPtr<BlobImpl>> blobImpls;
|
||||
|
||||
for (uint32_t i = 0; i < aFileList->Length(); ++i) {
|
||||
const OwningFileOrDirectory& data = aFileList->UnsafeItem(i);
|
||||
|
||||
if (data.IsFile()) {
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
EnsureBlobForBackgroundManager(data.GetAsFile()->Impl(), nullptr, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
|
||||
aHolder->BlobImpls().Length())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aHolder->BlobImpls().AppendElement(blobImpl);
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(data.IsDirectory());
|
||||
|
||||
nsAutoString path;
|
||||
data.GetAsDirectory()->GetFullRealPath(path);
|
||||
|
||||
size_t charSize = sizeof(nsString::char_type);
|
||||
if (!JS_WriteUint32Pair(aWriter,
|
||||
(uint32_t)data.GetAsDirectory()->Type(),
|
||||
path.Length()) ||
|
||||
!JS_WriteBytes(aWriter, path.get(), path.Length() * charSize)) {
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl(), nullptr, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(blobImpl);
|
||||
blobImpls.AppendElement(blobImpl);
|
||||
}
|
||||
|
||||
aHolder->BlobImpls().AppendElements(blobImpls);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1050,9 +1004,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
|
|||
// See if this is a FileList object.
|
||||
{
|
||||
FileList* fileList = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList)) &&
|
||||
(mSupportedContext == SameProcessSameThread ||
|
||||
fileList->ClonableToDifferentThreadOrProcess())) {
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
|
||||
return WriteFileList(aWriter, fileList, this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7625,6 +7625,7 @@ 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.
|
||||
|
|
|
@ -1,25 +1,15 @@
|
|||
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.importGlobalProperties(["File"]);
|
||||
|
||||
addMessageListener("file.open", function () {
|
||||
var testFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get("ProfD", Ci.nsIFile);
|
||||
testFile.append("prefs.js");
|
||||
var testFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get("ProfD", Ci.nsIFile);
|
||||
testFile.append("prefs.js");
|
||||
|
||||
addMessageListener("file.open", function () {
|
||||
sendAsyncMessage("file.opened", {
|
||||
file: new File(testFile)
|
||||
});
|
||||
});
|
||||
|
||||
addMessageListener("dir.open", function () {
|
||||
var testFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get("ProfD", Ci.nsIFile);
|
||||
|
||||
sendAsyncMessage("dir.opened", {
|
||||
dir: testFile.path
|
||||
});
|
||||
});
|
||||
|
|
|
@ -61,18 +61,18 @@ function compare(a, b) {
|
|||
}
|
||||
|
||||
var clonableObjects = [
|
||||
{ crossThreads: true, data: 'hello world' },
|
||||
{ crossThreads: true, data: 123 },
|
||||
{ crossThreads: true, data: null },
|
||||
{ crossThreads: true, data: true },
|
||||
{ crossThreads: true, data: new Date() },
|
||||
{ crossThreads: true, data: [ 1, 'test', true, new Date() ] },
|
||||
{ crossThreads: true, data: { a: true, b: null, c: new Date(), d: [ true, false, {} ] } },
|
||||
{ crossThreads: true, data: new Blob([123], { type: 'plain/text' }) },
|
||||
{ crossThreads: true, data: new ImageData(2, 2) },
|
||||
'hello world',
|
||||
123,
|
||||
null,
|
||||
true,
|
||||
new Date(),
|
||||
[ 1, 'test', true, new Date() ],
|
||||
{ a: true, b: null, c: new Date(), d: [ true, false, {} ] },
|
||||
new Blob([123], { type: 'plain/text' }),
|
||||
new ImageData(2, 2),
|
||||
];
|
||||
|
||||
function create_fileList_forFile() {
|
||||
function create_fileList() {
|
||||
var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
|
||||
var script = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
|
@ -84,7 +84,7 @@ function create_fileList_forFile() {
|
|||
var domFile = fileList.files[0];
|
||||
is(domFile.name, "prefs.js", "fileName should be prefs.js");
|
||||
|
||||
clonableObjects.push({ crossThreads: true, data: fileList.files });
|
||||
clonableObjects.push(fileList.files);
|
||||
script.destroy();
|
||||
next();
|
||||
}
|
||||
|
@ -93,27 +93,6 @@ function create_fileList_forFile() {
|
|||
script.sendAsyncMessage("file.open");
|
||||
}
|
||||
|
||||
function create_fileList_forDir() {
|
||||
var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
|
||||
var script = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
function onOpened(message) {
|
||||
var fileList = document.getElementById('fileList');
|
||||
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
|
||||
|
||||
// Just a simple test
|
||||
is(fileList.files.length, 1, "Filelist has 1 element");
|
||||
ok(fileList.files[0] instanceof Directory, "We have a directory.");
|
||||
|
||||
clonableObjects.push({ crossThreads: false, data: fileList.files });
|
||||
script.destroy();
|
||||
next();
|
||||
}
|
||||
|
||||
script.addMessageListener("dir.opened", onOpened);
|
||||
script.sendAsyncMessage("dir.open");
|
||||
}
|
||||
|
||||
function runTests(obj) {
|
||||
ok(('clonableObjects' in obj) &&
|
||||
('transferableObjects' in obj) &&
|
||||
|
@ -134,16 +113,8 @@ function runTests(obj) {
|
|||
}
|
||||
|
||||
var object = clonableObjects[clonableObjectsId++];
|
||||
|
||||
// If this test requires a cross-thread structured clone algorithm, maybe
|
||||
// we have to skip it.
|
||||
if (!object.crossThread && obj.crossThread) {
|
||||
runClonableTest();
|
||||
return;
|
||||
}
|
||||
|
||||
obj.send(object.data, []).then(function(received) {
|
||||
compare(received.data, object.data);
|
||||
obj.send(object, []).then(function(received) {
|
||||
compare(received.data, object);
|
||||
runClonableTest();
|
||||
});
|
||||
}
|
||||
|
@ -232,7 +203,6 @@ function test_windowToWindow() {
|
|||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: false,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
|
@ -286,7 +256,6 @@ function test_windowToIframeURL(url) {
|
|||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: false,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
|
@ -334,7 +303,6 @@ function test_workers() {
|
|||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
|
@ -378,7 +346,6 @@ function test_broadcastChannel() {
|
|||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: false,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
if (ports.length) {
|
||||
|
@ -424,7 +391,6 @@ function test_broadcastChannel_inWorkers() {
|
|||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: false,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
if (ports.length) {
|
||||
|
@ -466,7 +432,6 @@ function test_messagePort() {
|
|||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
|
@ -512,7 +477,6 @@ function test_messagePort_inWorkers() {
|
|||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
|
@ -534,8 +498,7 @@ function test_messagePort_inWorkers() {
|
|||
}
|
||||
|
||||
var tests = [
|
||||
create_fileList_forFile,
|
||||
create_fileList_forDir,
|
||||
create_fileList,
|
||||
|
||||
test_windowToWindow,
|
||||
test_windowToIframe,
|
||||
|
|
|
@ -101,9 +101,8 @@ public:
|
|||
|
||||
// we want to make sure that the names of file can't reach
|
||||
// outside of the type of storage the user asked for.
|
||||
bool IsSafePath() const;
|
||||
bool ValidateAndSplitPath(const nsAString& aPath,
|
||||
nsTArray<nsString>* aParts = nullptr) const;
|
||||
bool IsSafePath();
|
||||
bool IsSafePath(const nsAString& aPath);
|
||||
|
||||
void Dump(const char* label);
|
||||
|
||||
|
@ -138,6 +137,7 @@ public:
|
|||
private:
|
||||
~DeviceStorageFile() {}
|
||||
void Init();
|
||||
void NormalizeFilePath();
|
||||
void AppendRelativePath(const nsAString& aPath);
|
||||
void AccumDirectoryUsage(nsIFile* aFile,
|
||||
uint64_t* aPicturesSoFar,
|
||||
|
|
|
@ -582,16 +582,7 @@ DeviceStorageStatics::ResetOverrideRootDir()
|
|||
nsCOMPtr<nsIFile> f;
|
||||
DS_LOG_INFO("");
|
||||
|
||||
// For users running on desktop, it's convenient to be able to override
|
||||
// all of the directories to point to a single tree, much like what happens
|
||||
// on a real device.
|
||||
const nsAdoptingString& overrideRootDir =
|
||||
mozilla::Preferences::GetString(kPrefOverrideRootDir);
|
||||
if (overrideRootDir && !overrideRootDir.IsEmpty()) {
|
||||
NS_NewLocalFile(overrideRootDir, false, getter_AddRefs(f));
|
||||
}
|
||||
|
||||
if (!f && Preferences::GetBool(kPrefTesting, false)) {
|
||||
if (Preferences::GetBool(kPrefTesting, false)) {
|
||||
DS_LOG_INFO("temp");
|
||||
nsCOMPtr<nsIProperties> dirService
|
||||
= do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
|
||||
|
@ -601,6 +592,15 @@ DeviceStorageStatics::ResetOverrideRootDir()
|
|||
f->AppendRelativeNativePath(
|
||||
NS_LITERAL_CSTRING("device-storage-testing"));
|
||||
}
|
||||
} else {
|
||||
// For users running on desktop, it's convenient to be able to override
|
||||
// all of the directories to point to a single tree, much like what happens
|
||||
// on a real device.
|
||||
const nsAdoptingString& overrideRootDir =
|
||||
mozilla::Preferences::GetString(kPrefOverrideRootDir);
|
||||
if (overrideRootDir && !overrideRootDir.IsEmpty()) {
|
||||
NS_NewLocalFile(overrideRootDir, false, getter_AddRefs(f));
|
||||
}
|
||||
}
|
||||
|
||||
if (f) {
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIFile.h"
|
||||
|
@ -77,35 +76,10 @@ using namespace mozilla::dom;
|
|||
using namespace mozilla::dom::devicestorage;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
namespace mozilla {
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, PR_Close);
|
||||
} // namespace mozilla
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
NormalizeFilePath(nsAString& aPath)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
char16_t* cur = aPath.BeginWriting();
|
||||
char16_t* end = aPath.EndWriting();
|
||||
for (; cur < end; ++cur) {
|
||||
if (char16_t('\\') == *cur) {
|
||||
*cur = FILESYSTEM_DOM_PATH_SEPARATOR_CHAR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerIgnoreNothing(char16_t /* aChar */)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
StaticAutoPtr<DeviceStorageUsedSpaceCache>
|
||||
DeviceStorageUsedSpaceCache::sDeviceStorageUsedSpaceCache;
|
||||
|
||||
|
@ -536,8 +510,7 @@ DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType,
|
|||
if (!mPath.EqualsLiteral("")) {
|
||||
AppendRelativePath(mPath);
|
||||
}
|
||||
|
||||
NormalizeFilePath(mPath);
|
||||
NormalizeFilePath();
|
||||
}
|
||||
|
||||
DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType,
|
||||
|
@ -552,7 +525,7 @@ DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType,
|
|||
{
|
||||
Init();
|
||||
AppendRelativePath(aPath);
|
||||
NormalizeFilePath(mPath);
|
||||
NormalizeFilePath();
|
||||
}
|
||||
|
||||
DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType,
|
||||
|
@ -761,7 +734,7 @@ DeviceStorageFile::CreateUnique(const nsAString& aStorageType,
|
|||
void
|
||||
DeviceStorageFile::SetPath(const nsAString& aPath) {
|
||||
mPath.Assign(aPath);
|
||||
NormalizeFilePath(mPath);
|
||||
NormalizeFilePath();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -772,14 +745,13 @@ DeviceStorageFile::SetEditable(bool aEditable) {
|
|||
// we want to make sure that the names of file can't reach
|
||||
// outside of the type of storage the user asked for.
|
||||
bool
|
||||
DeviceStorageFile::IsSafePath() const
|
||||
DeviceStorageFile::IsSafePath()
|
||||
{
|
||||
return ValidateAndSplitPath(mRootDir) && ValidateAndSplitPath(mPath);
|
||||
return IsSafePath(mRootDir) && IsSafePath(mPath);
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStorageFile::ValidateAndSplitPath(const nsAString& aPath,
|
||||
nsTArray<nsString>* aParts) const
|
||||
DeviceStorageFile::IsSafePath(const nsAString& aPath)
|
||||
{
|
||||
nsAString::const_iterator start, end;
|
||||
aPath.BeginReading(start);
|
||||
|
@ -792,43 +764,33 @@ DeviceStorageFile::ValidateAndSplitPath(const nsAString& aPath,
|
|||
StringBeginsWith(aPath, tildeSlash)) {
|
||||
NS_WARNING("Path name starts with tilde!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// split on /. if any token is "", ., or .., return false.
|
||||
NS_ConvertUTF16toUTF8 cname(aPath);
|
||||
char* buffer = cname.BeginWriting();
|
||||
const char* token;
|
||||
|
||||
NS_NAMED_LITERAL_STRING(kCurrentDir, ".");
|
||||
NS_NAMED_LITERAL_STRING(kParentDir, "..");
|
||||
|
||||
// Split path and check each path component.
|
||||
nsCharSeparatedTokenizerTemplate<TokenizerIgnoreNothing>
|
||||
tokenizer(aPath, FILESYSTEM_DOM_PATH_SEPARATOR_CHAR);
|
||||
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
nsDependentSubstring pathComponent = tokenizer.nextToken();
|
||||
// The path containing empty components, such as "foo//bar", is invalid.
|
||||
// We don't allow paths, such as "../foo", "foo/./bar" and "foo/../bar",
|
||||
// to walk up the directory.
|
||||
if (pathComponent.IsEmpty() ||
|
||||
pathComponent.Equals(kCurrentDir) ||
|
||||
pathComponent.Equals(kParentDir)) {
|
||||
while ((token = nsCRT::strtok(buffer, "/", &buffer))) {
|
||||
if (PL_strcmp(token, "") == 0 ||
|
||||
PL_strcmp(token, ".") == 0 ||
|
||||
PL_strcmp(token, "..") == 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aParts) {
|
||||
aParts->AppendElement(pathComponent);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DeviceStorageFile::AppendRelativePath(const nsAString& aPath)
|
||||
{
|
||||
DeviceStorageFile::NormalizeFilePath() {
|
||||
FileSystemUtils::LocalPathToNormalizedPath(mPath, mPath);
|
||||
}
|
||||
|
||||
void
|
||||
DeviceStorageFile::AppendRelativePath(const nsAString& aPath) {
|
||||
if (!mFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsString> parts;
|
||||
|
||||
if (!ValidateAndSplitPath(aPath, &parts)) {
|
||||
if (!IsSafePath(aPath)) {
|
||||
// All of the APIs (in the child) do checks to verify that the path is
|
||||
// valid and return PERMISSION_DENIED if a non-safe path is entered.
|
||||
// This check is done in the parent and prevents a compromised
|
||||
|
@ -838,13 +800,9 @@ DeviceStorageFile::AppendRelativePath(const nsAString& aPath)
|
|||
NS_WARNING(NS_LossyConvertUTF16toASCII(aPath).get());
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < parts.Length(); ++i) {
|
||||
nsresult rv = mFile->AppendRelativePath(parts[i]);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
nsString localPath;
|
||||
FileSystemUtils::NormalizedPathToLocalPath(aPath, localPath);
|
||||
mFile->AppendRelativePath(localPath);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -20,20 +20,12 @@ Object.defineProperty(Array.prototype, "remove", {
|
|||
function devicestorage_setup(callback) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const Cc = SpecialPowers.Cc;
|
||||
const Ci = SpecialPowers.Ci;
|
||||
var directoryService = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties);
|
||||
var f = directoryService.get("TmpD", Ci.nsIFile);
|
||||
f.appendRelativePath("device-storage-testing");
|
||||
|
||||
let script = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('remove_testing_directory.js'));
|
||||
|
||||
script.addMessageListener('directory-removed', function listener () {
|
||||
script.removeMessageListener('directory-removed', listener);
|
||||
var prefs = [["device.storage.enabled", true],
|
||||
["device.storage.testing", true],
|
||||
["device.storage.overrideRootDir", f.path],
|
||||
["device.storage.prompt.testing", true]];
|
||||
SpecialPowers.pushPrefEnv({"set": prefs}, callback);
|
||||
});
|
||||
|
|
|
@ -34,14 +34,14 @@ function testCreateDirectory(rootDir, path) {
|
|||
}
|
||||
|
||||
function createDirectorySuccess(d) {
|
||||
is(d.name, gName, "Failed to create directory: name mismatch.");
|
||||
ok(d.name === gName, "Failed to create directory: name mismatch.");
|
||||
|
||||
// Get the new created directory from the root.
|
||||
gRoot.get(gPath).then(getSuccess, cbError);
|
||||
}
|
||||
|
||||
function getSuccess(d) {
|
||||
is(d.name, gName, "Should get directory - " + (gPath || "[root]") + ".");
|
||||
ok(d.name === gName, "Should get directory - " + (gPath || "[root]") + ".");
|
||||
switch (gTestCount) {
|
||||
case 0:
|
||||
gRoot = d;
|
||||
|
|
|
@ -149,7 +149,8 @@ try {
|
|||
// The remove will fail if the directory doesn't exist, which is fine.
|
||||
f.remove(true);
|
||||
} catch (e) {}
|
||||
SpecialPowers.pushPrefEnv({'set': [["device.storage.overrideRootDir", f.path]]},
|
||||
SpecialPowers.pushPrefEnv({'set': [["device.storage.overrideRootDir", f.path],
|
||||
["device.storage.testing", false]]},
|
||||
function() {
|
||||
startTest();
|
||||
});
|
||||
|
|
|
@ -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(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
|
||||
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(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mItems)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage)
|
||||
|
@ -281,12 +281,11 @@ DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
|
|||
FileList*
|
||||
DataTransfer::GetFiles(ErrorResult& aRv)
|
||||
{
|
||||
return GetFileListInternal(aRv, nsContentUtils::SubjectPrincipal());
|
||||
return GetFilesInternal(aRv, nsContentUtils::SubjectPrincipal());
|
||||
}
|
||||
|
||||
FileList*
|
||||
DataTransfer::GetFileListInternal(ErrorResult& aRv,
|
||||
nsIPrincipal* aSubjectPrincipal)
|
||||
DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal)
|
||||
{
|
||||
if (mEventMessage != eDrop &&
|
||||
mEventMessage != eLegacyDragDrop &&
|
||||
|
@ -294,15 +293,14 @@ DataTransfer::GetFileListInternal(ErrorResult& aRv,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mFileList) {
|
||||
mFileList = new FileList(static_cast<nsIDOMDataTransfer*>(this));
|
||||
if (!mFiles) {
|
||||
mFiles = 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;
|
||||
}
|
||||
|
@ -340,18 +338,21 @@ DataTransfer::GetFileListInternal(ErrorResult& aRv,
|
|||
MOZ_ASSERT(domFile);
|
||||
}
|
||||
|
||||
mFileList->Append(domFile);
|
||||
if (!mFiles->Append(domFile)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mFileList;
|
||||
return mFiles;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataTransfer::GetFiles(nsIDOMFileList** aFileList)
|
||||
{
|
||||
ErrorResult rv;
|
||||
NS_IF_ADDREF(*aFileList = GetFileListInternal(rv, nsContentUtils::GetSystemPrincipal()));
|
||||
NS_IF_ADDREF(*aFileList = GetFilesInternal(rv, nsContentUtils::GetSystemPrincipal()));
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
|
@ -853,7 +854,7 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mFileList) {
|
||||
if (!mFiles) {
|
||||
GetFiles(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
|
@ -861,9 +862,40 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
|
|||
}
|
||||
|
||||
Sequence<OwningFileOrDirectory> filesAndDirsSeq;
|
||||
mFileList->ToSequence(filesAndDirsSeq, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
|
||||
if (mFiles && mFiles->Length()) {
|
||||
if (!filesAndDirsSeq.SetLength(mFiles->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p->MaybeResolve(filesAndDirsSeq);
|
||||
|
|
|
@ -252,7 +252,7 @@ protected:
|
|||
void FillInExternalData(TransferItem& aItem, uint32_t aIndex);
|
||||
|
||||
|
||||
FileList* GetFileListInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal);
|
||||
FileList* GetFilesInternal(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,9 +300,8 @@ protected:
|
|||
// array of items, each containing an array of format->data pairs
|
||||
nsTArray<nsTArray<TransferItem> > mItems;
|
||||
|
||||
// array of files and directories, containing only the files present in the
|
||||
// dataTransfer
|
||||
RefPtr<FileList> mFileList;
|
||||
// array of files, containing only the files present in the dataTransfer
|
||||
RefPtr<FileList> mFiles;
|
||||
|
||||
// the target of the drag. The drag and dragend events will fire at this.
|
||||
nsCOMPtr<mozilla::dom::Element> mDragTarget;
|
||||
|
|
|
@ -318,7 +318,8 @@ ConvertActorToFile(FileHandleBase* aFileHandle,
|
|||
actor->SetMysteryBlobInfo(mutableFile->Name(),
|
||||
mutableFile->Type(),
|
||||
size.get_uint64_t(),
|
||||
lastModified.get_int64_t());
|
||||
lastModified.get_int64_t(),
|
||||
BlobDirState::eUnknownIfDir);
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
|
|
@ -16,73 +16,33 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* 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->GetParentObject());
|
||||
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<CreateDirectoryTask>
|
||||
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& 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<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)
|
||||
const nsAString& aPath,
|
||||
ErrorResult& aRv)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mTargetRealPath(aPath)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
CreateDirectoryTask::CreateDirectoryTask(
|
||||
FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
CreateDirectoryTask::~CreateDirectoryTask()
|
||||
|
@ -99,44 +59,25 @@ CreateDirectoryTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
CreateDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
CreateDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemCreateDirectoryParams();
|
||||
}
|
||||
|
||||
return FileSystemCreateDirectoryParams(aSerializedDOMPath, path);
|
||||
return FileSystemCreateDirectoryParams(aFileSystem, mTargetRealPath);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
CreateDirectoryTask::GetSuccessRequestResult() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemDirectoryResponse();
|
||||
}
|
||||
|
||||
return FileSystemDirectoryResponse(path);
|
||||
return FileSystemDirectoryResponse(mTargetRealPath);
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemDirectoryResponse r = aValue;
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
mTargetRealPath = r.realPath();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -150,8 +91,13 @@ 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 = mTargetPath->Exists(&fileExists);
|
||||
nsresult rv = file->Exists(&fileExists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -160,12 +106,8 @@ CreateDirectoryTask::Work()
|
|||
return NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
|
||||
}
|
||||
|
||||
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0770);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0770);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -182,12 +124,7 @@ CreateDirectoryTask::HandlerCallback()
|
|||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
Directory::eNotDOMRootDirectory,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
RefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
|
|
@ -16,19 +16,16 @@ namespace dom {
|
|||
|
||||
class Promise;
|
||||
|
||||
class CreateDirectoryTask final : public FileSystemTaskBase
|
||||
class CreateDirectoryTask final
|
||||
: public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
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);
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aPath,
|
||||
ErrorResult& aRv);
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual
|
||||
~CreateDirectoryTask();
|
||||
|
@ -41,15 +38,13 @@ public:
|
|||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
GetSuccessRequestResult() const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -58,15 +53,8 @@ protected:
|
|||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath);
|
||||
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
nsString mTargetRealPath;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -25,104 +25,34 @@ namespace dom {
|
|||
|
||||
uint32_t CreateFileTask::sOutputBufferSize = 0;
|
||||
|
||||
/* static */ already_AddRefed<CreateFileTask>
|
||||
CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Blob* aBlobData,
|
||||
InfallibleTArray<uint8_t>& aArrayData,
|
||||
bool aReplace,
|
||||
ErrorResult& aRv)
|
||||
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aPath,
|
||||
Blob* aBlobData,
|
||||
InfallibleTArray<uint8_t>& aArrayData,
|
||||
bool replace,
|
||||
ErrorResult& aRv)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetRealPath(aPath)
|
||||
, mReplace(replace)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateFileTask> task =
|
||||
new CreateFileTask(aFileSystem, aTargetPath, aReplace);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
task->GetOutputBufferSize();
|
||||
|
||||
GetOutputBufferSize();
|
||||
if (aBlobData) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
aBlobData->GetInternalStream(getter_AddRefs(task->mBlobStream), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
aBlobData->GetInternalStream(getter_AddRefs(mBlobStream), aRv);
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
} else {
|
||||
task->mBlobData = aBlobData;
|
||||
mBlobData = aBlobData;
|
||||
}
|
||||
}
|
||||
|
||||
task->mArrayData.SwapElements(aArrayData);
|
||||
|
||||
mArrayData.SwapElements(aArrayData);
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aFileSystem->GetParentObject());
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
do_QueryInterface(aFileSystem->GetWindow());
|
||||
if (!globalObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
mPromise = Promise::Create(globalObject, aRv);
|
||||
}
|
||||
|
||||
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
|
@ -131,9 +61,32 @@ 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()
|
||||
|
@ -154,22 +107,16 @@ CreateFileTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
CreateFileTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemCreateFileParams param;
|
||||
param.filesystem() = aSerializedDOMPath;
|
||||
|
||||
aRv = mTargetPath->GetPath(param.realPath());
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.filesystem() = aFileSystem;
|
||||
param.realPath() = mTargetRealPath;
|
||||
param.replace() = mReplace;
|
||||
if (mBlobData) {
|
||||
BlobChild* actor =
|
||||
ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlobData);
|
||||
BlobChild* actor
|
||||
= ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlobData);
|
||||
if (actor) {
|
||||
param.data() = actor;
|
||||
}
|
||||
|
@ -180,7 +127,7 @@ CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
|||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
CreateFileTask::GetSuccessRequestResult() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
BlobParent* actor = GetBlobParent(mTargetBlobImpl);
|
||||
|
@ -193,8 +140,7 @@ CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
|||
}
|
||||
|
||||
void
|
||||
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemFileResponse r = aValue;
|
||||
|
@ -205,7 +151,7 @@ CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
|||
nsresult
|
||||
CreateFileTask::Work()
|
||||
{
|
||||
class MOZ_RAII AutoClose final
|
||||
class AutoClose
|
||||
{
|
||||
public:
|
||||
explicit AutoClose(nsIOutputStream* aStream)
|
||||
|
@ -218,7 +164,6 @@ CreateFileTask::Work()
|
|||
{
|
||||
mStream->Close();
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIOutputStream> mStream;
|
||||
};
|
||||
|
@ -231,19 +176,24 @@ CreateFileTask::Work()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mFileSystem->IsSafeFile(mTargetPath)) {
|
||||
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
|
||||
if (!file) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
|
||||
if (!mFileSystem->IsSafeFile(file)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
bool exists = false;
|
||||
nsresult rv = mTargetPath->Exists(&exists);
|
||||
nsresult rv = file->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
bool isFile = false;
|
||||
rv = mTargetPath->IsFile(&isFile);
|
||||
rv = file->IsFile(&isFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -257,19 +207,19 @@ CreateFileTask::Work()
|
|||
}
|
||||
|
||||
// Remove the old file before creating.
|
||||
rv = mTargetPath->Remove(false);
|
||||
rv = file->Remove(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
rv = mTargetPath->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mTargetPath);
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -312,7 +262,7 @@ CreateFileTask::Work()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mTargetBlobImpl = new BlobImplFile(mTargetPath);
|
||||
mTargetBlobImpl = new BlobImplFile(file);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -331,7 +281,7 @@ CreateFileTask::Work()
|
|||
return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
mTargetBlobImpl = new BlobImplFile(mTargetPath);
|
||||
mTargetBlobImpl = new BlobImplFile(file);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -352,8 +302,7 @@ CreateFileTask::HandlerCallback()
|
|||
return;
|
||||
}
|
||||
|
||||
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetParentObject(),
|
||||
mTargetBlobImpl);
|
||||
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetBlobImpl);
|
||||
mPromise->MaybeResolve(blob);
|
||||
mPromise = nullptr;
|
||||
mBlobData = nullptr;
|
||||
|
|
|
@ -20,22 +20,19 @@ class Blob;
|
|||
class BlobImpl;
|
||||
class Promise;
|
||||
|
||||
class CreateFileTask final : public FileSystemTaskBase
|
||||
class CreateFileTask final
|
||||
: public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
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);
|
||||
CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aPath,
|
||||
Blob* aBlobData,
|
||||
InfallibleTArray<uint8_t>& aArrayData,
|
||||
bool replace,
|
||||
ErrorResult& aRv);
|
||||
CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual
|
||||
~CreateFileTask();
|
||||
|
@ -48,15 +45,13 @@ public:
|
|||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
GetSuccessRequestResult() const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -65,20 +60,12 @@ 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;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
nsString mTargetRealPath;
|
||||
|
||||
// Not thread-safe and should be released on main thread.
|
||||
RefPtr<Blob> mBlobData;
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
|
||||
const nsAString& aStorageName)
|
||||
DeviceStorageFileSystem::DeviceStorageFileSystem(
|
||||
const nsAString& aStorageType,
|
||||
const nsAString& aStorageName)
|
||||
: mWindowId(0)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
@ -30,6 +31,12 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
|
|||
mStorageType = aStorageType;
|
||||
mStorageName = aStorageName;
|
||||
|
||||
// Generate the string representation of the file system.
|
||||
mString.AppendLiteral("devicestorage-");
|
||||
mString.Append(mStorageType);
|
||||
mString.Append('-');
|
||||
mString.Append(mStorageName);
|
||||
|
||||
mRequiresPermissionChecks =
|
||||
!mozilla::Preferences::GetBool("device.storage.prompt.testing", false);
|
||||
|
||||
|
@ -39,16 +46,19 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
|
|||
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);
|
||||
|
||||
// DeviceStorageTypeChecker is a singleton object and must be initialized on
|
||||
// the main thread. We initialize it here so that we can use it on the worker
|
||||
|
@ -79,8 +89,8 @@ DeviceStorageFileSystem::Shutdown()
|
|||
mShutdown = true;
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
DeviceStorageFileSystem::GetParentObject() const
|
||||
nsPIDOMWindowInner*
|
||||
DeviceStorageFileSystem::GetWindow() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
|
||||
|
@ -101,15 +111,12 @@ DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
|
|||
"Should be on parent process!");
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
nsCOMPtr<nsIFile> rootPath;
|
||||
nsresult rv = NS_NewLocalFile(GetLocalRootPath(), false,
|
||||
getter_AddRefs(rootPath));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// Check if this file belongs to this storage.
|
||||
nsAutoString path;
|
||||
if (NS_FAILED(aFile->GetPath(path))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this file belongs to this storage.
|
||||
if (NS_WARN_IF(!FileSystemUtils::IsDescendantPath(rootPath, aFile))) {
|
||||
if (!LocalPathToRealPath(path, path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -125,32 +132,10 @@ DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aDir);
|
||||
|
||||
ErrorResult rv;
|
||||
RefPtr<FileSystemBase> fs = aDir->GetFileSystem(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString fsSerialization;
|
||||
fs->SerializeDOMPath(fsSerialization);
|
||||
|
||||
nsAutoString thisSerialization;
|
||||
SerializeDOMPath(thisSerialization);
|
||||
|
||||
RefPtr<FileSystemBase> fs = aDir->GetFileSystem();
|
||||
MOZ_ASSERT(fs);
|
||||
// Check if the given directory is from this storage.
|
||||
return fsSerialization == thisSerialization;
|
||||
}
|
||||
|
||||
void
|
||||
DeviceStorageFileSystem::SerializeDOMPath(nsAString& aString) const
|
||||
{
|
||||
// Generate the string representation of the file system.
|
||||
aString.AssignLiteral("devicestorage-");
|
||||
aString.Append(mStorageType);
|
||||
aString.Append('-');
|
||||
aString.Append(mStorageName);
|
||||
return fs->ToString() == mString;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -30,8 +30,8 @@ public:
|
|||
virtual void
|
||||
Shutdown() override;
|
||||
|
||||
virtual nsISupports*
|
||||
GetParentObject() const override;
|
||||
virtual nsPIDOMWindowInner*
|
||||
GetWindow() const override;
|
||||
|
||||
virtual void
|
||||
GetRootName(nsAString& aRetval) const override;
|
||||
|
@ -41,10 +41,6 @@ public:
|
|||
|
||||
virtual bool
|
||||
IsSafeDirectory(Directory* aDir) const override;
|
||||
|
||||
virtual void
|
||||
SerializeDOMPath(nsAString& aSerializedString) const override;
|
||||
|
||||
private:
|
||||
virtual
|
||||
~DeviceStorageFileSystem();
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#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
|
||||
|
@ -35,70 +34,15 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
bool
|
||||
TokenizerIgnoreNothing(char16_t /* aChar */)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
IsValidRelativeDOMPath(const nsString& aPath, nsTArray<nsString>& aParts)
|
||||
{
|
||||
// We don't allow empty relative path to access the root.
|
||||
if (aPath.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Leading and trailing "/" are not allowed.
|
||||
if (aPath.First() == FILESYSTEM_DOM_PATH_SEPARATOR_CHAR ||
|
||||
aPath.Last() == FILESYSTEM_DOM_PATH_SEPARATOR_CHAR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_STRING(kCurrentDir, ".");
|
||||
NS_NAMED_LITERAL_STRING(kParentDir, "..");
|
||||
|
||||
// Split path and check each path component.
|
||||
nsCharSeparatedTokenizerTemplate<TokenizerIgnoreNothing>
|
||||
tokenizer(aPath, FILESYSTEM_DOM_PATH_SEPARATOR_CHAR);
|
||||
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
nsDependentSubstring pathComponent = tokenizer.nextToken();
|
||||
// The path containing empty components, such as "foo//bar", is invalid.
|
||||
// We don't allow paths, such as "../foo", "foo/./bar" and "foo/../bar",
|
||||
// to walk up the directory.
|
||||
if (pathComponent.IsEmpty() ||
|
||||
pathComponent.Equals(kCurrentDir) ||
|
||||
pathComponent.Equals(kParentDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aParts.AppendElement(pathComponent);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(Directory)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Directory)
|
||||
if (tmp->mFileSystem) {
|
||||
tmp->mFileSystem->Unlink();
|
||||
tmp->mFileSystem = nullptr;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
tmp->mFileSystem->Unlink();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Directory)
|
||||
if (tmp->mFileSystem) {
|
||||
tmp->mFileSystem->Traverse(cb);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
tmp->mFileSystem->Traverse(cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
|
@ -115,67 +59,33 @@ NS_INTERFACE_MAP_END
|
|||
already_AddRefed<Promise>
|
||||
Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
nsCOMPtr<nsIFile> path;
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aFileSystem->GetLocalRootPath()),
|
||||
true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
RefPtr<GetFileOrDirectoryTask> task = new GetFileOrDirectoryTask(
|
||||
aFileSystem, EmptyString(), true, aRv);
|
||||
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();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Directory>
|
||||
Directory::Create(nsISupports* aParent, nsIFile* aFile,
|
||||
DirectoryType aType, FileSystemBase* aFileSystem)
|
||||
Directory::Directory(FileSystemBase* aFileSystem,
|
||||
const nsAString& aPath)
|
||||
: mFileSystem(aFileSystem)
|
||||
, mPath(aPath)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aParent);
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isDir;
|
||||
nsresult rv = aFile->IsDirectory(&isDir);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) && isDir);
|
||||
#endif
|
||||
|
||||
RefPtr<Directory> directory =
|
||||
new Directory(aParent, aFile, aType, aFileSystem);
|
||||
return directory.forget();
|
||||
}
|
||||
|
||||
Directory::Directory(nsISupports* aParent,
|
||||
nsIFile* aFile,
|
||||
DirectoryType aType,
|
||||
FileSystemBase* aFileSystem)
|
||||
: mParent(aParent)
|
||||
, 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.
|
||||
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
|
||||
// Remove the trailing "/".
|
||||
mPath.Trim(FILESYSTEM_DOM_PATH_SEPARATOR, false, true);
|
||||
}
|
||||
|
||||
Directory::~Directory()
|
||||
{
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
nsPIDOMWindowInner*
|
||||
Directory::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
return mFileSystem->GetWindow();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -185,28 +95,25 @@ Directory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
}
|
||||
|
||||
void
|
||||
Directory::GetName(nsAString& aRetval, ErrorResult& aRv)
|
||||
Directory::GetName(nsAString& aRetval) const
|
||||
{
|
||||
aRetval.Truncate();
|
||||
|
||||
if (mType == eDOMRootDirectory) {
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
fs->GetRootName(aRetval);
|
||||
if (mPath.IsEmpty()) {
|
||||
mFileSystem->GetRootName(aRetval);
|
||||
return;
|
||||
}
|
||||
|
||||
aRv = mFile->GetLeafName(aRetval);
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
aRetval = Substring(mPath,
|
||||
mPath.RFindChar(FileSystemUtils::kSeparatorChar) + 1);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -231,20 +138,15 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
|||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
|
||||
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
if (!DOMPathToRealPath(aPath, realPath)) {
|
||||
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
|
||||
RefPtr<CreateFileTask> task =
|
||||
CreateFileTask::Create(fs, realPath, blobData, arrayData, replace, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
new CreateFileTask(mFileSystem, realPath, blobData, arrayData, replace, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->SetError(error);
|
||||
FileSystemPermissionRequest::RequestForTask(task);
|
||||
return task->GetPromise();
|
||||
|
@ -253,20 +155,16 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
|||
already_AddRefed<Promise>
|
||||
Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
|
||||
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
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()) {
|
||||
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();
|
||||
|
@ -275,21 +173,16 @@ Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
|
|||
already_AddRefed<Promise>
|
||||
Directory::Get(const nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
|
||||
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
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()) {
|
||||
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();
|
||||
|
@ -312,33 +205,30 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
|
|||
ErrorResult& aRv)
|
||||
{
|
||||
nsresult error = NS_OK;
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
nsAutoString 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()) {
|
||||
error = DOMPathToRealPath(aPath.GetAsString(), getter_AddRefs(realPath));
|
||||
} else if (!fs->IsSafeDirectory(&aPath.GetAsDirectory())) {
|
||||
if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) {
|
||||
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
} else if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) {
|
||||
error = NS_ERROR_DOM_SECURITY_ERR;
|
||||
} else {
|
||||
realPath = aPath.GetAsDirectory().mFile;
|
||||
realPath = aPath.GetAsDirectory().mPath;
|
||||
// The target must be a descendant of this directory.
|
||||
if (!FileSystemUtils::IsDescendantPath(mFile, realPath)) {
|
||||
if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) {
|
||||
error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<RemoveTask> task =
|
||||
RemoveTask::Create(fs, mFile, blob, realPath, aRecursive, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
RefPtr<RemoveTask> task = new RemoveTask(mFileSystem, mPath, blob, realPath,
|
||||
aRecursive, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
task->SetError(error);
|
||||
|
@ -347,38 +237,23 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
|
|||
}
|
||||
|
||||
void
|
||||
Directory::GetPath(nsAString& aRetval, ErrorResult& aRv)
|
||||
Directory::GetPath(nsAString& aRetval) const
|
||||
{
|
||||
if (mType == eDOMRootDirectory) {
|
||||
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
|
||||
if (mPath.IsEmpty()) {
|
||||
// The Directory ctor removes any trailing '/'; this is the root directory.
|
||||
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
|
||||
} else {
|
||||
// TODO: this should be a bit different...
|
||||
GetName(aRetval, aRv);
|
||||
aRetval = mPath;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
Directory::GetFullRealPath(nsAString& aPath)
|
||||
{
|
||||
nsresult rv = mFile->GetPath(aPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Directory::GetFilesAndDirectories(ErrorResult& aRv)
|
||||
Directory::GetFilesAndDirectories()
|
||||
{
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
RefPtr<GetDirectoryListingTask> task =
|
||||
GetDirectoryListingTask::Create(fs, mFile, mType, mFilters, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
new GetDirectoryListingTask(mFileSystem, mPath, mFilters, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -393,38 +268,16 @@ Directory::SetContentFilters(const nsAString& aFilters)
|
|||
}
|
||||
|
||||
FileSystemBase*
|
||||
Directory::GetFileSystem(ErrorResult& aRv)
|
||||
Directory::GetFileSystem() const
|
||||
{
|
||||
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(mParent);
|
||||
|
||||
mFileSystem = fs;
|
||||
}
|
||||
|
||||
return mFileSystem;
|
||||
return mFileSystem.get();
|
||||
}
|
||||
|
||||
nsresult
|
||||
Directory::DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const
|
||||
bool
|
||||
Directory::DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const
|
||||
{
|
||||
aRealPath.Truncate();
|
||||
|
||||
nsString relativePath;
|
||||
relativePath = aPath;
|
||||
|
||||
|
@ -432,26 +285,49 @@ Directory::DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const
|
|||
static const char kWhitespace[] = "\b\t\r\n ";
|
||||
relativePath.Trim(kWhitespace);
|
||||
|
||||
nsTArray<nsString> parts;
|
||||
if (!IsValidRelativeDOMPath(relativePath, parts)) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
if (!IsValidRelativePath(relativePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = mFile->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
aRealPath = mPath + NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR) +
|
||||
relativePath;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
Directory::IsValidRelativePath(const nsString& aPath)
|
||||
{
|
||||
// We don't allow empty relative path to access the root.
|
||||
if (aPath.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < parts.Length(); ++i) {
|
||||
rv = file->AppendRelativePath(parts[i]);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
// Leading and trailing "/" are not allowed.
|
||||
if (aPath.First() == FileSystemUtils::kSeparatorChar ||
|
||||
aPath.Last() == FileSystemUtils::kSeparatorChar) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_STRING(kCurrentDir, ".");
|
||||
NS_NAMED_LITERAL_STRING(kParentDir, "..");
|
||||
|
||||
// Split path and check each path component.
|
||||
nsCharSeparatedTokenizer tokenizer(aPath, FileSystemUtils::kSeparatorChar);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
nsDependentSubstring pathComponent = tokenizer.nextToken();
|
||||
// The path containing empty components, such as "foo//bar", is invalid.
|
||||
// We don't allow paths, such as "../foo", "foo/./bar" and "foo/../bar",
|
||||
// to walk up the directory.
|
||||
if (pathComponent.IsEmpty() ||
|
||||
pathComponent.Equals(kCurrentDir) ||
|
||||
pathComponent.Equals(kParentDir)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
file.forget(aFile);
|
||||
return NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/dom/File.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
// Resolve the name collision of Microsoft's API name with macros defined in
|
||||
|
@ -40,48 +41,25 @@ 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);
|
||||
|
||||
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(nsISupports* aParent, nsIFile* aDirectory,
|
||||
DirectoryType aType, FileSystemBase* aFileSystem = 0);
|
||||
Directory(FileSystemBase* aFileSystem, const nsAString& aPath);
|
||||
|
||||
// ========= Begin WebIDL bindings. ===========
|
||||
|
||||
nsISupports*
|
||||
nsPIDOMWindowInner*
|
||||
GetParentObject() const;
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void
|
||||
GetName(nsAString& aRetval, ErrorResult& aRv);
|
||||
GetName(nsAString& aRetval) const;
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
||||
|
@ -102,13 +80,10 @@ public:
|
|||
// From https://microsoftedge.github.io/directory-upload/proposal.html#directory-interface :
|
||||
|
||||
void
|
||||
GetPath(nsAString& aRetval, ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
GetFullRealPath(nsAString& aPath);
|
||||
GetPath(nsAString& aRetval) const;
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetFilesAndDirectories(ErrorResult& aRv);
|
||||
GetFilesAndDirectories();
|
||||
|
||||
// =========== End WebIDL bindings.============
|
||||
|
||||
|
@ -138,34 +113,26 @@ public:
|
|||
SetContentFilters(const nsAString& aFilters);
|
||||
|
||||
FileSystemBase*
|
||||
GetFileSystem(ErrorResult& aRv);
|
||||
|
||||
DirectoryType Type() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
GetFileSystem() const;
|
||||
private:
|
||||
Directory(nsISupports* aParent,
|
||||
nsIFile* aFile, DirectoryType aType,
|
||||
FileSystemBase* aFileSystem = nullptr);
|
||||
~Directory();
|
||||
|
||||
static bool
|
||||
IsValidRelativePath(const nsString& aPath);
|
||||
|
||||
/*
|
||||
* Convert relative DOM path to the absolute real path.
|
||||
* @return true if succeed. false if the DOM path is invalid.
|
||||
*/
|
||||
nsresult
|
||||
DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const;
|
||||
bool
|
||||
DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const;
|
||||
|
||||
already_AddRefed<Promise>
|
||||
RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
DirectoryType mType;
|
||||
|
||||
nsString mPath;
|
||||
nsString mFilters;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace dom {
|
|||
|
||||
// static
|
||||
already_AddRefed<FileSystemBase>
|
||||
FileSystemBase::DeserializeDOMPath(const nsAString& aString)
|
||||
FileSystemBase::FromString(const nsAString& aString)
|
||||
{
|
||||
if (StringBeginsWith(aString, NS_LITERAL_STRING("devicestorage-"))) {
|
||||
// The string representation of devicestorage file system is of the format:
|
||||
|
@ -38,7 +38,6 @@ FileSystemBase::DeserializeDOMPath(const nsAString& aString)
|
|||
new DeviceStorageFileSystem(storageType, storageName);
|
||||
return f.forget();
|
||||
}
|
||||
|
||||
return RefPtr<OSFileSystem>(new OSFileSystem(aString)).forget();
|
||||
}
|
||||
|
||||
|
@ -58,19 +57,37 @@ FileSystemBase::Shutdown()
|
|||
mShutdown = true;
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
FileSystemBase::GetParentObject() const
|
||||
nsPIDOMWindowInner*
|
||||
FileSystemBase::GetWindow() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIFile>
|
||||
FileSystemBase::GetLocalFile(const nsAString& aRealPath) const
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Should be on parent process!");
|
||||
nsAutoString localPath;
|
||||
FileSystemUtils::NormalizedPathToLocalPath(aRealPath, localPath);
|
||||
localPath = mLocalRootPath + localPath;
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = NS_NewLocalFile(localPath, false, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
|
||||
FileSystemBase::GetRealPath(BlobImpl* aFile, nsAString& aRealPath) 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);
|
||||
|
@ -78,13 +95,7 @@ FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
|
|||
return false;
|
||||
}
|
||||
|
||||
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(filePath),
|
||||
true, aPath);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return LocalPathToRealPath(filePath, aRealPath);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -99,5 +110,19 @@ FileSystemBase::IsSafeDirectory(Directory* aDir) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemBase::LocalPathToRealPath(const nsAString& aLocalPath,
|
||||
nsAString& aRealPath) const
|
||||
{
|
||||
nsAutoString path;
|
||||
FileSystemUtils::LocalPathToNormalizedPath(aLocalPath, path);
|
||||
if (!FileSystemUtils::IsDescendantPath(mNormalizedLocalRootPath, path)) {
|
||||
aRealPath.Truncate();
|
||||
return false;
|
||||
}
|
||||
aRealPath = Substring(path, mNormalizedLocalRootPath.Length());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "nsAutoPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -23,19 +25,28 @@ public:
|
|||
|
||||
// Create file system object from its string representation.
|
||||
static already_AddRefed<FileSystemBase>
|
||||
DeserializeDOMPath(const nsAString& aString);
|
||||
FromString(const nsAString& aString);
|
||||
|
||||
FileSystemBase();
|
||||
|
||||
virtual void
|
||||
Shutdown();
|
||||
|
||||
// SerializeDOMPath the FileSystem to string.
|
||||
virtual void
|
||||
SerializeDOMPath(nsAString& aOutput) const = 0;
|
||||
// Get the string representation of the file system.
|
||||
const nsString&
|
||||
ToString() const
|
||||
{
|
||||
return mString;
|
||||
}
|
||||
|
||||
virtual nsISupports*
|
||||
GetParentObject() const;
|
||||
virtual nsPIDOMWindowInner*
|
||||
GetWindow() const;
|
||||
|
||||
/**
|
||||
* Create nsIFile object from the given real path (absolute DOM path).
|
||||
*/
|
||||
already_AddRefed<nsIFile>
|
||||
GetLocalFile(const nsAString& aRealPath) const;
|
||||
|
||||
/*
|
||||
* Get the virtual name of the root directory. This name will be exposed to
|
||||
|
@ -62,8 +73,13 @@ 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, nsIFile** aPath) const;
|
||||
GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const;
|
||||
|
||||
/*
|
||||
* Get the permission name required to access this file system.
|
||||
|
@ -87,12 +103,21 @@ public:
|
|||
protected:
|
||||
virtual ~FileSystemBase();
|
||||
|
||||
bool
|
||||
LocalPathToRealPath(const nsAString& aLocalPath, nsAString& aRealPath) const;
|
||||
|
||||
// The local path of the root (i.e. the OS path, with OS path separators, of
|
||||
// the OS directory that acts as the root of this OSFileSystem).
|
||||
// Only available in the parent process.
|
||||
// In the child process, we don't use it and its value should be empty.
|
||||
nsString mLocalRootPath;
|
||||
|
||||
// The same, but with path separators normalized to "/".
|
||||
nsString mNormalizedLocalRootPath;
|
||||
|
||||
// The string representation of the file system.
|
||||
nsString mString;
|
||||
|
||||
bool mShutdown;
|
||||
|
||||
// The permission name required to access the file system.
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(FileSystemPermissionRequest, nsIRunnable,
|
||||
nsIContentPermissionRequest)
|
||||
NS_IMPL_ISUPPORTS(FileSystemPermissionRequest, nsIRunnable, nsIContentPermissionRequest)
|
||||
|
||||
// static
|
||||
void
|
||||
|
@ -29,7 +28,8 @@ FileSystemPermissionRequest::RequestForTask(FileSystemTaskBase* aTask)
|
|||
NS_DispatchToCurrentThread(request);
|
||||
}
|
||||
|
||||
FileSystemPermissionRequest::FileSystemPermissionRequest(FileSystemTaskBase* aTask)
|
||||
FileSystemPermissionRequest::FileSystemPermissionRequest(
|
||||
FileSystemTaskBase* aTask)
|
||||
: mTask(aTask)
|
||||
{
|
||||
MOZ_ASSERT(mTask, "aTask should not be null!");
|
||||
|
@ -44,8 +44,8 @@ FileSystemPermissionRequest::FileSystemPermissionRequest(FileSystemTaskBase* aTa
|
|||
|
||||
mPermissionType = filesystem->GetPermission();
|
||||
|
||||
mWindow = do_QueryInterface(filesystem->GetParentObject());
|
||||
if (NS_WARN_IF(!mWindow)) {
|
||||
mWindow = filesystem->GetWindow();
|
||||
if (!mWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,11 +28,8 @@ FileSystemRequestParent::~FileSystemRequestParent()
|
|||
#define FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(name) \
|
||||
case FileSystemParams::TFileSystem##name##Params: { \
|
||||
const FileSystem##name##Params& p = aParams; \
|
||||
mFileSystem = FileSystemBase::DeserializeDOMPath(p.filesystem()); \
|
||||
task = name##Task::Create(mFileSystem, p, this, rv); \
|
||||
if (NS_WARN_IF(rv.Failed())) { \
|
||||
return false; \
|
||||
} \
|
||||
mFileSystem = FileSystemBase::FromString(p.filesystem()); \
|
||||
task = new name##Task(mFileSystem, p, this); \
|
||||
break; \
|
||||
}
|
||||
|
||||
|
@ -42,8 +39,6 @@ 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)
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace dom {
|
|||
|
||||
namespace {
|
||||
|
||||
class FileSystemReleaseRunnable final : public nsRunnable
|
||||
class FileSystemReleaseRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit FileSystemReleaseRunnable(RefPtr<FileSystemBase>& aDoomed)
|
||||
|
@ -106,22 +106,12 @@ FileSystemTaskBase::Start()
|
|||
return;
|
||||
}
|
||||
|
||||
nsAutoString serialization;
|
||||
mFileSystem->SerializeDOMPath(serialization);
|
||||
|
||||
ErrorResult rv;
|
||||
FileSystemParams params = GetRequestParams(serialization, 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,
|
||||
params);
|
||||
GetRequestParams(mFileSystem->ToString()));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -164,17 +154,11 @@ FileSystemTaskBase::GetRequestResult() const
|
|||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (!HasError()) {
|
||||
ErrorResult rv;
|
||||
FileSystemResponseValue value = GetSuccessRequestResult(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return FileSystemErrorResponse(rv.StealNSResult());
|
||||
}
|
||||
|
||||
return value;
|
||||
if (HasError()) {
|
||||
return FileSystemErrorResponse(mErrorValue);
|
||||
} else {
|
||||
return GetSuccessRequestResult();
|
||||
}
|
||||
|
||||
return FileSystemErrorResponse(mErrorValue);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -187,9 +171,7 @@ FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
|
|||
FileSystemErrorResponse r = aValue;
|
||||
mErrorValue = r.error();
|
||||
} else {
|
||||
ErrorResult rv;
|
||||
SetSuccessRequestResult(aValue, rv);
|
||||
mErrorValue = rv.StealNSResult();
|
||||
SetSuccessRequestResult(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,8 +176,7 @@ protected:
|
|||
* @param filesystem The string representation of the file system.
|
||||
*/
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const = 0;
|
||||
GetRequestParams(const nsString& aFileSystem) const = 0;
|
||||
|
||||
/*
|
||||
* Wrap the task success result to FileSystemResponseValue for sending it
|
||||
|
@ -186,7 +185,7 @@ protected:
|
|||
* send the task success result back to the child process.
|
||||
*/
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const = 0;
|
||||
GetSuccessRequestResult() const = 0;
|
||||
|
||||
/*
|
||||
* Unwrap the IPC message to get the task success result.
|
||||
|
@ -195,8 +194,7 @@ protected:
|
|||
* success result.
|
||||
*/
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) = 0;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) = 0;
|
||||
|
||||
bool
|
||||
HasError() const { return mErrorValue != NS_OK; }
|
||||
|
|
|
@ -6,28 +6,59 @@
|
|||
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ bool
|
||||
FileSystemUtils::IsDescendantPath(nsIFile* aFile,
|
||||
nsIFile* aDescendantFile)
|
||||
// static
|
||||
void
|
||||
FileSystemUtils::LocalPathToNormalizedPath(const nsAString& aLocal,
|
||||
nsAString& aNorm)
|
||||
{
|
||||
nsAutoString path;
|
||||
nsresult rv = aFile->GetPath(path);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
nsString result;
|
||||
result = aLocal;
|
||||
#if defined(XP_WIN)
|
||||
char16_t* cur = result.BeginWriting();
|
||||
char16_t* end = result.EndWriting();
|
||||
for (; cur < end; ++cur) {
|
||||
if (char16_t('\\') == *cur)
|
||||
*cur = char16_t('/');
|
||||
}
|
||||
#endif
|
||||
aNorm = result;
|
||||
}
|
||||
|
||||
nsAutoString descendantPath;
|
||||
rv = aDescendantFile->GetPath(descendantPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
// static
|
||||
void
|
||||
FileSystemUtils::NormalizedPathToLocalPath(const nsAString& aNorm,
|
||||
nsAString& aLocal)
|
||||
{
|
||||
nsString result;
|
||||
result = aNorm;
|
||||
#if defined(XP_WIN)
|
||||
char16_t* cur = result.BeginWriting();
|
||||
char16_t* end = result.EndWriting();
|
||||
for (; cur < end; ++cur) {
|
||||
if (char16_t('/') == *cur)
|
||||
*cur = char16_t('\\');
|
||||
}
|
||||
#endif
|
||||
aLocal = result;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
FileSystemUtils::IsDescendantPath(const nsAString& aPath,
|
||||
const nsAString& aDescendantPath)
|
||||
{
|
||||
// The descendant path should begin with its ancestor path.
|
||||
nsAutoString prefix;
|
||||
prefix = aPath + NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR);
|
||||
|
||||
// Check the sub-directory path to see if it has the parent path as prefix.
|
||||
if (descendantPath.Length() <= path.Length() ||
|
||||
!StringBeginsWith(descendantPath, path)) {
|
||||
if (aDescendantPath.Length() < prefix.Length() ||
|
||||
!StringBeginsWith(aDescendantPath, prefix)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
#ifndef mozilla_dom_FileSystemUtils_h
|
||||
#define mozilla_dom_FileSystemUtils_h
|
||||
|
||||
class nsIFile;
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#define FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL "/"
|
||||
#define FILESYSTEM_DOM_PATH_SEPARATOR_CHAR '/'
|
||||
#define FILESYSTEM_DOM_PATH_SEPARATOR "/"
|
||||
|
||||
/*
|
||||
* This class is for error handling.
|
||||
|
@ -23,10 +22,26 @@ class FileSystemUtils
|
|||
{
|
||||
public:
|
||||
/*
|
||||
* Return true if aDescendantPath is a descendant of aPath.
|
||||
* Convert the path separator to "/".
|
||||
*/
|
||||
static void
|
||||
LocalPathToNormalizedPath(const nsAString& aLocal, nsAString& aNorm);
|
||||
|
||||
/*
|
||||
* Convert the normalized path separator "/" to the system dependent path
|
||||
* separator, which is "/" on Mac and Linux, and "\" on Windows.
|
||||
*/
|
||||
static void
|
||||
NormalizedPathToLocalPath(const nsAString& aNorm, nsAString& aLocal);
|
||||
|
||||
/*
|
||||
* Return true if aDescendantPath is a descendant of aPath. Both aPath and
|
||||
* aDescendantPath are absolute DOM path.
|
||||
*/
|
||||
static bool
|
||||
IsDescendantPath(nsIFile* aPath, nsIFile* aDescendantPath);
|
||||
IsDescendantPath(const nsAString& aPath, const nsAString& aDescendantPath);
|
||||
|
||||
static const char16_t kSeparatorChar = char16_t('/');
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#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"
|
||||
|
@ -20,80 +21,33 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* 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->GetParentObject());
|
||||
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<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::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters)
|
||||
const nsAString& aTargetPath,
|
||||
const nsAString& aFilters,
|
||||
ErrorResult& aRv)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mTargetRealPath(aTargetPath)
|
||||
, mFilters(aFilters)
|
||||
, mType(aType)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -112,79 +66,43 @@ GetDirectoryListingTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
GetDirectoryListingTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
GetDirectoryListingTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemGetDirectoryListingParams();
|
||||
}
|
||||
|
||||
return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
|
||||
mType == Directory::eDOMRootDirectory,
|
||||
return FileSystemGetDirectoryListingParams(aFileSystem, mTargetRealPath,
|
||||
mFilters);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetDirectoryListingTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
GetDirectoryListingTask::GetSuccessRequestResult() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
InfallibleTArray<PBlobParent*> blobs;
|
||||
|
||||
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);
|
||||
for (unsigned i = 0; i < mTargetBlobImpls.Length(); i++) {
|
||||
BlobParent* blobParent = GetBlobParent(mTargetBlobImpls[i]);
|
||||
if (blobParent) {
|
||||
blobs.AppendElement(blobParent);
|
||||
}
|
||||
}
|
||||
|
||||
FileSystemDirectoryListingResponse response;
|
||||
response.data().SwapElements(inputs);
|
||||
response.blobsParent().SwapElements(blobs);
|
||||
return response;
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aValue.type() ==
|
||||
FileSystemResponseValue::TFileSystemDirectoryListingResponse);
|
||||
|
||||
FileSystemDirectoryListingResponse r = aValue;
|
||||
for (uint32_t i = 0; i < r.data().Length(); ++i) {
|
||||
const FileSystemDirectoryListingResponseData& data = r.data()[i];
|
||||
nsTArray<PBlobChild*>& blobs = r.blobsChild();
|
||||
|
||||
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();
|
||||
}
|
||||
for (unsigned i = 0; i < blobs.Length(); i++) {
|
||||
mTargetBlobImpls.AppendElement(static_cast<BlobChild*>(blobs[i])->GetBlobImpl());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,19 +117,27 @@ 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 = mTargetPath->Exists(&exists);
|
||||
nsresult rv = dir->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
if (mType == Directory::eNotDOMRootDirectory) {
|
||||
if (!getRoot) {
|
||||
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
// If the root directory doesn't exit, create it.
|
||||
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -219,7 +145,7 @@ GetDirectoryListingTask::Work()
|
|||
|
||||
// Get isDirectory.
|
||||
bool isDir;
|
||||
rv = mTargetPath->IsDirectory(&isDir);
|
||||
rv = dir->IsDirectory(&isDir);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -229,7 +155,7 @@ GetDirectoryListingTask::Work()
|
|||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
rv = mTargetPath->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
rv = dir->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -260,7 +186,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))) ||
|
||||
|
@ -287,22 +213,9 @@ GetDirectoryListingTask::Work()
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
BlobImplFile* impl = new BlobImplFile(currFile);
|
||||
impl->LookupAndCacheIsDirectory();
|
||||
mTargetBlobImpls.AppendElement(impl);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -322,55 +235,37 @@ GetDirectoryListingTask::HandlerCallback()
|
|||
return;
|
||||
}
|
||||
|
||||
size_t count = mTargetData.Length();
|
||||
size_t count = mTargetBlobImpls.Length();
|
||||
|
||||
Sequence<OwningFileOrDirectory> listing;
|
||||
|
||||
if (!listing.SetLength(count, mozilla::fallible_t())) {
|
||||
mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
if (mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (mTargetBlobImpls[i]->IsDirectory()) {
|
||||
nsAutoString name;
|
||||
mTargetBlobImpls[i]->GetName(name);
|
||||
nsAutoString path(mTargetRealPath);
|
||||
path.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
|
||||
path.Append(name);
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIFile> rootPath;
|
||||
rv = NS_NewLocalFile(mFileSystem->GetLocalRootPath(), false,
|
||||
getter_AddRefs(rootPath));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
if (XRE_IsParentProcess()) {
|
||||
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(path);
|
||||
bool exist;
|
||||
file->Exists(&exist);
|
||||
MOZ_ASSERT(exist);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, directoryPath));
|
||||
#endif
|
||||
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(mFileSystem->GetParentObject(),
|
||||
directoryPath,
|
||||
Directory::eNotDOMRootDirectory,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
RefPtr<Directory> directory = new Directory(mFileSystem, path);
|
||||
// Propogate mFilter onto sub-Directory object:
|
||||
directory->SetContentFilters(mFilters);
|
||||
listing[i].SetAsDirectory() = directory;
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl);
|
||||
listing[i].SetAsFile() =
|
||||
File::Create(mFileSystem->GetParentObject(), mTargetData[i].mBlobImpl);
|
||||
listing[i].SetAsFile() = File::Create(mFileSystem->GetWindow(), mTargetBlobImpls[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#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"
|
||||
|
@ -17,21 +16,18 @@ namespace dom {
|
|||
|
||||
class BlobImpl;
|
||||
|
||||
class GetDirectoryListingTask final : public FileSystemTaskBase
|
||||
class GetDirectoryListingTask final
|
||||
: public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
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);
|
||||
// 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);
|
||||
|
||||
virtual
|
||||
~GetDirectoryListingTask();
|
||||
|
@ -41,28 +37,15 @@ public:
|
|||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
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);
|
||||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
GetSuccessRequestResult() const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -70,14 +53,14 @@ private:
|
|||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
nsString mTargetRealPath;
|
||||
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<Directory::BlobImplOrDirectoryPath> mTargetData;
|
||||
nsTArray<RefPtr<BlobImpl>> mTargetBlobImpls;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#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"
|
||||
|
@ -19,82 +20,37 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* 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->GetParentObject());
|
||||
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<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::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly)
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(
|
||||
FileSystemBase* aFileSystem,
|
||||
const nsAString& aTargetPath,
|
||||
bool aDirectoryOnly,
|
||||
ErrorResult& aRv)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mTargetRealPath(aTargetPath)
|
||||
, mIsDirectory(aDirectoryOnly)
|
||||
, mType(aType)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
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()
|
||||
|
@ -111,33 +67,18 @@ GetFileOrDirectoryTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
GetFileOrDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
GetFileOrDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemGetFileOrDirectoryParams();
|
||||
}
|
||||
|
||||
return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path,
|
||||
mType == Directory::eDOMRootDirectory);
|
||||
return FileSystemGetFileOrDirectoryParams(aFileSystem, mTargetRealPath);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetFileOrDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
GetFileOrDirectoryTask::GetSuccessRequestResult() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mIsDirectory) {
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemDirectoryResponse();
|
||||
}
|
||||
|
||||
return FileSystemDirectoryResponse(path);
|
||||
return FileSystemDirectoryResponse(mTargetRealPath);
|
||||
}
|
||||
|
||||
BlobParent* actor = GetBlobParent(mTargetBlobImpl);
|
||||
|
@ -150,8 +91,7 @@ GetFileOrDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
|||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
switch (aValue.type()) {
|
||||
|
@ -164,13 +104,7 @@ GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& a
|
|||
}
|
||||
case FileSystemResponseValue::TFileSystemDirectoryResponse: {
|
||||
FileSystemDirectoryResponse r = aValue;
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTargetRealPath = r.realPath();
|
||||
mIsDirectory = true;
|
||||
break;
|
||||
}
|
||||
|
@ -193,26 +127,33 @@ 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 = mTargetPath->Exists(&exists);
|
||||
nsresult rv = file->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
if (mType == Directory::eNotDOMRootDirectory) {
|
||||
if (!getRoot) {
|
||||
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
// If the root directory doesn't exit, create it.
|
||||
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Get isDirectory.
|
||||
rv = mTargetPath->IsDirectory(&mIsDirectory);
|
||||
rv = file->IsDirectory(&mIsDirectory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -222,13 +163,13 @@ GetFileOrDirectoryTask::Work()
|
|||
}
|
||||
|
||||
// Check if the root is a directory.
|
||||
if (mType == Directory::eDOMRootDirectory) {
|
||||
if (getRoot) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
|
||||
}
|
||||
|
||||
bool isFile;
|
||||
// Get isFile
|
||||
rv = mTargetPath->IsFile(&isFile);
|
||||
rv = file->IsFile(&isFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -238,11 +179,11 @@ GetFileOrDirectoryTask::Work()
|
|||
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
|
||||
}
|
||||
|
||||
if (!mFileSystem->IsSafeFile(mTargetPath)) {
|
||||
if (!mFileSystem->IsSafeFile(file)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
mTargetBlobImpl = new BlobImplFile(mTargetPath);
|
||||
mTargetBlobImpl = new BlobImplFile(file);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -263,19 +204,13 @@ GetFileOrDirectoryTask::HandlerCallback()
|
|||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
mType,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
RefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetParentObject(),
|
||||
mTargetBlobImpl);
|
||||
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetBlobImpl);
|
||||
mPromise->MaybeResolve(blob);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#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"
|
||||
|
@ -17,21 +16,18 @@ namespace dom {
|
|||
|
||||
class BlobImpl;
|
||||
|
||||
class GetFileOrDirectoryTask final : public FileSystemTaskBase
|
||||
class GetFileOrDirectoryTask final
|
||||
: public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
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);
|
||||
// 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);
|
||||
|
||||
virtual
|
||||
~GetFileOrDirectoryTask();
|
||||
|
@ -43,15 +39,13 @@ public:
|
|||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
GetSuccessRequestResult() const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -60,22 +54,10 @@ 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;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
nsString mTargetRealPath;
|
||||
// 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.
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -20,41 +20,40 @@ namespace dom {
|
|||
OSFileSystem::OSFileSystem(const nsAString& aRootDir)
|
||||
{
|
||||
mLocalRootPath = aRootDir;
|
||||
FileSystemUtils::LocalPathToNormalizedPath(mLocalRootPath,
|
||||
mNormalizedLocalRootPath);
|
||||
|
||||
// Non-mobile devices don't have the concept of separate permissions to
|
||||
// access different parts of devices storage like Pictures, or Videos, etc.
|
||||
mRequiresPermissionChecks = false;
|
||||
|
||||
mString = mLocalRootPath;
|
||||
|
||||
#ifdef DEBUG
|
||||
mPermission.AssignLiteral("never-used");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
OSFileSystem::Init(nsISupports* aParent)
|
||||
OSFileSystem::Init(nsPIDOMWindowInner* aWindow)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(!mParent, "No duple Init() calls");
|
||||
MOZ_ASSERT(aParent);
|
||||
mParent = aParent;
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIGlobalObject> obj = do_QueryInterface(aParent);
|
||||
MOZ_ASSERT(obj);
|
||||
#endif
|
||||
MOZ_ASSERT(!mWindow, "No duple Init() calls");
|
||||
MOZ_ASSERT(aWindow);
|
||||
mWindow = aWindow;
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
OSFileSystem::GetParentObject() const
|
||||
nsPIDOMWindowInner*
|
||||
OSFileSystem::GetWindow() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return mParent;
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
void
|
||||
OSFileSystem::GetRootName(nsAString& aRetval) const
|
||||
{
|
||||
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
|
||||
return aRetval.AssignLiteral("/");
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -80,20 +79,14 @@ OSFileSystem::IsSafeDirectory(Directory* aDir) const
|
|||
void
|
||||
OSFileSystem::Unlink()
|
||||
{
|
||||
mParent = nullptr;
|
||||
mWindow = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb)
|
||||
{
|
||||
OSFileSystem* tmp = this;
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent);
|
||||
}
|
||||
|
||||
void
|
||||
OSFileSystem::SerializeDOMPath(nsAString& aOutput) const
|
||||
{
|
||||
aOutput = mLocalRootPath;
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -18,12 +18,12 @@ public:
|
|||
explicit OSFileSystem(const nsAString& aRootDir);
|
||||
|
||||
void
|
||||
Init(nsISupports* aParent);
|
||||
Init(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
// Overrides FileSystemBase
|
||||
|
||||
virtual nsISupports*
|
||||
GetParentObject() const override;
|
||||
virtual nsPIDOMWindowInner*
|
||||
GetWindow() const override;
|
||||
|
||||
virtual void
|
||||
GetRootName(nsAString& aRetval) const override;
|
||||
|
@ -34,9 +34,6 @@ public:
|
|||
virtual bool
|
||||
IsSafeDirectory(Directory* aDir) const override;
|
||||
|
||||
virtual void
|
||||
SerializeDOMPath(nsAString& aOutput) const override;
|
||||
|
||||
// CC methods
|
||||
virtual void Unlink() override;
|
||||
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) override;
|
||||
|
@ -44,7 +41,7 @@ public:
|
|||
private:
|
||||
virtual ~OSFileSystem() {}
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -20,26 +20,9 @@ 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
|
||||
{
|
||||
FileSystemDirectoryListingResponseData[] data;
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
struct FileSystemErrorResponse
|
||||
|
|
|
@ -18,94 +18,27 @@
|
|||
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->GetParentObject());
|
||||
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,
|
||||
nsIFile* aDirPath,
|
||||
const nsAString& aDirPath,
|
||||
BlobImpl* aTargetBlob,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive)
|
||||
const nsAString& aTargetPath,
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mDirPath(aDirPath)
|
||||
, mDirRealPath(aDirPath)
|
||||
, mTargetBlobImpl(aTargetBlob)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mTargetRealPath(aTargetPath)
|
||||
, mRecursive(aRecursive)
|
||||
, mReturnValue(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
MOZ_ASSERT(aDirPath);
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aFileSystem->GetWindow());
|
||||
if (!globalObject) {
|
||||
return;
|
||||
}
|
||||
mPromise = Promise::Create(globalObject, aRv);
|
||||
}
|
||||
|
||||
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
|
||||
|
@ -115,9 +48,25 @@ 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()
|
||||
|
@ -134,49 +83,36 @@ RemoveTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
RemoveTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
RemoveTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemRemoveParams param;
|
||||
param.filesystem() = aSerializedDOMPath;
|
||||
|
||||
aRv = mDirPath->GetPath(param.directory());
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.filesystem() = aFileSystem;
|
||||
param.directory() = mDirRealPath;
|
||||
param.recursive() = mRecursive;
|
||||
if (mTargetBlobImpl) {
|
||||
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetParentObject(),
|
||||
mTargetBlobImpl);
|
||||
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(),
|
||||
mTargetBlobImpl);
|
||||
BlobChild* actor
|
||||
= ContentChild::GetSingleton()->GetOrCreateActorForBlob(blob);
|
||||
if (actor) {
|
||||
param.target() = actor;
|
||||
}
|
||||
} else {
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.target() = path;
|
||||
param.target() = mTargetRealPath;
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
RemoveTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
RemoveTask::GetSuccessRequestResult() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return FileSystemBooleanResponse(mReturnValue);
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemBooleanResponse r = aValue;
|
||||
|
@ -194,19 +130,23 @@ RemoveTask::Work()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Get the path if a File is passed as the target.
|
||||
// Get the DOM path if a File is passed as the target.
|
||||
if (mTargetBlobImpl) {
|
||||
if (!mFileSystem->GetRealPath(mTargetBlobImpl,
|
||||
getter_AddRefs(mTargetPath))) {
|
||||
if (!mFileSystem->GetRealPath(mTargetBlobImpl, mTargetRealPath)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
if (!FileSystemUtils::IsDescendantPath(mDirPath, mTargetPath)) {
|
||||
if (!FileSystemUtils::IsDescendantPath(mDirRealPath, mTargetRealPath)) {
|
||||
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 = mTargetPath->Exists(&exists);
|
||||
nsresult rv = file->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -217,16 +157,16 @@ RemoveTask::Work()
|
|||
}
|
||||
|
||||
bool isFile = false;
|
||||
rv = mTargetPath->IsFile(&isFile);
|
||||
rv = file->IsFile(&isFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (isFile && !mFileSystem->IsSafeFile(mTargetPath)) {
|
||||
if (isFile && !mFileSystem->IsSafeFile(file)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
rv = mTargetPath->Remove(mRecursive);
|
||||
rv = file->Remove(mRecursive);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -17,22 +17,19 @@ namespace dom {
|
|||
class BlobImpl;
|
||||
class Promise;
|
||||
|
||||
class RemoveTask final : public FileSystemTaskBase
|
||||
class RemoveTask final
|
||||
: public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
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);
|
||||
RemoveTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aDirPath,
|
||||
BlobImpl* aTargetBlob,
|
||||
const nsAString& aTargetPath,
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv);
|
||||
RemoveTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual
|
||||
~RemoveTask();
|
||||
|
@ -45,15 +42,13 @@ public:
|
|||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
GetSuccessRequestResult() const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -62,23 +57,12 @@ 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;
|
||||
nsCOMPtr<nsIFile> mDirPath;
|
||||
|
||||
nsString mDirRealPath;
|
||||
// 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;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
nsString mTargetRealPath;
|
||||
bool mRecursive;
|
||||
bool mReturnValue;
|
||||
};
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['tests']
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'DeviceStorageFileSystem.h',
|
||||
'Directory.h',
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
script_fileList.js
|
||||
|
||||
[test_basic.html]
|
|
@ -1,7 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
|
@ -1,25 +0,0 @@
|
|||
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.importGlobalProperties(["File"]);
|
||||
|
||||
addMessageListener("file.open", function () {
|
||||
var testFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get("ProfD", Ci.nsIFile);
|
||||
testFile.append("prefs.js");
|
||||
|
||||
sendAsyncMessage("file.opened", {
|
||||
file: new File(testFile)
|
||||
});
|
||||
});
|
||||
|
||||
addMessageListener("dir.open", function () {
|
||||
var testFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get("ProfD", Ci.nsIFile);
|
||||
|
||||
sendAsyncMessage("dir.opened", {
|
||||
dir: testFile.path
|
||||
});
|
||||
});
|
|
@ -1,103 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Directory API</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<input id="fileList" type="file"></input>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var directory;
|
||||
|
||||
function create_fileList() {
|
||||
var url = SimpleTest.getTestFileURL("script_fileList.js");
|
||||
var script = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
function onOpened(message) {
|
||||
var fileList = document.getElementById('fileList');
|
||||
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
|
||||
|
||||
// Just a simple test
|
||||
is(fileList.files.length, 1, "Filelist has 1 element");
|
||||
ok(fileList.files[0] instanceof Directory, "We have a directory.");
|
||||
|
||||
directory = fileList.files[0];
|
||||
|
||||
script.destroy();
|
||||
next();
|
||||
}
|
||||
|
||||
script.addMessageListener("dir.opened", onOpened);
|
||||
script.sendAsyncMessage("dir.open");
|
||||
}
|
||||
|
||||
function test_basic() {
|
||||
ok(directory, "Directory exists.");
|
||||
ok(directory instanceof Directory, "We have a directory.");
|
||||
is(directory.name, '/', "directory.name must be '/'");
|
||||
is(directory.path, '/', "directory.path must be '/'");
|
||||
next();
|
||||
}
|
||||
|
||||
function checkSubDir(dir) {
|
||||
dir.getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
|
||||
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getFilesAndDirectories() {
|
||||
directory.getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
ok(data.length, "We should have some data.");
|
||||
var promises = [];
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
|
||||
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
|
||||
promises.push(checkSubDir(data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
function() {
|
||||
ok(false, "Something when wrong");
|
||||
}
|
||||
).then(next);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
create_fileList,
|
||||
|
||||
test_basic,
|
||||
|
||||
getFilesAndDirectories,
|
||||
];
|
||||
|
||||
function next() {
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
next();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -11,6 +11,8 @@
|
|||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/Date.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/OSFileSystem.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsCRTGlue.h"
|
||||
|
||||
|
@ -249,63 +251,16 @@ class HTMLInputElementState final : public nsISupports
|
|||
mValue = aValue;
|
||||
}
|
||||
|
||||
void
|
||||
GetFilesOrDirectories(nsPIDOMWindowInner* aWindow,
|
||||
nsTArray<OwningFileOrDirectory>& aResult) const
|
||||
const nsTArray<RefPtr<BlobImpl>>& GetBlobImpls()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
return mBlobImpls;
|
||||
}
|
||||
|
||||
void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aArray)
|
||||
void SetBlobImpls(const nsTArray<RefPtr<File>>& aFile)
|
||||
{
|
||||
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;
|
||||
}
|
||||
mBlobImpls.Clear();
|
||||
for (uint32_t i = 0, len = aFile.Length(); i < len; ++i) {
|
||||
mBlobImpls.AppendElement(aFile[i]->Impl());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,9 +274,7 @@ class HTMLInputElementState final : public nsISupports
|
|||
~HTMLInputElementState() {}
|
||||
|
||||
nsString mValue;
|
||||
|
||||
nsTArray<Directory::BlobImplOrDirectoryPath> mBlobImplsOrDirectoryPaths;
|
||||
|
||||
nsTArray<RefPtr<BlobImpl>> mBlobImpls;
|
||||
bool mChecked;
|
||||
bool mCheckedSet;
|
||||
};
|
||||
|
@ -387,65 +340,33 @@ UploadLastDir::ContentPrefCallback::HandleError(nsresult error)
|
|||
namespace {
|
||||
|
||||
/**
|
||||
* This may return nullptr if the DOM File's implementation of
|
||||
* This may return nullptr if aDomFile'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>
|
||||
DOMFileOrDirectoryToLocalFile(const OwningFileOrDirectory& aData)
|
||||
DOMFileToLocalFile(File* aDomFile)
|
||||
{
|
||||
nsString path;
|
||||
|
||||
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);
|
||||
ErrorResult rv;
|
||||
aDomFile->GetMozFullPathInternal(path, rv);
|
||||
if (rv.Failed() || path.IsEmpty()) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
|
||||
getter_AddRefs(localFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
|
||||
getter_AddRefs(localFile));
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
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
|
||||
|
||||
|
||||
|
@ -462,7 +383,7 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
|||
mFilePicker->GetMode(&mode);
|
||||
|
||||
// Collect new selected filenames
|
||||
nsTArray<OwningFileOrDirectory> newFilesOrDirectories;
|
||||
nsTArray<RefPtr<File>> newFiles;
|
||||
if (mode == static_cast<int16_t>(nsIFilePicker::modeOpenMultiple)) {
|
||||
nsCOMPtr<nsISimpleEnumerator> iter;
|
||||
nsresult rv =
|
||||
|
@ -481,12 +402,9 @@ 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) {
|
||||
continue;
|
||||
if (domBlob) {
|
||||
newFiles.AppendElement(static_cast<File*>(domBlob.get()));
|
||||
}
|
||||
|
||||
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
|
||||
element->SetAsFile() = static_cast<File*>(domBlob.get());
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(mode == static_cast<int16_t>(nsIFilePicker::modeOpen) ||
|
||||
|
@ -498,25 +416,16 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
|||
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(tmp);
|
||||
if (blob) {
|
||||
RefPtr<File> file = static_cast<Blob*>(blob.get())->ToFile();
|
||||
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;
|
||||
newFiles.AppendElement(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (newFilesOrDirectories.IsEmpty()) {
|
||||
if (newFiles.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Store the last used directory using the content pref service:
|
||||
nsCOMPtr<nsIFile> file =
|
||||
DOMFileOrDirectoryToLocalFile(newFilesOrDirectories[0]);
|
||||
|
||||
nsCOMPtr<nsIFile> file = DOMFileToLocalFile(newFiles[0]);
|
||||
if (file) {
|
||||
nsCOMPtr<nsIFile> lastUsedDir;
|
||||
file->GetParent(getter_AddRefs(lastUsedDir));
|
||||
|
@ -527,7 +436,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->SetFilesOrDirectories(newFilesOrDirectories, true);
|
||||
mInput->SetFiles(newFiles, true);
|
||||
return nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
|
||||
NS_LITERAL_STRING("change"), true,
|
||||
|
@ -763,8 +672,7 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
|
|||
// Set default directry and filename
|
||||
nsAutoString defaultName;
|
||||
|
||||
const nsTArray<OwningFileOrDirectory>& oldFiles =
|
||||
GetFilesOrDirectoriesInternal();
|
||||
const nsTArray<RefPtr<File>>& oldFiles = GetFilesInternal();
|
||||
|
||||
nsCOMPtr<nsIFilePickerShownCallback> callback =
|
||||
new HTMLInputElement::nsFilePickerShownCallback(this, filePicker);
|
||||
|
@ -773,10 +681,18 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
|
|||
aType != FILE_PICKER_DIRECTORY) {
|
||||
nsString path;
|
||||
|
||||
nsCOMPtr<nsIFile> localFile = DOMFileOrDirectoryToLocalFile(oldFiles[0]);
|
||||
if (localFile) {
|
||||
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> parentFile;
|
||||
nsresult rv = localFile->GetParent(getter_AddRefs(parentFile));
|
||||
rv = localFile->GetParent(getter_AddRefs(parentFile));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
filePicker->SetDisplayDirectory(parentFile);
|
||||
}
|
||||
|
@ -787,8 +703,7 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
|
|||
// one file was selected before.
|
||||
if (oldFiles.Length() == 1) {
|
||||
nsAutoString leafName;
|
||||
GetDOMFileOrDirectoryName(oldFiles[0], leafName);
|
||||
|
||||
oldFiles[0]->GetName(leafName);
|
||||
if (!leafName.IsEmpty()) {
|
||||
filePicker->SetDefaultString(leafName);
|
||||
}
|
||||
|
@ -841,7 +756,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
|
||||
|
@ -1020,7 +935,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement,
|
|||
if (tmp->IsSingleLineTextControl(false)) {
|
||||
tmp->mInputData.mState->Traverse(cb);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesOrDirectories)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesAndDirectoriesPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
@ -1029,7 +944,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(mFilesOrDirectories)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesAndDirectoriesPromise)
|
||||
if (tmp->IsSingleLineTextControl(false)) {
|
||||
|
@ -1088,8 +1003,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->mFilesOrDirectories.Clear();
|
||||
it->mFilesOrDirectories.AppendElements(mFilesOrDirectories);
|
||||
it->mFiles.Clear();
|
||||
it->mFiles.AppendElements(mFiles);
|
||||
}
|
||||
break;
|
||||
case VALUE_MODE_DEFAULT_ON:
|
||||
|
@ -1527,9 +1442,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 (!mFilesOrDirectories.IsEmpty()) {
|
||||
if (!mFiles.IsEmpty()) {
|
||||
ErrorResult rv;
|
||||
GetDOMFileOrDirectoryPath(mFilesOrDirectories[0], aValue, rv);
|
||||
mFiles[0]->GetMozFullPath(aValue, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
@ -1541,10 +1456,10 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const
|
|||
#endif
|
||||
} else {
|
||||
// Just return the leaf name
|
||||
if (mFilesOrDirectories.IsEmpty()) {
|
||||
if (mFiles.IsEmpty()) {
|
||||
aValue.Truncate();
|
||||
} else {
|
||||
GetDOMFileOrDirectoryName(mFilesOrDirectories[0], aValue);
|
||||
mFiles[0]->GetName(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1579,8 +1494,8 @@ HTMLInputElement::IsValueEmpty() const
|
|||
void
|
||||
HTMLInputElement::ClearFiles(bool aSetValueChanged)
|
||||
{
|
||||
nsTArray<OwningFileOrDirectory> data;
|
||||
SetFilesOrDirectories(data, aSetValueChanged);
|
||||
nsTArray<RefPtr<File>> files;
|
||||
SetFiles(files, aSetValueChanged);
|
||||
}
|
||||
|
||||
/* static */ Decimal
|
||||
|
@ -2150,9 +2065,9 @@ void
|
|||
HTMLInputElement::MozGetFileNameArray(nsTArray<nsString>& aArray,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); i++) {
|
||||
nsAutoString str;
|
||||
GetDOMFileOrDirectoryPath(mFilesOrDirectories[i], str, aRv);
|
||||
for (uint32_t i = 0; i < mFiles.Length(); i++) {
|
||||
nsString str;
|
||||
mFiles[i]->GetMozFullPathInternal(str, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
@ -2202,29 +2117,25 @@ HTMLInputElement::MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles)
|
|||
if (!global) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<OwningFileOrDirectory> files;
|
||||
nsTArray<RefPtr<File>> files;
|
||||
for (uint32_t i = 0; i < aFiles.Length(); ++i) {
|
||||
RefPtr<File> file = File::Create(global, aFiles[i].get()->Impl());
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
OwningFileOrDirectory* element = files.AppendElement();
|
||||
element->SetAsFile() = file;
|
||||
files.AppendElement(file);
|
||||
}
|
||||
|
||||
SetFilesOrDirectories(files, true);
|
||||
SetFiles(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<OwningFileOrDirectory> files;
|
||||
nsTArray<RefPtr<File>> files;
|
||||
for (uint32_t i = 0; i < aFileNames.Length(); ++i) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
|
||||
|
@ -2241,28 +2152,21 @@ HTMLInputElement::MozSetFileNameArray(const Sequence<nsString>& aFileNames,
|
|||
NS_NewLocalFile(aFileNames[i], false, getter_AddRefs(file));
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
if (file) {
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
RefPtr<File> domFile = File::CreateFromFile(global, file);
|
||||
files.AppendElement(domFile);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
SetFilesOrDirectories(files, true);
|
||||
SetFiles(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
|
||||
|
@ -2284,34 +2188,6 @@ HTMLInputElement::MozSetFileNameArray(const char16_t** aFileNames,
|
|||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::MozSetDirectory(const nsAString& aDirectoryPath,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file;
|
||||
NS_ConvertUTF16toUTF8 path(aDirectoryPath);
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
|
||||
if (NS_WARN_IF(!window)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Directory> directory = Directory::Create(window, file,
|
||||
Directory::eDOMRootDirectory);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
nsTArray<OwningFileOrDirectory> array;
|
||||
OwningFileOrDirectory* element = array.AppendElement();
|
||||
element->SetAsDirectory() = directory;
|
||||
|
||||
SetFilesOrDirectories(array, true);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLInputElement::MozIsTextField(bool aExcludePassword)
|
||||
{
|
||||
|
@ -2503,14 +2379,14 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
|
|||
return;
|
||||
}
|
||||
|
||||
if (mFilesOrDirectories.Length() == 1) {
|
||||
GetDOMFileOrDirectoryName(mFilesOrDirectories[0], aValue);
|
||||
if (mFiles.Length() == 1) {
|
||||
mFiles[0]->GetName(aValue);
|
||||
return;
|
||||
}
|
||||
|
||||
nsXPIDLString value;
|
||||
|
||||
if (mFilesOrDirectories.IsEmpty()) {
|
||||
if (mFiles.IsEmpty()) {
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
"NoFilesSelected", value);
|
||||
|
@ -2520,7 +2396,7 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
|
|||
}
|
||||
} else {
|
||||
nsString count;
|
||||
count.AppendInt(int(mFilesOrDirectories.Length()));
|
||||
count.AppendInt(int(mFiles.Length()));
|
||||
|
||||
const char16_t* params[] = { count.get() };
|
||||
nsContentUtils::FormatLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
|
@ -2531,13 +2407,13 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
|
|||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories,
|
||||
bool aSetValueChanged)
|
||||
HTMLInputElement::SetFiles(const nsTArray<RefPtr<File>>& aFiles,
|
||||
bool aSetValueChanged)
|
||||
{
|
||||
mFilesOrDirectories.Clear();
|
||||
mFilesOrDirectories.AppendElements(aFilesOrDirectories);
|
||||
mFiles.Clear();
|
||||
mFiles.AppendElements(aFiles);
|
||||
|
||||
AfterSetFilesOrDirectories(aSetValueChanged);
|
||||
AfterSetFiles(aSetValueChanged);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2545,22 +2421,22 @@ HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
|
|||
bool aSetValueChanged)
|
||||
{
|
||||
RefPtr<FileList> files = static_cast<FileList*>(aFiles);
|
||||
mFilesOrDirectories.Clear();
|
||||
mFiles.Clear();
|
||||
|
||||
if (aFiles) {
|
||||
uint32_t listLength;
|
||||
aFiles->GetLength(&listLength);
|
||||
for (uint32_t i = 0; i < listLength; i++) {
|
||||
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
|
||||
*element = files->UnsafeItem(i);
|
||||
RefPtr<File> file = files->Item(i);
|
||||
mFiles.AppendElement(file);
|
||||
}
|
||||
}
|
||||
|
||||
AfterSetFilesOrDirectories(aSetValueChanged);
|
||||
AfterSetFiles(aSetValueChanged);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::AfterSetFilesOrDirectories(bool aSetValueChanged)
|
||||
HTMLInputElement::AfterSetFiles(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
|
||||
|
@ -2578,11 +2454,11 @@ HTMLInputElement::AfterSetFilesOrDirectories(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 (mFilesOrDirectories.IsEmpty()) {
|
||||
if (mFiles.IsEmpty()) {
|
||||
mFirstFilePath.Truncate();
|
||||
} else {
|
||||
ErrorResult rv;
|
||||
GetDOMFileOrDirectoryPath(mFilesOrDirectories[0], mFirstFilePath, rv);
|
||||
mFiles[0]->GetMozFullPath(mFirstFilePath, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
}
|
||||
|
@ -2656,27 +2532,24 @@ HTMLInputElement::HandleNumberControlSpin(void* aData)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsresult
|
||||
HTMLInputElement::UpdateFileList()
|
||||
{
|
||||
if (mFileList) {
|
||||
mFileList->Clear();
|
||||
|
||||
const nsTArray<OwningFileOrDirectory>& array =
|
||||
GetFilesOrDirectoriesInternal();
|
||||
|
||||
for (uint32_t i = 0; i < array.Length(); ++i) {
|
||||
if (array[i].IsFile()) {
|
||||
mFileList->Append(array[i].GetAsFile());
|
||||
} else {
|
||||
MOZ_ASSERT(array[i].IsDirectory());
|
||||
mFileList->Append(array[i].GetAsDirectory());
|
||||
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
|
||||
for (uint32_t i = 0; i < files.Length(); ++i) {
|
||||
if (!mFileList->Append(files[i])) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we (lazily) create a new Promise for GetFilesAndDirectories:
|
||||
mFilesAndDirectoriesPromise = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -4115,7 +3988,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())) {
|
||||
|
@ -4666,7 +4539,7 @@ HTMLInputElement::GetValueAsDate(const nsAString& aValue,
|
|||
}
|
||||
|
||||
uint32_t endOfYearOffset = aValue.Length() - 6;
|
||||
|
||||
|
||||
if (aValue[endOfYearOffset] != '-' ||
|
||||
aValue[endOfYearOffset + 3] != '-') {
|
||||
return false;
|
||||
|
@ -5034,38 +4907,45 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const nsTArray<OwningFileOrDirectory>& filesAndDirs =
|
||||
GetFilesOrDirectoriesInternal();
|
||||
const nsTArray<RefPtr<File>>& filesAndDirs = GetFilesInternal();
|
||||
|
||||
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<Directory> directory = filesAndDirs[i].GetAsDirectory();
|
||||
RefPtr<OSFileSystem> fs = new OSFileSystem(dirname);
|
||||
fs->Init(OwnerDoc()->GetInnerWindow());
|
||||
|
||||
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].GetAsFile();
|
||||
filesAndDirsSeq[i].SetAsFile() = filesAndDirs[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5699,18 +5579,13 @@ HTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
|
|||
if (mType == NS_FORM_INPUT_FILE) {
|
||||
// Submit files
|
||||
|
||||
const nsTArray<OwningFileOrDirectory>& files =
|
||||
GetFilesOrDirectoriesInternal();
|
||||
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
|
||||
|
||||
bool hasBlobs = false;
|
||||
for (uint32_t i = 0; i < files.Length(); ++i) {
|
||||
if (files[i].IsFile()) {
|
||||
hasBlobs = true;
|
||||
aFormSubmission->AddNameBlobOrNullPair(name, files[i].GetAsFile());
|
||||
}
|
||||
aFormSubmission->AddNameBlobOrNullPair(name, files[i]);
|
||||
}
|
||||
|
||||
if (!hasBlobs) {
|
||||
if (files.IsEmpty()) {
|
||||
aFormSubmission->AddNameBlobOrNullPair(name, nullptr);
|
||||
}
|
||||
|
||||
|
@ -5744,9 +5619,9 @@ HTMLInputElement::SaveState()
|
|||
}
|
||||
break;
|
||||
case VALUE_MODE_FILENAME:
|
||||
if (!mFilesOrDirectories.IsEmpty()) {
|
||||
if (!mFiles.IsEmpty()) {
|
||||
inputState = new HTMLInputElementState();
|
||||
inputState->SetFilesOrDirectories(mFilesOrDirectories);
|
||||
inputState->SetBlobImpls(mFiles);
|
||||
}
|
||||
break;
|
||||
case VALUE_MODE_VALUE:
|
||||
|
@ -5915,7 +5790,7 @@ HTMLInputElement::AddStates(EventStates aStates)
|
|||
}
|
||||
}
|
||||
}
|
||||
nsGenericHTMLFormElementWithState::AddStates(aStates);
|
||||
nsGenericHTMLFormElementWithState::AddStates(aStates);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -5952,13 +5827,20 @@ HTMLInputElement::RestoreState(nsPresState* aState)
|
|||
break;
|
||||
case VALUE_MODE_FILENAME:
|
||||
{
|
||||
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
|
||||
if (window) {
|
||||
nsTArray<OwningFileOrDirectory> array;
|
||||
inputState->GetFilesOrDirectories(window, array);
|
||||
const nsTArray<RefPtr<BlobImpl>>& blobImpls = inputState->GetBlobImpls();
|
||||
|
||||
SetFilesOrDirectories(array, true);
|
||||
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);
|
||||
}
|
||||
|
||||
SetFiles(files, true);
|
||||
}
|
||||
break;
|
||||
case VALUE_MODE_VALUE:
|
||||
|
@ -6468,15 +6350,15 @@ HTMLInputElement::IsValueMissing() const
|
|||
switch (GetValueMode()) {
|
||||
case VALUE_MODE_VALUE:
|
||||
return IsValueEmpty();
|
||||
|
||||
case VALUE_MODE_FILENAME:
|
||||
return GetFilesOrDirectoriesInternal().IsEmpty();
|
||||
|
||||
{
|
||||
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
|
||||
return files.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,7 +20,6 @@
|
|||
#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"
|
||||
|
@ -221,13 +220,12 @@ public:
|
|||
|
||||
void GetDisplayFileName(nsAString& aFileName) const;
|
||||
|
||||
const nsTArray<OwningFileOrDirectory>& GetFilesOrDirectoriesInternal() const
|
||||
const nsTArray<RefPtr<File>>& GetFilesInternal() const
|
||||
{
|
||||
return mFilesOrDirectories;
|
||||
return mFiles;
|
||||
}
|
||||
|
||||
void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories,
|
||||
bool aSetValueChanged);
|
||||
void SetFiles(const nsTArray<RefPtr<File>>& aFiles, bool aSetValueChanged);
|
||||
void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
|
||||
|
||||
// Called when a nsIFilePicker or a nsIColorPicker terminate.
|
||||
|
@ -724,7 +722,6 @@ public:
|
|||
|
||||
void MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv);
|
||||
void MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles);
|
||||
void MozSetDirectory(const nsAString& aDirectoryPath, ErrorResult& aRv);
|
||||
|
||||
HTMLInputElement* GetOwnerNumberControl();
|
||||
|
||||
|
@ -925,12 +922,12 @@ protected:
|
|||
/**
|
||||
* Update mFileList with the currently selected file.
|
||||
*/
|
||||
void UpdateFileList();
|
||||
nsresult UpdateFileList();
|
||||
|
||||
/**
|
||||
* Called after calling one of the SetFilesOrDirectories() functions.
|
||||
* Called after calling one of the SetFiles() functions.
|
||||
*/
|
||||
void AfterSetFilesOrDirectories(bool aSetValueChanged);
|
||||
void AfterSetFiles(bool aSetValueChanged);
|
||||
|
||||
/**
|
||||
* Determine whether the editor needs to be initialized explicitly for
|
||||
|
@ -1269,16 +1266,16 @@ protected:
|
|||
} mInputData;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
|
||||
nsTArray<RefPtr<File>> mFiles;
|
||||
|
||||
#ifndef MOZ_CHILD_PERMISSIONS
|
||||
/**
|
||||
|
|
|
@ -187,6 +187,30 @@ 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,7 +444,8 @@ ResolveMysteryFile(BlobImpl* aImpl,
|
|||
BlobChild* actor = ActorFromRemoteBlobImpl(aImpl);
|
||||
if (actor) {
|
||||
return actor->SetMysteryBlobInfo(aName, aContentType,
|
||||
aSize, aLastModifiedDate);
|
||||
aSize, aLastModifiedDate,
|
||||
BlobDirState::eUnknownIfDir);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -670,7 +670,8 @@ public:
|
|||
EmptyBlobImpl(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate)
|
||||
: BlobImplBase(aName, aContentType, 0, aLastModifiedDate)
|
||||
: BlobImplBase(aName, aContentType, 0, aLastModifiedDate,
|
||||
BlobDirState::eIsNotDir)
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
@ -715,12 +716,14 @@ 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)
|
||||
{
|
||||
|
@ -962,6 +965,7 @@ CreateBlobImpl(const ParentBlobConstructorParams& aParams,
|
|||
metadata.mName = params.name();
|
||||
metadata.mLength = params.length();
|
||||
metadata.mLastModifiedDate = params.modDate();
|
||||
metadata.mDirState = BlobDirState(params.dirState());
|
||||
}
|
||||
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
|
@ -1771,6 +1775,7 @@ public:
|
|||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aModDate,
|
||||
BlobDirState aDirState,
|
||||
bool aIsSameProcessBlob);
|
||||
|
||||
// For Blob.
|
||||
|
@ -2048,6 +2053,18 @@ 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;
|
||||
|
||||
|
@ -2079,8 +2096,9 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
|
|||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aModDate,
|
||||
BlobDirState aDirState,
|
||||
bool aIsSameProcessBlob)
|
||||
: BlobImplBase(aName, aContentType, aLength, aModDate)
|
||||
: BlobImplBase(aName, aContentType, aLength, aModDate, aDirState)
|
||||
, mIsSlice(false)
|
||||
{
|
||||
if (aIsSameProcessBlob) {
|
||||
|
@ -2796,6 +2814,34 @@ 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
|
||||
|
@ -2987,7 +3033,8 @@ BlobChild::CommonInit(BlobChild* aOther, BlobImpl* aBlobImpl)
|
|||
MOZ_ASSERT(!rv.Failed());
|
||||
|
||||
remoteBlob = new RemoteBlobImpl(this, otherImpl, name, contentType, length,
|
||||
modDate, false /* SameProcessBlobImpl */);
|
||||
modDate, otherImpl->GetDirState(),
|
||||
false /* SameProcessBlobImpl */);
|
||||
} else {
|
||||
remoteBlob = new RemoteBlobImpl(this, otherImpl, contentType, length,
|
||||
false /* SameProcessBlobImpl */);
|
||||
|
@ -3039,6 +3086,7 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
|
|||
params.contentType(),
|
||||
params.length(),
|
||||
params.modDate(),
|
||||
BlobDirState(params.dirState()),
|
||||
false /* SameProcessBlobImpl */);
|
||||
break;
|
||||
}
|
||||
|
@ -3074,6 +3122,7 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
|
|||
contentType,
|
||||
size,
|
||||
lastModifiedDate,
|
||||
blobImpl->GetDirState(),
|
||||
true /* SameProcessBlobImpl */);
|
||||
} else {
|
||||
remoteBlob = new RemoteBlobImpl(this, blobImpl, contentType, size,
|
||||
|
@ -3254,7 +3303,8 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
|
|||
MOZ_ASSERT(!rv.Failed());
|
||||
|
||||
blobParams =
|
||||
FileBlobConstructorParams(name, contentType, length, modDate, blobData);
|
||||
FileBlobConstructorParams(name, contentType, length, modDate,
|
||||
aBlobImpl->GetDirState(), blobData);
|
||||
} else {
|
||||
blobParams = NormalBlobConstructorParams(contentType, length, blobData);
|
||||
}
|
||||
|
@ -3427,7 +3477,8 @@ bool
|
|||
BlobChild::SetMysteryBlobInfo(const nsString& aName,
|
||||
const nsString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate)
|
||||
int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mBlobImpl);
|
||||
|
@ -3440,6 +3491,7 @@ BlobChild::SetMysteryBlobInfo(const nsString& aName,
|
|||
aContentType,
|
||||
aLength,
|
||||
aLastModifiedDate,
|
||||
aDirState,
|
||||
void_t() /* optionalBlobData */);
|
||||
return SendResolveMystery(params);
|
||||
}
|
||||
|
@ -3802,7 +3854,7 @@ BlobParent::GetOrCreateFromImpl(ParentManagerType* aManager,
|
|||
|
||||
blobParams =
|
||||
FileBlobConstructorParams(name, contentType, length, modDate,
|
||||
void_t());
|
||||
aBlobImpl->GetDirState(), void_t());
|
||||
} else {
|
||||
blobParams = NormalBlobConstructorParams(contentType, length, void_t());
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ class ContentChild;
|
|||
class nsIContentChild;
|
||||
class PBlobStreamChild;
|
||||
|
||||
enum BlobDirState : uint32_t;
|
||||
|
||||
class BlobChild final
|
||||
: public PBlobChild
|
||||
{
|
||||
|
@ -115,7 +117,8 @@ public:
|
|||
SetMysteryBlobInfo(const nsString& aName,
|
||||
const nsString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate);
|
||||
int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState);
|
||||
|
||||
// Use this for non-file blobs.
|
||||
bool
|
||||
|
|
|
@ -73,6 +73,7 @@ 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,18 +53,15 @@ 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::IORunnable::IORunnable(FilePickerParent *aFPParent,
|
||||
nsTArray<nsCOMPtr<nsIFile>>& aFiles,
|
||||
bool aIsDirectory)
|
||||
FilePickerParent::FileSizeAndDateRunnable::FileSizeAndDateRunnable(FilePickerParent *aFPParent,
|
||||
nsTArray<RefPtr<BlobImpl>>& aBlobs)
|
||||
: mFilePickerParent(aFPParent)
|
||||
, mIsDirectory(aIsDirectory)
|
||||
{
|
||||
mFiles.SwapElements(aFiles);
|
||||
MOZ_ASSERT_IF(aIsDirectory, mFiles.Length() == 1);
|
||||
mBlobs.SwapElements(aBlobs);
|
||||
}
|
||||
|
||||
bool
|
||||
FilePickerParent::IORunnable::Dispatch()
|
||||
FilePickerParent::FileSizeAndDateRunnable::Dispatch()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -78,49 +75,23 @@ FilePickerParent::IORunnable::Dispatch()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FilePickerParent::IORunnable::Run()
|
||||
FilePickerParent::FileSizeAndDateRunnable::Run()
|
||||
{
|
||||
// If we're on the main thread, then that means we're done. Just send the
|
||||
// results.
|
||||
if (NS_IsMainThread()) {
|
||||
if (mFilePickerParent) {
|
||||
mFilePickerParent->SendFilesOrDirectories(mResults);
|
||||
mFilePickerParent->SendFiles(mBlobs);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// 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;
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Dispatch ourselves back on the main thread.
|
||||
|
@ -130,46 +101,29 @@ FilePickerParent::IORunnable::Run()
|
|||
// thread.
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FilePickerParent::IORunnable::Destroy()
|
||||
FilePickerParent::FileSizeAndDateRunnable::Destroy()
|
||||
{
|
||||
mFilePickerParent = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FilePickerParent::SendFilesOrDirectories(const nsTArray<BlobImplOrString>& aData)
|
||||
FilePickerParent::SendFiles(const nsTArray<RefPtr<BlobImpl>>& aBlobs)
|
||||
{
|
||||
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 < aData.Length(); i++) {
|
||||
MOZ_ASSERT(aData[i].mType == BlobImplOrString::eBlobImpl);
|
||||
BlobParent* blobParent = parent->GetOrCreateActorForBlobImpl(aData[i].mBlobImpl);
|
||||
for (unsigned i = 0; i < aBlobs.Length(); i++) {
|
||||
BlobParent* blobParent = parent->GetOrCreateActorForBlobImpl(aBlobs[i]);
|
||||
if (blobParent) {
|
||||
blobs.AppendElement(blobParent);
|
||||
}
|
||||
}
|
||||
|
||||
InputBlobs inblobs;
|
||||
InputFiles inblobs;
|
||||
inblobs.blobsParent().SwapElements(blobs);
|
||||
Unused << Send__delete__(this, inblobs, mResult);
|
||||
}
|
||||
|
@ -184,7 +138,7 @@ FilePickerParent::Done(int16_t aResult)
|
|||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsCOMPtr<nsIFile>> files;
|
||||
nsTArray<RefPtr<BlobImpl>> blobs;
|
||||
if (mMode == nsIFilePicker::modeOpenMultiple) {
|
||||
nsCOMPtr<nsISimpleEnumerator> iter;
|
||||
NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
|
||||
|
@ -195,26 +149,22 @@ FilePickerParent::Done(int16_t aResult)
|
|||
iter->GetNext(getter_AddRefs(supports));
|
||||
if (supports) {
|
||||
nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
|
||||
MOZ_ASSERT(file);
|
||||
files.AppendElement(file);
|
||||
|
||||
RefPtr<BlobImpl> blobimpl = new BlobImplFile(file);
|
||||
blobs.AppendElement(blobimpl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
mFilePicker->GetFile(getter_AddRefs(file));
|
||||
if (file) {
|
||||
files.AppendElement(file);
|
||||
RefPtr<BlobImpl> blobimpl = new BlobImplFile(file);
|
||||
blobs.AppendElement(blobimpl);
|
||||
}
|
||||
}
|
||||
|
||||
if (files.IsEmpty()) {
|
||||
Unused << Send__delete__(this, void_t(), mResult);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mRunnable);
|
||||
mRunnable = new IORunnable(this, files, mMode == nsIFilePicker::modeGetFolder);
|
||||
|
||||
mRunnable = new FileSizeAndDateRunnable(this, blobs);
|
||||
// Dispatch to background thread to do I/O:
|
||||
if (!mRunnable->Dispatch()) {
|
||||
Unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/PFilePickerParent.h"
|
||||
|
||||
class nsIFile;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -31,19 +29,7 @@ class FilePickerParent : public PFilePickerParent
|
|||
virtual ~FilePickerParent();
|
||||
|
||||
void Done(int16_t aResult);
|
||||
|
||||
struct BlobImplOrString
|
||||
{
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
nsString mDirectoryPath;
|
||||
|
||||
enum {
|
||||
eBlobImpl,
|
||||
eDirectoryPath
|
||||
} mType;
|
||||
};
|
||||
|
||||
void SendFilesOrDirectories(const nsTArray<BlobImplOrString>& aData);
|
||||
void SendFiles(const nsTArray<RefPtr<BlobImpl>>& aDomBlobs);
|
||||
|
||||
virtual bool RecvOpen(const int16_t& aSelectedType,
|
||||
const bool& aAddToRecentDocs,
|
||||
|
@ -75,26 +61,21 @@ class FilePickerParent : public PFilePickerParent
|
|||
private:
|
||||
bool CreateFilePicker();
|
||||
|
||||
// This runnable is used to do some I/O operation on a separate thread.
|
||||
class IORunnable : public nsRunnable
|
||||
class FileSizeAndDateRunnable : public nsRunnable
|
||||
{
|
||||
FilePickerParent* mFilePickerParent;
|
||||
nsTArray<nsCOMPtr<nsIFile>> mFiles;
|
||||
nsTArray<BlobImplOrString> mResults;
|
||||
nsTArray<RefPtr<BlobImpl>> mBlobs;
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
bool mIsDirectory;
|
||||
|
||||
public:
|
||||
IORunnable(FilePickerParent *aFPParent,
|
||||
nsTArray<nsCOMPtr<nsIFile>>& aFiles,
|
||||
bool aIsDirectory);
|
||||
|
||||
FileSizeAndDateRunnable(FilePickerParent *aFPParent,
|
||||
nsTArray<RefPtr<BlobImpl>>& aBlobs);
|
||||
bool Dispatch();
|
||||
NS_IMETHOD Run();
|
||||
void Destroy();
|
||||
};
|
||||
|
||||
RefPtr<IORunnable> mRunnable;
|
||||
RefPtr<FileSizeAndDateRunnable> mRunnable;
|
||||
RefPtr<FilePickerShownCallback> mCallback;
|
||||
nsCOMPtr<nsIFilePicker> mFilePicker;
|
||||
|
||||
|
|
|
@ -289,7 +289,6 @@ 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,
|
||||
|
@ -306,7 +305,6 @@ struct FileSystemGetFileOrDirectoryParams
|
|||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
};
|
||||
|
||||
union FileSystemPathOrFileValue
|
||||
|
|
|
@ -12,20 +12,14 @@ using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct InputBlobs
|
||||
struct InputFiles
|
||||
{
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
struct InputDirectory
|
||||
union MaybeInputFiles
|
||||
{
|
||||
nsString directoryPath;
|
||||
};
|
||||
|
||||
union MaybeInputData
|
||||
{
|
||||
InputBlobs;
|
||||
InputDirectory;
|
||||
InputFiles;
|
||||
void_t;
|
||||
};
|
||||
|
||||
|
@ -39,7 +33,7 @@ parent:
|
|||
nsString displayDirectory);
|
||||
|
||||
child:
|
||||
async __delete__(MaybeInputData data, int16_t result);
|
||||
async __delete__(MaybeInputFiles files, int16_t result);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -20,7 +20,6 @@ interface Directory {
|
|||
/*
|
||||
* The leaf name of the directory.
|
||||
*/
|
||||
[Throws]
|
||||
readonly attribute DOMString name;
|
||||
|
||||
/*
|
||||
|
@ -106,13 +105,11 @@ 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();
|
||||
};
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
*/
|
||||
|
||||
interface FileList {
|
||||
[Throws]
|
||||
getter (File or Directory)? item(unsigned long index);
|
||||
|
||||
getter File? item(unsigned long index);
|
||||
readonly attribute unsigned long length;
|
||||
};
|
||||
|
|
|
@ -155,10 +155,6 @@ partial interface HTMLInputElement {
|
|||
[ChromeOnly]
|
||||
void mozSetFileArray(sequence<File> files);
|
||||
|
||||
// This method is meant to use for testing only.
|
||||
[ChromeOnly, Throws]
|
||||
void mozSetDirectory(DOMString directoryPath);
|
||||
|
||||
// Number controls (<input type=number>) have an anonymous text control
|
||||
// (<input type=text>) in the anonymous shadow tree that they contain. On
|
||||
// such an anonymous text control this property provides access to the
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#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"
|
||||
|
@ -31,36 +30,6 @@ 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.
|
||||
|
@ -105,9 +74,9 @@ class nsBaseFilePickerEnumerator : public nsISimpleEnumerator
|
|||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsBaseFilePickerEnumerator(nsPIDOMWindowOuter* aParent,
|
||||
nsISimpleEnumerator* iterator,
|
||||
int16_t aMode)
|
||||
explicit nsBaseFilePickerEnumerator(nsPIDOMWindowOuter* aParent,
|
||||
nsISimpleEnumerator* iterator,
|
||||
int16_t aMode)
|
||||
: mIterator(iterator)
|
||||
, mParent(aParent->GetCurrentInnerWindow())
|
||||
, mMode(aMode)
|
||||
|
@ -129,10 +98,32 @@ public:
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return LocalFileToDirectoryOrBlob(mParent,
|
||||
mMode == nsIFilePicker::modeGetFolder,
|
||||
localFile,
|
||||
aResult);
|
||||
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;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
|
@ -358,10 +349,10 @@ nsBaseFilePicker::GetDomFileOrDirectory(nsISupports** aValue)
|
|||
|
||||
auto* innerParent = mParent ? mParent->GetCurrentInnerWindow() : nullptr;
|
||||
|
||||
return LocalFileToDirectoryOrBlob(innerParent,
|
||||
mMode == nsIFilePicker::modeGetFolder,
|
||||
localFile,
|
||||
aValue);
|
||||
RefPtr<File> domFile = File::CreateFromFile(innerParent, localFile);
|
||||
domFile->Impl()->SetIsDirectory(mMode == nsIFilePicker::modeGetFolder);
|
||||
nsCOMPtr<nsIDOMBlob>(domFile).forget(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#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"
|
||||
|
@ -143,11 +142,11 @@ nsFilePickerProxy::Open(nsIFilePickerShownCallback* aCallback)
|
|||
}
|
||||
|
||||
bool
|
||||
nsFilePickerProxy::Recv__delete__(const MaybeInputData& aData,
|
||||
nsFilePickerProxy::Recv__delete__(const MaybeInputFiles& aFiles,
|
||||
const int16_t& aResult)
|
||||
{
|
||||
if (aData.type() == MaybeInputData::TInputBlobs) {
|
||||
const InfallibleTArray<PBlobChild*>& blobs = aData.get_InputBlobs().blobsChild();
|
||||
if (aFiles.type() == MaybeInputFiles::TInputFiles) {
|
||||
const InfallibleTArray<PBlobChild*>& blobs = aFiles.get_InputFiles().blobsChild();
|
||||
for (uint32_t i = 0; i < blobs.Length(); ++i) {
|
||||
BlobChild* actor = static_cast<BlobChild*>(blobs[i]);
|
||||
RefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
|
||||
|
@ -162,24 +161,8 @@ nsFilePickerProxy::Recv__delete__(const MaybeInputData& aData,
|
|||
RefPtr<File> file = File::Create(inner, blobImpl);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
|
||||
element->SetAsFile() = file;
|
||||
mFilesOrDirectories.AppendElement(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) {
|
||||
|
@ -199,16 +182,8 @@ nsFilePickerProxy::GetDomFileOrDirectory(nsISupports** aValue)
|
|||
}
|
||||
|
||||
MOZ_ASSERT(mFilesOrDirectories.Length() == 1);
|
||||
|
||||
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);
|
||||
nsCOMPtr<nsIDOMBlob> blob = mFilesOrDirectories[0].get();
|
||||
blob.forget(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -219,9 +194,8 @@ class SimpleEnumerator final : public nsISimpleEnumerator
|
|||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit
|
||||
SimpleEnumerator(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories)
|
||||
: mFilesOrDirectories(aFilesOrDirectories)
|
||||
explicit SimpleEnumerator(const nsTArray<RefPtr<File>>& aFiles)
|
||||
: mFiles(aFiles)
|
||||
, mIndex(0)
|
||||
{}
|
||||
|
||||
|
@ -229,26 +203,17 @@ public:
|
|||
HasMoreElements(bool* aRetvalue) override
|
||||
{
|
||||
MOZ_ASSERT(aRetvalue);
|
||||
*aRetvalue = mIndex < mFilesOrDirectories.Length();
|
||||
*aRetvalue = mIndex < mFiles.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetNext(nsISupports** aValue) override
|
||||
GetNext(nsISupports** aSupports) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mIndex < mFilesOrDirectories.Length(), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(mIndex < mFiles.Length(), NS_ERROR_FAILURE);
|
||||
|
||||
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);
|
||||
nsCOMPtr<nsIDOMBlob> blob = mFiles[mIndex++].get();
|
||||
blob.forget(aSupports);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -256,7 +221,7 @@ private:
|
|||
~SimpleEnumerator()
|
||||
{}
|
||||
|
||||
nsTArray<mozilla::dom::OwningFileOrDirectory> mFilesOrDirectories;
|
||||
nsTArray<RefPtr<File>> mFiles;
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
|
@ -267,8 +232,7 @@ 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,12 +13,17 @@
|
|||
#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
|
||||
|
@ -54,13 +59,13 @@ public:
|
|||
|
||||
// PFilePickerChild
|
||||
virtual bool
|
||||
Recv__delete__(const MaybeInputData& aData, const int16_t& aResult) override;
|
||||
Recv__delete__(const MaybeInputFiles& aFiles, const int16_t& aResult) override;
|
||||
|
||||
private:
|
||||
~nsFilePickerProxy();
|
||||
void InitNative(nsIWidget*, const nsAString&) override;
|
||||
|
||||
nsTArray<mozilla::dom::OwningFileOrDirectory> mFilesOrDirectories;
|
||||
nsTArray<RefPtr<mozilla::dom::File>> mFilesOrDirectories;
|
||||
nsCOMPtr<nsIFilePickerShownCallback> mCallback;
|
||||
|
||||
int16_t mSelectedType;
|
||||
|
|
Загрузка…
Ссылка в новой задаче