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"
15 #include "nsIRunnable.h"
16 #include "nsISeekableStream.h"
17 #include "nsThreadUtils.h"
24 class ProgressRunnable MOZ_FINAL
: public nsIRunnable
27 NS_DECL_THREADSAFE_ISUPPORTS
30 ProgressRunnable(FileHelper
* aFileHelper
,
32 uint64_t aProgressMax
)
33 : mFileHelper(aFileHelper
),
35 mProgressMax(aProgressMax
)
40 ~ProgressRunnable() {}
42 nsRefPtr
<FileHelper
> mFileHelper
;
44 uint64_t mProgressMax
;
47 class CloseRunnable MOZ_FINAL
: public nsIRunnable
50 NS_DECL_THREADSAFE_ISUPPORTS
53 CloseRunnable(FileHelper
* aFileHelper
)
54 : mFileHelper(aFileHelper
)
60 nsRefPtr
<FileHelper
> mFileHelper
;
63 class DestroyRunnable MOZ_FINAL
: public nsIRunnable
66 NS_DECL_THREADSAFE_ISUPPORTS
69 DestroyRunnable(FileHelper
* aFileHelper
)
70 : mFileHelper(aFileHelper
)
76 nsRefPtr
<FileHelper
> mFileHelper
;
79 } // anonymous namespace
81 FileStreamWrapper::FileStreamWrapper(nsISupports
* aFileStream
,
82 FileHelper
* aFileHelper
,
86 : mFileStream(aFileStream
),
87 mFileHelper(aFileHelper
),
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();
104 nsCOMPtr
<nsIRunnable
> runnable
=
105 new DestroyRunnable(mFileHelper
);
107 nsresult rv
= NS_DispatchToMainThread(runnable
);
109 NS_WARNING("Failed to dispatch to the main thread!");
115 NS_IMPL_ISUPPORTS0(FileStreamWrapper
)
117 FileInputStreamWrapper::FileInputStreamWrapper(nsISupports
* aFileStream
,
118 FileHelper
* aFileHelper
,
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
,
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!");
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
163 if (NS_IsMainThread()) {
164 return NS_BASE_STREAM_CLOSED
;
167 return mInputStream
->Available(_retval
);
171 FileInputStreamWrapper::Read(char* aBuf
, uint32_t aCount
, uint32_t* _retval
)
173 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
180 if (mOffset
!= UINT64_MAX
) {
181 nsCOMPtr
<nsISeekableStream
> seekable
= do_QueryInterface(mInputStream
);
183 rv
= seekable
->Seek(nsISeekableStream::NS_SEEK_SET
, mOffset
);
184 NS_ENSURE_SUCCESS(rv
, rv
);
191 uint64_t max
= mLimit
- mOffset
;
201 rv
= mInputStream
->Read(aBuf
, aCount
, _retval
);
202 NS_ENSURE_SUCCESS(rv
, rv
);
206 if (mFlags
& NOTIFY_PROGRESS
) {
207 nsCOMPtr
<nsIRunnable
> runnable
=
208 new ProgressRunnable(mFileHelper
, mOffset
, mLimit
);
210 rv
= NS_DispatchToMainThread(runnable
);
212 NS_WARNING("Failed to dispatch to the main thread!");
220 FileInputStreamWrapper::ReadSegments(nsWriteSegmentFun aWriter
, void* aClosure
,
221 uint32_t aCount
, uint32_t* _retval
)
223 return NS_ERROR_NOT_IMPLEMENTED
;
227 FileInputStreamWrapper::IsNonBlocking(bool* _retval
)
233 FileOutputStreamWrapper::FileOutputStreamWrapper(nsISupports
* aFileStream
,
234 FileHelper
* aFileHelper
,
238 : FileStreamWrapper(aFileStream
, aFileHelper
, aOffset
, aLimit
, aFlags
)
240 , mWriteThread(nullptr)
243 mOutputStream
= do_QueryInterface(mFileStream
);
244 NS_ASSERTION(mOutputStream
, "This should always succeed!");
247 NS_IMPL_ISUPPORTS_INHERITED(FileOutputStreamWrapper
,
252 FileOutputStreamWrapper::Close()
254 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
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!");
279 FileOutputStreamWrapper::Write(const char* aBuf
, uint32_t aCount
,
282 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
290 mWriteThread
= PR_GetCurrentThread();
292 mFileHelper
->mMutableFile
->SetThreadLocals();
294 nsCOMPtr
<nsISeekableStream
> seekable
= do_QueryInterface(mOutputStream
);
296 if (mOffset
== UINT64_MAX
) {
297 rv
= seekable
->Seek(nsISeekableStream::NS_SEEK_END
, 0);
300 rv
= seekable
->Seek(nsISeekableStream::NS_SEEK_SET
, mOffset
);
302 NS_ENSURE_SUCCESS(rv
, rv
);
308 uint64_t max
= mLimit
- mOffset
;
318 rv
= mOutputStream
->Write(aBuf
, aCount
, _retval
);
319 NS_ENSURE_SUCCESS(rv
, rv
);
323 if (mFlags
& NOTIFY_PROGRESS
) {
324 nsCOMPtr
<nsIRunnable
> runnable
=
325 new ProgressRunnable(mFileHelper
, mOffset
, mLimit
);
327 NS_DispatchToMainThread(runnable
);
334 FileOutputStreamWrapper::Flush()
340 FileOutputStreamWrapper::WriteFrom(nsIInputStream
* aFromStream
,
341 uint32_t aCount
, uint32_t* _retval
)
343 return NS_ERROR_NOT_IMPLEMENTED
;
347 FileOutputStreamWrapper::WriteSegments(nsReadSegmentFun aReader
,
348 void* aClosure
, uint32_t aCount
,
351 return NS_ERROR_NOT_IMPLEMENTED
;
355 FileOutputStreamWrapper::IsNonBlocking(bool* _retval
)
361 NS_IMPL_ISUPPORTS(ProgressRunnable
, nsIRunnable
)
364 ProgressRunnable::Run()
366 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
368 mFileHelper
->OnStreamProgress(mProgress
, mProgressMax
);
369 mFileHelper
= nullptr;
374 NS_IMPL_ISUPPORTS(CloseRunnable
, nsIRunnable
)
379 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
381 mFileHelper
->OnStreamClose();
382 mFileHelper
= nullptr;
387 NS_IMPL_ISUPPORTS(DestroyRunnable
, nsIRunnable
)
390 DestroyRunnable::Run()
392 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
394 mFileHelper
->OnStreamDestroy();
395 mFileHelper
= nullptr;
401 } // namespace mozilla