зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1173320 - patch 1/8 - Implement Directory object as string and not as BlobImpl, r=smaug
This commit is contained in:
Родитель
1f36475812
Коммит
f1f32823dd
|
@ -227,12 +227,6 @@ Blob::IsFile() const
|
|||
return mImpl->IsFile();
|
||||
}
|
||||
|
||||
bool
|
||||
Blob::IsDirectory() const
|
||||
{
|
||||
return mImpl->IsDirectory();
|
||||
}
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>*
|
||||
Blob::GetSubBlobImpls() const
|
||||
{
|
||||
|
@ -420,11 +414,10 @@ File::Create(nsISupports* aParent, BlobImpl* aImpl)
|
|||
/* static */ already_AddRefed<File>
|
||||
File::Create(nsISupports* aParent, const nsAString& aName,
|
||||
const nsAString& aContentType, uint64_t aLength,
|
||||
int64_t aLastModifiedDate, BlobDirState aDirState)
|
||||
int64_t aLastModifiedDate)
|
||||
{
|
||||
RefPtr<File> file = new File(aParent,
|
||||
new BlobImplBase(aName, aContentType, aLength, aLastModifiedDate,
|
||||
aDirState));
|
||||
new BlobImplBase(aName, aContentType, aLength, aLastModifiedDate));
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
|
@ -946,17 +939,6 @@ BlobImplFile::SetPath(const nsAString& aPath)
|
|||
mPath = aPath;
|
||||
}
|
||||
|
||||
void
|
||||
BlobImplFile::LookupAndCacheIsDirectory()
|
||||
{
|
||||
MOZ_ASSERT(mIsFile,
|
||||
"This should only be called when this object has been created "
|
||||
"from an nsIFile to note that the nsIFile is a directory");
|
||||
bool isDir;
|
||||
mFile->IsDirectory(&isDir);
|
||||
mDirState = isDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// EmptyBlobImpl implementation
|
||||
|
||||
|
|
|
@ -44,18 +44,6 @@ class BlobImpl;
|
|||
class File;
|
||||
class OwningArrayBufferOrArrayBufferViewOrBlobOrString;
|
||||
|
||||
/**
|
||||
* Used to indicate when a Blob/BlobImpl that was created from an nsIFile
|
||||
* (when IsFile() will return true) was from an nsIFile for which
|
||||
* nsIFile::IsDirectory() returned true. This is a tri-state to enable us to
|
||||
* assert that the state is always set when callers request it.
|
||||
*/
|
||||
enum BlobDirState : uint32_t {
|
||||
eIsDir,
|
||||
eIsNotDir,
|
||||
eUnknownIfDir
|
||||
};
|
||||
|
||||
class Blob : public nsIDOMBlob
|
||||
, public nsIXHRSendable
|
||||
, public nsIMutable
|
||||
|
@ -101,12 +89,6 @@ public:
|
|||
|
||||
bool IsFile() const;
|
||||
|
||||
/**
|
||||
* This may return true if the Blob was created from an nsIFile that is a
|
||||
* directory.
|
||||
*/
|
||||
bool IsDirectory() const;
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>* GetSubBlobImpls() const;
|
||||
|
||||
// This method returns null if this Blob is not a File; it returns
|
||||
|
@ -114,9 +96,6 @@ public:
|
|||
// otherwise it returns a new File object with the same BlobImpl.
|
||||
already_AddRefed<File> ToFile();
|
||||
|
||||
// XXXjwatt Consider having a ToDirectory() method. The need for a FileSystem
|
||||
// object complicates that though.
|
||||
|
||||
// This method creates a new File object with the given name and the same
|
||||
// BlobImpl.
|
||||
already_AddRefed<File> ToFile(const nsAString& aName,
|
||||
|
@ -194,7 +173,7 @@ public:
|
|||
static already_AddRefed<File>
|
||||
Create(nsISupports* aParent, const nsAString& aName,
|
||||
const nsAString& aContentType, uint64_t aLength,
|
||||
int64_t aLastModifiedDate, BlobDirState aDirState);
|
||||
int64_t aLastModifiedDate);
|
||||
|
||||
// The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
|
||||
// freed by free so it must be allocated by malloc or something
|
||||
|
@ -339,28 +318,6 @@ public:
|
|||
|
||||
virtual bool IsFile() const = 0;
|
||||
|
||||
/**
|
||||
* Called when this BlobImpl was created from an nsIFile in order to call
|
||||
* nsIFile::IsDirectory() and cache the result so that when the BlobImpl is
|
||||
* copied to another process that informaton is available.
|
||||
* nsIFile::IsDirectory() does synchronous I/O, and BlobImpl objects may be
|
||||
* created on the main thread or in a non-chrome process (where I/O is not
|
||||
* allowed). Do not call this on a non-chrome process, and preferably do not
|
||||
* call it on the main thread.
|
||||
*
|
||||
* Not all creators of BlobImplFile will call this method, in which case
|
||||
* calling IsDirectory will MOZ_ASSERT.
|
||||
*/
|
||||
virtual void LookupAndCacheIsDirectory() = 0;
|
||||
virtual void SetIsDirectory(bool aIsDir) = 0;
|
||||
virtual bool IsDirectory() const = 0;
|
||||
|
||||
/**
|
||||
* Prefer IsDirectory(). This exists to help consumer code pass on state from
|
||||
* one BlobImpl when creating another.
|
||||
*/
|
||||
virtual BlobDirState GetDirState() const = 0;
|
||||
|
||||
// True if this implementation can be sent to other threads.
|
||||
virtual bool MayBeClonedToOtherThreads() const
|
||||
{
|
||||
|
@ -377,11 +334,9 @@ class BlobImplBase : public BlobImpl
|
|||
{
|
||||
public:
|
||||
BlobImplBase(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState = BlobDirState::eUnknownIfDir)
|
||||
uint64_t aLength, int64_t aLastModifiedDate)
|
||||
: mIsFile(true)
|
||||
, mImmutable(false)
|
||||
, mDirState(aDirState)
|
||||
, mContentType(aContentType)
|
||||
, mName(aName)
|
||||
, mStart(0)
|
||||
|
@ -397,7 +352,6 @@ public:
|
|||
uint64_t aLength)
|
||||
: mIsFile(true)
|
||||
, mImmutable(false)
|
||||
, mDirState(BlobDirState::eUnknownIfDir)
|
||||
, mContentType(aContentType)
|
||||
, mName(aName)
|
||||
, mStart(0)
|
||||
|
@ -412,7 +366,6 @@ public:
|
|||
BlobImplBase(const nsAString& aContentType, uint64_t aLength)
|
||||
: mIsFile(false)
|
||||
, mImmutable(false)
|
||||
, mDirState(BlobDirState::eUnknownIfDir)
|
||||
, mContentType(aContentType)
|
||||
, mStart(0)
|
||||
, mLength(aLength)
|
||||
|
@ -427,7 +380,6 @@ public:
|
|||
uint64_t aLength)
|
||||
: mIsFile(false)
|
||||
, mImmutable(false)
|
||||
, mDirState(BlobDirState::eUnknownIfDir)
|
||||
, mContentType(aContentType)
|
||||
, mStart(aStart)
|
||||
, mLength(aLength)
|
||||
|
@ -518,36 +470,6 @@ public:
|
|||
return mIsFile;
|
||||
}
|
||||
|
||||
virtual void LookupAndCacheIsDirectory() override
|
||||
{
|
||||
MOZ_ASSERT(false, "Why is this being called on a non-BlobImplFile?");
|
||||
}
|
||||
|
||||
virtual void SetIsDirectory(bool aIsDir) override
|
||||
{
|
||||
MOZ_ASSERT(mIsFile,
|
||||
"This should only be called when this object has been created "
|
||||
"from an nsIFile to note that the nsIFile is a directory");
|
||||
mDirState = aIsDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the nsIFile that this object wraps is a directory.
|
||||
*/
|
||||
virtual bool IsDirectory() const override
|
||||
{
|
||||
MOZ_ASSERT(mDirState != BlobDirState::eUnknownIfDir,
|
||||
"Must only be used by callers for whom the code paths are "
|
||||
"know to call LookupAndCacheIsDirectory() or "
|
||||
"SetIsDirectory()");
|
||||
return mDirState == BlobDirState::eIsDir;
|
||||
}
|
||||
|
||||
virtual BlobDirState GetDirState() const override
|
||||
{
|
||||
return mDirState;
|
||||
}
|
||||
|
||||
virtual bool IsSizeUnknown() const override
|
||||
{
|
||||
return mLength == UINT64_MAX;
|
||||
|
@ -565,7 +487,6 @@ protected:
|
|||
|
||||
bool mIsFile;
|
||||
bool mImmutable;
|
||||
BlobDirState mDirState;
|
||||
|
||||
nsString mContentType;
|
||||
nsString mName;
|
||||
|
@ -590,8 +511,7 @@ public:
|
|||
|
||||
BlobImplMemory(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
|
||||
const nsAString& aContentType, int64_t aLastModifiedDate)
|
||||
: BlobImplBase(aName, aContentType, aLength, aLastModifiedDate,
|
||||
BlobDirState::eIsNotDir)
|
||||
: BlobImplBase(aName, aContentType, aLength, aLastModifiedDate)
|
||||
, mDataOwner(new DataOwner(aMemoryBuffer, aLength))
|
||||
{
|
||||
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
|
||||
|
@ -792,8 +712,6 @@ public:
|
|||
|
||||
void SetPath(const nsAString& aFullPath);
|
||||
|
||||
virtual void LookupAndCacheIsDirectory() override;
|
||||
|
||||
// We always have size and date for this kind of blob.
|
||||
virtual bool IsSizeUnknown() const override { return false; }
|
||||
virtual bool IsDateUnknown() const override { return false; }
|
||||
|
|
|
@ -7625,7 +7625,6 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
|
|||
// has this data available to it when passed over:
|
||||
blobImpl->GetSize(rv);
|
||||
blobImpl->GetLastModified(rv);
|
||||
blobImpl->LookupAndCacheIsDirectory();
|
||||
} else {
|
||||
if (aInSyncMessage) {
|
||||
// Can't do anything.
|
||||
|
|
|
@ -49,7 +49,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mItems)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage)
|
||||
|
@ -57,7 +57,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mItems)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage)
|
||||
|
@ -281,11 +281,12 @@ DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
|
|||
FileList*
|
||||
DataTransfer::GetFiles(ErrorResult& aRv)
|
||||
{
|
||||
return GetFilesInternal(aRv, nsContentUtils::SubjectPrincipal());
|
||||
return GetFileListInternal(aRv, nsContentUtils::SubjectPrincipal());
|
||||
}
|
||||
|
||||
FileList*
|
||||
DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal)
|
||||
DataTransfer::GetFileListInternal(ErrorResult& aRv,
|
||||
nsIPrincipal* aSubjectPrincipal)
|
||||
{
|
||||
if (mEventMessage != eDrop &&
|
||||
mEventMessage != eLegacyDragDrop &&
|
||||
|
@ -293,14 +294,15 @@ DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mFiles) {
|
||||
mFiles = new FileList(static_cast<nsIDOMDataTransfer*>(this));
|
||||
if (!mFileList) {
|
||||
mFileList = new FileList(static_cast<nsIDOMDataTransfer*>(this));
|
||||
|
||||
uint32_t count = mItems.Length();
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIVariant> variant;
|
||||
aRv = GetDataAtInternal(NS_ConvertUTF8toUTF16(kFileMime), i, aSubjectPrincipal, getter_AddRefs(variant));
|
||||
aRv = GetDataAtInternal(NS_ConvertUTF8toUTF16(kFileMime), i,
|
||||
aSubjectPrincipal, getter_AddRefs(variant));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -338,21 +340,21 @@ DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal
|
|||
MOZ_ASSERT(domFile);
|
||||
}
|
||||
|
||||
if (!mFiles->Append(domFile)) {
|
||||
if (!mFileList->Append(domFile)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mFiles;
|
||||
return mFileList;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataTransfer::GetFiles(nsIDOMFileList** aFileList)
|
||||
{
|
||||
ErrorResult rv;
|
||||
NS_IF_ADDREF(*aFileList = GetFilesInternal(rv, nsContentUtils::GetSystemPrincipal()));
|
||||
NS_IF_ADDREF(*aFileList = GetFileListInternal(rv, nsContentUtils::GetSystemPrincipal()));
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
|
@ -854,7 +856,7 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mFiles) {
|
||||
if (!mFileList) {
|
||||
GetFiles(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
|
@ -863,38 +865,14 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
|
|||
|
||||
Sequence<OwningFileOrDirectory> filesAndDirsSeq;
|
||||
|
||||
if (mFiles && mFiles->Length()) {
|
||||
if (!filesAndDirsSeq.SetLength(mFiles->Length(), mozilla::fallible_t())) {
|
||||
if (mFileList && mFileList->Length()) {
|
||||
if (!filesAndDirsSeq.SetLength(mFileList->Length(), mozilla::fallible_t())) {
|
||||
p->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mFiles->Length(); ++i) {
|
||||
if (mFiles->Item(i)->Impl()->IsDirectory()) {
|
||||
#if defined(ANDROID) || defined(MOZ_B2G)
|
||||
MOZ_ASSERT(false,
|
||||
"Directory picking should have been redirected to normal "
|
||||
"file picking for platforms that don't have a directory "
|
||||
"picker");
|
||||
#endif
|
||||
nsAutoString path;
|
||||
mFiles->Item(i)->GetMozFullPathInternal(path, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
int32_t leafSeparatorIndex = path.RFind(FILE_PATH_SEPARATOR);
|
||||
nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex);
|
||||
nsDependentSubstring basename = Substring(path, leafSeparatorIndex);
|
||||
|
||||
RefPtr<OSFileSystem> fs = new OSFileSystem(dirname);
|
||||
fs->Init(parentNode->OwnerDoc()->GetInnerWindow());
|
||||
|
||||
RefPtr<Directory> directory = new Directory(fs, basename);
|
||||
directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive"));
|
||||
filesAndDirsSeq[i].SetAsDirectory() = directory;
|
||||
} else {
|
||||
filesAndDirsSeq[i].SetAsFile() = mFiles->Item(i);
|
||||
}
|
||||
for (uint32_t i = 0; i < mFileList->Length(); ++i) {
|
||||
filesAndDirsSeq[i].SetAsFile() = mFileList->Item(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ protected:
|
|||
void FillInExternalData(TransferItem& aItem, uint32_t aIndex);
|
||||
|
||||
|
||||
FileList* GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal);
|
||||
FileList* GetFileListInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal);
|
||||
nsresult GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aSubjectPrincipal, nsIVariant** aData);
|
||||
nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex,
|
||||
|
@ -300,8 +300,9 @@ protected:
|
|||
// array of items, each containing an array of format->data pairs
|
||||
nsTArray<nsTArray<TransferItem> > mItems;
|
||||
|
||||
// array of files, containing only the files present in the dataTransfer
|
||||
RefPtr<FileList> mFiles;
|
||||
// array of files and directories, containing only the files present in the
|
||||
// dataTransfer
|
||||
RefPtr<FileList> mFileList;
|
||||
|
||||
// the target of the drag. The drag and dragend events will fire at this.
|
||||
nsCOMPtr<mozilla::dom::Element> mDragTarget;
|
||||
|
|
|
@ -318,8 +318,7 @@ ConvertActorToFile(FileHandleBase* aFileHandle,
|
|||
actor->SetMysteryBlobInfo(mutableFile->Name(),
|
||||
mutableFile->Type(),
|
||||
size.get_uint64_t(),
|
||||
lastModified.get_int64_t(),
|
||||
BlobDirState::eUnknownIfDir);
|
||||
lastModified.get_int64_t());
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
|
|
@ -16,33 +16,73 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aPath,
|
||||
ErrorResult& aRv)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetRealPath(aPath)
|
||||
/* static */ already_AddRefed<CreateDirectoryTask>
|
||||
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateDirectoryTask> task =
|
||||
new CreateDirectoryTask(aFileSystem, aTargetPath);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aFileSystem->GetWindow());
|
||||
if (!globalObject) {
|
||||
return;
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
mPromise = Promise::Create(globalObject, aRv);
|
||||
|
||||
task->mPromise = Promise::Create(globalObject, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateDirectoryTask::CreateDirectoryTask(
|
||||
FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
/* static */ already_AddRefed<CreateDirectoryTask>
|
||||
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateDirectoryTask> task =
|
||||
new CreateDirectoryTask(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
mTargetRealPath = aParam.realPath();
|
||||
}
|
||||
|
||||
CreateDirectoryTask::~CreateDirectoryTask()
|
||||
|
@ -59,25 +99,44 @@ CreateDirectoryTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
CreateDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
CreateDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return FileSystemCreateDirectoryParams(aFileSystem, mTargetRealPath);
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemCreateDirectoryParams();
|
||||
}
|
||||
|
||||
return FileSystemCreateDirectoryParams(aSerializedDOMPath, path);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateDirectoryTask::GetSuccessRequestResult() const
|
||||
CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return FileSystemDirectoryResponse(mTargetRealPath);
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemDirectoryResponse();
|
||||
}
|
||||
|
||||
return FileSystemDirectoryResponse(path);
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemDirectoryResponse r = aValue;
|
||||
mTargetRealPath = r.realPath();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -91,13 +150,8 @@ CreateDirectoryTask::Work()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
|
||||
if (!file) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
|
||||
bool fileExists;
|
||||
nsresult rv = file->Exists(&fileExists);
|
||||
nsresult rv = mTargetPath->Exists(&fileExists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -106,8 +160,12 @@ CreateDirectoryTask::Work()
|
|||
return NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
|
||||
}
|
||||
|
||||
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0770);
|
||||
return rv;
|
||||
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0770);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -124,7 +182,12 @@ CreateDirectoryTask::HandlerCallback()
|
|||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
RefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetWindow(),
|
||||
mTargetPath,
|
||||
Directory::eNotDOMRootDirectory,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
|
|
@ -16,16 +16,19 @@ namespace dom {
|
|||
|
||||
class Promise;
|
||||
|
||||
class CreateDirectoryTask final
|
||||
: public FileSystemTaskBase
|
||||
class CreateDirectoryTask final : public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aPath,
|
||||
ErrorResult& aRv);
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
static already_AddRefed<CreateDirectoryTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<CreateDirectoryTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~CreateDirectoryTask();
|
||||
|
@ -38,13 +41,15 @@ public:
|
|||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult() const override;
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -53,8 +58,15 @@ protected:
|
|||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath);
|
||||
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsString mTargetRealPath;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -25,34 +25,104 @@ namespace dom {
|
|||
|
||||
uint32_t CreateFileTask::sOutputBufferSize = 0;
|
||||
|
||||
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aPath,
|
||||
Blob* aBlobData,
|
||||
InfallibleTArray<uint8_t>& aArrayData,
|
||||
bool replace,
|
||||
ErrorResult& aRv)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetRealPath(aPath)
|
||||
, mReplace(replace)
|
||||
/* static */ already_AddRefed<CreateFileTask>
|
||||
CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Blob* aBlobData,
|
||||
InfallibleTArray<uint8_t>& aArrayData,
|
||||
bool aReplace,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
GetOutputBufferSize();
|
||||
|
||||
RefPtr<CreateFileTask> task =
|
||||
new CreateFileTask(aFileSystem, aTargetPath, aReplace);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
task->GetOutputBufferSize();
|
||||
|
||||
if (aBlobData) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
aBlobData->GetInternalStream(getter_AddRefs(mBlobStream), aRv);
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
aBlobData->GetInternalStream(getter_AddRefs(task->mBlobStream), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
mBlobData = aBlobData;
|
||||
task->mBlobData = aBlobData;
|
||||
}
|
||||
}
|
||||
mArrayData.SwapElements(aArrayData);
|
||||
|
||||
task->mArrayData.SwapElements(aArrayData);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aFileSystem->GetWindow());
|
||||
if (!globalObject) {
|
||||
return;
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
mPromise = Promise::Create(globalObject, aRv);
|
||||
|
||||
task->mPromise = Promise::Create(globalObject, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<CreateFileTask>
|
||||
CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateFileTask> task =
|
||||
new CreateFileTask(aFileSystem, aParam, aParent);
|
||||
|
||||
task->GetOutputBufferSize();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mReplace = aParam.replace();
|
||||
|
||||
auto& data = aParam.data();
|
||||
|
||||
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
|
||||
task->mArrayData = data;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
|
||||
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl, "blobData should not be null.");
|
||||
|
||||
ErrorResult rv;
|
||||
blobImpl->GetInternalStream(getter_AddRefs(task->mBlobStream), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
bool aReplace)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mReplace(aReplace)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
|
@ -61,32 +131,9 @@ CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
|||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mReplace(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
GetOutputBufferSize();
|
||||
|
||||
mTargetRealPath = aParam.realPath();
|
||||
|
||||
mReplace = aParam.replace();
|
||||
|
||||
auto& data = aParam.data();
|
||||
|
||||
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
|
||||
mArrayData = data;
|
||||
return;
|
||||
}
|
||||
|
||||
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
|
||||
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl, "blobData should not be null.");
|
||||
|
||||
ErrorResult rv;
|
||||
blobImpl->GetInternalStream(getter_AddRefs(mBlobStream), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
}
|
||||
}
|
||||
|
||||
CreateFileTask::~CreateFileTask()
|
||||
|
@ -107,12 +154,18 @@ CreateFileTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
CreateFileTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemCreateFileParams param;
|
||||
param.filesystem() = aFileSystem;
|
||||
param.realPath() = mTargetRealPath;
|
||||
param.filesystem() = aSerializedDOMPath;
|
||||
|
||||
aRv = mTargetPath->GetPath(param.realPath());
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.replace() = mReplace;
|
||||
if (mBlobData) {
|
||||
BlobChild* actor
|
||||
|
@ -127,7 +180,7 @@ CreateFileTask::GetRequestParams(const nsString& aFileSystem) const
|
|||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateFileTask::GetSuccessRequestResult() const
|
||||
CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
BlobParent* actor = GetBlobParent(mTargetBlobImpl);
|
||||
|
@ -140,7 +193,8 @@ CreateFileTask::GetSuccessRequestResult() const
|
|||
}
|
||||
|
||||
void
|
||||
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemFileResponse r = aValue;
|
||||
|
@ -176,24 +230,19 @@ CreateFileTask::Work()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
|
||||
if (!file) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
|
||||
if (!mFileSystem->IsSafeFile(file)) {
|
||||
if (!mFileSystem->IsSafeFile(mTargetPath)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
bool exists = false;
|
||||
nsresult rv = file->Exists(&exists);
|
||||
nsresult rv = mTargetPath->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
bool isFile = false;
|
||||
rv = file->IsFile(&isFile);
|
||||
rv = mTargetPath->IsFile(&isFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -207,19 +256,19 @@ CreateFileTask::Work()
|
|||
}
|
||||
|
||||
// Remove the old file before creating.
|
||||
rv = file->Remove(false);
|
||||
rv = mTargetPath->Remove(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
rv = mTargetPath->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mTargetPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -262,7 +311,7 @@ CreateFileTask::Work()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mTargetBlobImpl = new BlobImplFile(file);
|
||||
mTargetBlobImpl = new BlobImplFile(mTargetPath);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -281,7 +330,7 @@ CreateFileTask::Work()
|
|||
return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
mTargetBlobImpl = new BlobImplFile(file);
|
||||
mTargetBlobImpl = new BlobImplFile(mTargetPath);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,19 +20,22 @@ class Blob;
|
|||
class BlobImpl;
|
||||
class Promise;
|
||||
|
||||
class CreateFileTask final
|
||||
: public FileSystemTaskBase
|
||||
class CreateFileTask final : public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aPath,
|
||||
Blob* aBlobData,
|
||||
InfallibleTArray<uint8_t>& aArrayData,
|
||||
bool replace,
|
||||
ErrorResult& aRv);
|
||||
CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
static already_AddRefed<CreateFileTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aFile,
|
||||
Blob* aBlobData,
|
||||
InfallibleTArray<uint8_t>& aArrayData,
|
||||
bool replace,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<CreateFileTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~CreateFileTask();
|
||||
|
@ -45,13 +48,15 @@ public:
|
|||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult() const override;
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -60,12 +65,20 @@ protected:
|
|||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
CreateFileTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aFile,
|
||||
bool aReplace);
|
||||
|
||||
CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
void
|
||||
GetOutputBufferSize() const;
|
||||
|
||||
static uint32_t sOutputBufferSize;
|
||||
RefPtr<Promise> mPromise;
|
||||
nsString mTargetRealPath;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
// Not thread-safe and should be released on main thread.
|
||||
RefPtr<Blob> mBlobData;
|
||||
|
|
|
@ -46,17 +46,17 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(
|
|||
NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
// Get the local path of the file system root.
|
||||
// Since the child process is not allowed to access the file system, we only
|
||||
// do this from the parent process.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIFile> rootFile;
|
||||
DeviceStorageFile::GetRootDirectoryForType(aStorageType,
|
||||
aStorageName,
|
||||
getter_AddRefs(rootFile));
|
||||
|
||||
NS_WARN_IF(!rootFile || NS_FAILED(rootFile->GetPath(mLocalRootPath)));
|
||||
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileSystemUtils::LocalPathToNormalizedPath(mLocalRootPath,
|
||||
mNormalizedLocalRootPath);
|
||||
|
||||
|
@ -132,8 +132,14 @@ DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aDir);
|
||||
RefPtr<FileSystemBase> fs = aDir->GetFileSystem();
|
||||
MOZ_ASSERT(fs);
|
||||
|
||||
ErrorResult rv;
|
||||
RefPtr<FileSystemBase> fs = aDir->GetFileSystem(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the given directory is from this storage.
|
||||
return fs->ToString() == mString;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "mozilla/dom/DirectoryBinding.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/OSFileSystem.h"
|
||||
|
||||
// Resolve the name collision of Microsoft's API name with macros defined in
|
||||
// Windows header files. Undefine the macro of CreateDirectory to avoid
|
||||
|
@ -37,12 +38,19 @@ namespace dom {
|
|||
NS_IMPL_CYCLE_COLLECTION_CLASS(Directory)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Directory)
|
||||
tmp->mFileSystem->Unlink();
|
||||
if (tmp->mFileSystem) {
|
||||
tmp->mFileSystem->Unlink();
|
||||
tmp->mFileSystem = nullptr;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Directory)
|
||||
tmp->mFileSystem->Traverse(cb);
|
||||
if (tmp->mFileSystem) {
|
||||
tmp->mFileSystem->Traverse(cb);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
|
@ -59,23 +67,57 @@ NS_INTERFACE_MAP_END
|
|||
already_AddRefed<Promise>
|
||||
Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<GetFileOrDirectoryTask> task = new GetFileOrDirectoryTask(
|
||||
aFileSystem, EmptyString(), true, aRv);
|
||||
if (aRv.Failed()) {
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
nsCOMPtr<nsIFile> path;
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aFileSystem->GetLocalRootPath()),
|
||||
true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetFileOrDirectoryTask> task =
|
||||
GetFileOrDirectoryTask::Create(aFileSystem, path, eDOMRootDirectory, true, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSystemPermissionRequest::RequestForTask(task);
|
||||
return task->GetPromise();
|
||||
}
|
||||
|
||||
Directory::Directory(FileSystemBase* aFileSystem,
|
||||
const nsAString& aPath)
|
||||
: mFileSystem(aFileSystem)
|
||||
, mPath(aPath)
|
||||
/* static */ already_AddRefed<Directory>
|
||||
Directory::Create(nsPIDOMWindowInner* aWindow, nsIFile* aFile,
|
||||
DirectoryType aType, FileSystemBase* aFileSystem)
|
||||
{
|
||||
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
|
||||
// Remove the trailing "/".
|
||||
mPath.Trim(FILESYSTEM_DOM_PATH_SEPARATOR, false, true);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isDir;
|
||||
nsresult rv = aFile->IsDirectory(&isDir);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) && isDir);
|
||||
#endif
|
||||
|
||||
RefPtr<Directory> directory =
|
||||
new Directory(aWindow, aFile, aType, aFileSystem);
|
||||
return directory.forget();
|
||||
}
|
||||
|
||||
Directory::Directory(nsPIDOMWindowInner* aWindow,
|
||||
nsIFile* aFile,
|
||||
DirectoryType aType,
|
||||
FileSystemBase* aFileSystem)
|
||||
: mWindow(aWindow)
|
||||
, mFileSystem(aFileSystem)
|
||||
, mFile(aFile)
|
||||
, mType(aType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
// aFileSystem can be null. In this case we create a OSFileSystem when needed.
|
||||
}
|
||||
|
||||
Directory::~Directory()
|
||||
|
@ -85,7 +127,7 @@ Directory::~Directory()
|
|||
nsPIDOMWindowInner*
|
||||
Directory::GetParentObject() const
|
||||
{
|
||||
return mFileSystem->GetWindow();
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -95,25 +137,28 @@ Directory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
}
|
||||
|
||||
void
|
||||
Directory::GetName(nsAString& aRetval) const
|
||||
Directory::GetName(nsAString& aRetval, ErrorResult& aRv)
|
||||
{
|
||||
aRetval.Truncate();
|
||||
|
||||
if (mPath.IsEmpty()) {
|
||||
mFileSystem->GetRootName(aRetval);
|
||||
if (mType == eDOMRootDirectory) {
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
fs->GetRootName(aRetval);
|
||||
return;
|
||||
}
|
||||
|
||||
aRetval = Substring(mPath,
|
||||
mPath.RFindChar(FileSystemUtils::kSeparatorChar) + 1);
|
||||
aRv = mFile->GetLeafName(aRetval);
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsresult error = NS_OK;
|
||||
nsAutoString realPath;
|
||||
RefPtr<Blob> blobData;
|
||||
InfallibleTArray<uint8_t> arrayData;
|
||||
bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace);
|
||||
|
@ -138,15 +183,20 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
|||
}
|
||||
}
|
||||
|
||||
if (!DOMPathToRealPath(aPath, realPath)) {
|
||||
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
|
||||
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CreateFileTask> task =
|
||||
new CreateFileTask(mFileSystem, realPath, blobData, arrayData, replace, aRv);
|
||||
if (aRv.Failed()) {
|
||||
CreateFileTask::Create(fs, realPath, blobData, arrayData, replace, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->SetError(error);
|
||||
FileSystemPermissionRequest::RequestForTask(task);
|
||||
return task->GetPromise();
|
||||
|
@ -155,16 +205,20 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
|||
already_AddRefed<Promise>
|
||||
Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
nsresult error = NS_OK;
|
||||
nsAutoString realPath;
|
||||
if (!DOMPathToRealPath(aPath, realPath)) {
|
||||
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
RefPtr<CreateDirectoryTask> task = new CreateDirectoryTask(
|
||||
mFileSystem, realPath, aRv);
|
||||
if (aRv.Failed()) {
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
|
||||
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CreateDirectoryTask> task =
|
||||
CreateDirectoryTask::Create(fs, realPath, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->SetError(error);
|
||||
FileSystemPermissionRequest::RequestForTask(task);
|
||||
return task->GetPromise();
|
||||
|
@ -173,16 +227,21 @@ Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
|
|||
already_AddRefed<Promise>
|
||||
Directory::Get(const nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
nsresult error = NS_OK;
|
||||
nsAutoString realPath;
|
||||
if (!DOMPathToRealPath(aPath, realPath)) {
|
||||
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
RefPtr<GetFileOrDirectoryTask> task = new GetFileOrDirectoryTask(
|
||||
mFileSystem, realPath, false, aRv);
|
||||
if (aRv.Failed()) {
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
|
||||
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetFileOrDirectoryTask> task =
|
||||
GetFileOrDirectoryTask::Create(fs, realPath, eNotDOMRootDirectory, false,
|
||||
aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->SetError(error);
|
||||
FileSystemPermissionRequest::RequestForTask(task);
|
||||
return task->GetPromise();
|
||||
|
@ -205,30 +264,33 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
|
|||
ErrorResult& aRv)
|
||||
{
|
||||
nsresult error = NS_OK;
|
||||
nsAutoString realPath;
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
RefPtr<BlobImpl> blob;
|
||||
|
||||
// Check and get the target path.
|
||||
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aPath.IsFile()) {
|
||||
blob = aPath.GetAsFile().Impl();
|
||||
} else if (aPath.IsString()) {
|
||||
if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) {
|
||||
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
} else if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) {
|
||||
error = DOMPathToRealPath(aPath.GetAsString(), getter_AddRefs(realPath));
|
||||
} else if (!fs->IsSafeDirectory(&aPath.GetAsDirectory())) {
|
||||
error = NS_ERROR_DOM_SECURITY_ERR;
|
||||
} else {
|
||||
realPath = aPath.GetAsDirectory().mPath;
|
||||
realPath = aPath.GetAsDirectory().mFile;
|
||||
// The target must be a descendant of this directory.
|
||||
if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) {
|
||||
if (!FileSystemUtils::IsDescendantPath(mFile, realPath)) {
|
||||
error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<RemoveTask> task = new RemoveTask(mFileSystem, mPath, blob, realPath,
|
||||
aRecursive, aRv);
|
||||
if (aRv.Failed()) {
|
||||
RefPtr<RemoveTask> task =
|
||||
RemoveTask::Create(fs, mFile, blob, realPath, aRecursive, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
task->SetError(error);
|
||||
|
@ -237,23 +299,38 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
|
|||
}
|
||||
|
||||
void
|
||||
Directory::GetPath(nsAString& aRetval) const
|
||||
Directory::GetPath(nsAString& aRetval, ErrorResult& aRv)
|
||||
{
|
||||
if (mPath.IsEmpty()) {
|
||||
// The Directory ctor removes any trailing '/'; this is the root directory.
|
||||
if (mType == eDOMRootDirectory) {
|
||||
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
|
||||
} else {
|
||||
aRetval = mPath;
|
||||
// TODO: this should be a bit different...
|
||||
GetName(aRetval, aRv);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Directory::GetFilesAndDirectories()
|
||||
nsresult
|
||||
Directory::GetFullRealPath(nsAString& aPath)
|
||||
{
|
||||
ErrorResult rv;
|
||||
nsresult rv = mFile->GetPath(aPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Directory::GetFilesAndDirectories(ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetDirectoryListingTask> task =
|
||||
new GetDirectoryListingTask(mFileSystem, mPath, mFilters, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
GetDirectoryListingTask::Create(fs, mFile, mType, mFilters, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -268,16 +345,38 @@ Directory::SetContentFilters(const nsAString& aFilters)
|
|||
}
|
||||
|
||||
FileSystemBase*
|
||||
Directory::GetFileSystem() const
|
||||
Directory::GetFileSystem(ErrorResult& aRv)
|
||||
{
|
||||
return mFileSystem.get();
|
||||
if (!mFileSystem) {
|
||||
nsCOMPtr<nsIFile> parent;
|
||||
aRv = mFile->GetParent(getter_AddRefs(parent));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Parent can be null if mFile is pointing to the top directory.
|
||||
if (!parent) {
|
||||
parent = mFile;
|
||||
}
|
||||
|
||||
nsAutoString path;
|
||||
aRv = parent->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<OSFileSystem> fs = new OSFileSystem(path);
|
||||
fs->Init(mWindow);
|
||||
|
||||
mFileSystem = fs;
|
||||
}
|
||||
|
||||
return mFileSystem;
|
||||
}
|
||||
|
||||
bool
|
||||
Directory::DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const
|
||||
nsresult
|
||||
Directory::DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const
|
||||
{
|
||||
aRealPath.Truncate();
|
||||
|
||||
nsString relativePath;
|
||||
relativePath = aPath;
|
||||
|
||||
|
@ -286,13 +385,22 @@ Directory::DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const
|
|||
relativePath.Trim(kWhitespace);
|
||||
|
||||
if (!IsValidRelativePath(relativePath)) {
|
||||
return false;
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
|
||||
aRealPath = mPath + NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR) +
|
||||
relativePath;
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = mFile->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return true;
|
||||
rv = file->AppendRelativePath(relativePath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
file.forget(aFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -41,14 +41,37 @@ class Directory final
|
|||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
struct BlobImplOrDirectoryPath
|
||||
{
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
nsString mDirectoryPath;
|
||||
|
||||
enum {
|
||||
eBlobImpl,
|
||||
eDirectoryPath
|
||||
} mType;
|
||||
};
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
|
||||
|
||||
public:
|
||||
static already_AddRefed<Promise>
|
||||
GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
|
||||
|
||||
Directory(FileSystemBase* aFileSystem, const nsAString& aPath);
|
||||
enum DirectoryType {
|
||||
// When a directory is selected using a HTMLInputElement, that will be the
|
||||
// DOM root directory and its name will be '/'. All the sub directory will
|
||||
// be called with they real name. We use this enum to mark what we must
|
||||
// consider the '/' of this DOM filesystem.
|
||||
eDOMRootDirectory,
|
||||
|
||||
// All the sub directories of the '/' will be marked using this other value.
|
||||
eNotDOMRootDirectory
|
||||
};
|
||||
|
||||
static already_AddRefed<Directory>
|
||||
Create(nsPIDOMWindowInner* aWindow, nsIFile* aDirectory,
|
||||
DirectoryType aType, FileSystemBase* aFileSystem = 0);
|
||||
|
||||
// ========= Begin WebIDL bindings. ===========
|
||||
|
||||
|
@ -59,7 +82,7 @@ public:
|
|||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void
|
||||
GetName(nsAString& aRetval) const;
|
||||
GetName(nsAString& aRetval, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
||||
|
@ -80,10 +103,13 @@ public:
|
|||
// From https://microsoftedge.github.io/directory-upload/proposal.html#directory-interface :
|
||||
|
||||
void
|
||||
GetPath(nsAString& aRetval) const;
|
||||
GetPath(nsAString& aRetval, ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
GetFullRealPath(nsAString& aPath);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetFilesAndDirectories();
|
||||
GetFilesAndDirectories(ErrorResult& aRv);
|
||||
|
||||
// =========== End WebIDL bindings.============
|
||||
|
||||
|
@ -113,8 +139,12 @@ public:
|
|||
SetContentFilters(const nsAString& aFilters);
|
||||
|
||||
FileSystemBase*
|
||||
GetFileSystem() const;
|
||||
GetFileSystem(ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
Directory(nsPIDOMWindowInner* aWindow,
|
||||
nsIFile* aFile, DirectoryType aType,
|
||||
FileSystemBase* aFileSystem = nullptr);
|
||||
~Directory();
|
||||
|
||||
static bool
|
||||
|
@ -122,17 +152,19 @@ private:
|
|||
|
||||
/*
|
||||
* Convert relative DOM path to the absolute real path.
|
||||
* @return true if succeed. false if the DOM path is invalid.
|
||||
*/
|
||||
bool
|
||||
DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const;
|
||||
nsresult
|
||||
DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const;
|
||||
|
||||
already_AddRefed<Promise>
|
||||
RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
nsString mPath;
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
DirectoryType mType;
|
||||
|
||||
nsString mFilters;
|
||||
};
|
||||
|
||||
|
|
|
@ -68,26 +68,41 @@ FileSystemBase::GetLocalFile(const nsAString& aRealPath) const
|
|||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Should be on parent process!");
|
||||
|
||||
// Let's convert the input path to /path
|
||||
nsAutoString localPath;
|
||||
FileSystemUtils::NormalizedPathToLocalPath(aRealPath, localPath);
|
||||
localPath = mLocalRootPath + localPath;
|
||||
if (!aRealPath.IsEmpty() &&
|
||||
!StringBeginsWith(aRealPath,
|
||||
NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR))) {
|
||||
localPath.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
|
||||
}
|
||||
localPath.Append(aRealPath);
|
||||
|
||||
// We have to normalize the path string in order to follow the separator
|
||||
// schema of this OS.
|
||||
nsAutoString normalizedPath;
|
||||
FileSystemUtils::NormalizedPathToLocalPath(localPath, normalizedPath);
|
||||
|
||||
// The full path is mLocalRootPath + normalizedPath.
|
||||
nsAutoString path(mLocalRootPath);
|
||||
path.Append(normalizedPath);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = NS_NewLocalFile(localPath, false, getter_AddRefs(file));
|
||||
nsresult rv = NS_NewLocalFile(path, false, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemBase::GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const
|
||||
FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Should be on parent process!");
|
||||
MOZ_ASSERT(aFile, "aFile Should not be null.");
|
||||
|
||||
aRealPath.Truncate();
|
||||
|
||||
nsAutoString filePath;
|
||||
ErrorResult rv;
|
||||
aFile->GetMozFullPathInternal(filePath, rv);
|
||||
|
@ -95,7 +110,13 @@ FileSystemBase::GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const
|
|||
return false;
|
||||
}
|
||||
|
||||
return LocalPathToRealPath(filePath, aRealPath);
|
||||
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(filePath),
|
||||
true, aPath);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -120,6 +141,7 @@ FileSystemBase::LocalPathToRealPath(const nsAString& aLocalPath,
|
|||
aRealPath.Truncate();
|
||||
return false;
|
||||
}
|
||||
|
||||
aRealPath = Substring(path, mNormalizedLocalRootPath.Length());
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -73,13 +73,8 @@ public:
|
|||
virtual bool
|
||||
IsSafeDirectory(Directory* aDir) const;
|
||||
|
||||
/*
|
||||
* Get the real path (absolute DOM path) of the DOM file in the file system.
|
||||
* If succeeded, returns true. Otherwise, returns false and set aRealPath to
|
||||
* empty string.
|
||||
*/
|
||||
bool
|
||||
GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const;
|
||||
GetRealPath(BlobImpl* aFile, nsIFile** aPath) const;
|
||||
|
||||
/*
|
||||
* Get the permission name required to access this file system.
|
||||
|
|
|
@ -29,7 +29,10 @@ FileSystemRequestParent::~FileSystemRequestParent()
|
|||
case FileSystemParams::TFileSystem##name##Params: { \
|
||||
const FileSystem##name##Params& p = aParams; \
|
||||
mFileSystem = FileSystemBase::FromString(p.filesystem()); \
|
||||
task = new name##Task(mFileSystem, p, this); \
|
||||
task = name##Task::Create(mFileSystem, p, this, rv); \
|
||||
if (NS_WARN_IF(rv.Failed())) { \
|
||||
return false; \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
|
||||
|
@ -39,6 +42,8 @@ FileSystemRequestParent::Dispatch(ContentParent* aParent,
|
|||
{
|
||||
MOZ_ASSERT(aParent, "aParent should not be null.");
|
||||
RefPtr<FileSystemTaskBase> task;
|
||||
ErrorResult rv;
|
||||
|
||||
switch (aParams.type()) {
|
||||
|
||||
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(CreateDirectory)
|
||||
|
|
|
@ -106,12 +106,19 @@ FileSystemTaskBase::Start()
|
|||
return;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
FileSystemParams params = GetRequestParams(mFileSystem->ToString(), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Retain a reference so the task object isn't deleted without IPDL's
|
||||
// knowledge. The reference will be released by
|
||||
// mozilla::dom::ContentChild::DeallocPFileSystemRequestChild.
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
ContentChild::GetSingleton()->SendPFileSystemRequestConstructor(this,
|
||||
GetRequestParams(mFileSystem->ToString()));
|
||||
params);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -154,11 +161,17 @@ FileSystemTaskBase::GetRequestResult() const
|
|||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (HasError()) {
|
||||
return FileSystemErrorResponse(mErrorValue);
|
||||
} else {
|
||||
return GetSuccessRequestResult();
|
||||
if (!HasError()) {
|
||||
ErrorResult rv;
|
||||
FileSystemResponseValue value = GetSuccessRequestResult(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return FileSystemErrorResponse(rv.StealNSResult());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return FileSystemErrorResponse(mErrorValue);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -171,7 +184,9 @@ FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
|
|||
FileSystemErrorResponse r = aValue;
|
||||
mErrorValue = r.error();
|
||||
} else {
|
||||
SetSuccessRequestResult(aValue);
|
||||
ErrorResult rv;
|
||||
SetSuccessRequestResult(aValue, rv);
|
||||
mErrorValue = rv.StealNSResult();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,8 @@ protected:
|
|||
* @param filesystem The string representation of the file system.
|
||||
*/
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aFileSystem) const = 0;
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const = 0;
|
||||
|
||||
/*
|
||||
* Wrap the task success result to FileSystemResponseValue for sending it
|
||||
|
@ -185,7 +186,7 @@ protected:
|
|||
* send the task success result back to the child process.
|
||||
*/
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult() const = 0;
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const = 0;
|
||||
|
||||
/*
|
||||
* Unwrap the IPC message to get the task success result.
|
||||
|
@ -194,7 +195,8 @@ protected:
|
|||
* success result.
|
||||
*/
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) = 0;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) = 0;
|
||||
|
||||
bool
|
||||
HasError() const { return mErrorValue != NS_OK; }
|
||||
|
|
|
@ -65,5 +65,31 @@ FileSystemUtils::IsDescendantPath(const nsAString& aPath,
|
|||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
FileSystemUtils::IsDescendantPath(nsIFile* aFile,
|
||||
nsIFile* aDescendantFile)
|
||||
{
|
||||
nsAutoString path;
|
||||
nsresult rv = aFile->GetPath(path);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString descendantPath;
|
||||
rv = aDescendantFile->GetPath(descendantPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the sub-directory path to see if it has the parent path as prefix.
|
||||
if (descendantPath.Length() <= path.Length() ||
|
||||
!StringBeginsWith(descendantPath, path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -34,6 +34,12 @@ public:
|
|||
static void
|
||||
NormalizedPathToLocalPath(const nsAString& aNorm, nsAString& aLocal);
|
||||
|
||||
/*
|
||||
* Return true if aDescendantPath is a descendant of aPath.
|
||||
*/
|
||||
static bool
|
||||
IsDescendantPath(nsIFile* aPath, nsIFile* aDescendantPath);
|
||||
|
||||
/*
|
||||
* Return true if aDescendantPath is a descendant of aPath. Both aPath and
|
||||
* aDescendantPath are absolute DOM path.
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "HTMLSplitOnSpacesTokenizer.h"
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
|
@ -21,33 +20,80 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aTargetPath,
|
||||
const nsAString& aFilters,
|
||||
ErrorResult& aRv)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetRealPath(aTargetPath)
|
||||
, mFilters(aFilters)
|
||||
/* static */ already_AddRefed<GetDirectoryListingTask>
|
||||
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetDirectoryListingTask> task =
|
||||
new GetDirectoryListingTask(aFileSystem, aTargetPath, aType, aFilters);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aFileSystem->GetWindow());
|
||||
if (!globalObject) {
|
||||
return;
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
mPromise = Promise::Create(globalObject, aRv);
|
||||
|
||||
task->mPromise = Promise::Create(globalObject, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<GetDirectoryListingTask>
|
||||
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetDirectoryListingTask> task =
|
||||
new GetDirectoryListingTask(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mFilters(aFilters)
|
||||
, mType(aType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mTargetRealPath(aParam.realPath())
|
||||
, mFilters(aParam.filters())
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
@ -66,43 +112,88 @@ GetDirectoryListingTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
GetDirectoryListingTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
GetDirectoryListingTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return FileSystemGetDirectoryListingParams(aFileSystem, mTargetRealPath,
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemGetDirectoryListingParams();
|
||||
}
|
||||
|
||||
return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
|
||||
mType == Directory::eDOMRootDirectory,
|
||||
mFilters);
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::CreateNormalizedRelativePath(const nsAString& aPath,
|
||||
nsAString& aRelativePath) const
|
||||
{
|
||||
uint32_t rootPathLen = mFileSystem->GetLocalRootPath().Length();
|
||||
FileSystemUtils::LocalPathToNormalizedPath(
|
||||
Substring(aPath, rootPathLen, aPath.Length() - rootPathLen), aRelativePath);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetDirectoryListingTask::GetSuccessRequestResult() const
|
||||
GetDirectoryListingTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
InfallibleTArray<PBlobParent*> blobs;
|
||||
|
||||
for (unsigned i = 0; i < mTargetBlobImpls.Length(); i++) {
|
||||
BlobParent* blobParent = GetBlobParent(mTargetBlobImpls[i]);
|
||||
if (blobParent) {
|
||||
blobs.AppendElement(blobParent);
|
||||
nsTArray<FileSystemDirectoryListingResponseData> inputs;
|
||||
|
||||
for (unsigned i = 0; i < mTargetData.Length(); i++) {
|
||||
if (mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl) {
|
||||
BlobParent* blobParent = GetBlobParent(mTargetData[i].mBlobImpl);
|
||||
if (!blobParent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FileSystemDirectoryListingResponseBlob blobData;
|
||||
blobData.blobParent() = blobParent;
|
||||
inputs.AppendElement(blobData);
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath);
|
||||
FileSystemDirectoryListingResponseDirectory directoryData;
|
||||
directoryData.directoryRealPath() = mTargetData[i].mDirectoryPath;
|
||||
inputs.AppendElement(directoryData);
|
||||
}
|
||||
}
|
||||
|
||||
FileSystemDirectoryListingResponse response;
|
||||
response.blobsParent().SwapElements(blobs);
|
||||
response.data().SwapElements(inputs);
|
||||
return response;
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aValue.type() ==
|
||||
FileSystemResponseValue::TFileSystemDirectoryListingResponse);
|
||||
|
||||
FileSystemDirectoryListingResponse r = aValue;
|
||||
nsTArray<PBlobChild*>& blobs = r.blobsChild();
|
||||
for (uint32_t i = 0; i < r.data().Length(); ++i) {
|
||||
const FileSystemDirectoryListingResponseData& data = r.data()[i];
|
||||
|
||||
for (unsigned i = 0; i < blobs.Length(); i++) {
|
||||
mTargetBlobImpls.AppendElement(static_cast<BlobChild*>(blobs[i])->GetBlobImpl());
|
||||
if (data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseBlob) {
|
||||
PBlobChild* blob = data.get_FileSystemDirectoryListingResponseBlob().blobChild();
|
||||
|
||||
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
|
||||
element->mType = Directory::BlobImplOrDirectoryPath::eBlobImpl;
|
||||
element->mBlobImpl = static_cast<BlobChild*>(blob)->GetBlobImpl();
|
||||
} else {
|
||||
MOZ_ASSERT(data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseDirectory);
|
||||
|
||||
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
|
||||
element->mType = Directory::BlobImplOrDirectoryPath::eDirectoryPath;
|
||||
element->mDirectoryPath = data.get_FileSystemDirectoryListingResponseDirectory().directoryRealPath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,27 +208,19 @@ GetDirectoryListingTask::Work()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Whether we want to get the root directory.
|
||||
bool getRoot = mTargetRealPath.IsEmpty();
|
||||
|
||||
nsCOMPtr<nsIFile> dir = mFileSystem->GetLocalFile(mTargetRealPath);
|
||||
if (!dir) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
|
||||
bool exists;
|
||||
nsresult rv = dir->Exists(&exists);
|
||||
nsresult rv = mTargetPath->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
if (!getRoot) {
|
||||
if (mType == Directory::eNotRootDirectory) {
|
||||
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
// If the root directory doesn't exit, create it.
|
||||
rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -145,7 +228,7 @@ GetDirectoryListingTask::Work()
|
|||
|
||||
// Get isDirectory.
|
||||
bool isDir;
|
||||
rv = dir->IsDirectory(&isDir);
|
||||
rv = mTargetPath->IsDirectory(&isDir);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -155,7 +238,7 @@ GetDirectoryListingTask::Work()
|
|||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
rv = dir->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
rv = mTargetPath->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -186,7 +269,7 @@ GetDirectoryListingTask::Work()
|
|||
|
||||
nsCOMPtr<nsIFile> currFile = do_QueryInterface(supp);
|
||||
MOZ_ASSERT(currFile);
|
||||
|
||||
|
||||
bool isLink, isSpecial, isFile;
|
||||
if (NS_WARN_IF(NS_FAILED(currFile->IsSymlink(&isLink)) ||
|
||||
NS_FAILED(currFile->IsSpecial(&isSpecial))) ||
|
||||
|
@ -213,9 +296,22 @@ GetDirectoryListingTask::Work()
|
|||
}
|
||||
}
|
||||
|
||||
BlobImplFile* impl = new BlobImplFile(currFile);
|
||||
impl->LookupAndCacheIsDirectory();
|
||||
mTargetBlobImpls.AppendElement(impl);
|
||||
if (isDir) {
|
||||
nsAutoString path;
|
||||
if (NS_WARN_IF(NS_FAILED(currFile->GetPath(path)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
|
||||
element->mType = Directory::BlobImplOrDirectoryPath::eDirectoryPath;
|
||||
element->mDirectoryPath = path;
|
||||
} else {
|
||||
BlobImplFile* impl = new BlobImplFile(currFile);
|
||||
|
||||
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
|
||||
element->mType = Directory::BlobImplOrDirectoryPath::eBlobImpl;
|
||||
element->mBlobImpl = impl;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -235,7 +331,7 @@ GetDirectoryListingTask::HandlerCallback()
|
|||
return;
|
||||
}
|
||||
|
||||
size_t count = mTargetBlobImpls.Length();
|
||||
size_t count = mTargetData.Length();
|
||||
|
||||
Sequence<OwningFileOrDirectory> listing;
|
||||
|
||||
|
@ -246,26 +342,65 @@ GetDirectoryListingTask::HandlerCallback()
|
|||
}
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
if (mTargetBlobImpls[i]->IsDirectory()) {
|
||||
nsAutoString name;
|
||||
mTargetBlobImpls[i]->GetName(name);
|
||||
nsAutoString path(mTargetRealPath);
|
||||
path.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
|
||||
path.Append(name);
|
||||
if (mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath) {
|
||||
#ifdef DEBUG
|
||||
if (XRE_IsParentProcess()) {
|
||||
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(path);
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = NS_NewLocalFile(mTargetData[i].mDirectoryPath, false,
|
||||
getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
bool exist;
|
||||
file->Exists(&exist);
|
||||
MOZ_ASSERT(exist);
|
||||
rv = file->Exists(&exist);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// We cannot assert here because the file can be done in the meantime.
|
||||
NS_ASSERTION(exist, "The file doesn't exist anymore?!?");
|
||||
|
||||
nsAutoString normalizedLocalRootPath;
|
||||
FileSystemUtils::NormalizedPathToLocalPath(mFileSystem->GetLocalRootPath(),
|
||||
normalizedLocalRootPath);
|
||||
|
||||
nsAutoString directoryPath;
|
||||
FileSystemUtils::NormalizedPathToLocalPath(mTargetData[i].mDirectoryPath,
|
||||
directoryPath);
|
||||
|
||||
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(normalizedLocalRootPath,
|
||||
directoryPath));
|
||||
}
|
||||
#endif
|
||||
RefPtr<Directory> directory = new Directory(mFileSystem, path);
|
||||
|
||||
nsCOMPtr<nsIFile> directoryPath;
|
||||
NS_ConvertUTF16toUTF8 path(mTargetData[i].mDirectoryPath);
|
||||
nsresult rv = NS_NewNativeLocalFile(path, true,
|
||||
getter_AddRefs(directoryPath));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Directory> directory = Directory::Create(mFileSystem->GetWindow(),
|
||||
directoryPath,
|
||||
Directory::eNotRootDirectory,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
// Propogate mFilter onto sub-Directory object:
|
||||
directory->SetContentFilters(mFilters);
|
||||
listing[i].SetAsDirectory() = directory;
|
||||
} else {
|
||||
listing[i].SetAsFile() = File::Create(mFileSystem->GetWindow(), mTargetBlobImpls[i]);
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl);
|
||||
listing[i].SetAsFile() =
|
||||
File::Create(mFileSystem->GetWindow(), mTargetData[i].mBlobImpl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef mozilla_dom_GetDirectoryListing_h
|
||||
#define mozilla_dom_GetDirectoryListing_h
|
||||
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
@ -16,18 +17,21 @@ namespace dom {
|
|||
|
||||
class BlobImpl;
|
||||
|
||||
class GetDirectoryListingTask final
|
||||
: public FileSystemTaskBase
|
||||
class GetDirectoryListingTask final : public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
// If aDirectoryOnly is set, we should ensure that the target is a directory.
|
||||
GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aTargetPath,
|
||||
const nsAString& aFilters,
|
||||
ErrorResult& aRv);
|
||||
GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
static already_AddRefed<GetDirectoryListingTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<GetDirectoryListingTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~GetDirectoryListingTask();
|
||||
|
@ -37,15 +41,28 @@ public:
|
|||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
protected:
|
||||
|
||||
private:
|
||||
// If aDirectoryOnly is set, we should ensure that the target is a directory.
|
||||
GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters);
|
||||
|
||||
GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult() const override;
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -53,14 +70,18 @@ protected:
|
|||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
void
|
||||
CreateNormalizedRelativePath(const nsAString& aPath,
|
||||
nsAString& aRelativePath) const;
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsString mTargetRealPath;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
nsString mFilters;
|
||||
Directory::DirectoryType mType;
|
||||
|
||||
// We cannot store File or Directory objects bacause this object is created
|
||||
// on a different thread and File and Directory are not thread-safe.
|
||||
nsTArray<RefPtr<BlobImpl>> mTargetBlobImpls;
|
||||
nsTArray<Directory::BlobImplOrDirectoryPath> mTargetData;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "GetFileOrDirectoryTask.h"
|
||||
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
|
@ -20,37 +19,82 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(
|
||||
FileSystemBase* aFileSystem,
|
||||
const nsAString& aTargetPath,
|
||||
bool aDirectoryOnly,
|
||||
ErrorResult& aRv)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetRealPath(aTargetPath)
|
||||
, mIsDirectory(aDirectoryOnly)
|
||||
/* static */ already_AddRefed<GetFileOrDirectoryTask>
|
||||
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetFileOrDirectoryTask> task =
|
||||
new GetFileOrDirectoryTask(aFileSystem, aTargetPath, aType, aDirectoryOnly);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aFileSystem->GetWindow());
|
||||
if (!globalObject) {
|
||||
return;
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
mPromise = Promise::Create(globalObject, aRv);
|
||||
|
||||
task->mPromise = Promise::Create(globalObject, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(
|
||||
FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
/* static */ already_AddRefed<GetFileOrDirectoryTask>
|
||||
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetFileOrDirectoryTask> task =
|
||||
new GetFileOrDirectoryTask(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mIsDirectory(aDirectoryOnly)
|
||||
, mType(aType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mIsDirectory(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
mTargetRealPath = aParam.realPath();
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::~GetFileOrDirectoryTask()
|
||||
|
@ -67,18 +111,33 @@ GetFileOrDirectoryTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
GetFileOrDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
GetFileOrDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return FileSystemGetFileOrDirectoryParams(aFileSystem, mTargetRealPath);
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemGetFileOrDirectoryParams();
|
||||
}
|
||||
|
||||
return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path,
|
||||
mType == Directory::eDOMRootDirectory);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetFileOrDirectoryTask::GetSuccessRequestResult() const
|
||||
GetFileOrDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mIsDirectory) {
|
||||
return FileSystemDirectoryResponse(mTargetRealPath);
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemDirectoryResponse();
|
||||
}
|
||||
|
||||
return FileSystemDirectoryResponse(path);
|
||||
}
|
||||
|
||||
BlobParent* actor = GetBlobParent(mTargetBlobImpl);
|
||||
|
@ -91,7 +150,8 @@ GetFileOrDirectoryTask::GetSuccessRequestResult() const
|
|||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
switch (aValue.type()) {
|
||||
|
@ -104,7 +164,13 @@ GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& a
|
|||
}
|
||||
case FileSystemResponseValue::TFileSystemDirectoryResponse: {
|
||||
FileSystemDirectoryResponse r = aValue;
|
||||
mTargetRealPath = r.realPath();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsDirectory = true;
|
||||
break;
|
||||
}
|
||||
|
@ -127,33 +193,26 @@ GetFileOrDirectoryTask::Work()
|
|||
}
|
||||
|
||||
// Whether we want to get the root directory.
|
||||
bool getRoot = mTargetRealPath.IsEmpty();
|
||||
|
||||
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
|
||||
if (!file) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
|
||||
bool exists;
|
||||
nsresult rv = file->Exists(&exists);
|
||||
nsresult rv = mTargetPath->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
if (!getRoot) {
|
||||
if (mType == Directory::eNotRootDirectory) {
|
||||
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
// If the root directory doesn't exit, create it.
|
||||
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Get isDirectory.
|
||||
rv = file->IsDirectory(&mIsDirectory);
|
||||
rv = mTargetPath->IsDirectory(&mIsDirectory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -163,13 +222,13 @@ GetFileOrDirectoryTask::Work()
|
|||
}
|
||||
|
||||
// Check if the root is a directory.
|
||||
if (getRoot) {
|
||||
if (mType == Directory::eDOMRootDirectory) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
|
||||
}
|
||||
|
||||
bool isFile;
|
||||
// Get isFile
|
||||
rv = file->IsFile(&isFile);
|
||||
rv = mTargetPath->IsFile(&isFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -179,11 +238,11 @@ GetFileOrDirectoryTask::Work()
|
|||
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
|
||||
}
|
||||
|
||||
if (!mFileSystem->IsSafeFile(file)) {
|
||||
if (!mFileSystem->IsSafeFile(mTargetPath)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
mTargetBlobImpl = new BlobImplFile(file);
|
||||
mTargetBlobImpl = new BlobImplFile(mTargetPath);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -204,7 +263,12 @@ GetFileOrDirectoryTask::HandlerCallback()
|
|||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
RefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetWindow(),
|
||||
mTargetPath,
|
||||
mType,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef mozilla_dom_GetFileOrDirectory_h
|
||||
#define mozilla_dom_GetFileOrDirectory_h
|
||||
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
@ -16,18 +17,21 @@ namespace dom {
|
|||
|
||||
class BlobImpl;
|
||||
|
||||
class GetFileOrDirectoryTask final
|
||||
: public FileSystemTaskBase
|
||||
class GetFileOrDirectoryTask final : public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
// If aDirectoryOnly is set, we should ensure that the target is a directory.
|
||||
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aTargetPath,
|
||||
bool aDirectoryOnly,
|
||||
ErrorResult& aRv);
|
||||
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
static already_AddRefed<GetFileOrDirectoryTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<GetFileOrDirectoryTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~GetFileOrDirectoryTask();
|
||||
|
@ -39,13 +43,15 @@ public:
|
|||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult() const override;
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -54,10 +60,22 @@ protected:
|
|||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
// If aDirectoryOnly is set, we should ensure that the target is a directory.
|
||||
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly);
|
||||
|
||||
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsString mTargetRealPath;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
// Whether we get a directory.
|
||||
bool mIsDirectory;
|
||||
Directory::DirectoryType mType;
|
||||
|
||||
// This cannot be a File bacause this object is created on a different
|
||||
// thread and File is not thread-safe. Let's use the BlobImpl instead.
|
||||
|
|
|
@ -20,9 +20,26 @@ struct FileSystemDirectoryResponse
|
|||
nsString realPath;
|
||||
};
|
||||
|
||||
struct FileSystemDirectoryListingResponseBlob
|
||||
{
|
||||
PBlob blob;
|
||||
};
|
||||
|
||||
struct FileSystemDirectoryListingResponseDirectory
|
||||
{
|
||||
// This is the full real path for the directory that we are sending via IPC.
|
||||
nsString directoryRealPath;
|
||||
};
|
||||
|
||||
union FileSystemDirectoryListingResponseData
|
||||
{
|
||||
FileSystemDirectoryListingResponseBlob;
|
||||
FileSystemDirectoryListingResponseDirectory;
|
||||
};
|
||||
|
||||
struct FileSystemDirectoryListingResponse
|
||||
{
|
||||
PBlob[] blobs;
|
||||
FileSystemDirectoryListingResponseData[] data;
|
||||
};
|
||||
|
||||
struct FileSystemErrorResponse
|
||||
|
|
|
@ -18,27 +18,94 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ already_AddRefed<RemoveTask>
|
||||
RemoveTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
BlobImpl* aTargetBlob,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
MOZ_ASSERT(aDirPath);
|
||||
|
||||
RefPtr<RemoveTask> task =
|
||||
new RemoveTask(aFileSystem, aDirPath, aTargetBlob, aTargetPath, aRecursive);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aFileSystem->GetWindow());
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mPromise = Promise::Create(globalObject, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<RemoveTask>
|
||||
RemoveTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<RemoveTask> task =
|
||||
new RemoveTask(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 directoryPath(aParam.directory());
|
||||
aRv = NS_NewNativeLocalFile(directoryPath, true,
|
||||
getter_AddRefs(task->mDirPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mRecursive = aParam.recursive();
|
||||
|
||||
const FileSystemPathOrFileValue& target = aParam.target();
|
||||
|
||||
if (target.type() == FileSystemPathOrFileValue::TnsString) {
|
||||
NS_ConvertUTF16toUTF8 path(target);
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
|
||||
task->mTargetBlobImpl = bp->GetBlobImpl();
|
||||
MOZ_ASSERT(task->mTargetBlobImpl);
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aDirPath,
|
||||
nsIFile* aDirPath,
|
||||
BlobImpl* aTargetBlob,
|
||||
const nsAString& aTargetPath,
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv)
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mDirRealPath(aDirPath)
|
||||
, mDirPath(aDirPath)
|
||||
, mTargetBlobImpl(aTargetBlob)
|
||||
, mTargetRealPath(aTargetPath)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mRecursive(aRecursive)
|
||||
, mReturnValue(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aFileSystem->GetWindow());
|
||||
if (!globalObject) {
|
||||
return;
|
||||
}
|
||||
mPromise = Promise::Create(globalObject, aRv);
|
||||
MOZ_ASSERT(aDirPath);
|
||||
}
|
||||
|
||||
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
|
||||
|
@ -48,25 +115,9 @@ RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
|
|||
, mRecursive(false)
|
||||
, mReturnValue(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
mDirRealPath = aParam.directory();
|
||||
|
||||
mRecursive = aParam.recursive();
|
||||
|
||||
const FileSystemPathOrFileValue& target = aParam.target();
|
||||
|
||||
if (target.type() == FileSystemPathOrFileValue::TnsString) {
|
||||
mTargetRealPath = target;
|
||||
return;
|
||||
}
|
||||
|
||||
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
|
||||
mTargetBlobImpl = bp->GetBlobImpl();
|
||||
MOZ_ASSERT(mTargetBlobImpl);
|
||||
}
|
||||
|
||||
RemoveTask::~RemoveTask()
|
||||
|
@ -83,36 +134,49 @@ RemoveTask::GetPromise()
|
|||
}
|
||||
|
||||
FileSystemParams
|
||||
RemoveTask::GetRequestParams(const nsString& aFileSystem) const
|
||||
RemoveTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemRemoveParams param;
|
||||
param.filesystem() = aFileSystem;
|
||||
param.directory() = mDirRealPath;
|
||||
param.filesystem() = aSerializedDOMPath;
|
||||
|
||||
aRv = mDirPath->GetPath(param.directory());
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.recursive() = mRecursive;
|
||||
if (mTargetBlobImpl) {
|
||||
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(),
|
||||
mTargetBlobImpl);
|
||||
mTargetBlobImpl);
|
||||
BlobChild* actor
|
||||
= ContentChild::GetSingleton()->GetOrCreateActorForBlob(blob);
|
||||
if (actor) {
|
||||
param.target() = actor;
|
||||
}
|
||||
} else {
|
||||
param.target() = mTargetRealPath;
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.target() = path;
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
RemoveTask::GetSuccessRequestResult() const
|
||||
RemoveTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return FileSystemBooleanResponse(mReturnValue);
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
|
||||
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemBooleanResponse r = aValue;
|
||||
|
@ -130,23 +194,19 @@ RemoveTask::Work()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Get the DOM path if a File is passed as the target.
|
||||
// Get the path if a File is passed as the target.
|
||||
if (mTargetBlobImpl) {
|
||||
if (!mFileSystem->GetRealPath(mTargetBlobImpl, mTargetRealPath)) {
|
||||
if (!mFileSystem->GetRealPath(mTargetBlobImpl,
|
||||
getter_AddRefs(mTargetPath))) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
if (!FileSystemUtils::IsDescendantPath(mDirRealPath, mTargetRealPath)) {
|
||||
if (!FileSystemUtils::IsDescendantPath(mDirPath, mTargetPath)) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
|
||||
if (!file) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
}
|
||||
|
||||
bool exists = false;
|
||||
nsresult rv = file->Exists(&exists);
|
||||
nsresult rv = mTargetPath->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -157,16 +217,16 @@ RemoveTask::Work()
|
|||
}
|
||||
|
||||
bool isFile = false;
|
||||
rv = file->IsFile(&isFile);
|
||||
rv = mTargetPath->IsFile(&isFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (isFile && !mFileSystem->IsSafeFile(file)) {
|
||||
if (isFile && !mFileSystem->IsSafeFile(mTargetPath)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
rv = file->Remove(mRecursive);
|
||||
rv = mTargetPath->Remove(mRecursive);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -17,19 +17,22 @@ namespace dom {
|
|||
class BlobImpl;
|
||||
class Promise;
|
||||
|
||||
class RemoveTask final
|
||||
: public FileSystemTaskBase
|
||||
class RemoveTask final : public FileSystemTaskBase
|
||||
{
|
||||
public:
|
||||
RemoveTask(FileSystemBase* aFileSystem,
|
||||
const nsAString& aDirPath,
|
||||
BlobImpl* aTargetBlob,
|
||||
const nsAString& aTargetPath,
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv);
|
||||
RemoveTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
static already_AddRefed<RemoveTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
BlobImpl* aTargetBlob,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<RemoveTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~RemoveTask();
|
||||
|
@ -42,13 +45,15 @@ public:
|
|||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aFileSystem) const override;
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult() const override;
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
@ -57,12 +62,23 @@ protected:
|
|||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
RemoveTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
BlobImpl* aTargetBlob,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive);
|
||||
|
||||
RemoveTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsString mDirRealPath;
|
||||
nsCOMPtr<nsIFile> mDirPath;
|
||||
|
||||
// This cannot be a File because this object will be used on a different
|
||||
// thread and File is not thread-safe. Let's use the BlobImpl instead.
|
||||
RefPtr<BlobImpl> mTargetBlobImpl;
|
||||
nsString mTargetRealPath;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
bool mRecursive;
|
||||
bool mReturnValue;
|
||||
};
|
||||
|
|
|
@ -251,16 +251,63 @@ class HTMLInputElementState final : public nsISupports
|
|||
mValue = aValue;
|
||||
}
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>& GetBlobImpls()
|
||||
void
|
||||
GetFilesOrDirectories(nsPIDOMWindowInner* aWindow,
|
||||
nsTArray<OwningFileOrDirectory>& aResult) const
|
||||
{
|
||||
return mBlobImpls;
|
||||
for (uint32_t i = 0; i < mBlobImplsOrDirectoryPaths.Length(); ++i) {
|
||||
if (mBlobImplsOrDirectoryPaths[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl) {
|
||||
RefPtr<File> file =
|
||||
File::Create(aWindow,
|
||||
mBlobImplsOrDirectoryPaths[i].mBlobImpl);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
OwningFileOrDirectory* element = aResult.AppendElement();
|
||||
element->SetAsFile() = file;
|
||||
} else {
|
||||
MOZ_ASSERT(mBlobImplsOrDirectoryPaths[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
NS_ConvertUTF16toUTF8 path(mBlobImplsOrDirectoryPaths[i].mDirectoryPath);
|
||||
nsresult rv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RefPtr<Directory> directory = Directory::Create(aWindow, file,
|
||||
Directory::eDOMRootDirectory);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
OwningFileOrDirectory* element = aResult.AppendElement();
|
||||
element->SetAsDirectory() = directory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetBlobImpls(const nsTArray<RefPtr<File>>& aFile)
|
||||
void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aArray)
|
||||
{
|
||||
mBlobImpls.Clear();
|
||||
for (uint32_t i = 0, len = aFile.Length(); i < len; ++i) {
|
||||
mBlobImpls.AppendElement(aFile[i]->Impl());
|
||||
mBlobImplsOrDirectoryPaths.Clear();
|
||||
for (uint32_t i = 0; i < aArray.Length(); ++i) {
|
||||
if (aArray[i].IsFile()) {
|
||||
Directory::BlobImplOrDirectoryPath* data =
|
||||
mBlobImplsOrDirectoryPaths.AppendElement();
|
||||
|
||||
data->mBlobImpl = aArray[i].GetAsFile()->Impl();
|
||||
data->mType = Directory::BlobImplOrDirectoryPath::eBlobImpl;
|
||||
} else {
|
||||
MOZ_ASSERT(aArray[i].IsDirectory());
|
||||
nsAutoString fullPath;
|
||||
nsresult rv = aArray[i].GetAsDirectory()->GetFullRealPath(fullPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Directory::BlobImplOrDirectoryPath* data =
|
||||
mBlobImplsOrDirectoryPaths.AppendElement();
|
||||
|
||||
data->mDirectoryPath = fullPath;
|
||||
data->mType = Directory::BlobImplOrDirectoryPath::eDirectoryPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,7 +321,9 @@ class HTMLInputElementState final : public nsISupports
|
|||
~HTMLInputElementState() {}
|
||||
|
||||
nsString mValue;
|
||||
nsTArray<RefPtr<BlobImpl>> mBlobImpls;
|
||||
|
||||
nsTArray<Directory::BlobImplOrDirectoryPath> mBlobImplsOrDirectoryPaths;
|
||||
|
||||
bool mChecked;
|
||||
bool mCheckedSet;
|
||||
};
|
||||
|
@ -340,33 +389,65 @@ UploadLastDir::ContentPrefCallback::HandleError(nsresult error)
|
|||
namespace {
|
||||
|
||||
/**
|
||||
* This may return nullptr if aDomFile's implementation of
|
||||
* This may return nullptr if the DOM File's implementation of
|
||||
* File::mozFullPathInternal does not successfully return a non-empty
|
||||
* string that is a valid path. This can happen on Firefox OS, for example,
|
||||
* where the file picker can create Blobs.
|
||||
*/
|
||||
static already_AddRefed<nsIFile>
|
||||
DOMFileToLocalFile(File* aDomFile)
|
||||
DOMFileOrDirectoryToLocalFile(const OwningFileOrDirectory& aData)
|
||||
{
|
||||
nsString path;
|
||||
ErrorResult rv;
|
||||
aDomFile->GetMozFullPathInternal(path, rv);
|
||||
if (rv.Failed() || path.IsEmpty()) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
|
||||
if (aData.IsFile()) {
|
||||
ErrorResult rv;
|
||||
aData.GetAsFile()->GetMozFullPathInternal(path, rv);
|
||||
if (rv.Failed() || path.IsEmpty()) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(aData.IsDirectory());
|
||||
aData.GetAsDirectory()->GetFullRealPath(path);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
|
||||
getter_AddRefs(localFile));
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
|
||||
getter_AddRefs(localFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return localFile.forget();
|
||||
}
|
||||
|
||||
void
|
||||
GetDOMFileOrDirectoryName(const OwningFileOrDirectory& aData,
|
||||
nsAString& aName)
|
||||
{
|
||||
if (aData.IsFile()) {
|
||||
aData.GetAsFile()->GetName(aName);
|
||||
} else {
|
||||
MOZ_ASSERT(aData.IsDirectory());
|
||||
ErrorResult rv;
|
||||
aData.GetAsDirectory()->GetName(aName, rv);
|
||||
NS_WARN_IF(rv.Failed());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetDOMFileOrDirectoryPath(const OwningFileOrDirectory& aData,
|
||||
nsAString& aPath,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (aData.IsFile()) {
|
||||
aData.GetAsFile()->GetMozFullPathInternal(aPath, aRv);
|
||||
} else {
|
||||
MOZ_ASSERT(aData.IsDirectory());
|
||||
aData.GetAsDirectory()->GetFullRealPath(aPath);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
@ -383,7 +464,7 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
|||
mFilePicker->GetMode(&mode);
|
||||
|
||||
// Collect new selected filenames
|
||||
nsTArray<RefPtr<File>> newFiles;
|
||||
nsTArray<OwningFileOrDirectory> newFilesOrDirectories;
|
||||
if (mode == static_cast<int16_t>(nsIFilePicker::modeOpenMultiple)) {
|
||||
nsCOMPtr<nsISimpleEnumerator> iter;
|
||||
nsresult rv =
|
||||
|
@ -402,9 +483,12 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
|||
nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(tmp);
|
||||
MOZ_ASSERT(domBlob,
|
||||
"Null file object from FilePicker's file enumerator?");
|
||||
if (domBlob) {
|
||||
newFiles.AppendElement(static_cast<File*>(domBlob.get()));
|
||||
if (!domBlob) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
|
||||
element->SetAsFile() = static_cast<File*>(domBlob.get());
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(mode == static_cast<int16_t>(nsIFilePicker::modeOpen) ||
|
||||
|
@ -416,16 +500,25 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
|||
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(tmp);
|
||||
if (blob) {
|
||||
RefPtr<File> file = static_cast<Blob*>(blob.get())->ToFile();
|
||||
newFiles.AppendElement(file);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
|
||||
element->SetAsFile() = file;
|
||||
} else if (tmp) {
|
||||
RefPtr<Directory> directory = static_cast<Directory*>(tmp.get());
|
||||
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
|
||||
element->SetAsDirectory() = directory;
|
||||
}
|
||||
}
|
||||
|
||||
if (newFiles.IsEmpty()) {
|
||||
if (newFilesOrDirectories.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Store the last used directory using the content pref service:
|
||||
nsCOMPtr<nsIFile> file = DOMFileToLocalFile(newFiles[0]);
|
||||
nsCOMPtr<nsIFile> file =
|
||||
DOMFileOrDirectoryToLocalFile(newFilesOrDirectories[0]);
|
||||
|
||||
if (file) {
|
||||
nsCOMPtr<nsIFile> lastUsedDir;
|
||||
file->GetParent(getter_AddRefs(lastUsedDir));
|
||||
|
@ -436,7 +529,7 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
|||
// The text control frame (if there is one) isn't going to send a change
|
||||
// event because it will think this is done by a script.
|
||||
// So, we can safely send one by ourself.
|
||||
mInput->SetFiles(newFiles, true);
|
||||
mInput->SetFilesOrDirectories(newFilesOrDirectories, true);
|
||||
return nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
|
||||
NS_LITERAL_STRING("change"), true,
|
||||
|
@ -672,7 +765,8 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
|
|||
// Set default directry and filename
|
||||
nsAutoString defaultName;
|
||||
|
||||
const nsTArray<RefPtr<File>>& oldFiles = GetFilesInternal();
|
||||
const nsTArray<OwningFileOrDirectory>& oldFiles =
|
||||
GetFilesOrDirectoriesInternal();
|
||||
|
||||
nsCOMPtr<nsIFilePickerShownCallback> callback =
|
||||
new HTMLInputElement::nsFilePickerShownCallback(this, filePicker);
|
||||
|
@ -681,18 +775,10 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
|
|||
aType != FILE_PICKER_DIRECTORY) {
|
||||
nsString path;
|
||||
|
||||
ErrorResult error;
|
||||
oldFiles[0]->GetMozFullPathInternal(path, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
rv = NS_NewLocalFile(path, false, getter_AddRefs(localFile));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIFile> localFile = DOMFileOrDirectoryToLocalFile(oldFiles[0]);
|
||||
if (localFile) {
|
||||
nsCOMPtr<nsIFile> parentFile;
|
||||
rv = localFile->GetParent(getter_AddRefs(parentFile));
|
||||
nsresult rv = localFile->GetParent(getter_AddRefs(parentFile));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
filePicker->SetDisplayDirectory(parentFile);
|
||||
}
|
||||
|
@ -703,7 +789,8 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
|
|||
// one file was selected before.
|
||||
if (oldFiles.Length() == 1) {
|
||||
nsAutoString leafName;
|
||||
oldFiles[0]->GetName(leafName);
|
||||
GetDOMFileOrDirectoryName(oldFiles[0], leafName);
|
||||
|
||||
if (!leafName.IsEmpty()) {
|
||||
filePicker->SetDefaultString(leafName);
|
||||
}
|
||||
|
@ -756,7 +843,7 @@ UploadLastDir::FetchDirectoryAndDisplayPicker(nsIDocument* aDoc,
|
|||
NS_PRECONDITION(docURI, "docURI is null");
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
|
||||
nsCOMPtr<nsIContentPrefCallback2> prefCallback =
|
||||
nsCOMPtr<nsIContentPrefCallback2> prefCallback =
|
||||
new UploadLastDir::ContentPrefCallback(aFilePicker, aFpCallback);
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
|
@ -935,7 +1022,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement,
|
|||
if (tmp->IsSingleLineTextControl(false)) {
|
||||
tmp->mInputData.mState->Traverse(cb);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesOrDirectories)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesAndDirectoriesPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
@ -944,7 +1031,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
|
|||
nsGenericHTMLFormElementWithState)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesOrDirectories)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesAndDirectoriesPromise)
|
||||
if (tmp->IsSingleLineTextControl(false)) {
|
||||
|
@ -1003,8 +1090,8 @@ HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) co
|
|||
// we can just grab the pretty string and use it as wallpaper
|
||||
GetDisplayFileName(it->mStaticDocFileList);
|
||||
} else {
|
||||
it->mFiles.Clear();
|
||||
it->mFiles.AppendElements(mFiles);
|
||||
it->mFilesOrDirectories.Clear();
|
||||
it->mFilesOrDirectories.AppendElements(mFilesOrDirectories);
|
||||
}
|
||||
break;
|
||||
case VALUE_MODE_DEFAULT_ON:
|
||||
|
@ -1442,9 +1529,9 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const
|
|||
#else
|
||||
// XXX We'd love to assert that this can't happen, but some mochitests
|
||||
// use SpecialPowers to circumvent our more sane security model.
|
||||
if (!mFiles.IsEmpty()) {
|
||||
if (!mFilesOrDirectories.IsEmpty()) {
|
||||
ErrorResult rv;
|
||||
mFiles[0]->GetMozFullPath(aValue, rv);
|
||||
GetDOMFileOrDirectoryPath(mFilesOrDirectories[0], aValue, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
@ -1456,10 +1543,10 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const
|
|||
#endif
|
||||
} else {
|
||||
// Just return the leaf name
|
||||
if (mFiles.IsEmpty()) {
|
||||
if (mFilesOrDirectories.IsEmpty()) {
|
||||
aValue.Truncate();
|
||||
} else {
|
||||
mFiles[0]->GetName(aValue);
|
||||
GetDOMFileOrDirectoryName(mFilesOrDirectories[0], aValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1494,8 +1581,8 @@ HTMLInputElement::IsValueEmpty() const
|
|||
void
|
||||
HTMLInputElement::ClearFiles(bool aSetValueChanged)
|
||||
{
|
||||
nsTArray<RefPtr<File>> files;
|
||||
SetFiles(files, aSetValueChanged);
|
||||
nsTArray<OwningFileOrDirectory> data;
|
||||
SetFilesOrDirectories(data, aSetValueChanged);
|
||||
}
|
||||
|
||||
/* static */ Decimal
|
||||
|
@ -2065,9 +2152,9 @@ void
|
|||
HTMLInputElement::MozGetFileNameArray(nsTArray<nsString>& aArray,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
for (uint32_t i = 0; i < mFiles.Length(); i++) {
|
||||
nsString str;
|
||||
mFiles[i]->GetMozFullPathInternal(str, aRv);
|
||||
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); i++) {
|
||||
nsAutoString str;
|
||||
GetDOMFileOrDirectoryPath(mFilesOrDirectories[i], str, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
@ -2117,25 +2204,29 @@ HTMLInputElement::MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles)
|
|||
if (!global) {
|
||||
return;
|
||||
}
|
||||
nsTArray<RefPtr<File>> files;
|
||||
|
||||
nsTArray<OwningFileOrDirectory> files;
|
||||
for (uint32_t i = 0; i < aFiles.Length(); ++i) {
|
||||
RefPtr<File> file = File::Create(global, aFiles[i].get()->Impl());
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
files.AppendElement(file);
|
||||
OwningFileOrDirectory* element = files.AppendElement();
|
||||
element->SetAsFile() = file;
|
||||
}
|
||||
SetFiles(files, true);
|
||||
|
||||
SetFilesOrDirectories(files, true);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv)
|
||||
HTMLInputElement::MozSetFileNameArray(const Sequence<nsString>& aFileNames,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (XRE_IsContentProcess()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<File>> files;
|
||||
nsTArray<OwningFileOrDirectory> files;
|
||||
for (uint32_t i = 0; i < aFileNames.Length(); ++i) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
|
||||
|
@ -2152,21 +2243,28 @@ HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames, Er
|
|||
NS_NewLocalFile(aFileNames[i], false, getter_AddRefs(file));
|
||||
}
|
||||
|
||||
if (file) {
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
RefPtr<File> domFile = File::CreateFromFile(global, file);
|
||||
files.AppendElement(domFile);
|
||||
} else {
|
||||
if (!file) {
|
||||
continue; // Not much we can do if the file doesn't exist
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> domFile = File::CreateFromFile(global, file);
|
||||
|
||||
OwningFileOrDirectory* element = files.AppendElement();
|
||||
element->SetAsFile() = domFile;
|
||||
}
|
||||
|
||||
SetFiles(files, true);
|
||||
SetFilesOrDirectories(files, true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLInputElement::MozSetFileNameArray(const char16_t** aFileNames, uint32_t aLength)
|
||||
HTMLInputElement::MozSetFileNameArray(const char16_t** aFileNames,
|
||||
uint32_t aLength)
|
||||
{
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
// setting the value of a "FILE" input widget requires chrome privilege
|
||||
|
@ -2379,14 +2477,14 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
|
|||
return;
|
||||
}
|
||||
|
||||
if (mFiles.Length() == 1) {
|
||||
mFiles[0]->GetName(aValue);
|
||||
if (mFilesOrDirectories.Length() == 1) {
|
||||
GetDOMFileOrDirectoryName(mFilesOrDirectories[0], aValue);
|
||||
return;
|
||||
}
|
||||
|
||||
nsXPIDLString value;
|
||||
|
||||
if (mFiles.IsEmpty()) {
|
||||
if (mFilesOrDirectories.IsEmpty()) {
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
"NoFilesSelected", value);
|
||||
|
@ -2396,7 +2494,7 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
|
|||
}
|
||||
} else {
|
||||
nsString count;
|
||||
count.AppendInt(int(mFiles.Length()));
|
||||
count.AppendInt(int(mFilesOrDirectories.Length()));
|
||||
|
||||
const char16_t* params[] = { count.get() };
|
||||
nsContentUtils::FormatLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
|
@ -2407,13 +2505,13 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
|
|||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::SetFiles(const nsTArray<RefPtr<File>>& aFiles,
|
||||
bool aSetValueChanged)
|
||||
HTMLInputElement::SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories,
|
||||
bool aSetValueChanged)
|
||||
{
|
||||
mFiles.Clear();
|
||||
mFiles.AppendElements(aFiles);
|
||||
mFilesOrDirectories.Clear();
|
||||
mFilesOrDirectories.AppendElements(aFilesOrDirectories);
|
||||
|
||||
AfterSetFiles(aSetValueChanged);
|
||||
AfterSetFilesOrDirectories(aSetValueChanged);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2421,22 +2519,24 @@ HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
|
|||
bool aSetValueChanged)
|
||||
{
|
||||
RefPtr<FileList> files = static_cast<FileList*>(aFiles);
|
||||
mFiles.Clear();
|
||||
mFilesOrDirectories.Clear();
|
||||
|
||||
if (aFiles) {
|
||||
uint32_t listLength;
|
||||
aFiles->GetLength(&listLength);
|
||||
for (uint32_t i = 0; i < listLength; i++) {
|
||||
RefPtr<File> file = files->Item(i);
|
||||
mFiles.AppendElement(file);
|
||||
|
||||
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
|
||||
element->SetAsFile() = file;
|
||||
}
|
||||
}
|
||||
|
||||
AfterSetFiles(aSetValueChanged);
|
||||
AfterSetFilesOrDirectories(aSetValueChanged);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::AfterSetFiles(bool aSetValueChanged)
|
||||
HTMLInputElement::AfterSetFilesOrDirectories(bool aSetValueChanged)
|
||||
{
|
||||
// No need to flush here, if there's no frame at this point we
|
||||
// don't need to force creation of one just to tell it about this
|
||||
|
@ -2454,11 +2554,11 @@ HTMLInputElement::AfterSetFiles(bool aSetValueChanged)
|
|||
// call under GetMozFullPath won't be rejected for not being urgent.
|
||||
// XXX Protected by the ifndef because the blob code doesn't allow us to send
|
||||
// this message in b2g.
|
||||
if (mFiles.IsEmpty()) {
|
||||
if (mFilesOrDirectories.IsEmpty()) {
|
||||
mFirstFilePath.Truncate();
|
||||
} else {
|
||||
ErrorResult rv;
|
||||
mFiles[0]->GetMozFullPath(mFirstFilePath, rv);
|
||||
GetDOMFileOrDirectoryPath(mFilesOrDirectories[0], mFirstFilePath, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
}
|
||||
|
@ -2538,9 +2638,11 @@ HTMLInputElement::UpdateFileList()
|
|||
if (mFileList) {
|
||||
mFileList->Clear();
|
||||
|
||||
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
|
||||
for (uint32_t i = 0; i < files.Length(); ++i) {
|
||||
if (!mFileList->Append(files[i])) {
|
||||
const nsTArray<OwningFileOrDirectory>& array =
|
||||
GetFilesOrDirectoriesInternal();
|
||||
|
||||
for (uint32_t i = 0; i < array.Length(); ++i) {
|
||||
if (array[i].IsFile() && !mFileList->Append(array[i].GetAsFile())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -3988,7 +4090,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
|||
nsNumberControlFrame* numberControlFrame =
|
||||
do_QueryFrame(GetPrimaryFrame());
|
||||
if (numberControlFrame) {
|
||||
if (aVisitor.mEvent->mMessage == eMouseDown &&
|
||||
if (aVisitor.mEvent->mMessage == eMouseDown &&
|
||||
IsMutable()) {
|
||||
switch (numberControlFrame->GetSpinButtonForPointerEvent(
|
||||
aVisitor.mEvent->AsMouseEvent())) {
|
||||
|
@ -4539,7 +4641,7 @@ HTMLInputElement::GetValueAsDate(const nsAString& aValue,
|
|||
}
|
||||
|
||||
uint32_t endOfYearOffset = aValue.Length() - 6;
|
||||
|
||||
|
||||
if (aValue[endOfYearOffset] != '-' ||
|
||||
aValue[endOfYearOffset + 3] != '-') {
|
||||
return false;
|
||||
|
@ -4907,45 +5009,38 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const nsTArray<RefPtr<File>>& filesAndDirs = GetFilesInternal();
|
||||
const nsTArray<OwningFileOrDirectory>& filesAndDirs =
|
||||
GetFilesOrDirectoriesInternal();
|
||||
|
||||
Sequence<OwningFileOrDirectory> filesAndDirsSeq;
|
||||
|
||||
if (!filesAndDirsSeq.SetLength(filesAndDirs.Length(), mozilla::fallible_t())) {
|
||||
if (!filesAndDirsSeq.SetLength(filesAndDirs.Length(),
|
||||
mozilla::fallible_t())) {
|
||||
p->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < filesAndDirs.Length(); ++i) {
|
||||
if (filesAndDirs[i]->IsDirectory()) {
|
||||
if (filesAndDirs[i].IsDirectory()) {
|
||||
#if defined(ANDROID) || defined(MOZ_B2G)
|
||||
MOZ_ASSERT(false,
|
||||
"Directory picking should have been redirected to normal "
|
||||
"file picking for platforms that don't have a directory "
|
||||
"picker");
|
||||
#endif
|
||||
nsAutoString path;
|
||||
filesAndDirs[i]->GetMozFullPathInternal(path, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
int32_t leafSeparatorIndex = path.RFind(FILE_PATH_SEPARATOR);
|
||||
nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex);
|
||||
|
||||
RefPtr<OSFileSystem> fs = new OSFileSystem(dirname);
|
||||
fs->Init(OwnerDoc()->GetInnerWindow());
|
||||
RefPtr<Directory> directory = filesAndDirs[i].GetAsDirectory();
|
||||
|
||||
nsAutoString dompath(NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR));
|
||||
dompath.Append(Substring(path, leafSeparatorIndex + 1));
|
||||
RefPtr<Directory> directory = new Directory(fs, dompath);
|
||||
// In future we could refactor SetFilePickerFiltersFromAccept to return a
|
||||
// semicolon separated list of file extensions and include that in the
|
||||
// filter string passed here.
|
||||
directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive"));
|
||||
filesAndDirsSeq[i].SetAsDirectory() = directory;
|
||||
} else {
|
||||
MOZ_ASSERT(filesAndDirs[i].IsFile());
|
||||
|
||||
// This file was directly selected by the user, so don't filter it.
|
||||
filesAndDirsSeq[i].SetAsFile() = filesAndDirs[i];
|
||||
filesAndDirsSeq[i].SetAsFile() = filesAndDirs[i].GetAsFile();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5579,13 +5674,18 @@ HTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
|
|||
if (mType == NS_FORM_INPUT_FILE) {
|
||||
// Submit files
|
||||
|
||||
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
|
||||
const nsTArray<OwningFileOrDirectory>& files =
|
||||
GetFilesOrDirectoriesInternal();
|
||||
|
||||
bool hasBlobs = false;
|
||||
for (uint32_t i = 0; i < files.Length(); ++i) {
|
||||
aFormSubmission->AddNameBlobOrNullPair(name, files[i]);
|
||||
if (files[i].IsFile()) {
|
||||
hasBlobs = true;
|
||||
aFormSubmission->AddNameBlobOrNullPair(name, files[i].GetAsFile());
|
||||
}
|
||||
}
|
||||
|
||||
if (files.IsEmpty()) {
|
||||
if (!hasBlobs) {
|
||||
aFormSubmission->AddNameBlobOrNullPair(name, nullptr);
|
||||
}
|
||||
|
||||
|
@ -5619,9 +5719,9 @@ HTMLInputElement::SaveState()
|
|||
}
|
||||
break;
|
||||
case VALUE_MODE_FILENAME:
|
||||
if (!mFiles.IsEmpty()) {
|
||||
if (!mFilesOrDirectories.IsEmpty()) {
|
||||
inputState = new HTMLInputElementState();
|
||||
inputState->SetBlobImpls(mFiles);
|
||||
inputState->SetFilesOrDirectories(mFilesOrDirectories);
|
||||
}
|
||||
break;
|
||||
case VALUE_MODE_VALUE:
|
||||
|
@ -5790,7 +5890,7 @@ HTMLInputElement::AddStates(EventStates aStates)
|
|||
}
|
||||
}
|
||||
}
|
||||
nsGenericHTMLFormElementWithState::AddStates(aStates);
|
||||
nsGenericHTMLFormElementWithState::AddStates(aStates);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -5827,20 +5927,13 @@ HTMLInputElement::RestoreState(nsPresState* aState)
|
|||
break;
|
||||
case VALUE_MODE_FILENAME:
|
||||
{
|
||||
const nsTArray<RefPtr<BlobImpl>>& blobImpls = inputState->GetBlobImpls();
|
||||
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
|
||||
if (window) {
|
||||
nsTArray<OwningFileOrDirectory> array;
|
||||
inputState->GetFilesOrDirectories(window, array);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
nsTArray<RefPtr<File>> files;
|
||||
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
|
||||
RefPtr<File> file = File::Create(global, blobImpls[i]);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
files.AppendElement(file);
|
||||
SetFilesOrDirectories(array, true);
|
||||
}
|
||||
|
||||
SetFiles(files, true);
|
||||
}
|
||||
break;
|
||||
case VALUE_MODE_VALUE:
|
||||
|
@ -6350,15 +6443,15 @@ HTMLInputElement::IsValueMissing() const
|
|||
switch (GetValueMode()) {
|
||||
case VALUE_MODE_VALUE:
|
||||
return IsValueEmpty();
|
||||
|
||||
case VALUE_MODE_FILENAME:
|
||||
{
|
||||
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
|
||||
return files.IsEmpty();
|
||||
}
|
||||
return GetFilesOrDirectoriesInternal().IsEmpty();
|
||||
|
||||
case VALUE_MODE_DEFAULT_ON:
|
||||
// This should not be used for type radio.
|
||||
// See the MOZ_ASSERT at the beginning of the method.
|
||||
return !mChecked;
|
||||
|
||||
case VALUE_MODE_DEFAULT:
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/dom/HTMLFormElement.h" // for HasEverTriedInvalidSubmit()
|
||||
#include "mozilla/dom/HTMLInputElementBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "nsIFilePicker.h"
|
||||
#include "nsIContentPrefService2.h"
|
||||
#include "mozilla/Decimal.h"
|
||||
|
@ -220,12 +221,13 @@ public:
|
|||
|
||||
void GetDisplayFileName(nsAString& aFileName) const;
|
||||
|
||||
const nsTArray<RefPtr<File>>& GetFilesInternal() const
|
||||
const nsTArray<OwningFileOrDirectory>& GetFilesOrDirectoriesInternal() const
|
||||
{
|
||||
return mFiles;
|
||||
return mFilesOrDirectories;
|
||||
}
|
||||
|
||||
void SetFiles(const nsTArray<RefPtr<File>>& aFiles, bool aSetValueChanged);
|
||||
void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories,
|
||||
bool aSetValueChanged);
|
||||
void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
|
||||
|
||||
// Called when a nsIFilePicker or a nsIColorPicker terminate.
|
||||
|
@ -925,9 +927,9 @@ protected:
|
|||
nsresult UpdateFileList();
|
||||
|
||||
/**
|
||||
* Called after calling one of the SetFiles() functions.
|
||||
* Called after calling one of the SetFilesOrDirectories() functions.
|
||||
*/
|
||||
void AfterSetFiles(bool aSetValueChanged);
|
||||
void AfterSetFilesOrDirectories(bool aSetValueChanged);
|
||||
|
||||
/**
|
||||
* Determine whether the editor needs to be initialized explicitly for
|
||||
|
@ -1266,16 +1268,16 @@ protected:
|
|||
} mInputData;
|
||||
|
||||
/**
|
||||
* The value of the input if it is a file input. This is the list of filenames
|
||||
* used when uploading a file. It is vital that this is kept separate from
|
||||
* mValue so that it won't be possible to 'leak' the value from a text-input
|
||||
* to a file-input. Additionally, the logic for this value is kept as simple
|
||||
* as possible to avoid accidental errors where the wrong filename is used.
|
||||
* Therefor the list of filenames is always owned by this member, never by
|
||||
* the frame. Whenever the frame wants to change the filename it has to call
|
||||
* SetFileNames to update this member.
|
||||
* The value of the input if it is a file input. This is the list of files or
|
||||
* directories DOM objects used when uploading a file. It is vital that this
|
||||
* is kept separate from mValue so that it won't be possible to 'leak' the
|
||||
* value from a text-input to a file-input. Additionally, the logic for this
|
||||
* value is kept as simple as possible to avoid accidental errors where the
|
||||
* wrong filename is used. Therefor the list of filenames is always owned by
|
||||
* this member, never by the frame. Whenever the frame wants to change the
|
||||
* filename it has to call SetFilesOrDirectories to update this member.
|
||||
*/
|
||||
nsTArray<RefPtr<File>> mFiles;
|
||||
nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
|
||||
|
||||
#ifndef MOZ_CHILD_PERMISSIONS
|
||||
/**
|
||||
|
|
|
@ -187,30 +187,6 @@ private:
|
|||
return mBlobImpl->IsFile();
|
||||
}
|
||||
|
||||
virtual void
|
||||
LookupAndCacheIsDirectory() override
|
||||
{
|
||||
mBlobImpl->LookupAndCacheIsDirectory();
|
||||
}
|
||||
|
||||
virtual void
|
||||
SetIsDirectory(bool aIsDir) override
|
||||
{
|
||||
return mBlobImpl->SetIsDirectory(aIsDir);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsDirectory() const override
|
||||
{
|
||||
return mBlobImpl->IsDirectory();
|
||||
}
|
||||
|
||||
virtual BlobDirState
|
||||
GetDirState() const override
|
||||
{
|
||||
return mBlobImpl->GetDirState();
|
||||
}
|
||||
|
||||
virtual bool
|
||||
MayBeClonedToOtherThreads() const override
|
||||
{
|
||||
|
|
|
@ -444,8 +444,7 @@ ResolveMysteryFile(BlobImpl* aImpl,
|
|||
BlobChild* actor = ActorFromRemoteBlobImpl(aImpl);
|
||||
if (actor) {
|
||||
return actor->SetMysteryBlobInfo(aName, aContentType,
|
||||
aSize, aLastModifiedDate,
|
||||
BlobDirState::eUnknownIfDir);
|
||||
aSize, aLastModifiedDate);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -670,8 +670,7 @@ public:
|
|||
EmptyBlobImpl(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate)
|
||||
: BlobImplBase(aName, aContentType, 0, aLastModifiedDate,
|
||||
BlobDirState::eIsNotDir)
|
||||
: BlobImplBase(aName, aContentType, 0, aLastModifiedDate)
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
@ -716,14 +715,12 @@ struct MOZ_STACK_CLASS CreateBlobImplMetadata final
|
|||
nsString mName;
|
||||
uint64_t mLength;
|
||||
int64_t mLastModifiedDate;
|
||||
BlobDirState mDirState;
|
||||
bool mHasRecursed;
|
||||
const bool mIsSameProcessActor;
|
||||
|
||||
explicit CreateBlobImplMetadata(bool aIsSameProcessActor)
|
||||
: mLength(0)
|
||||
, mLastModifiedDate(0)
|
||||
, mDirState(BlobDirState::eUnknownIfDir)
|
||||
, mHasRecursed(false)
|
||||
, mIsSameProcessActor(aIsSameProcessActor)
|
||||
{
|
||||
|
@ -965,7 +962,6 @@ CreateBlobImpl(const ParentBlobConstructorParams& aParams,
|
|||
metadata.mName = params.name();
|
||||
metadata.mLength = params.length();
|
||||
metadata.mLastModifiedDate = params.modDate();
|
||||
metadata.mDirState = BlobDirState(params.dirState());
|
||||
}
|
||||
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
|
@ -1775,7 +1771,6 @@ public:
|
|||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aModDate,
|
||||
BlobDirState aDirState,
|
||||
bool aIsSameProcessBlob);
|
||||
|
||||
// For Blob.
|
||||
|
@ -2053,18 +2048,6 @@ public:
|
|||
virtual bool
|
||||
IsFile() const override;
|
||||
|
||||
virtual void
|
||||
LookupAndCacheIsDirectory() override;
|
||||
|
||||
virtual void
|
||||
SetIsDirectory(bool aIsDir) override;
|
||||
|
||||
virtual bool
|
||||
IsDirectory() const override;
|
||||
|
||||
virtual BlobDirState
|
||||
GetDirState() const override;
|
||||
|
||||
virtual bool
|
||||
MayBeClonedToOtherThreads() const override;
|
||||
|
||||
|
@ -2096,9 +2079,8 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
|
|||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aModDate,
|
||||
BlobDirState aDirState,
|
||||
bool aIsSameProcessBlob)
|
||||
: BlobImplBase(aName, aContentType, aLength, aModDate, aDirState)
|
||||
: BlobImplBase(aName, aContentType, aLength, aModDate)
|
||||
, mIsSlice(false)
|
||||
{
|
||||
if (aIsSameProcessBlob) {
|
||||
|
@ -2814,34 +2796,6 @@ RemoteBlobImpl::IsFile() const
|
|||
return mBlobImpl->IsFile();
|
||||
}
|
||||
|
||||
void
|
||||
BlobParent::
|
||||
RemoteBlobImpl::LookupAndCacheIsDirectory()
|
||||
{
|
||||
return mBlobImpl->LookupAndCacheIsDirectory();
|
||||
}
|
||||
|
||||
void
|
||||
BlobParent::
|
||||
RemoteBlobImpl::SetIsDirectory(bool aIsDir)
|
||||
{
|
||||
return mBlobImpl->SetIsDirectory(aIsDir);
|
||||
}
|
||||
|
||||
bool
|
||||
BlobParent::
|
||||
RemoteBlobImpl::IsDirectory() const
|
||||
{
|
||||
return mBlobImpl->IsDirectory();
|
||||
}
|
||||
|
||||
BlobDirState
|
||||
BlobParent::
|
||||
RemoteBlobImpl::GetDirState() const
|
||||
{
|
||||
return mBlobImpl->GetDirState();
|
||||
}
|
||||
|
||||
bool
|
||||
BlobParent::
|
||||
RemoteBlobImpl::MayBeClonedToOtherThreads() const
|
||||
|
@ -3033,8 +2987,7 @@ BlobChild::CommonInit(BlobChild* aOther, BlobImpl* aBlobImpl)
|
|||
MOZ_ASSERT(!rv.Failed());
|
||||
|
||||
remoteBlob = new RemoteBlobImpl(this, otherImpl, name, contentType, length,
|
||||
modDate, otherImpl->GetDirState(),
|
||||
false /* SameProcessBlobImpl */);
|
||||
modDate, false /* SameProcessBlobImpl */);
|
||||
} else {
|
||||
remoteBlob = new RemoteBlobImpl(this, otherImpl, contentType, length,
|
||||
false /* SameProcessBlobImpl */);
|
||||
|
@ -3086,7 +3039,6 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
|
|||
params.contentType(),
|
||||
params.length(),
|
||||
params.modDate(),
|
||||
BlobDirState(params.dirState()),
|
||||
false /* SameProcessBlobImpl */);
|
||||
break;
|
||||
}
|
||||
|
@ -3122,7 +3074,6 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
|
|||
contentType,
|
||||
size,
|
||||
lastModifiedDate,
|
||||
blobImpl->GetDirState(),
|
||||
true /* SameProcessBlobImpl */);
|
||||
} else {
|
||||
remoteBlob = new RemoteBlobImpl(this, blobImpl, contentType, size,
|
||||
|
@ -3303,8 +3254,7 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
|
|||
MOZ_ASSERT(!rv.Failed());
|
||||
|
||||
blobParams =
|
||||
FileBlobConstructorParams(name, contentType, length, modDate,
|
||||
aBlobImpl->GetDirState(), blobData);
|
||||
FileBlobConstructorParams(name, contentType, length, modDate, blobData);
|
||||
} else {
|
||||
blobParams = NormalBlobConstructorParams(contentType, length, blobData);
|
||||
}
|
||||
|
@ -3477,8 +3427,7 @@ bool
|
|||
BlobChild::SetMysteryBlobInfo(const nsString& aName,
|
||||
const nsString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState)
|
||||
int64_t aLastModifiedDate)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mBlobImpl);
|
||||
|
@ -3491,7 +3440,6 @@ BlobChild::SetMysteryBlobInfo(const nsString& aName,
|
|||
aContentType,
|
||||
aLength,
|
||||
aLastModifiedDate,
|
||||
aDirState,
|
||||
void_t() /* optionalBlobData */);
|
||||
return SendResolveMystery(params);
|
||||
}
|
||||
|
@ -3854,7 +3802,7 @@ BlobParent::GetOrCreateFromImpl(ParentManagerType* aManager,
|
|||
|
||||
blobParams =
|
||||
FileBlobConstructorParams(name, contentType, length, modDate,
|
||||
aBlobImpl->GetDirState(), void_t());
|
||||
void_t());
|
||||
} else {
|
||||
blobParams = NormalBlobConstructorParams(contentType, length, void_t());
|
||||
}
|
||||
|
|
|
@ -31,8 +31,6 @@ class ContentChild;
|
|||
class nsIContentChild;
|
||||
class PBlobStreamChild;
|
||||
|
||||
enum BlobDirState : uint32_t;
|
||||
|
||||
class BlobChild final
|
||||
: public PBlobChild
|
||||
{
|
||||
|
@ -117,8 +115,7 @@ public:
|
|||
SetMysteryBlobInfo(const nsString& aName,
|
||||
const nsString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState);
|
||||
int64_t aLastModifiedDate);
|
||||
|
||||
// Use this for non-file blobs.
|
||||
bool
|
||||
|
|
|
@ -73,7 +73,6 @@ struct FileBlobConstructorParams
|
|||
nsString contentType;
|
||||
uint64_t length;
|
||||
int64_t modDate;
|
||||
uint32_t dirState;
|
||||
|
||||
// This must be of type BlobData in a child->parent message, and will always
|
||||
// be of type void_t in a parent->child message.
|
||||
|
|
|
@ -53,15 +53,18 @@ FilePickerParent::~FilePickerParent()
|
|||
// 2. The stream transport thread stat()s the file in Run() and then dispatches
|
||||
// the same runnable on the main thread.
|
||||
// 3. The main thread sends the results over IPC.
|
||||
FilePickerParent::FileSizeAndDateRunnable::FileSizeAndDateRunnable(FilePickerParent *aFPParent,
|
||||
nsTArray<RefPtr<BlobImpl>>& aBlobs)
|
||||
FilePickerParent::IORunnable::IORunnable(FilePickerParent *aFPParent,
|
||||
nsTArray<nsCOMPtr<nsIFile>>& aFiles,
|
||||
bool aIsDirectory)
|
||||
: mFilePickerParent(aFPParent)
|
||||
, mIsDirectory(aIsDirectory)
|
||||
{
|
||||
mBlobs.SwapElements(aBlobs);
|
||||
mFiles.SwapElements(aFiles);
|
||||
MOZ_ASSERT_IF(aIsDirectory, mFiles.Length() == 1);
|
||||
}
|
||||
|
||||
bool
|
||||
FilePickerParent::FileSizeAndDateRunnable::Dispatch()
|
||||
FilePickerParent::IORunnable::Dispatch()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -75,23 +78,49 @@ FilePickerParent::FileSizeAndDateRunnable::Dispatch()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FilePickerParent::FileSizeAndDateRunnable::Run()
|
||||
FilePickerParent::IORunnable::Run()
|
||||
{
|
||||
// If we're on the main thread, then that means we're done. Just send the
|
||||
// results.
|
||||
if (NS_IsMainThread()) {
|
||||
if (mFilePickerParent) {
|
||||
mFilePickerParent->SendFiles(mBlobs);
|
||||
mFilePickerParent->SendFilesOrDirectories(mResults);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We're not on the main thread, so do the stat().
|
||||
for (unsigned i = 0; i < mBlobs.Length(); i++) {
|
||||
ErrorResult rv;
|
||||
mBlobs[i]->GetSize(rv);
|
||||
mBlobs[i]->GetLastModified(rv);
|
||||
mBlobs[i]->LookupAndCacheIsDirectory();
|
||||
// We're not on the main thread, so do the IO.
|
||||
|
||||
for (uint32_t i = 0; i < mFiles.Length(); ++i) {
|
||||
if (mIsDirectory) {
|
||||
nsAutoString path;
|
||||
nsresult rv = mFiles[i]->GetPath(path);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlobImplOrString* data = mResults.AppendElement();
|
||||
data->mType = BlobImplOrString::eDirectoryPath;
|
||||
data->mDirectoryPath = path;
|
||||
continue;
|
||||
}
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = new BlobImplFile(mFiles[i]);
|
||||
|
||||
ErrorResult error;
|
||||
blobImpl->GetSize(error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
blobImpl->GetLastModified(error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlobImplOrString* data = mResults.AppendElement();
|
||||
data->mType = BlobImplOrString::eBlobImpl;
|
||||
data->mBlobImpl = blobImpl;
|
||||
}
|
||||
|
||||
// Dispatch ourselves back on the main thread.
|
||||
|
@ -101,29 +130,46 @@ FilePickerParent::FileSizeAndDateRunnable::Run()
|
|||
// thread.
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FilePickerParent::FileSizeAndDateRunnable::Destroy()
|
||||
FilePickerParent::IORunnable::Destroy()
|
||||
{
|
||||
mFilePickerParent = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FilePickerParent::SendFiles(const nsTArray<RefPtr<BlobImpl>>& aBlobs)
|
||||
FilePickerParent::SendFilesOrDirectories(const nsTArray<BlobImplOrString>& aData)
|
||||
{
|
||||
if (mMode == nsIFilePicker::modeGetFolder) {
|
||||
MOZ_ASSERT(aData.Length() <= 1);
|
||||
if (aData.IsEmpty()) {
|
||||
Unused << Send__delete__(this, void_t(), mResult);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aData[0].mType == BlobImplOrString::eDirectoryPath);
|
||||
|
||||
InputDirectory input;
|
||||
input.directoryPath() = aData[0].mDirectoryPath;
|
||||
Unused << Send__delete__(this, input, mResult);
|
||||
return;
|
||||
}
|
||||
|
||||
nsIContentParent* parent = TabParent::GetFrom(Manager())->Manager();
|
||||
InfallibleTArray<PBlobParent*> blobs;
|
||||
|
||||
for (unsigned i = 0; i < aBlobs.Length(); i++) {
|
||||
BlobParent* blobParent = parent->GetOrCreateActorForBlobImpl(aBlobs[i]);
|
||||
for (unsigned i = 0; i < aData.Length(); i++) {
|
||||
MOZ_ASSERT(aData[i].mType == BlobImplOrString::eBlobImpl);
|
||||
BlobParent* blobParent = parent->GetOrCreateActorForBlobImpl(aData[i].mBlobImpl);
|
||||
if (blobParent) {
|
||||
blobs.AppendElement(blobParent);
|
||||
}
|
||||
}
|
||||
|
||||
InputFiles inblobs;
|
||||
InputBlobs inblobs;
|
||||
inblobs.blobsParent().SwapElements(blobs);
|
||||
Unused << Send__delete__(this, inblobs, mResult);
|
||||
}
|
||||
|
@ -138,7 +184,7 @@ FilePickerParent::Done(int16_t aResult)
|
|||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<BlobImpl>> blobs;
|
||||
nsTArray<nsCOMPtr<nsIFile>> files;
|
||||
if (mMode == nsIFilePicker::modeOpenMultiple) {
|
||||
nsCOMPtr<nsISimpleEnumerator> iter;
|
||||
NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
|
||||
|
@ -149,22 +195,26 @@ FilePickerParent::Done(int16_t aResult)
|
|||
iter->GetNext(getter_AddRefs(supports));
|
||||
if (supports) {
|
||||
nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
|
||||
|
||||
RefPtr<BlobImpl> blobimpl = new BlobImplFile(file);
|
||||
blobs.AppendElement(blobimpl);
|
||||
MOZ_ASSERT(file);
|
||||
files.AppendElement(file);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
mFilePicker->GetFile(getter_AddRefs(file));
|
||||
if (file) {
|
||||
RefPtr<BlobImpl> blobimpl = new BlobImplFile(file);
|
||||
blobs.AppendElement(blobimpl);
|
||||
files.AppendElement(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (files.IsEmpty()) {
|
||||
Unused << Send__delete__(this, void_t(), mResult);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mRunnable);
|
||||
mRunnable = new FileSizeAndDateRunnable(this, blobs);
|
||||
mRunnable = new IORunnable(this, files, mMode == nsIFilePicker::modeGetFolder);
|
||||
|
||||
// Dispatch to background thread to do I/O:
|
||||
if (!mRunnable->Dispatch()) {
|
||||
Unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/PFilePickerParent.h"
|
||||
|
||||
class nsIFile;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -29,7 +31,19 @@ class FilePickerParent : public PFilePickerParent
|
|||
virtual ~FilePickerParent();
|
||||
|
||||
void Done(int16_t aResult);
|
||||
void SendFiles(const nsTArray<RefPtr<BlobImpl>>& aDomBlobs);
|
||||
|
||||
struct BlobImplOrString
|
||||
{
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
nsString mDirectoryPath;
|
||||
|
||||
enum {
|
||||
eBlobImpl,
|
||||
eDirectoryPath
|
||||
} mType;
|
||||
};
|
||||
|
||||
void SendFilesOrDirectories(const nsTArray<BlobImplOrString>& aData);
|
||||
|
||||
virtual bool RecvOpen(const int16_t& aSelectedType,
|
||||
const bool& aAddToRecentDocs,
|
||||
|
@ -61,21 +75,26 @@ class FilePickerParent : public PFilePickerParent
|
|||
private:
|
||||
bool CreateFilePicker();
|
||||
|
||||
class FileSizeAndDateRunnable : public nsRunnable
|
||||
// This runnable is used to do some I/O operation on a separate thread.
|
||||
class IORunnable : public nsRunnable
|
||||
{
|
||||
FilePickerParent* mFilePickerParent;
|
||||
nsTArray<RefPtr<BlobImpl>> mBlobs;
|
||||
nsTArray<nsCOMPtr<nsIFile>> mFiles;
|
||||
nsTArray<BlobImplOrString> mResults;
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
bool mIsDirectory;
|
||||
|
||||
public:
|
||||
FileSizeAndDateRunnable(FilePickerParent *aFPParent,
|
||||
nsTArray<RefPtr<BlobImpl>>& aBlobs);
|
||||
IORunnable(FilePickerParent *aFPParent,
|
||||
nsTArray<nsCOMPtr<nsIFile>>& aFiles,
|
||||
bool aIsDirectory);
|
||||
|
||||
bool Dispatch();
|
||||
NS_IMETHOD Run();
|
||||
void Destroy();
|
||||
};
|
||||
|
||||
RefPtr<FileSizeAndDateRunnable> mRunnable;
|
||||
RefPtr<IORunnable> mRunnable;
|
||||
RefPtr<FilePickerShownCallback> mCallback;
|
||||
nsCOMPtr<nsIFilePicker> mFilePicker;
|
||||
|
||||
|
|
|
@ -289,6 +289,7 @@ struct FileSystemGetDirectoryListingParams
|
|||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
// 'filters' could be an array rather than a semicolon separated string
|
||||
// (we'd then use InfallibleTArray<nsString> internally), but that is
|
||||
// wasteful. E10s requires us to pass the filters over as a string anyway,
|
||||
|
@ -305,6 +306,7 @@ struct FileSystemGetFileOrDirectoryParams
|
|||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
};
|
||||
|
||||
union FileSystemPathOrFileValue
|
||||
|
|
|
@ -12,14 +12,20 @@ using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct InputFiles
|
||||
struct InputBlobs
|
||||
{
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
union MaybeInputFiles
|
||||
struct InputDirectory
|
||||
{
|
||||
InputFiles;
|
||||
nsString directoryPath;
|
||||
};
|
||||
|
||||
union MaybeInputData
|
||||
{
|
||||
InputBlobs;
|
||||
InputDirectory;
|
||||
void_t;
|
||||
};
|
||||
|
||||
|
@ -33,7 +39,7 @@ parent:
|
|||
nsString displayDirectory);
|
||||
|
||||
child:
|
||||
async __delete__(MaybeInputFiles files, int16_t result);
|
||||
async __delete__(MaybeInputData data, int16_t result);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -20,6 +20,7 @@ interface Directory {
|
|||
/*
|
||||
* The leaf name of the directory.
|
||||
*/
|
||||
[Throws]
|
||||
readonly attribute DOMString name;
|
||||
|
||||
/*
|
||||
|
@ -105,11 +106,13 @@ partial interface Directory {
|
|||
* to obtain this Directory. Full filesystem paths are not exposed to
|
||||
* unprivilaged content.
|
||||
*/
|
||||
[Throws]
|
||||
readonly attribute DOMString path;
|
||||
|
||||
/*
|
||||
* Getter for the immediate children of this directory.
|
||||
*/
|
||||
[Throws]
|
||||
Promise<sequence<(File or Directory)>> getFilesAndDirectories();
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "nsCOMArray.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "WidgetUtils.h"
|
||||
|
@ -30,6 +31,36 @@ using namespace mozilla::dom;
|
|||
#define FILEPICKER_TITLES "chrome://global/locale/filepicker.properties"
|
||||
#define FILEPICKER_FILTERS "chrome://global/content/filepicker.properties"
|
||||
|
||||
namespace {
|
||||
|
||||
nsresult
|
||||
LocalFileToDirectoryOrBlob(nsPIDOMWindowInner* aWindow,
|
||||
bool aIsDirectory,
|
||||
nsIFile* aFile,
|
||||
nsISupports** aResult)
|
||||
{
|
||||
if (aIsDirectory) {
|
||||
#ifdef DEBUG
|
||||
bool isDir;
|
||||
aFile->IsDirectory(&isDir);
|
||||
MOZ_ASSERT(isDir);
|
||||
#endif
|
||||
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(aWindow, aFile, Directory::eDOMRootDirectory);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
directory.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = File::CreateFromFile(aWindow, aFile);
|
||||
blob.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/**
|
||||
* A runnable to dispatch from the main thread to the main thread to display
|
||||
* the file picker while letting the showAsync method return right away.
|
||||
|
@ -74,9 +105,9 @@ class nsBaseFilePickerEnumerator : public nsISimpleEnumerator
|
|||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit nsBaseFilePickerEnumerator(nsPIDOMWindowOuter* aParent,
|
||||
nsISimpleEnumerator* iterator,
|
||||
int16_t aMode)
|
||||
nsBaseFilePickerEnumerator(nsPIDOMWindowOuter* aParent,
|
||||
nsISimpleEnumerator* iterator,
|
||||
int16_t aMode)
|
||||
: mIterator(iterator)
|
||||
, mParent(aParent->GetCurrentInnerWindow())
|
||||
, mMode(aMode)
|
||||
|
@ -98,32 +129,10 @@ public:
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<File> domFile = File::CreateFromFile(mParent, localFile);
|
||||
|
||||
// Right now we're on the main thread of the chrome process. We need
|
||||
// to call SetIsDirectory on the BlobImpl, but it's preferable not to
|
||||
// call nsIFile::IsDirectory to determine what argument to pass since
|
||||
// IsDirectory does synchronous I/O. It's true that since we've just
|
||||
// been called synchronously directly after nsIFilePicker::Show blocked
|
||||
// the main thread while the picker was being shown and the OS did file
|
||||
// system access, doing more I/O to stat the selected files probably
|
||||
// wouldn't be the end of the world. However, we can simply check
|
||||
// mMode and avoid calling IsDirectory.
|
||||
//
|
||||
// In future we may take advantage of OS X's ability to allow both
|
||||
// files and directories to be picked at the same time, so we do assert
|
||||
// in debug builds that the mMode trick produces the correct results.
|
||||
// If we do add that support maybe it's better to use IsDirectory
|
||||
// directly, but in an nsRunnable punted off to a background thread.
|
||||
#ifdef DEBUG
|
||||
bool isDir;
|
||||
localFile->IsDirectory(&isDir);
|
||||
MOZ_ASSERT(isDir == (mMode == nsIFilePicker::modeGetFolder));
|
||||
#endif
|
||||
domFile->Impl()->SetIsDirectory(mMode == nsIFilePicker::modeGetFolder);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob>(domFile).forget(aResult);
|
||||
return NS_OK;
|
||||
return LocalFileToDirectoryOrBlob(mParent,
|
||||
mMode == nsIFilePicker::modeGetFolder,
|
||||
localFile,
|
||||
aResult);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
|
@ -349,10 +358,10 @@ nsBaseFilePicker::GetDomFileOrDirectory(nsISupports** aValue)
|
|||
|
||||
auto* innerParent = mParent ? mParent->GetCurrentInnerWindow() : nullptr;
|
||||
|
||||
RefPtr<File> domFile = File::CreateFromFile(innerParent, localFile);
|
||||
domFile->Impl()->SetIsDirectory(mMode == nsIFilePicker::modeGetFolder);
|
||||
nsCOMPtr<nsIDOMBlob>(domFile).forget(aValue);
|
||||
return NS_OK;
|
||||
return LocalFileToDirectoryOrBlob(innerParent,
|
||||
mMode == nsIFilePicker::modeGetFolder,
|
||||
localFile,
|
||||
aValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "nsFilePickerProxy.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIFile.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
|
@ -142,11 +143,11 @@ nsFilePickerProxy::Open(nsIFilePickerShownCallback* aCallback)
|
|||
}
|
||||
|
||||
bool
|
||||
nsFilePickerProxy::Recv__delete__(const MaybeInputFiles& aFiles,
|
||||
nsFilePickerProxy::Recv__delete__(const MaybeInputData& aData,
|
||||
const int16_t& aResult)
|
||||
{
|
||||
if (aFiles.type() == MaybeInputFiles::TInputFiles) {
|
||||
const InfallibleTArray<PBlobChild*>& blobs = aFiles.get_InputFiles().blobsChild();
|
||||
if (aData.type() == MaybeInputData::TInputBlobs) {
|
||||
const InfallibleTArray<PBlobChild*>& blobs = aData.get_InputBlobs().blobsChild();
|
||||
for (uint32_t i = 0; i < blobs.Length(); ++i) {
|
||||
BlobChild* actor = static_cast<BlobChild*>(blobs[i]);
|
||||
RefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
|
||||
|
@ -161,8 +162,24 @@ nsFilePickerProxy::Recv__delete__(const MaybeInputFiles& aFiles,
|
|||
RefPtr<File> file = File::Create(inner, blobImpl);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
mFilesOrDirectories.AppendElement(file);
|
||||
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
|
||||
element->SetAsFile() = file;
|
||||
}
|
||||
} else if (aData.type() == MaybeInputData::TInputDirectory) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
NS_ConvertUTF16toUTF8 path(aData.get_InputDirectory().directoryPath());
|
||||
nsresult rv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(mParent->GetCurrentInnerWindow(), file,
|
||||
Directory::eDOMRootDirectory);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
|
||||
element->SetAsDirectory() = directory;
|
||||
}
|
||||
|
||||
if (mCallback) {
|
||||
|
@ -182,8 +199,16 @@ nsFilePickerProxy::GetDomFileOrDirectory(nsISupports** aValue)
|
|||
}
|
||||
|
||||
MOZ_ASSERT(mFilesOrDirectories.Length() == 1);
|
||||
nsCOMPtr<nsIDOMBlob> blob = mFilesOrDirectories[0].get();
|
||||
blob.forget(aValue);
|
||||
|
||||
if (mFilesOrDirectories[0].IsFile()) {
|
||||
nsCOMPtr<nsIDOMBlob> blob = mFilesOrDirectories[0].GetAsFile().get();
|
||||
blob.forget(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mFilesOrDirectories[0].IsDirectory());
|
||||
RefPtr<Directory> directory = mFilesOrDirectories[0].GetAsDirectory();
|
||||
directory.forget(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -194,8 +219,9 @@ class SimpleEnumerator final : public nsISimpleEnumerator
|
|||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit SimpleEnumerator(const nsTArray<RefPtr<File>>& aFiles)
|
||||
: mFiles(aFiles)
|
||||
explicit
|
||||
SimpleEnumerator(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories)
|
||||
: mFilesOrDirectories(aFilesOrDirectories)
|
||||
, mIndex(0)
|
||||
{}
|
||||
|
||||
|
@ -203,17 +229,26 @@ public:
|
|||
HasMoreElements(bool* aRetvalue) override
|
||||
{
|
||||
MOZ_ASSERT(aRetvalue);
|
||||
*aRetvalue = mIndex < mFiles.Length();
|
||||
*aRetvalue = mIndex < mFilesOrDirectories.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetNext(nsISupports** aSupports) override
|
||||
GetNext(nsISupports** aValue) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mIndex < mFiles.Length(), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(mIndex < mFilesOrDirectories.Length(), NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = mFiles[mIndex++].get();
|
||||
blob.forget(aSupports);
|
||||
uint32_t index = mIndex++;
|
||||
|
||||
if (mFilesOrDirectories[index].IsFile()) {
|
||||
nsCOMPtr<nsIDOMBlob> blob = mFilesOrDirectories[index].GetAsFile().get();
|
||||
blob.forget(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mFilesOrDirectories[index].IsDirectory());
|
||||
RefPtr<Directory> directory = mFilesOrDirectories[index].GetAsDirectory();
|
||||
directory.forget(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -221,7 +256,7 @@ private:
|
|||
~SimpleEnumerator()
|
||||
{}
|
||||
|
||||
nsTArray<RefPtr<File>> mFiles;
|
||||
nsTArray<mozilla::dom::OwningFileOrDirectory> mFilesOrDirectories;
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
|
@ -232,7 +267,8 @@ NS_IMPL_ISUPPORTS(SimpleEnumerator, nsISimpleEnumerator)
|
|||
NS_IMETHODIMP
|
||||
nsFilePickerProxy::GetDomFileOrDirectoryEnumerator(nsISimpleEnumerator** aDomfiles)
|
||||
{
|
||||
RefPtr<SimpleEnumerator> enumerator = new SimpleEnumerator(mFilesOrDirectories);
|
||||
RefPtr<SimpleEnumerator> enumerator =
|
||||
new SimpleEnumerator(mFilesOrDirectories);
|
||||
enumerator.forget(aDomfiles);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -13,17 +13,12 @@
|
|||
#include "nsCOMArray.h"
|
||||
|
||||
#include "mozilla/dom/PFilePickerChild.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
|
||||
class nsIWidget;
|
||||
class nsIFile;
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class File;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
This class creates a proxy file picker to be used in content processes.
|
||||
The file picker just collects the initialization data and when Show() is
|
||||
|
@ -59,13 +54,13 @@ public:
|
|||
|
||||
// PFilePickerChild
|
||||
virtual bool
|
||||
Recv__delete__(const MaybeInputFiles& aFiles, const int16_t& aResult) override;
|
||||
Recv__delete__(const MaybeInputData& aData, const int16_t& aResult) override;
|
||||
|
||||
private:
|
||||
~nsFilePickerProxy();
|
||||
void InitNative(nsIWidget*, const nsAString&) override;
|
||||
|
||||
nsTArray<RefPtr<mozilla::dom::File>> mFilesOrDirectories;
|
||||
nsTArray<mozilla::dom::OwningFileOrDirectory> mFilesOrDirectories;
|
||||
nsCOMPtr<nsIFilePickerShownCallback> mCallback;
|
||||
|
||||
int16_t mSelectedType;
|
||||
|
|
Загрузка…
Ссылка в новой задаче