dom/filesystem/CreateFileTask.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial