Bumping manifests a=b2g-bump
[gecko.git] / dom / filehandle / FileStreamWrappers.cpp
blob130f6e00f115d1049d51c042035629b7c874352d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 "FileStreamWrappers.h"
9 #include "FileHelper.h"
10 #include "MainThreadUtils.h"
11 #include "mozilla/Attributes.h"
12 #include "MutableFile.h"
13 #include "nsDebug.h"
14 #include "nsError.h"
15 #include "nsIRunnable.h"
16 #include "nsISeekableStream.h"
17 #include "nsThreadUtils.h"
19 namespace mozilla {
20 namespace dom {
22 namespace {
24 class ProgressRunnable MOZ_FINAL : public nsIRunnable
26 public:
27 NS_DECL_THREADSAFE_ISUPPORTS
28 NS_DECL_NSIRUNNABLE
30 ProgressRunnable(FileHelper* aFileHelper,
31 uint64_t aProgress,
32 uint64_t aProgressMax)
33 : mFileHelper(aFileHelper),
34 mProgress(aProgress),
35 mProgressMax(aProgressMax)
39 private:
40 ~ProgressRunnable() {}
42 nsRefPtr<FileHelper> mFileHelper;
43 uint64_t mProgress;
44 uint64_t mProgressMax;
47 class CloseRunnable MOZ_FINAL : public nsIRunnable
49 public:
50 NS_DECL_THREADSAFE_ISUPPORTS
51 NS_DECL_NSIRUNNABLE
53 CloseRunnable(FileHelper* aFileHelper)
54 : mFileHelper(aFileHelper)
55 { }
57 private:
58 ~CloseRunnable() {}
60 nsRefPtr<FileHelper> mFileHelper;
63 class DestroyRunnable MOZ_FINAL : public nsIRunnable
65 public:
66 NS_DECL_THREADSAFE_ISUPPORTS
67 NS_DECL_NSIRUNNABLE
69 DestroyRunnable(FileHelper* aFileHelper)
70 : mFileHelper(aFileHelper)
71 { }
73 private:
74 ~DestroyRunnable() {}
76 nsRefPtr<FileHelper> mFileHelper;
79 } // anonymous namespace
81 FileStreamWrapper::FileStreamWrapper(nsISupports* aFileStream,
82 FileHelper* aFileHelper,
83 uint64_t aOffset,
84 uint64_t aLimit,
85 uint32_t aFlags)
86 : mFileStream(aFileStream),
87 mFileHelper(aFileHelper),
88 mOffset(aOffset),
89 mLimit(aLimit),
90 mFlags(aFlags),
91 mFirstTime(true)
93 NS_ASSERTION(mFileStream, "Must have a file stream!");
94 NS_ASSERTION(mFileHelper, "Must have a file helper!");
97 FileStreamWrapper::~FileStreamWrapper()
99 if (mFlags & NOTIFY_DESTROY) {
100 if (NS_IsMainThread()) {
101 mFileHelper->OnStreamDestroy();
103 else {
104 nsCOMPtr<nsIRunnable> runnable =
105 new DestroyRunnable(mFileHelper);
107 nsresult rv = NS_DispatchToMainThread(runnable);
108 if (NS_FAILED(rv)) {
109 NS_WARNING("Failed to dispatch to the main thread!");
115 NS_IMPL_ISUPPORTS0(FileStreamWrapper)
117 FileInputStreamWrapper::FileInputStreamWrapper(nsISupports* aFileStream,
118 FileHelper* aFileHelper,
119 uint64_t aOffset,
120 uint64_t aLimit,
121 uint32_t aFlags)
122 : FileStreamWrapper(aFileStream, aFileHelper, aOffset, aLimit, aFlags)
124 mInputStream = do_QueryInterface(mFileStream);
125 NS_ASSERTION(mInputStream, "This should always succeed!");
128 NS_IMPL_ISUPPORTS_INHERITED(FileInputStreamWrapper,
129 FileStreamWrapper,
130 nsIInputStream)
132 NS_IMETHODIMP
133 FileInputStreamWrapper::Close()
135 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
137 if (mFlags & NOTIFY_CLOSE) {
138 nsCOMPtr<nsIRunnable> runnable = new CloseRunnable(mFileHelper);
140 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
141 NS_WARNING("Failed to dispatch to the main thread!");
145 mOffset = 0;
146 mLimit = 0;
148 return NS_OK;
151 NS_IMETHODIMP
152 FileInputStreamWrapper::Available(uint64_t* _retval)
154 // Performing sync IO on the main thread is generally not allowed.
155 // However, the input stream wrapper is also used to track reads performed by
156 // other APIs like FileReader, XHR, etc.
157 // In that case nsInputStreamChannel::OpenContentStream() calls Available()
158 // before setting the content length property. This property is not important
159 // to perform reads properly, so we can just return NS_BASE_STREAM_CLOSED
160 // here. It causes OpenContentStream() to set the content length property to
161 // zero.
163 if (NS_IsMainThread()) {
164 return NS_BASE_STREAM_CLOSED;
167 return mInputStream->Available(_retval);
170 NS_IMETHODIMP
171 FileInputStreamWrapper::Read(char* aBuf, uint32_t aCount, uint32_t* _retval)
173 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
175 nsresult rv;
177 if (mFirstTime) {
178 mFirstTime = false;
180 if (mOffset != UINT64_MAX) {
181 nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mInputStream);
182 if (seekable) {
183 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
184 NS_ENSURE_SUCCESS(rv, rv);
188 mOffset = 0;
191 uint64_t max = mLimit - mOffset;
192 if (max == 0) {
193 *_retval = 0;
194 return NS_OK;
197 if (aCount > max) {
198 aCount = max;
201 rv = mInputStream->Read(aBuf, aCount, _retval);
202 NS_ENSURE_SUCCESS(rv, rv);
204 mOffset += *_retval;
206 if (mFlags & NOTIFY_PROGRESS) {
207 nsCOMPtr<nsIRunnable> runnable =
208 new ProgressRunnable(mFileHelper, mOffset, mLimit);
210 rv = NS_DispatchToMainThread(runnable);
211 if (NS_FAILED(rv)) {
212 NS_WARNING("Failed to dispatch to the main thread!");
216 return NS_OK;
219 NS_IMETHODIMP
220 FileInputStreamWrapper::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
221 uint32_t aCount, uint32_t* _retval)
223 return NS_ERROR_NOT_IMPLEMENTED;
226 NS_IMETHODIMP
227 FileInputStreamWrapper::IsNonBlocking(bool* _retval)
229 *_retval = false;
230 return NS_OK;
233 FileOutputStreamWrapper::FileOutputStreamWrapper(nsISupports* aFileStream,
234 FileHelper* aFileHelper,
235 uint64_t aOffset,
236 uint64_t aLimit,
237 uint32_t aFlags)
238 : FileStreamWrapper(aFileStream, aFileHelper, aOffset, aLimit, aFlags)
239 #ifdef DEBUG
240 , mWriteThread(nullptr)
241 #endif
243 mOutputStream = do_QueryInterface(mFileStream);
244 NS_ASSERTION(mOutputStream, "This should always succeed!");
247 NS_IMPL_ISUPPORTS_INHERITED(FileOutputStreamWrapper,
248 FileStreamWrapper,
249 nsIOutputStream)
251 NS_IMETHODIMP
252 FileOutputStreamWrapper::Close()
254 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
256 nsresult rv = NS_OK;
258 if (!mFirstTime) {
259 NS_ASSERTION(PR_GetCurrentThread() == mWriteThread,
260 "Unsetting thread locals on wrong thread!");
261 mFileHelper->mMutableFile->UnsetThreadLocals();
264 if (mFlags & NOTIFY_CLOSE) {
265 nsCOMPtr<nsIRunnable> runnable = new CloseRunnable(mFileHelper);
267 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
268 NS_WARNING("Failed to dispatch to the main thread!");
272 mOffset = 0;
273 mLimit = 0;
275 return rv;
278 NS_IMETHODIMP
279 FileOutputStreamWrapper::Write(const char* aBuf, uint32_t aCount,
280 uint32_t* _retval)
282 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
284 nsresult rv;
286 if (mFirstTime) {
287 mFirstTime = false;
289 #ifdef DEBUG
290 mWriteThread = PR_GetCurrentThread();
291 #endif
292 mFileHelper->mMutableFile->SetThreadLocals();
294 nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mOutputStream);
295 if (seekable) {
296 if (mOffset == UINT64_MAX) {
297 rv = seekable->Seek(nsISeekableStream::NS_SEEK_END, 0);
299 else {
300 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
302 NS_ENSURE_SUCCESS(rv, rv);
305 mOffset = 0;
308 uint64_t max = mLimit - mOffset;
309 if (max == 0) {
310 *_retval = 0;
311 return NS_OK;
314 if (aCount > max) {
315 aCount = max;
318 rv = mOutputStream->Write(aBuf, aCount, _retval);
319 NS_ENSURE_SUCCESS(rv, rv);
321 mOffset += *_retval;
323 if (mFlags & NOTIFY_PROGRESS) {
324 nsCOMPtr<nsIRunnable> runnable =
325 new ProgressRunnable(mFileHelper, mOffset, mLimit);
327 NS_DispatchToMainThread(runnable);
330 return NS_OK;
333 NS_IMETHODIMP
334 FileOutputStreamWrapper::Flush()
336 return NS_OK;
339 NS_IMETHODIMP
340 FileOutputStreamWrapper::WriteFrom(nsIInputStream* aFromStream,
341 uint32_t aCount, uint32_t* _retval)
343 return NS_ERROR_NOT_IMPLEMENTED;
346 NS_IMETHODIMP
347 FileOutputStreamWrapper::WriteSegments(nsReadSegmentFun aReader,
348 void* aClosure, uint32_t aCount,
349 uint32_t* _retval)
351 return NS_ERROR_NOT_IMPLEMENTED;
354 NS_IMETHODIMP
355 FileOutputStreamWrapper::IsNonBlocking(bool* _retval)
357 *_retval = false;
358 return NS_OK;
361 NS_IMPL_ISUPPORTS(ProgressRunnable, nsIRunnable)
363 NS_IMETHODIMP
364 ProgressRunnable::Run()
366 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
368 mFileHelper->OnStreamProgress(mProgress, mProgressMax);
369 mFileHelper = nullptr;
371 return NS_OK;
374 NS_IMPL_ISUPPORTS(CloseRunnable, nsIRunnable)
376 NS_IMETHODIMP
377 CloseRunnable::Run()
379 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
381 mFileHelper->OnStreamClose();
382 mFileHelper = nullptr;
384 return NS_OK;
387 NS_IMPL_ISUPPORTS(DestroyRunnable, nsIRunnable)
389 NS_IMETHODIMP
390 DestroyRunnable::Run()
392 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
394 mFileHelper->OnStreamDestroy();
395 mFileHelper = nullptr;
397 return NS_OK;
400 } // namespace dom
401 } // namespace mozilla