dom/filesystem/CreateFileTask.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "CreateFileTask.h"
     9 #include <algorithm>
    11 #include "DOMError.h"
    12 #include "mozilla/Preferences.h"
    13 #include "mozilla/dom/FileSystemBase.h"
    14 #include "mozilla/dom/FileSystemUtils.h"
    15 #include "mozilla/dom/Promise.h"
    16 #include "nsDOMFile.h"
    17 #include "nsIFile.h"
    18 #include "nsNetUtil.h"
    19 #include "nsStringGlue.h"
    21 namespace mozilla {
    22 namespace dom {
    24 uint32_t CreateFileTask::sOutputBufferSize = 0;
    26 CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
    27                                const nsAString& aPath,
    28                                nsIDOMBlob* aBlobData,
    29                                InfallibleTArray<uint8_t>& aArrayData,
    30                                bool replace)
    31   : FileSystemTaskBase(aFileSystem)
    32   , mTargetRealPath(aPath)
    33   , mBlobData(aBlobData)
    34   , mReplace(replace)
    35 {
    36   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
    37   MOZ_ASSERT(aFileSystem);
    38   GetOutputBufferSize();
    39   if (mBlobData) {
    40     nsresult rv = mBlobData->GetInternalStream(getter_AddRefs(mBlobStream));
    41     NS_WARN_IF(NS_FAILED(rv));
    42   }
    43   mArrayData.SwapElements(aArrayData);
    44   nsCOMPtr<nsIGlobalObject> globalObject =
    45     do_QueryInterface(aFileSystem->GetWindow());
    46   if (!globalObject) {
    47     return;
    48   }
    49   mPromise = new Promise(globalObject);
    50 }
    52 CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
    53                        const FileSystemCreateFileParams& aParam,
    54                        FileSystemRequestParent* aParent)
    55   : FileSystemTaskBase(aFileSystem, aParam, aParent)
    56   , mReplace(false)
    57 {
    58   MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
    59              "Only call from parent process!");
    60   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
    61   MOZ_ASSERT(aFileSystem);
    62   GetOutputBufferSize();
    64   mTargetRealPath = aParam.realPath();
    66   mReplace = aParam.replace();
    68   auto& data = aParam.data();
    70   if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
    71     mArrayData = data;
    72     return;
    73   }
    75   BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
    76   mBlobData = bp->GetBlob();
    77   MOZ_ASSERT(mBlobData, "mBlobData should not be null.");
    78   nsresult rv = mBlobData->GetInternalStream(getter_AddRefs(mBlobStream));
    79   NS_WARN_IF(NS_FAILED(rv));
    80 }
    82 CreateFileTask::~CreateFileTask()
    83 {
    84   MOZ_ASSERT(!mPromise || NS_IsMainThread(),
    85              "mPromise should be released on main thread!");
    86   if (mBlobStream) {
    87     mBlobStream->Close();
    88   }
    89 }
    91 already_AddRefed<Promise>
    92 CreateFileTask::GetPromise()
    93 {
    94   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
    95   return nsRefPtr<Promise>(mPromise).forget();
    96 }
    98 FileSystemParams
    99 CreateFileTask::GetRequestParams(const nsString& aFileSystem) const
   100 {
   101   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   102   FileSystemCreateFileParams param;
   103   param.filesystem() = aFileSystem;
   104   param.realPath() = mTargetRealPath;
   105   param.replace() = mReplace;
   106   if (mBlobData) {
   107     BlobChild* actor
   108       = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlobData);
   109     if (actor) {
   110       param.data() = actor;
   111     }
   112   } else {
   113     param.data() = mArrayData;
   114   }
   115   return param;
   116 }
   118 FileSystemResponseValue
   119 CreateFileTask::GetSuccessRequestResult() const
   120 {
   121   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   122   BlobParent* actor = GetBlobParent(mTargetFile);
   123   if (!actor) {
   124     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   125   }
   126   FileSystemFileResponse response;
   127   response.blobParent() = actor;
   128   return response;
   129 }
   131 void
   132 CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
   133 {
   134   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   135   FileSystemFileResponse r = aValue;
   136   BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
   137   nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
   138   mTargetFile = do_QueryInterface(blob);
   139 }
   141 nsresult
   142 CreateFileTask::Work()
   143 {
   144   class AutoClose
   145   {
   146   public:
   147     AutoClose(nsIOutputStream* aStream)
   148       : mStream(aStream)
   149     {
   150       MOZ_ASSERT(aStream);
   151     }
   153     ~AutoClose()
   154     {
   155       mStream->Close();
   156     }
   157   private:
   158     nsCOMPtr<nsIOutputStream> mStream;
   159   };
   161   MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
   162              "Only call from parent process!");
   163   MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
   165   if (mFileSystem->IsShutdown()) {
   166     return NS_ERROR_FAILURE;
   167   }
   169   nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
   170   if (!file) {
   171     return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
   172   }
   174   if (!mFileSystem->IsSafeFile(file)) {
   175     return NS_ERROR_DOM_SECURITY_ERR;
   176   }
   178   bool exists = false;
   179   nsresult rv = file->Exists(&exists);
   180   if (NS_WARN_IF(NS_FAILED(rv))) {
   181     return rv;
   182   }
   184   if (exists) {
   185     bool isFile = false;
   186     rv = file->IsFile(&isFile);
   187     if (NS_WARN_IF(NS_FAILED(rv))) {
   188       return rv;
   189     }
   191     if (!isFile) {
   192       return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
   193     }
   195     if (!mReplace) {
   196       return NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
   197     }
   199     // Remove the old file before creating.
   200     rv = file->Remove(false);
   201     if (NS_WARN_IF(NS_FAILED(rv))) {
   202       return rv;
   203     }
   204   }
   206   rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
   207   if (NS_WARN_IF(NS_FAILED(rv))) {
   208     return rv;
   209   }
   211   nsCOMPtr<nsIOutputStream> outputStream;
   212   rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
   213   if (NS_WARN_IF(NS_FAILED(rv))) {
   214     return rv;
   215   }
   217   AutoClose acOutputStream(outputStream);
   219   nsCOMPtr<nsIOutputStream> bufferedOutputStream;
   220   rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
   221                                   outputStream,
   222                                   sOutputBufferSize);
   223   if (NS_WARN_IF(NS_FAILED(rv))) {
   224     return rv;
   225   }
   227   AutoClose acBufferedOutputStream(bufferedOutputStream);
   229   if (mBlobStream) {
   230     // Write the file content from blob data.
   232     uint64_t bufSize = 0;
   233     rv = mBlobStream->Available(&bufSize);
   234     if (NS_WARN_IF(NS_FAILED(rv))) {
   235       return rv;
   236     }
   238     while (bufSize && !mFileSystem->IsShutdown()) {
   239       uint32_t written = 0;
   240       uint32_t writeSize = bufSize < UINT32_MAX ? bufSize : UINT32_MAX;
   241       rv = bufferedOutputStream->WriteFrom(mBlobStream, writeSize, &written);
   242       if (NS_WARN_IF(NS_FAILED(rv))) {
   243         return rv;
   244       }
   245       bufSize -= written;
   246     }
   248     mBlobStream->Close();
   249     mBlobStream = nullptr;
   251     if (mFileSystem->IsShutdown()) {
   252       return NS_ERROR_FAILURE;
   253     }
   255     mTargetFile = new nsDOMFileFile(file);
   256     return NS_OK;
   257   }
   259   // Write file content from array data.
   261   uint32_t written;
   262   rv = bufferedOutputStream->Write(
   263     reinterpret_cast<char*>(mArrayData.Elements()),
   264     mArrayData.Length(),
   265     &written);
   266   if (NS_WARN_IF(NS_FAILED(rv))) {
   267     return rv;
   268   }
   270   if (mArrayData.Length() != written) {
   271     return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
   272   }
   274   mTargetFile = new nsDOMFileFile(file);
   275   return NS_OK;
   276 }
   278 void
   279 CreateFileTask::HandlerCallback()
   280 {
   281   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   282   if (mFileSystem->IsShutdown()) {
   283     mPromise = nullptr;
   284     return;
   285   }
   287   if (HasError()) {
   288     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
   289       mErrorValue);
   290     mPromise->MaybeReject(domError);
   291     mPromise = nullptr;
   292     return;
   293   }
   295   mPromise->MaybeResolve(mTargetFile);
   296   mPromise = nullptr;
   297 }
   299 void
   300 CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
   301 {
   302   if (mReplace) {
   303     aAccess.AssignLiteral("write");
   304     return;
   305   }
   307   aAccess.AssignLiteral("create");
   308 }
   310 void
   311 CreateFileTask::GetOutputBufferSize() const
   312 {
   313   if (sOutputBufferSize || !FileSystemUtils::IsParentProcess()) {
   314     return;
   315   }
   316   sOutputBufferSize =
   317     mozilla::Preferences::GetUint("dom.filesystem.outputBufferSize", 4096 * 4);
   318 }
   320 } // namespace dom
   321 } // namespace mozilla

mercurial