LCOV - code coverage report
Current view: top level - netwerk/base - nsFileStreams.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 226 415 54.5 %
Date: 2017-07-14 16:53:18 Functions: 43 64 67.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "ipc/IPCMessageUtils.h"
       7             : 
       8             : #if defined(XP_UNIX) || defined(XP_BEOS)
       9             : #include <unistd.h>
      10             : #elif defined(XP_WIN)
      11             : #include <windows.h>
      12             : #include "nsILocalFileWin.h"
      13             : #else
      14             : // XXX add necessary include file for ftruncate (or equivalent)
      15             : #endif
      16             : 
      17             : #include "private/pprio.h"
      18             : 
      19             : #include "nsFileStreams.h"
      20             : #include "nsIFile.h"
      21             : #include "nsReadLine.h"
      22             : #include "nsIClassInfoImpl.h"
      23             : #include "mozilla/ipc/InputStreamUtils.h"
      24             : #include "mozilla/Unused.h"
      25             : #include "mozilla/FileUtils.h"
      26             : #include "nsNetCID.h"
      27             : #include "nsXULAppAPI.h"
      28             : 
      29             : typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType;
      30             : 
      31             : using namespace mozilla::ipc;
      32             : using mozilla::DebugOnly;
      33             : using mozilla::Maybe;
      34             : using mozilla::Nothing;
      35             : using mozilla::Some;
      36             : 
      37             : ////////////////////////////////////////////////////////////////////////////////
      38             : // nsFileStreamBase
      39             : 
      40         285 : nsFileStreamBase::nsFileStreamBase()
      41             :     : mFD(nullptr)
      42             :     , mBehaviorFlags(0)
      43             :     , mState(eUnitialized)
      44         285 :     , mErrorValue(NS_ERROR_FAILURE)
      45             : {
      46         285 : }
      47             : 
      48         560 : nsFileStreamBase::~nsFileStreamBase()
      49             : {
      50         280 :     Close();
      51         280 : }
      52             : 
      53        4358 : NS_IMPL_ISUPPORTS(nsFileStreamBase,
      54             :                   nsISeekableStream,
      55             :                   nsIFileMetadata)
      56             : 
      57             : NS_IMETHODIMP
      58           0 : nsFileStreamBase::Seek(int32_t whence, int64_t offset)
      59             : {
      60           0 :     nsresult rv = DoPendingOpen();
      61           0 :     NS_ENSURE_SUCCESS(rv, rv);
      62             : 
      63           0 :     int64_t cnt = PR_Seek64(mFD, offset, (PRSeekWhence)whence);
      64           0 :     if (cnt == int64_t(-1)) {
      65           0 :         return NS_ErrorAccordingToNSPR();
      66             :     }
      67           0 :     return NS_OK;
      68             : }
      69             : 
      70             : NS_IMETHODIMP
      71           0 : nsFileStreamBase::Tell(int64_t *result)
      72             : {
      73           0 :     nsresult rv = DoPendingOpen();
      74           0 :     NS_ENSURE_SUCCESS(rv, rv);
      75             : 
      76           0 :     int64_t cnt = PR_Seek64(mFD, 0, PR_SEEK_CUR);
      77           0 :     if (cnt == int64_t(-1)) {
      78           0 :         return NS_ErrorAccordingToNSPR();
      79             :     }
      80           0 :     *result = cnt;
      81           0 :     return NS_OK;
      82             : }
      83             : 
      84             : NS_IMETHODIMP
      85           0 : nsFileStreamBase::SetEOF()
      86             : {
      87           0 :     nsresult rv = DoPendingOpen();
      88           0 :     NS_ENSURE_SUCCESS(rv, rv);
      89             : 
      90             : #if defined(XP_UNIX) || defined(XP_BEOS)
      91             :     // Some system calls require an EOF offset.
      92             :     int64_t offset;
      93           0 :     rv = Tell(&offset);
      94           0 :     if (NS_FAILED(rv)) return rv;
      95             : #endif
      96             : 
      97             : #if defined(XP_UNIX) || defined(XP_BEOS)
      98           0 :     if (ftruncate(PR_FileDesc2NativeHandle(mFD), offset) != 0) {
      99           0 :         NS_ERROR("ftruncate failed");
     100           0 :         return NS_ERROR_FAILURE;
     101             :     }
     102             : #elif defined(XP_WIN)
     103             :     if (!SetEndOfFile((HANDLE) PR_FileDesc2NativeHandle(mFD))) {
     104             :         NS_ERROR("SetEndOfFile failed");
     105             :         return NS_ERROR_FAILURE;
     106             :     }
     107             : #else
     108             :     // XXX not implemented
     109             : #endif
     110             : 
     111           0 :     return NS_OK;
     112             : }
     113             : 
     114             : NS_IMETHODIMP
     115           0 : nsFileStreamBase::GetSize(int64_t* _retval)
     116             : {
     117           0 :     nsresult rv = DoPendingOpen();
     118           0 :     NS_ENSURE_SUCCESS(rv, rv);
     119             : 
     120             :     PRFileInfo64 info;
     121           0 :     if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) {
     122           0 :         return NS_BASE_STREAM_OSERROR;
     123             :     }
     124             : 
     125           0 :     *_retval = int64_t(info.size);
     126             : 
     127           0 :     return NS_OK;
     128             : }
     129             : 
     130             : NS_IMETHODIMP
     131           0 : nsFileStreamBase::GetLastModified(int64_t* _retval)
     132             : {
     133           0 :     nsresult rv = DoPendingOpen();
     134           0 :     NS_ENSURE_SUCCESS(rv, rv);
     135             : 
     136             :     PRFileInfo64 info;
     137           0 :     if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) {
     138           0 :         return NS_BASE_STREAM_OSERROR;
     139             :     }
     140             : 
     141           0 :     int64_t modTime = int64_t(info.modifyTime);
     142           0 :     if (modTime == 0) {
     143           0 :         *_retval = 0;
     144             :     }
     145             :     else {
     146           0 :         *_retval = modTime / int64_t(PR_USEC_PER_MSEC);
     147             :     }
     148             : 
     149           0 :     return NS_OK;
     150             : }
     151             : 
     152             : NS_IMETHODIMP
     153           0 : nsFileStreamBase::GetFileDescriptor(PRFileDesc** _retval)
     154             : {
     155           0 :     nsresult rv = DoPendingOpen();
     156           0 :     NS_ENSURE_SUCCESS(rv, rv);
     157             : 
     158           0 :     *_retval = mFD;
     159           0 :     return NS_OK;
     160             : }
     161             : 
     162             : nsresult
     163         658 : nsFileStreamBase::Close()
     164             : {
     165         658 :     CleanUpOpen();
     166             : 
     167         658 :     nsresult rv = NS_OK;
     168         658 :     if (mFD) {
     169         280 :         if (PR_Close(mFD) == PR_FAILURE)
     170           0 :             rv = NS_BASE_STREAM_OSERROR;
     171         280 :         mFD = nullptr;
     172         280 :         mState = eClosed;
     173             :     }
     174         658 :     return rv;
     175             : }
     176             : 
     177             : nsresult
     178         133 : nsFileStreamBase::Available(uint64_t* aResult)
     179             : {
     180         133 :     nsresult rv = DoPendingOpen();
     181         133 :     NS_ENSURE_SUCCESS(rv, rv);
     182             : 
     183             :     // PR_Available with files over 4GB returns an error, so we have to
     184             :     // use the 64-bit version of PR_Available.
     185         133 :     int64_t avail = PR_Available64(mFD);
     186         133 :     if (avail == -1) {
     187           0 :         return NS_ErrorAccordingToNSPR();
     188             :     }
     189             : 
     190             :     // If available is greater than 4GB, return 4GB
     191         133 :     *aResult = (uint64_t)avail;
     192         133 :     return NS_OK;
     193             : }
     194             : 
     195             : nsresult
     196         373 : nsFileStreamBase::Read(char* aBuf, uint32_t aCount, uint32_t* aResult)
     197             : {
     198         373 :     nsresult rv = DoPendingOpen();
     199         373 :     if (rv == NS_BASE_STREAM_CLOSED) {
     200           0 :         *aResult = 0;
     201           0 :         return NS_OK;
     202             :     }
     203             : 
     204         373 :     if (NS_FAILED(rv)) {
     205           0 :         return rv;
     206             :     }
     207             : 
     208         373 :     int32_t bytesRead = PR_Read(mFD, aBuf, aCount);
     209         373 :     if (bytesRead == -1) {
     210           0 :         return NS_ErrorAccordingToNSPR();
     211             :     }
     212             : 
     213         373 :     *aResult = bytesRead;
     214         373 :     return NS_OK;
     215             : }
     216             : 
     217             : nsresult
     218          46 : nsFileStreamBase::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
     219             :                                uint32_t aCount, uint32_t* aResult)
     220             : {
     221             :     // ReadSegments is not implemented because it would be inefficient when
     222             :     // the writer does not consume all data.  If you want to call ReadSegments,
     223             :     // wrap a BufferedInputStream around the file stream.  That will call
     224             :     // Read().
     225             : 
     226          46 :     return NS_ERROR_NOT_IMPLEMENTED;
     227             : }
     228             : 
     229             : nsresult
     230          63 : nsFileStreamBase::IsNonBlocking(bool *aNonBlocking)
     231             : {
     232          63 :     *aNonBlocking = false;
     233          63 :     return NS_OK;
     234             : }
     235             : 
     236             : nsresult
     237           6 : nsFileStreamBase::Flush(void)
     238             : {
     239           6 :     nsresult rv = DoPendingOpen();
     240           6 :     NS_ENSURE_SUCCESS(rv, rv);
     241             : 
     242           6 :     int32_t cnt = PR_Sync(mFD);
     243           6 :     if (cnt == -1) {
     244           0 :         return NS_ErrorAccordingToNSPR();
     245             :     }
     246           6 :     return NS_OK;
     247             : }
     248             : 
     249             : nsresult
     250          98 : nsFileStreamBase::Write(const char *buf, uint32_t count, uint32_t *result)
     251             : {
     252          98 :     nsresult rv = DoPendingOpen();
     253          98 :     NS_ENSURE_SUCCESS(rv, rv);
     254             : 
     255          98 :     int32_t cnt = PR_Write(mFD, buf, count);
     256          98 :     if (cnt == -1) {
     257           0 :         return NS_ErrorAccordingToNSPR();
     258             :     }
     259          98 :     *result = cnt;
     260          98 :     return NS_OK;
     261             : }
     262             : 
     263             : nsresult
     264           0 : nsFileStreamBase::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval)
     265             : {
     266           0 :     NS_NOTREACHED("WriteFrom (see source comment)");
     267           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     268             :     // File streams intentionally do not support this method.
     269             :     // If you need something like this, then you should wrap
     270             :     // the file stream using nsIBufferedOutputStream
     271             : }
     272             : 
     273             : nsresult
     274           0 : nsFileStreamBase::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval)
     275             : {
     276           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     277             :     // File streams intentionally do not support this method.
     278             :     // If you need something like this, then you should wrap
     279             :     // the file stream using nsIBufferedOutputStream
     280             : }
     281             : 
     282             : nsresult
     283         285 : nsFileStreamBase::MaybeOpen(nsIFile* aFile, int32_t aIoFlags,
     284             :                             int32_t aPerm, bool aDeferred)
     285             : {
     286         285 :     NS_ENSURE_STATE(aFile);
     287             : 
     288         285 :     mOpenParams.ioFlags = aIoFlags;
     289         285 :     mOpenParams.perm = aPerm;
     290             : 
     291         285 :     if (aDeferred) {
     292             :         // Clone the file, as it may change between now and the deferred open
     293         126 :         nsCOMPtr<nsIFile> file;
     294          63 :         nsresult rv = aFile->Clone(getter_AddRefs(file));
     295          63 :         NS_ENSURE_SUCCESS(rv, rv);
     296             : 
     297          63 :         mOpenParams.localFile = do_QueryInterface(file);
     298          63 :         NS_ENSURE_TRUE(mOpenParams.localFile, NS_ERROR_UNEXPECTED);
     299             : 
     300          63 :         mState = eDeferredOpen;
     301          63 :         return NS_OK;
     302             :     }
     303             : 
     304         222 :     mOpenParams.localFile = aFile;
     305             : 
     306             :     // Following call open() at main thread.
     307             :     // Main thread might be blocked, while open a remote file.
     308         222 :     return DoOpen();
     309             : }
     310             : 
     311             : void
     312         943 : nsFileStreamBase::CleanUpOpen()
     313             : {
     314         943 :     mOpenParams.localFile = nullptr;
     315         943 : }
     316             : 
     317             : nsresult
     318         285 : nsFileStreamBase::DoOpen()
     319             : {
     320         285 :     MOZ_ASSERT(mState == eDeferredOpen || mState == eUnitialized ||
     321             :                mState == eClosed);
     322         285 :     NS_ASSERTION(!mFD, "Already have a file descriptor!");
     323         285 :     NS_ASSERTION(mOpenParams.localFile, "Must have a file to open");
     324             : 
     325             :     PRFileDesc* fd;
     326             :     nsresult rv;
     327             : 
     328         285 :     if (mOpenParams.ioFlags & PR_CREATE_FILE) {
     329          24 :         nsCOMPtr<nsIFile> parent;
     330          12 :         mOpenParams.localFile->GetParent(getter_AddRefs(parent));
     331             : 
     332             :         // Result doesn't need to be checked. If the file's parent path does not
     333             :         // exist, make it. If it does exist, do nothing.
     334          12 :         if (parent) {
     335          12 :             Unused << parent->Create(nsIFile::DIRECTORY_TYPE, 0644);
     336             :         }
     337             :     }
     338             : 
     339             : #ifdef XP_WIN
     340             :     if (mBehaviorFlags & nsIFileInputStream::SHARE_DELETE) {
     341             :       nsCOMPtr<nsILocalFileWin> file = do_QueryInterface(mOpenParams.localFile);
     342             :       MOZ_ASSERT(file);
     343             : 
     344             :       rv = file->OpenNSPRFileDescShareDelete(mOpenParams.ioFlags,
     345             :                                              mOpenParams.perm,
     346             :                                              &fd);
     347             :     } else
     348             : #endif // XP_WIN
     349             :     {
     350         570 :       rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags,
     351             :                                                    mOpenParams.perm,
     352         570 :                                                    &fd);
     353             :     }
     354             : 
     355         285 :     CleanUpOpen();
     356         285 :     if (NS_FAILED(rv)) {
     357           5 :         mState = eError;
     358           5 :         mErrorValue = rv;
     359           5 :         return rv;
     360             :     }
     361             : 
     362         280 :     mFD = fd;
     363         280 :     mState = eOpened;
     364             : 
     365         280 :     return NS_OK;
     366             : }
     367             : 
     368             : nsresult
     369         610 : nsFileStreamBase::DoPendingOpen()
     370             : {
     371         610 :     switch (mState) {
     372             :     case eUnitialized:
     373           0 :         MOZ_CRASH("This should not happen.");
     374             :         return NS_ERROR_FAILURE;
     375             : 
     376             :     case eDeferredOpen:
     377          63 :         return DoOpen();
     378             : 
     379             :     case eOpened:
     380         547 :         MOZ_ASSERT(mFD);
     381         547 :         return NS_OK;
     382             : 
     383             :     case eClosed:
     384           0 :         MOZ_ASSERT(!mFD);
     385           0 :         return NS_BASE_STREAM_CLOSED;
     386             : 
     387             :     case eError:
     388           0 :         return mErrorValue;
     389             :     }
     390             : 
     391           0 :     MOZ_CRASH("Invalid mState value.");
     392             :     return NS_ERROR_FAILURE;
     393             : }
     394             : 
     395             : 
     396             : ////////////////////////////////////////////////////////////////////////////////
     397             : // nsFileInputStream
     398             : 
     399        1913 : NS_IMPL_ADDREF_INHERITED(nsFileInputStream, nsFileStreamBase)
     400        1892 : NS_IMPL_RELEASE_INHERITED(nsFileInputStream, nsFileStreamBase)
     401             : 
     402           3 : NS_IMPL_CLASSINFO(nsFileInputStream, nullptr, nsIClassInfo::THREADSAFE,
     403             :                   NS_LOCALFILEINPUTSTREAM_CID)
     404             : 
     405        1666 : NS_INTERFACE_MAP_BEGIN(nsFileInputStream)
     406        1666 :     NS_INTERFACE_MAP_ENTRY(nsIInputStream)
     407        1065 :     NS_INTERFACE_MAP_ENTRY(nsIFileInputStream)
     408         517 :     NS_INTERFACE_MAP_ENTRY(nsILineInputStream)
     409         513 :     NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
     410         411 :     NS_IMPL_QUERY_CLASSINFO(nsFileInputStream)
     411         403 :     NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream, IsCloneable())
     412         403 : NS_INTERFACE_MAP_END_INHERITING(nsFileStreamBase)
     413             : 
     414           1 : NS_IMPL_CI_INTERFACE_GETTER(nsFileInputStream,
     415             :                             nsIInputStream,
     416             :                             nsIFileInputStream,
     417             :                             nsISeekableStream,
     418             :                             nsILineInputStream)
     419             : 
     420             : nsresult
     421         273 : nsFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
     422             : {
     423         273 :     NS_ENSURE_NO_AGGREGATION(aOuter);
     424             : 
     425         273 :     nsFileInputStream* stream = new nsFileInputStream();
     426         273 :     if (stream == nullptr)
     427           0 :         return NS_ERROR_OUT_OF_MEMORY;
     428         273 :     NS_ADDREF(stream);
     429         273 :     nsresult rv = stream->QueryInterface(aIID, aResult);
     430         273 :     NS_RELEASE(stream);
     431         273 :     return rv;
     432             : }
     433             : 
     434             : nsresult
     435         273 : nsFileInputStream::Open(nsIFile* aFile, int32_t aIOFlags, int32_t aPerm)
     436             : {
     437         273 :     nsresult rv = NS_OK;
     438             : 
     439             :     // If the previous file is open, close it
     440         273 :     if (mFD) {
     441           0 :         rv = Close();
     442           0 :         if (NS_FAILED(rv)) return rv;
     443             :     }
     444             : 
     445             :     // Open the file
     446         273 :     if (aIOFlags == -1)
     447         216 :         aIOFlags = PR_RDONLY;
     448         273 :     if (aPerm == -1)
     449         271 :         aPerm = 0;
     450             : 
     451         273 :     rv = MaybeOpen(aFile, aIOFlags, aPerm,
     452         546 :                    mBehaviorFlags & nsIFileInputStream::DEFER_OPEN);
     453             : 
     454         273 :     if (NS_FAILED(rv)) return rv;
     455             : 
     456             :     // if defer open is set, do not remove the file here.
     457             :     // remove the file while Close() is called.
     458         268 :     if ((mBehaviorFlags & DELETE_ON_CLOSE) &&
     459           0 :         !(mBehaviorFlags & nsIFileInputStream::DEFER_OPEN)) {
     460             :       // POSIX compatible filesystems allow a file to be unlinked while a
     461             :       // file descriptor is still referencing the file.  since we've already
     462             :       // opened the file descriptor, we'll try to remove the file.  if that
     463             :       // fails, then we'll just remember the nsIFile and remove it after we
     464             :       // close the file descriptor.
     465           0 :       rv = aFile->Remove(false);
     466           0 :       if (NS_SUCCEEDED(rv)) {
     467             :         // No need to remove it later. Clear the flag.
     468           0 :         mBehaviorFlags &= ~DELETE_ON_CLOSE;
     469             :       }
     470             :     }
     471             : 
     472         268 :     return NS_OK;
     473             : }
     474             : 
     475             : NS_IMETHODIMP
     476         273 : nsFileInputStream::Init(nsIFile* aFile, int32_t aIOFlags, int32_t aPerm,
     477             :                         int32_t aBehaviorFlags)
     478             : {
     479         273 :     NS_ENSURE_TRUE(!mFD, NS_ERROR_ALREADY_INITIALIZED);
     480         273 :     NS_ENSURE_TRUE(mState == eUnitialized || mState == eClosed,
     481             :                    NS_ERROR_ALREADY_INITIALIZED);
     482             : 
     483         273 :     mBehaviorFlags = aBehaviorFlags;
     484         273 :     mState = eUnitialized;
     485             : 
     486         273 :     mFile = aFile;
     487         273 :     mIOFlags = aIOFlags;
     488         273 :     mPerm = aPerm;
     489             : 
     490         273 :     return Open(aFile, aIOFlags, aPerm);
     491             : }
     492             : 
     493             : NS_IMETHODIMP
     494         348 : nsFileInputStream::Close()
     495             : {
     496             :     // Get the cache position at the time the file was close. This allows
     497             :     // NS_SEEK_CUR on a closed file that has been opened with
     498             :     // REOPEN_ON_REWIND.
     499         348 :     if (mBehaviorFlags & REOPEN_ON_REWIND) {
     500             :         // Get actual position. Not one modified by subclasses
     501           0 :         nsFileStreamBase::Tell(&mCachedPosition);
     502             :     }
     503             : 
     504             :     // null out mLineBuffer in case Close() is called again after failing
     505         348 :     mLineBuffer = nullptr;
     506         348 :     nsresult rv = nsFileStreamBase::Close();
     507         348 :     if (NS_FAILED(rv)) return rv;
     508         348 :     if (mFile && (mBehaviorFlags & DELETE_ON_CLOSE)) {
     509           0 :         rv = mFile->Remove(false);
     510           0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to delete file");
     511             :         // If we don't need to save the file for reopening, free it up
     512           0 :         if (!(mBehaviorFlags & REOPEN_ON_REWIND)) {
     513           0 :           mFile = nullptr;
     514             :         }
     515             :     }
     516         348 :     return rv;
     517             : }
     518             : 
     519             : NS_IMETHODIMP
     520         373 : nsFileInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* _retval)
     521             : {
     522         373 :     nsresult rv = nsFileStreamBase::Read(aBuf, aCount, _retval);
     523         373 :     if (rv == NS_ERROR_FILE_NOT_FOUND) {
     524             :       // Don't warn if this is a deffered file not found.
     525           0 :       return rv;
     526             :     }
     527             : 
     528         373 :     NS_ENSURE_SUCCESS(rv, rv);
     529             : 
     530             :     // Check if we're at the end of file and need to close
     531         373 :     if (mBehaviorFlags & CLOSE_ON_EOF && *_retval == 0) {
     532           0 :         Close();
     533             :     }
     534             : 
     535         373 :     return NS_OK;
     536             : }
     537             : 
     538             : NS_IMETHODIMP
     539         194 : nsFileInputStream::ReadLine(nsACString& aLine, bool* aResult)
     540             : {
     541         194 :     if (!mLineBuffer) {
     542           2 :       mLineBuffer = new nsLineBuffer<char>;
     543             :     }
     544         194 :     return NS_ReadLine(this, mLineBuffer.get(), aLine, aResult);
     545             : }
     546             : 
     547             : NS_IMETHODIMP
     548           0 : nsFileInputStream::Seek(int32_t aWhence, int64_t aOffset)
     549             : {
     550           0 :   return SeekInternal(aWhence, aOffset);
     551             : }
     552             : 
     553             : nsresult
     554           0 : nsFileInputStream::SeekInternal(int32_t aWhence, int64_t aOffset, bool aClearBuf)
     555             : {
     556           0 :     nsresult rv = DoPendingOpen();
     557           0 :     if (rv != NS_OK && rv != NS_BASE_STREAM_CLOSED) {
     558           0 :         return rv;
     559             :     }
     560             : 
     561           0 :     if (aClearBuf) {
     562           0 :         mLineBuffer = nullptr;
     563             :     }
     564             : 
     565           0 :     if (rv == NS_BASE_STREAM_CLOSED) {
     566           0 :         if (mBehaviorFlags & REOPEN_ON_REWIND) {
     567           0 :             rv = Open(mFile, mIOFlags, mPerm);
     568           0 :             NS_ENSURE_SUCCESS(rv, rv);
     569             : 
     570             :             // If the file was closed, and we do a relative seek, use the
     571             :             // position we cached when we closed the file to seek to the right
     572             :             // location.
     573           0 :             if (aWhence == NS_SEEK_CUR) {
     574           0 :                 aWhence = NS_SEEK_SET;
     575           0 :                 aOffset += mCachedPosition;
     576             :             }
     577             :         } else {
     578           0 :             return NS_BASE_STREAM_CLOSED;
     579             :         }
     580             :     }
     581             : 
     582           0 :     return nsFileStreamBase::Seek(aWhence, aOffset);
     583             : }
     584             : 
     585             : NS_IMETHODIMP
     586           0 : nsFileInputStream::Tell(int64_t *aResult)
     587             : {
     588           0 :     return nsFileStreamBase::Tell(aResult);
     589             : }
     590             : 
     591             : NS_IMETHODIMP
     592         133 : nsFileInputStream::Available(uint64_t *aResult)
     593             : {
     594         133 :     return nsFileStreamBase::Available(aResult);
     595             : }
     596             : 
     597             : void
     598           0 : nsFileInputStream::Serialize(InputStreamParams& aParams,
     599             :                              FileDescriptorArray& aFileDescriptors)
     600             : {
     601           0 :     FileInputStreamParams params;
     602             : 
     603           0 :     if (NS_SUCCEEDED(DoPendingOpen())) {
     604           0 :         MOZ_ASSERT(mFD);
     605           0 :         FileHandleType fd = FileHandleType(PR_FileDesc2NativeHandle(mFD));
     606           0 :         NS_ASSERTION(fd, "This should never be null!");
     607             : 
     608           0 :         DebugOnly<FileDescriptor*> dbgFD = aFileDescriptors.AppendElement(fd);
     609           0 :         NS_ASSERTION(dbgFD->IsValid(), "Sending an invalid file descriptor!");
     610             : 
     611           0 :         params.fileDescriptorIndex() = aFileDescriptors.Length() - 1;
     612             : 
     613           0 :         Close();
     614             :     } else {
     615             :         NS_WARNING("This file has not been opened (or could not be opened). "
     616           0 :                    "Sending an invalid file descriptor to the other process!");
     617             : 
     618           0 :         params.fileDescriptorIndex() = UINT32_MAX;
     619             :     }
     620             : 
     621           0 :     int32_t behaviorFlags = mBehaviorFlags;
     622             : 
     623             :     // The receiving process (or thread) is going to have an open file
     624             :     // descriptor automatically so transferring this flag is meaningless.
     625           0 :     behaviorFlags &= ~nsIFileInputStream::DEFER_OPEN;
     626             : 
     627           0 :     params.behaviorFlags() = behaviorFlags;
     628           0 :     params.ioFlags() = mIOFlags;
     629             : 
     630           0 :     aParams = params;
     631           0 : }
     632             : 
     633             : bool
     634           0 : nsFileInputStream::Deserialize(const InputStreamParams& aParams,
     635             :                                const FileDescriptorArray& aFileDescriptors)
     636             : {
     637           0 :     NS_ASSERTION(!mFD, "Already have a file descriptor?!");
     638           0 :     NS_ASSERTION(mState == nsFileStreamBase::eUnitialized, "Deferring open?!");
     639           0 :     NS_ASSERTION(!mFile, "Should never have a file here!");
     640           0 :     NS_ASSERTION(!mPerm, "This should always be 0!");
     641             : 
     642           0 :     if (aParams.type() != InputStreamParams::TFileInputStreamParams) {
     643           0 :         NS_WARNING("Received unknown parameters from the other process!");
     644           0 :         return false;
     645             :     }
     646             : 
     647           0 :     const FileInputStreamParams& params = aParams.get_FileInputStreamParams();
     648             : 
     649           0 :     uint32_t fileDescriptorIndex = params.fileDescriptorIndex();
     650             : 
     651           0 :     FileDescriptor fd;
     652           0 :     if (fileDescriptorIndex < aFileDescriptors.Length()) {
     653           0 :         fd = aFileDescriptors[fileDescriptorIndex];
     654           0 :         NS_WARNING_ASSERTION(fd.IsValid(),
     655             :                              "Received an invalid file descriptor!");
     656             :     } else {
     657           0 :         NS_WARNING("Received a bad file descriptor index!");
     658             :     }
     659             : 
     660           0 :     if (fd.IsValid()) {
     661           0 :         auto rawFD = fd.ClonePlatformHandle();
     662           0 :         PRFileDesc* fileDesc = PR_ImportFile(PROsfd(rawFD.release()));
     663           0 :         if (!fileDesc) {
     664           0 :             NS_WARNING("Failed to import file handle!");
     665           0 :             return false;
     666             :         }
     667           0 :         mFD = fileDesc;
     668           0 :         mState = eOpened;
     669             :     } else {
     670           0 :       mState = eError;
     671           0 :       mErrorValue = NS_ERROR_FILE_NOT_FOUND;
     672             :     }
     673             : 
     674           0 :     mBehaviorFlags = params.behaviorFlags();
     675             : 
     676           0 :     if (!XRE_IsParentProcess()) {
     677             :         // A child process shouldn't close when it reads the end because it will
     678             :         // not be able to reopen the file later.
     679           0 :         mBehaviorFlags &= ~nsIFileInputStream::CLOSE_ON_EOF;
     680             : 
     681             :         // A child process will not be able to reopen the file so this flag is
     682             :         // meaningless.
     683           0 :         mBehaviorFlags &= ~nsIFileInputStream::REOPEN_ON_REWIND;
     684             :     }
     685             : 
     686           0 :     mIOFlags = params.ioFlags();
     687             : 
     688           0 :     return true;
     689             : }
     690             : 
     691             : Maybe<uint64_t>
     692           0 : nsFileInputStream::ExpectedSerializedLength()
     693             : {
     694           0 :     return Nothing();
     695             : }
     696             : 
     697             : bool
     698         403 : nsFileInputStream::IsCloneable() const
     699             : {
     700             :     // This inputStream is cloneable only if has been created using Init() and
     701             :     // it owns a nsIFile. This is not true when it is deserialized from IPC.
     702         403 :     return XRE_IsParentProcess() && mFile;
     703             : }
     704             : 
     705             : NS_IMETHODIMP
     706           0 : nsFileInputStream::GetCloneable(bool* aCloneable)
     707             : {
     708           0 :     *aCloneable = IsCloneable();
     709           0 :     return NS_OK;
     710             : }
     711             : 
     712             : NS_IMETHODIMP
     713           0 : nsFileInputStream::Clone(nsIInputStream** aResult)
     714             : {
     715           0 :     MOZ_ASSERT(IsCloneable());
     716           0 :     return NS_NewLocalFileInputStream(aResult, mFile, mIOFlags, mPerm,
     717           0 :                                       mBehaviorFlags);
     718             : }
     719             : 
     720             : ////////////////////////////////////////////////////////////////////////////////
     721             : // nsFileOutputStream
     722             : 
     723         174 : NS_IMPL_ISUPPORTS_INHERITED(nsFileOutputStream,
     724             :                             nsFileStreamBase,
     725             :                             nsIOutputStream,
     726             :                             nsIFileOutputStream)
     727             : 
     728             : nsresult
     729           6 : nsFileOutputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
     730             : {
     731           6 :     NS_ENSURE_NO_AGGREGATION(aOuter);
     732             : 
     733           6 :     nsFileOutputStream* stream = new nsFileOutputStream();
     734           6 :     if (stream == nullptr)
     735           0 :         return NS_ERROR_OUT_OF_MEMORY;
     736           6 :     NS_ADDREF(stream);
     737           6 :     nsresult rv = stream->QueryInterface(aIID, aResult);
     738           6 :     NS_RELEASE(stream);
     739           6 :     return rv;
     740             : }
     741             : 
     742             : NS_IMETHODIMP
     743          12 : nsFileOutputStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm,
     744             :                          int32_t behaviorFlags)
     745             : {
     746          12 :     NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
     747          12 :     NS_ENSURE_TRUE(mState == eUnitialized || mState == eClosed,
     748             :                    NS_ERROR_ALREADY_INITIALIZED);
     749             : 
     750          12 :     mBehaviorFlags = behaviorFlags;
     751          12 :     mState = eUnitialized;
     752             : 
     753          12 :     if (ioFlags == -1)
     754           0 :         ioFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
     755          12 :     if (perm <= 0)
     756          12 :         perm = 0664;
     757             : 
     758          12 :     return MaybeOpen(file, ioFlags, perm,
     759          24 :                      mBehaviorFlags & nsIFileOutputStream::DEFER_OPEN);
     760             : }
     761             : 
     762             : NS_IMETHODIMP
     763           6 : nsFileOutputStream::Preallocate(int64_t aLength)
     764             : {
     765           6 :     if (!mFD) {
     766           0 :         return NS_ERROR_NOT_INITIALIZED;
     767             :     }
     768             : 
     769           6 :     if (!mozilla::fallocate(mFD, aLength)) {
     770           0 :         return NS_ERROR_FAILURE;
     771             :     }
     772             : 
     773           6 :     return NS_OK;
     774             : }
     775             : 
     776             : ////////////////////////////////////////////////////////////////////////////////
     777             : // nsAtomicFileOutputStream
     778             : 
     779          96 : NS_IMPL_ISUPPORTS_INHERITED(nsAtomicFileOutputStream,
     780             :                             nsFileOutputStream,
     781             :                             nsISafeOutputStream,
     782             :                             nsIOutputStream,
     783             :                             nsIFileOutputStream)
     784             : 
     785             : NS_IMETHODIMP
     786           6 : nsAtomicFileOutputStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm,
     787             :                              int32_t behaviorFlags)
     788             : {
     789             :     // While `PR_APPEND` is not supported, `-1` is used as `ioFlags` parameter
     790             :     // in some places, and `PR_APPEND | PR_TRUNCATE` does not require appending
     791             :     // to existing file. So, throw an exception only if `PR_APPEND` is
     792             :     // explicitly specified without `PR_TRUNCATE`.
     793           6 :     if ((ioFlags & PR_APPEND) && !(ioFlags & PR_TRUNCATE)) {
     794           0 :         return NS_ERROR_INVALID_ARG;
     795             :     }
     796           6 :     return nsFileOutputStream::Init(file, ioFlags, perm, behaviorFlags);
     797             : }
     798             : 
     799             : nsresult
     800           6 : nsAtomicFileOutputStream::DoOpen()
     801             : {
     802             :     // Make sure mOpenParams.localFile will be empty if we bail somewhere in
     803             :     // this function
     804          12 :     nsCOMPtr<nsIFile> file;
     805           6 :     file.swap(mOpenParams.localFile);
     806             : 
     807           6 :     if (!file) {
     808           0 :         return NS_ERROR_NOT_INITIALIZED;
     809             :     }
     810           6 :     nsresult rv = file->Exists(&mTargetFileExists);
     811           6 :     if (NS_FAILED(rv)) {
     812           0 :         NS_ERROR("Can't tell if target file exists");
     813           0 :         mTargetFileExists = true; // Safer to assume it exists - we just do more work.
     814             :     }
     815             : 
     816             :     // follow symlinks, for two reasons:
     817             :     // 1) if a user has deliberately set up a profile file as a symlink, we honor it
     818             :     // 2) to make the MoveToNative() in Finish() an atomic operation (which may not
     819             :     //    be the case if moving across directories on different filesystems).
     820          12 :     nsCOMPtr<nsIFile> tempResult;
     821           6 :     rv = file->Clone(getter_AddRefs(tempResult));
     822           6 :     if (NS_SUCCEEDED(rv)) {
     823           6 :         tempResult->SetFollowLinks(true);
     824             : 
     825             :         // XP_UNIX ignores SetFollowLinks(), so we have to normalize.
     826           6 :         if (mTargetFileExists) {
     827           6 :             tempResult->Normalize();
     828             :         }
     829             :     }
     830             : 
     831           6 :     if (NS_SUCCEEDED(rv) && mTargetFileExists) {
     832             :         uint32_t origPerm;
     833           6 :         if (NS_FAILED(file->GetPermissions(&origPerm))) {
     834           0 :             NS_ERROR("Can't get permissions of target file");
     835           0 :             origPerm = mOpenParams.perm;
     836             :         }
     837             :         // XXX What if |perm| is more restrictive then |origPerm|?
     838             :         // This leaves the user supplied permissions as they were.
     839           6 :         rv = tempResult->CreateUnique(nsIFile::NORMAL_FILE_TYPE, origPerm);
     840             :     }
     841           6 :     if (NS_SUCCEEDED(rv)) {
     842             :         // nsFileOutputStream::DoOpen will work on the temporary file, so we
     843             :         // prepare it and place it in mOpenParams.localFile.
     844           6 :         mOpenParams.localFile = tempResult;
     845           6 :         mTempFile = tempResult;
     846           6 :         mTargetFile = file;
     847           6 :         rv = nsFileOutputStream::DoOpen();
     848             :     }
     849           6 :     return rv;
     850             : }
     851             : 
     852             : NS_IMETHODIMP
     853           6 : nsAtomicFileOutputStream::Close()
     854             : {
     855           6 :     nsresult rv = nsFileOutputStream::Close();
     856             : 
     857             :     // the consumer doesn't want the original file overwritten -
     858             :     // so clean up by removing the temp file.
     859           6 :     if (mTempFile) {
     860           0 :         mTempFile->Remove(false);
     861           0 :         mTempFile = nullptr;
     862             :     }
     863             : 
     864           6 :     return rv;
     865             : }
     866             : 
     867             : NS_IMETHODIMP
     868           6 : nsAtomicFileOutputStream::Finish()
     869             : {
     870           6 :     nsresult rv = nsFileOutputStream::Close();
     871             : 
     872             :     // if there is no temp file, don't try to move it over the original target.
     873             :     // It would destroy the targetfile if close() is called twice.
     874           6 :     if (!mTempFile)
     875           0 :         return rv;
     876             : 
     877             :     // Only overwrite if everything was ok, and the temp file could be closed.
     878           6 :     if (NS_SUCCEEDED(mWriteResult) && NS_SUCCEEDED(rv)) {
     879           6 :         NS_ENSURE_STATE(mTargetFile);
     880             : 
     881           6 :         if (!mTargetFileExists) {
     882             :             // If the target file did not exist when we were initialized, then the
     883             :             // temp file we gave out was actually a reference to the target file.
     884             :             // since we succeeded in writing to the temp file (and hence succeeded
     885             :             // in writing to the target file), there is nothing more to do.
     886             : #ifdef DEBUG
     887             :             bool equal;
     888           0 :             if (NS_FAILED(mTargetFile->Equals(mTempFile, &equal)) || !equal)
     889           0 :                 NS_WARNING("mTempFile not equal to mTargetFile");
     890             : #endif
     891             :         }
     892             :         else {
     893          12 :             nsAutoString targetFilename;
     894           6 :             rv = mTargetFile->GetLeafName(targetFilename);
     895           6 :             if (NS_SUCCEEDED(rv)) {
     896             :                 // This will replace target.
     897           6 :                 rv = mTempFile->MoveTo(nullptr, targetFilename);
     898           6 :                 if (NS_FAILED(rv))
     899           0 :                     mTempFile->Remove(false);
     900             :             }
     901             :         }
     902             :     }
     903             :     else {
     904           0 :         mTempFile->Remove(false);
     905             : 
     906             :         // if writing failed, propagate the failure code to the caller.
     907           0 :         if (NS_FAILED(mWriteResult))
     908           0 :             rv = mWriteResult;
     909             :     }
     910           6 :     mTempFile = nullptr;
     911           6 :     return rv;
     912             : }
     913             : 
     914             : NS_IMETHODIMP
     915          92 : nsAtomicFileOutputStream::Write(const char *buf, uint32_t count, uint32_t *result)
     916             : {
     917          92 :     nsresult rv = nsFileOutputStream::Write(buf, count, result);
     918          92 :     if (NS_SUCCEEDED(mWriteResult)) {
     919          92 :         if (NS_FAILED(rv))
     920           0 :             mWriteResult = rv;
     921          92 :         else if (count != *result)
     922           0 :             mWriteResult = NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
     923             : 
     924          92 :         if (NS_FAILED(mWriteResult) && count > 0)
     925           0 :             NS_WARNING("writing to output stream failed! data may be lost");
     926             :     }
     927          92 :     return rv;
     928             : }
     929             : 
     930             : ////////////////////////////////////////////////////////////////////////////////
     931             : // nsSafeFileOutputStream
     932             : 
     933             : NS_IMETHODIMP
     934           6 : nsSafeFileOutputStream::Finish()
     935             : {
     936           6 :     (void) Flush();
     937           6 :     return nsAtomicFileOutputStream::Finish();
     938             : }
     939             : 
     940             : ////////////////////////////////////////////////////////////////////////////////
     941             : // nsFileStream
     942             : 
     943           0 : NS_IMPL_ISUPPORTS_INHERITED(nsFileStream,
     944             :                             nsFileStreamBase,
     945             :                             nsIInputStream,
     946             :                             nsIOutputStream,
     947             :                             nsIFileStream)
     948             : 
     949             : NS_IMETHODIMP
     950           0 : nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm,
     951             :                    int32_t behaviorFlags)
     952             : {
     953           0 :     NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
     954           0 :     NS_ENSURE_TRUE(mState == eUnitialized || mState == eClosed,
     955             :                    NS_ERROR_ALREADY_INITIALIZED);
     956             : 
     957           0 :     mBehaviorFlags = behaviorFlags;
     958           0 :     mState = eUnitialized;
     959             : 
     960           0 :     if (ioFlags == -1)
     961           0 :         ioFlags = PR_RDWR;
     962           0 :     if (perm <= 0)
     963           0 :         perm = 0;
     964             : 
     965           0 :     return MaybeOpen(file, ioFlags, perm,
     966           0 :                      mBehaviorFlags & nsIFileStream::DEFER_OPEN);
     967             : }
     968             : 
     969             : ////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.13