123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsTemporaryFileInputStream.h"
- #include "mozilla/ipc/InputStreamUtils.h"
- #include "mozilla/Mutex.h"
- #include "nsStreamUtils.h"
- #include "private/pprio.h"
- #include <algorithm>
- using namespace mozilla;
- using namespace mozilla::ipc;
- typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType;
- NS_IMPL_ISUPPORTS(nsTemporaryFileInputStream,
- nsIInputStream,
- nsISeekableStream,
- nsIIPCSerializableInputStream)
- nsTemporaryFileInputStream::nsTemporaryFileInputStream(FileDescOwner* aFileDescOwner, uint64_t aStartPos, uint64_t aEndPos)
- : mFileDescOwner(aFileDescOwner),
- mStartPos(aStartPos),
- mCurPos(aStartPos),
- mEndPos(aEndPos),
- mClosed(false)
- {
- NS_ASSERTION(aStartPos <= aEndPos, "StartPos should less equal than EndPos!");
- }
- nsTemporaryFileInputStream::nsTemporaryFileInputStream()
- : mStartPos(0),
- mCurPos(0),
- mEndPos(0),
- mClosed(false)
- {
- }
- NS_IMETHODIMP
- nsTemporaryFileInputStream::Close()
- {
- mClosed = true;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsTemporaryFileInputStream::Available(uint64_t * bytesAvailable)
- {
- if (mClosed)
- return NS_BASE_STREAM_CLOSED;
- NS_ASSERTION(mCurPos <= mEndPos, "CurPos should less equal than EndPos!");
- *bytesAvailable = mEndPos - mCurPos;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsTemporaryFileInputStream::Read(char* buffer, uint32_t count, uint32_t* bytesRead)
- {
- return ReadSegments(NS_CopySegmentToBuffer, buffer, count, bytesRead);
- }
- NS_IMETHODIMP
- nsTemporaryFileInputStream::ReadSegments(nsWriteSegmentFun writer,
- void * closure,
- uint32_t count,
- uint32_t * result)
- {
- NS_ASSERTION(result, "null ptr");
- NS_ASSERTION(mCurPos <= mEndPos, "bad stream state");
- *result = 0;
- if (mClosed) {
- return NS_BASE_STREAM_CLOSED;
- }
- mozilla::MutexAutoLock lock(mFileDescOwner->FileMutex());
- int64_t offset = PR_Seek64(mFileDescOwner->mFD, mCurPos, PR_SEEK_SET);
- if (offset == -1) {
- return NS_ErrorAccordingToNSPR();
- }
- // Limit requested count to the amount remaining in our section of the file.
- count = std::min(count, uint32_t(mEndPos - mCurPos));
- char buf[4096];
- while (*result < count) {
- uint32_t bufCount = std::min(count - *result, (uint32_t) sizeof(buf));
- int32_t bytesRead = PR_Read(mFileDescOwner->mFD, buf, bufCount);
- if (bytesRead == 0) {
- mClosed = true;
- return NS_OK;
- }
- if (bytesRead < 0) {
- return NS_ErrorAccordingToNSPR();
- }
- int32_t bytesWritten = 0;
- while (bytesWritten < bytesRead) {
- uint32_t writerCount = 0;
- nsresult rv = writer(this, closure, buf + bytesWritten, *result,
- bytesRead - bytesWritten, &writerCount);
- if (NS_FAILED(rv) || writerCount == 0) {
- // nsIInputStream::ReadSegments' contract specifies that errors
- // from writer are not propagated to ReadSegments' caller.
- //
- // If writer fails, leaving bytes still in buf, that's okay: we
- // only update mCurPos to reflect successful writes, so the call
- // to PR_Seek64 at the top will restart us at the right spot.
- return NS_OK;
- }
- NS_ASSERTION(writerCount <= (uint32_t) (bytesRead - bytesWritten),
- "writer should not write more than we asked it to write");
- bytesWritten += writerCount;
- *result += writerCount;
- mCurPos += writerCount;
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsTemporaryFileInputStream::IsNonBlocking(bool * nonBlocking)
- {
- *nonBlocking = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsTemporaryFileInputStream::Seek(int32_t aWhence, int64_t aOffset)
- {
- if (mClosed) {
- return NS_BASE_STREAM_CLOSED;
- }
- switch (aWhence) {
- case nsISeekableStream::NS_SEEK_SET:
- aOffset += mStartPos;
- break;
- case nsISeekableStream::NS_SEEK_CUR:
- aOffset += mCurPos;
- break;
- case nsISeekableStream::NS_SEEK_END:
- aOffset += mEndPos;
- break;
- default:
- return NS_ERROR_FAILURE;
- }
- if (aOffset < (int64_t)mStartPos || aOffset > (int64_t)mEndPos) {
- return NS_ERROR_INVALID_ARG;
- }
- mCurPos = aOffset;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsTemporaryFileInputStream::Tell(int64_t* aPos)
- {
- if (!aPos) {
- return NS_ERROR_FAILURE;
- }
- if (mClosed) {
- return NS_BASE_STREAM_CLOSED;
- }
- MOZ_ASSERT(mStartPos <= mCurPos, "StartPos should less equal than CurPos!");
- *aPos = mCurPos - mStartPos;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsTemporaryFileInputStream::SetEOF()
- {
- if (mClosed) {
- return NS_BASE_STREAM_CLOSED;
- }
- return Close();
- }
- void
- nsTemporaryFileInputStream::Serialize(InputStreamParams& aParams,
- FileDescriptorArray& aFileDescriptors)
- {
- TemporaryFileInputStreamParams params;
- MutexAutoLock lock(mFileDescOwner->FileMutex());
- MOZ_ASSERT(mFileDescOwner->mFD);
- if (!mClosed) {
- FileHandleType fd = FileHandleType(PR_FileDesc2NativeHandle(mFileDescOwner->mFD));
- NS_ASSERTION(fd, "This should never be null!");
- DebugOnly<FileDescriptor*> dbgFD = aFileDescriptors.AppendElement(fd);
- NS_ASSERTION(dbgFD->IsValid(), "Sending an invalid file descriptor!");
- params.fileDescriptorIndex() = aFileDescriptors.Length() - 1;
- Close();
- } else {
- NS_WARNING("The stream is already closed. "
- "Sending an invalid file descriptor to the other process!");
- params.fileDescriptorIndex() = UINT32_MAX;
- }
- params.startPos() = mCurPos;
- params.endPos() = mEndPos;
- aParams = params;
- }
- bool
- nsTemporaryFileInputStream::Deserialize(const InputStreamParams& aParams,
- const FileDescriptorArray& aFileDescriptors)
- {
- const TemporaryFileInputStreamParams& params = aParams.get_TemporaryFileInputStreamParams();
- uint32_t fileDescriptorIndex = params.fileDescriptorIndex();
- FileDescriptor fd;
- if (fileDescriptorIndex < aFileDescriptors.Length()) {
- fd = aFileDescriptors[fileDescriptorIndex];
- NS_WARNING_ASSERTION(fd.IsValid(),
- "Received an invalid file descriptor!");
- } else {
- NS_WARNING("Received a bad file descriptor index!");
- }
- if (fd.IsValid()) {
- auto rawFD = fd.ClonePlatformHandle();
- PRFileDesc* fileDesc = PR_ImportFile(PROsfd(rawFD.release()));
- if (!fileDesc) {
- NS_WARNING("Failed to import file handle!");
- return false;
- }
- mFileDescOwner = new FileDescOwner(fileDesc);
- } else {
- mClosed = true;
- }
- mStartPos = mCurPos = params.startPos();
- mEndPos = params.endPos();
- return true;
- }
- Maybe<uint64_t>
- nsTemporaryFileInputStream::ExpectedSerializedLength()
- {
- return Nothing();
- }
|