Wed, 31 Dec 2014 06:55:50 +0100
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