LCOV - code coverage report
Current view: directory - netwerk/base/src - nsFileStreams.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 366 306 83.6 %
Date: 2012-06-02 Functions: 58 54 93.1 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "IPC/IPCMessageUtils.h"
      39                 : 
      40                 : #if defined(XP_UNIX) || defined(XP_BEOS)
      41                 : #include <unistd.h>
      42                 : #elif defined(XP_WIN)
      43                 : #include <windows.h>
      44                 : #elif defined(XP_OS2)
      45                 : #define INCL_DOSERRORS
      46                 : #include <os2.h>
      47                 : #else
      48                 : // XXX add necessary include file for ftruncate (or equivalent)
      49                 : #endif
      50                 : 
      51                 : #include "private/pprio.h"
      52                 : 
      53                 : #include "nsFileStreams.h"
      54                 : #include "nsILocalFile.h"
      55                 : #include "nsXPIDLString.h"
      56                 : #include "prerror.h"
      57                 : #include "nsCRT.h"
      58                 : #include "nsIFile.h"
      59                 : #include "nsDirectoryIndexStream.h"
      60                 : #include "nsMimeTypes.h"
      61                 : #include "nsReadLine.h"
      62                 : #include "nsNetUtil.h"
      63                 : #include "nsIClassInfoImpl.h"
      64                 : 
      65                 : #define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067
      66                 : 
      67                 : ////////////////////////////////////////////////////////////////////////////////
      68                 : // nsFileStream
      69                 : 
      70           19607 : nsFileStream::nsFileStream()
      71                 :     : mFD(nsnull)
      72                 :     , mBehaviorFlags(0)
      73           19607 :     , mDeferredOpen(false)
      74                 : {
      75           19607 : }
      76                 : 
      77           39214 : nsFileStream::~nsFileStream()
      78                 : {
      79           19607 :     Close();
      80           39214 : }
      81                 : 
      82          310061 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStream, nsISeekableStream)
      83                 : 
      84                 : nsresult
      85           49595 : nsFileStream::Close()
      86                 : {
      87           49595 :     CleanUpOpen();
      88                 : 
      89           49595 :     nsresult rv = NS_OK;
      90           49595 :     if (mFD) {
      91           19186 :         if (PR_Close(mFD) == PR_FAILURE)
      92               0 :             rv = NS_BASE_STREAM_OSERROR;
      93           19186 :         mFD = nsnull;
      94                 :     }
      95           49595 :     return rv;
      96                 : }
      97                 : 
      98                 : NS_IMETHODIMP
      99            6005 : nsFileStream::Seek(PRInt32 whence, PRInt64 offset)
     100                 : {
     101            6005 :     nsresult rv = DoPendingOpen();
     102            6005 :     NS_ENSURE_SUCCESS(rv, rv);
     103                 : 
     104            6005 :     if (mFD == nsnull)
     105               0 :         return NS_BASE_STREAM_CLOSED;
     106                 : 
     107            6005 :     PRInt64 cnt = PR_Seek64(mFD, offset, (PRSeekWhence)whence);
     108            6005 :     if (cnt == PRInt64(-1)) {
     109               0 :         return NS_ErrorAccordingToNSPR();
     110                 :     }
     111            6005 :     return NS_OK;
     112                 : }
     113                 : 
     114                 : NS_IMETHODIMP
     115            4228 : nsFileStream::Tell(PRInt64 *result)
     116                 : {
     117            4228 :     nsresult rv = DoPendingOpen();
     118            4228 :     NS_ENSURE_SUCCESS(rv, rv);
     119                 : 
     120            4228 :     if (mFD == nsnull)
     121               0 :         return NS_BASE_STREAM_CLOSED;
     122                 : 
     123            4228 :     PRInt64 cnt = PR_Seek64(mFD, 0, PR_SEEK_CUR);
     124            4228 :     if (cnt == PRInt64(-1)) {
     125               0 :         return NS_ErrorAccordingToNSPR();
     126                 :     }
     127            4228 :     *result = cnt;
     128            4228 :     return NS_OK;
     129                 : }
     130                 : 
     131                 : NS_IMETHODIMP
     132             964 : nsFileStream::SetEOF()
     133                 : {
     134             964 :     if (mFD == nsnull)
     135               0 :         return NS_BASE_STREAM_CLOSED;
     136                 : 
     137                 : #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
     138                 :     // Some system calls require an EOF offset.
     139                 :     PRInt64 offset;
     140             964 :     nsresult rv = Tell(&offset);
     141             964 :     if (NS_FAILED(rv)) return rv;
     142                 : #endif
     143                 : 
     144                 : #if defined(XP_UNIX) || defined(XP_BEOS)
     145             964 :     if (ftruncate(PR_FileDesc2NativeHandle(mFD), offset) != 0) {
     146               0 :         NS_ERROR("ftruncate failed");
     147               0 :         return NS_ERROR_FAILURE;
     148                 :     }
     149                 : #elif defined(XP_WIN)
     150                 :     if (!SetEndOfFile((HANDLE) PR_FileDesc2NativeHandle(mFD))) {
     151                 :         NS_ERROR("SetEndOfFile failed");
     152                 :         return NS_ERROR_FAILURE;
     153                 :     }
     154                 : #elif defined(XP_OS2)
     155                 :     if (DosSetFileSize((HFILE) PR_FileDesc2NativeHandle(mFD), offset) != NO_ERROR) {
     156                 :         NS_ERROR("DosSetFileSize failed");
     157                 :         return NS_ERROR_FAILURE;
     158                 :     }
     159                 : #else
     160                 :     // XXX not implemented
     161                 : #endif
     162                 : 
     163             964 :     return NS_OK;
     164                 : }
     165                 : 
     166                 : nsresult
     167           19853 : nsFileStream::MaybeOpen(nsILocalFile* aFile, PRInt32 aIoFlags, PRInt32 aPerm,
     168                 :                         bool aDeferred)
     169                 : {
     170           19853 :     mOpenParams.ioFlags = aIoFlags;
     171           19853 :     mOpenParams.perm = aPerm;
     172                 : 
     173           19853 :     if (aDeferred) {
     174                 :         // Clone the file, as it may change between now and the deferred open
     175            2208 :         nsCOMPtr<nsIFile> file;
     176            1104 :         nsresult rv = aFile->Clone(getter_AddRefs(file));
     177            1104 :         NS_ENSURE_SUCCESS(rv, rv);
     178                 : 
     179            1104 :         mOpenParams.localFile = do_QueryInterface(file);
     180            1104 :         NS_ENSURE_TRUE(mOpenParams.localFile, NS_ERROR_UNEXPECTED);
     181                 : 
     182            1104 :         mDeferredOpen = true;
     183            1104 :         return NS_OK;
     184                 :     }
     185                 : 
     186           18749 :     mOpenParams.localFile = aFile;
     187                 : 
     188           18749 :     return DoOpen();
     189                 : }
     190                 : 
     191                 : void
     192           69441 : nsFileStream::CleanUpOpen()
     193                 : {
     194           69441 :     mOpenParams.localFile = nsnull;
     195           69441 :     mDeferredOpen = false;
     196           69441 : }
     197                 : 
     198                 : nsresult
     199           19846 : nsFileStream::DoOpen()
     200                 : {
     201           19846 :     NS_PRECONDITION(mOpenParams.localFile, "Must have a file to open");
     202                 : 
     203                 :     PRFileDesc* fd;
     204           19846 :     nsresult rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags, mOpenParams.perm, &fd);
     205           19846 :     CleanUpOpen();
     206           19846 :     if (NS_FAILED(rv)) return rv;
     207           19186 :     mFD = fd;
     208                 : 
     209           19186 :     return NS_OK;
     210                 : }
     211                 : 
     212                 : nsresult
     213          564795 : nsFileStream::DoPendingOpen()
     214                 : {
     215          564795 :     if (!mDeferredOpen) {
     216          563698 :         return NS_OK;
     217                 :     }
     218                 : 
     219            1097 :     return DoOpen();
     220                 : }
     221                 : 
     222                 : ////////////////////////////////////////////////////////////////////////////////
     223                 : // nsFileInputStream
     224                 : 
     225           94218 : NS_IMPL_ADDREF_INHERITED(nsFileInputStream, nsFileStream)
     226           94218 : NS_IMPL_RELEASE_INHERITED(nsFileInputStream, nsFileStream)
     227                 : 
     228                 : NS_IMPL_CLASSINFO(nsFileInputStream, NULL, nsIClassInfo::THREADSAFE,
     229                 :                   NS_LOCALFILEINPUTSTREAM_CID)
     230                 : 
     231           87825 : NS_INTERFACE_MAP_BEGIN(nsFileInputStream)
     232           87825 :     NS_INTERFACE_MAP_ENTRY(nsFileStream)
     233           87746 :     NS_INTERFACE_MAP_ENTRY(nsIInputStream)
     234           63010 :     NS_INTERFACE_MAP_ENTRY(nsIFileInputStream)
     235           31586 :     NS_INTERFACE_MAP_ENTRY(nsILineInputStream)
     236           30688 :     NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
     237           30688 :     NS_IMPL_QUERY_CLASSINFO(nsFileInputStream)
     238           27209 : NS_INTERFACE_MAP_END_INHERITING(nsFileStream)
     239                 : 
     240             924 : NS_IMPL_CI_INTERFACE_GETTER5(nsFileInputStream,
     241                 :                              nsIInputStream,
     242                 :                              nsIFileInputStream,
     243                 :                              nsISeekableStream,
     244                 :                              nsILineInputStream,
     245             924 :                              nsIIPCSerializable)
     246                 : 
     247                 : nsresult
     248           15676 : nsFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
     249                 : {
     250           15676 :     NS_ENSURE_NO_AGGREGATION(aOuter);
     251                 : 
     252           15676 :     nsFileInputStream* stream = new nsFileInputStream();
     253           15676 :     if (stream == nsnull)
     254               0 :         return NS_ERROR_OUT_OF_MEMORY;
     255           15676 :     NS_ADDREF(stream);
     256           15676 :     nsresult rv = stream->QueryInterface(aIID, aResult);
     257           15676 :     NS_RELEASE(stream);
     258           15676 :     return rv;
     259                 : }
     260                 : 
     261                 : nsresult
     262           15728 : nsFileInputStream::Open(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm)
     263                 : {   
     264           15728 :     nsresult rv = NS_OK;
     265                 : 
     266                 :     // If the previous file is open, close it
     267           15728 :     if (mFD) {
     268               0 :         rv = Close();
     269               0 :         if (NS_FAILED(rv)) return rv;
     270                 :     }
     271                 : 
     272                 :     // Open the file
     273           31456 :     nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile, &rv);
     274           15728 :     if (NS_FAILED(rv)) return rv;
     275           15728 :     if (aIOFlags == -1)
     276           13632 :         aIOFlags = PR_RDONLY;
     277           15728 :     if (aPerm == -1)
     278           13520 :         aPerm = 0;
     279                 : 
     280                 :     rv = MaybeOpen(localFile, aIOFlags, aPerm,
     281           15728 :                    mBehaviorFlags & nsIFileInputStream::DEFER_OPEN);
     282           15728 :     if (NS_FAILED(rv)) return rv;
     283                 : 
     284           15074 :     if (mBehaviorFlags & DELETE_ON_CLOSE) {
     285                 :         // POSIX compatible filesystems allow a file to be unlinked while a
     286                 :         // file descriptor is still referencing the file.  since we've already
     287                 :         // opened the file descriptor, we'll try to remove the file.  if that
     288                 :         // fails, then we'll just remember the nsIFile and remove it after we
     289                 :         // close the file descriptor.
     290               1 :         rv = aFile->Remove(false);
     291               1 :         if (NS_SUCCEEDED(rv)) {
     292                 :           // No need to remove it later. Clear the flag.
     293               1 :           mBehaviorFlags &= ~DELETE_ON_CLOSE;
     294                 :         }
     295                 :     }
     296                 : 
     297           15074 :     return NS_OK;
     298                 : }
     299                 : 
     300                 : NS_IMETHODIMP
     301           15724 : nsFileInputStream::Init(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm,
     302                 :                         PRInt32 aBehaviorFlags)
     303                 : {
     304           15724 :     NS_ENSURE_TRUE(!mFD, NS_ERROR_ALREADY_INITIALIZED);
     305           15724 :     NS_ENSURE_TRUE(!mDeferredOpen, NS_ERROR_ALREADY_INITIALIZED);
     306                 : 
     307           15724 :     mBehaviorFlags = aBehaviorFlags;
     308                 : 
     309           15724 :     mFile = aFile;
     310           15724 :     mIOFlags = aIOFlags;
     311           15724 :     mPerm = aPerm;
     312                 : 
     313           15724 :     return Open(aFile, aIOFlags, aPerm);
     314                 : }
     315                 : 
     316                 : NS_IMETHODIMP
     317           20354 : nsFileInputStream::Close()
     318                 : {
     319                 :     // null out mLineBuffer in case Close() is called again after failing
     320           20354 :     PR_FREEIF(mLineBuffer);
     321           20354 :     nsresult rv = nsFileStream::Close();
     322           20354 :     if (NS_FAILED(rv)) return rv;
     323           20354 :     if (mFile && (mBehaviorFlags & DELETE_ON_CLOSE)) {
     324               0 :         rv = mFile->Remove(false);
     325               0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to delete file");
     326                 :         // If we don't need to save the file for reopening, free it up
     327               0 :         if (!(mBehaviorFlags & REOPEN_ON_REWIND)) {
     328               0 :           mFile = nsnull;
     329                 :         }
     330                 :     }
     331           20354 :     return rv;
     332                 : }
     333                 : 
     334                 : NS_IMETHODIMP
     335           15603 : nsFileInputStream::Available(PRUint32* aResult)
     336                 : {
     337           15603 :     nsresult rv = DoPendingOpen();
     338           15603 :     NS_ENSURE_SUCCESS(rv, rv);
     339                 : 
     340           15603 :     if (!mFD) {
     341               2 :         return NS_BASE_STREAM_CLOSED;
     342                 :     }
     343                 : 
     344                 :     // PR_Available with files over 4GB returns an error, so we have to
     345                 :     // use the 64-bit version of PR_Available.
     346           15601 :     PRInt64 avail = PR_Available64(mFD);
     347           15601 :     if (avail == -1) {
     348               0 :         return NS_ErrorAccordingToNSPR();
     349                 :     }
     350                 : 
     351                 :     // If available is greater than 4GB, return 4GB
     352           15601 :     *aResult = avail > PR_UINT32_MAX ? PR_UINT32_MAX : (PRUint32)avail;
     353           15601 :     return NS_OK;
     354                 : }
     355                 : 
     356                 : NS_IMETHODIMP
     357           32932 : nsFileInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult)
     358                 : {
     359           32932 :     nsresult rv = DoPendingOpen();
     360           32932 :     NS_ENSURE_SUCCESS(rv, rv);
     361                 : 
     362           32932 :     if (!mFD) {
     363              13 :         *aResult = 0;
     364              13 :         return NS_OK;
     365                 :     }
     366                 : 
     367           32919 :     PRInt32 bytesRead = PR_Read(mFD, aBuf, aCount);
     368           32919 :     if (bytesRead == -1) {
     369               0 :         return NS_ErrorAccordingToNSPR();
     370                 :     }
     371                 :     // Check if we're at the end of file and need to close
     372           32919 :     if (mBehaviorFlags & CLOSE_ON_EOF) {
     373            1284 :         if (bytesRead == 0) {
     374             213 :             Close();
     375                 :         }
     376                 :     }
     377                 : 
     378           32919 :     *aResult = bytesRead;
     379           32919 :     return NS_OK;
     380                 : }
     381                 : 
     382                 : NS_IMETHODIMP
     383           50011 : nsFileInputStream::ReadLine(nsACString& aLine, bool* aResult)
     384                 : {
     385           50011 :     nsresult rv = DoPendingOpen();
     386           50011 :     NS_ENSURE_SUCCESS(rv, rv);
     387                 : 
     388           50011 :     if (!mLineBuffer) {
     389             556 :         nsresult rv = NS_InitLineBuffer(&mLineBuffer);
     390             556 :         if (NS_FAILED(rv)) return rv;
     391                 :     }
     392           50011 :     return NS_ReadLine(this, mLineBuffer, aLine, aResult);
     393                 : }
     394                 : 
     395                 : NS_IMETHODIMP
     396             527 : nsFileInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
     397                 :                                 PRUint32 aCount, PRUint32* aResult)
     398                 : {
     399                 :     // ReadSegments is not implemented because it would be inefficient when
     400                 :     // the writer does not consume all data.  If you want to call ReadSegments,
     401                 :     // wrap a BufferedInputStream around the file stream.  That will call
     402                 :     // Read().
     403                 : 
     404                 :     // If this is ever implemented you might need to modify
     405                 :     // nsPartialFileInputStream::ReadSegments
     406                 : 
     407             527 :     return NS_ERROR_NOT_IMPLEMENTED;
     408                 : }
     409                 : 
     410                 : NS_IMETHODIMP
     411              46 : nsFileInputStream::IsNonBlocking(bool *aNonBlocking)
     412                 : {
     413              46 :     *aNonBlocking = false;
     414              46 :     return NS_OK;
     415                 : }
     416                 : 
     417                 : NS_IMETHODIMP
     418             515 : nsFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset)
     419                 : {
     420             515 :     nsresult rv = DoPendingOpen();
     421             515 :     NS_ENSURE_SUCCESS(rv, rv);
     422                 : 
     423             515 :     PR_FREEIF(mLineBuffer); // this invalidates the line buffer
     424             515 :     if (!mFD) {
     425               4 :         if (mBehaviorFlags & REOPEN_ON_REWIND) {
     426               4 :             nsresult rv = Reopen();
     427               4 :             if (NS_FAILED(rv)) {
     428               1 :                 return rv;
     429                 :             }
     430                 :         } else {
     431               0 :             return NS_BASE_STREAM_CLOSED;
     432                 :         }
     433                 :     }
     434                 : 
     435             514 :     return nsFileStream::Seek(aWhence, aOffset);
     436                 : }
     437                 : 
     438                 : bool
     439               0 : nsFileInputStream::Read(const IPC::Message *aMsg, void **aIter)
     440                 : {
     441                 :     using IPC::ReadParam;
     442                 : 
     443               0 :     nsCString path;
     444                 :     bool followLinks;
     445                 :     PRInt32 flags;
     446               0 :     if (!ReadParam(aMsg, aIter, &path) ||
     447               0 :         !ReadParam(aMsg, aIter, &followLinks) ||
     448               0 :         !ReadParam(aMsg, aIter, &flags))
     449               0 :         return false;
     450                 : 
     451               0 :     nsCOMPtr<nsILocalFile> file;
     452               0 :     nsresult rv = NS_NewNativeLocalFile(path, followLinks, getter_AddRefs(file));
     453               0 :     if (NS_FAILED(rv))
     454               0 :         return false;
     455                 : 
     456                 :     // IO flags = -1 means readonly, and
     457                 :     // permissions are unimportant since we're reading
     458               0 :     rv = Init(file, -1, -1, flags);
     459               0 :     if (NS_FAILED(rv))
     460               0 :         return false;
     461                 : 
     462               0 :     return true;
     463                 : }
     464                 : 
     465                 : void
     466               0 : nsFileInputStream::Write(IPC::Message *aMsg)
     467                 : {
     468                 :     using IPC::WriteParam;
     469                 : 
     470               0 :     nsCString path;
     471               0 :     mFile->GetNativePath(path);
     472               0 :     WriteParam(aMsg, path);
     473               0 :     nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(mFile);
     474                 :     bool followLinks;
     475               0 :     localFile->GetFollowLinks(&followLinks);
     476               0 :     WriteParam(aMsg, followLinks);
     477               0 :     WriteParam(aMsg, mBehaviorFlags);
     478               0 : }
     479                 : 
     480                 : ////////////////////////////////////////////////////////////////////////////////
     481                 : // nsPartialFileInputStream
     482                 : 
     483                 : // Don't forward to nsFileInputStream as we don't want to QI to
     484                 : // nsIFileInputStream
     485            2920 : NS_IMPL_ISUPPORTS_INHERITED3(nsPartialFileInputStream,
     486                 :                              nsFileStream,
     487                 :                              nsIInputStream,
     488                 :                              nsIPartialFileInputStream,
     489                 :                              nsILineInputStream)
     490                 : 
     491                 : nsresult
     492              62 : nsPartialFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID,
     493                 :                                  void **aResult)
     494                 : {
     495              62 :     NS_ENSURE_NO_AGGREGATION(aOuter);
     496                 : 
     497              62 :     nsPartialFileInputStream* stream = new nsPartialFileInputStream();
     498                 : 
     499              62 :     NS_ADDREF(stream);
     500              62 :     nsresult rv = stream->QueryInterface(aIID, aResult);
     501              62 :     NS_RELEASE(stream);
     502              62 :     return rv;
     503                 : }
     504                 : 
     505                 : NS_IMETHODIMP
     506              62 : nsPartialFileInputStream::Init(nsIFile* aFile, PRUint64 aStart,
     507                 :                                PRUint64 aLength, PRInt32 aIOFlags,
     508                 :                                PRInt32 aPerm, PRInt32 aBehaviorFlags)
     509                 : {
     510              62 :     mStart = aStart;
     511              62 :     mLength = aLength;
     512              62 :     mPosition = 0;
     513                 : 
     514                 :     nsresult rv = nsFileInputStream::Init(aFile, aIOFlags, aPerm,
     515              62 :                                           aBehaviorFlags);
     516              62 :     NS_ENSURE_SUCCESS(rv, rv);
     517                 :     
     518              62 :     return nsFileInputStream::Seek(NS_SEEK_SET, mStart);
     519                 : }
     520                 : 
     521                 : NS_IMETHODIMP
     522            1889 : nsPartialFileInputStream::Tell(PRInt64 *aResult)
     523                 : {
     524                 :     PRInt64 tell;
     525            1889 :     nsresult rv = nsFileInputStream::Tell(&tell);
     526            1889 :     if (NS_SUCCEEDED(rv)) {
     527            1889 :         *aResult = tell - mStart;
     528                 :     }
     529            1889 :     return rv;
     530                 : }
     531                 : 
     532                 : NS_IMETHODIMP
     533            1889 : nsPartialFileInputStream::Available(PRUint32* aResult)
     534                 : {
     535                 :     PRUint32 available;
     536            1889 :     nsresult rv = nsFileInputStream::Available(&available);
     537            1889 :     if (NS_SUCCEEDED(rv)) {
     538            1889 :         *aResult = TruncateSize(available);
     539                 :     }
     540            1889 :     return rv;
     541                 : }
     542                 : 
     543                 : NS_IMETHODIMP
     544             313 : nsPartialFileInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult)
     545                 : {
     546             313 :     PRUint32 readsize = TruncateSize(aCount);
     547             313 :     if (readsize == 0 && mBehaviorFlags & CLOSE_ON_EOF) {
     548               4 :         Close();
     549               4 :         *aResult = 0;
     550               4 :         return NS_OK;
     551                 :     }
     552                 : 
     553             309 :     nsresult rv = nsFileInputStream::Read(aBuf, readsize, aResult);
     554             309 :     if (NS_SUCCEEDED(rv)) {
     555             309 :         mPosition += readsize;
     556                 :     }
     557             309 :     return rv;
     558                 : }
     559                 : 
     560                 : NS_IMETHODIMP
     561             614 : nsPartialFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset)
     562                 : {
     563                 :     PRInt64 offset;
     564             614 :     switch (aWhence) {
     565                 :         case NS_SEEK_SET:
     566             166 :             offset = mStart + aOffset;
     567             166 :             break;
     568                 :         case NS_SEEK_CUR:
     569             309 :             offset = mStart + mPosition + aOffset;
     570             309 :             break;
     571                 :         case NS_SEEK_END:
     572             139 :             offset = mStart + mLength + aOffset;
     573             139 :             break;
     574                 :         default:
     575               0 :             return NS_ERROR_ILLEGAL_VALUE;
     576                 :     }
     577                 : 
     578             614 :     if (offset < (PRInt64)mStart || offset > (PRInt64)(mStart + mLength)) {
     579             271 :         return NS_ERROR_INVALID_ARG;
     580                 :     }
     581                 : 
     582             343 :     nsresult rv = nsFileInputStream::Seek(NS_SEEK_SET, offset);
     583             343 :     if (NS_SUCCEEDED(rv)) {
     584             342 :         mPosition = offset - mStart;
     585                 :     }
     586             343 :     return rv;
     587                 : }
     588                 : 
     589                 : ////////////////////////////////////////////////////////////////////////////////
     590                 : // nsFileOutputStream
     591                 : 
     592          100229 : NS_IMPL_ISUPPORTS_INHERITED2(nsFileOutputStream, 
     593                 :                              nsFileStream,
     594                 :                              nsIOutputStream,
     595                 :                              nsIFileOutputStream)
     596                 :  
     597                 : nsresult
     598            2632 : nsFileOutputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
     599                 : {
     600            2632 :     NS_ENSURE_NO_AGGREGATION(aOuter);
     601                 : 
     602            2632 :     nsFileOutputStream* stream = new nsFileOutputStream();
     603            2632 :     if (stream == nsnull)
     604               0 :         return NS_ERROR_OUT_OF_MEMORY;
     605            2632 :     NS_ADDREF(stream);
     606            2632 :     nsresult rv = stream->QueryInterface(aIID, aResult);
     607            2632 :     NS_RELEASE(stream);
     608            2632 :     return rv;
     609                 : }
     610                 : 
     611                 : NS_IMETHODIMP
     612            4125 : nsFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm,
     613                 :                          PRInt32 behaviorFlags)
     614                 : {
     615            4125 :     NS_ENSURE_TRUE(mFD == nsnull, NS_ERROR_ALREADY_INITIALIZED);
     616            4125 :     NS_ENSURE_TRUE(!mDeferredOpen, NS_ERROR_ALREADY_INITIALIZED);
     617                 : 
     618            4125 :     mBehaviorFlags = behaviorFlags;
     619                 : 
     620                 :     nsresult rv;
     621            8250 :     nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(file, &rv);
     622            4125 :     if (NS_FAILED(rv)) return rv;
     623            4125 :     if (ioFlags == -1)
     624              38 :         ioFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
     625            4125 :     if (perm <= 0)
     626             989 :         perm = 0664;
     627                 : 
     628                 :     return MaybeOpen(localFile, ioFlags, perm,
     629            4125 :                      mBehaviorFlags & nsIFileOutputStream::DEFER_OPEN);
     630                 : }
     631                 : 
     632                 : NS_IMETHODIMP
     633            9634 : nsFileOutputStream::Close()
     634                 : {
     635            9634 :     return nsFileStream::Close();
     636                 : }
     637                 : 
     638                 : NS_IMETHODIMP
     639          454268 : nsFileOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result)
     640                 : {
     641          454268 :     nsresult rv = DoPendingOpen();
     642          454268 :     NS_ENSURE_SUCCESS(rv, rv);
     643                 : 
     644          454265 :     if (mFD == nsnull)
     645               2 :         return NS_BASE_STREAM_CLOSED;
     646                 : 
     647          454263 :     PRInt32 cnt = PR_Write(mFD, buf, count);
     648          454263 :     if (cnt == -1) {
     649               0 :         return NS_ErrorAccordingToNSPR();
     650                 :     }
     651          454263 :     *result = cnt;
     652          454263 :     return NS_OK;
     653                 : }
     654                 : 
     655                 : NS_IMETHODIMP
     656            1233 : nsFileOutputStream::Flush(void)
     657                 : {
     658            1233 :     nsresult rv = DoPendingOpen();
     659            1233 :     NS_ENSURE_SUCCESS(rv, rv);
     660                 : 
     661            1233 :     if (mFD == nsnull)
     662               0 :         return NS_BASE_STREAM_CLOSED;
     663                 : 
     664            1233 :     PRInt32 cnt = PR_Sync(mFD);
     665            1233 :     if (cnt == -1) {
     666               0 :         return NS_ErrorAccordingToNSPR();
     667                 :     }
     668            1233 :     return NS_OK;
     669                 : }
     670                 :     
     671                 : NS_IMETHODIMP
     672               0 : nsFileOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
     673                 : {
     674               0 :     NS_NOTREACHED("WriteFrom (see source comment)");
     675               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     676                 :     // File streams intentionally do not support this method.
     677                 :     // If you need something like this, then you should wrap
     678                 :     // the file stream using nsIBufferedOutputStream
     679                 : }
     680                 : 
     681                 : NS_IMETHODIMP
     682             386 : nsFileOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
     683                 : {
     684             386 :     return NS_ERROR_NOT_IMPLEMENTED;
     685                 :     // File streams intentionally do not support this method.
     686                 :     // If you need something like this, then you should wrap
     687                 :     // the file stream using nsIBufferedOutputStream
     688                 : }
     689                 : 
     690                 : NS_IMETHODIMP
     691             248 : nsFileOutputStream::IsNonBlocking(bool *aNonBlocking)
     692                 : {
     693             248 :     *aNonBlocking = false;
     694             248 :     return NS_OK;
     695                 : }
     696                 : 
     697                 : ////////////////////////////////////////////////////////////////////////////////
     698                 : // nsSafeFileOutputStream
     699                 : 
     700           32327 : NS_IMPL_ISUPPORTS_INHERITED3(nsSafeFileOutputStream, 
     701                 :                              nsFileOutputStream,
     702                 :                              nsISafeOutputStream,
     703                 :                              nsIOutputStream,
     704                 :                              nsIFileOutputStream)
     705                 : 
     706                 : NS_IMETHODIMP
     707            1237 : nsSafeFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm,
     708                 :                              PRInt32 behaviorFlags)
     709                 : {
     710            1237 :     return nsFileOutputStream::Init(file, ioFlags, perm, behaviorFlags);
     711                 : }
     712                 : 
     713                 : nsresult
     714            1234 : nsSafeFileOutputStream::DoOpen()
     715                 : {
     716                 :     // Make sure mOpenParams.localFile will be empty if we bail somewhere in
     717                 :     // this function
     718            2468 :     nsCOMPtr<nsILocalFile> file;
     719            1234 :     file.swap(mOpenParams.localFile);
     720                 : 
     721            1234 :     nsresult rv = file->Exists(&mTargetFileExists);
     722            1234 :     if (NS_FAILED(rv)) {
     723               0 :         NS_ERROR("Can't tell if target file exists");
     724               0 :         mTargetFileExists = true; // Safer to assume it exists - we just do more work.
     725                 :     }
     726                 : 
     727                 :     // follow symlinks, for two reasons:
     728                 :     // 1) if a user has deliberately set up a profile file as a symlink, we honor it
     729                 :     // 2) to make the MoveToNative() in Finish() an atomic operation (which may not
     730                 :     //    be the case if moving across directories on different filesystems).
     731            2468 :     nsCOMPtr<nsIFile> tempResult;
     732            1234 :     rv = file->Clone(getter_AddRefs(tempResult));
     733            1234 :     if (NS_SUCCEEDED(rv)) {
     734            2468 :         nsCOMPtr<nsILocalFile> tempLocal = do_QueryInterface(tempResult);
     735            1234 :         if (tempLocal)
     736            1234 :             tempLocal->SetFollowLinks(true);
     737                 : 
     738                 :         // XP_UNIX ignores SetFollowLinks(), so we have to normalize.
     739            1234 :         tempResult->Normalize();
     740                 :     }
     741                 : 
     742            1234 :     if (NS_SUCCEEDED(rv) && mTargetFileExists) {
     743                 :         PRUint32 origPerm;
     744             749 :         if (NS_FAILED(file->GetPermissions(&origPerm))) {
     745               0 :             NS_ERROR("Can't get permissions of target file");
     746               0 :             origPerm = mOpenParams.perm;
     747                 :         }
     748                 :         // XXX What if |perm| is more restrictive then |origPerm|?
     749                 :         // This leaves the user supplied permissions as they were.
     750             749 :         rv = tempResult->CreateUnique(nsIFile::NORMAL_FILE_TYPE, origPerm);
     751                 :     }
     752            1234 :     if (NS_SUCCEEDED(rv)) {
     753                 :         // nsFileOutputStream::DoOpen will work on the temporary file, so we
     754                 :         // prepare it and place it in mOpenParams.localFile.
     755            2468 :         nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(tempResult, &rv);
     756            1234 :         NS_ENSURE_SUCCESS(rv, rv);
     757            1234 :         mOpenParams.localFile = localFile;
     758            1234 :         mTempFile = tempResult;
     759            1234 :         mTargetFile = file;
     760            2468 :         rv = nsFileOutputStream::DoOpen();
     761                 :     }
     762            1234 :     return rv;
     763                 : }
     764                 : 
     765                 : NS_IMETHODIMP
     766            1243 : nsSafeFileOutputStream::Close()
     767                 : {
     768            1243 :     nsresult rv = nsFileOutputStream::Close();
     769                 : 
     770                 :     // the consumer doesn't want the original file overwritten -
     771                 :     // so clean up by removing the temp file.
     772            1243 :     if (mTempFile) {
     773               6 :         mTempFile->Remove(false);
     774               6 :         mTempFile = nsnull;
     775                 :     }
     776                 : 
     777            1243 :     return rv;
     778                 : }
     779                 : 
     780                 : NS_IMETHODIMP
     781            1228 : nsSafeFileOutputStream::Finish()
     782                 : {
     783            1228 :     Flush();
     784            1228 :     nsresult rv = nsFileOutputStream::Close();
     785                 : 
     786                 :     // if there is no temp file, don't try to move it over the original target.
     787                 :     // It would destroy the targetfile if close() is called twice.
     788            1228 :     if (!mTempFile)
     789               0 :         return rv;
     790                 : 
     791                 :     // Only overwrite if everything was ok, and the temp file could be closed.
     792            1228 :     if (NS_SUCCEEDED(mWriteResult) && NS_SUCCEEDED(rv)) {
     793            1228 :         NS_ENSURE_STATE(mTargetFile);
     794                 : 
     795            1228 :         if (!mTargetFileExists) {
     796                 :             // If the target file did not exist when we were initialized, then the
     797                 :             // temp file we gave out was actually a reference to the target file.
     798                 :             // since we succeeded in writing to the temp file (and hence succeeded
     799                 :             // in writing to the target file), there is nothing more to do.
     800                 : #ifdef DEBUG      
     801                 :             bool equal;
     802             479 :             if (NS_FAILED(mTargetFile->Equals(mTempFile, &equal)) || !equal)
     803               0 :                 NS_ERROR("mTempFile not equal to mTargetFile");
     804                 : #endif
     805                 :         }
     806                 :         else {
     807            1498 :             nsAutoString targetFilename;
     808             749 :             rv = mTargetFile->GetLeafName(targetFilename);
     809             749 :             if (NS_SUCCEEDED(rv)) {
     810                 :                 // This will replace target.
     811             749 :                 rv = mTempFile->MoveTo(nsnull, targetFilename);
     812             749 :                 if (NS_FAILED(rv))
     813               0 :                     mTempFile->Remove(false);
     814                 :             }
     815            1228 :         }
     816                 :     }
     817                 :     else {
     818               0 :         mTempFile->Remove(false);
     819                 : 
     820                 :         // if writing failed, propagate the failure code to the caller.
     821               0 :         if (NS_FAILED(mWriteResult))
     822               0 :             rv = mWriteResult;
     823                 :     }
     824            1228 :     mTempFile = nsnull;
     825            1228 :     return rv;
     826                 : }
     827                 : 
     828                 : NS_IMETHODIMP
     829            1253 : nsSafeFileOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result)
     830                 : {
     831            1253 :     nsresult rv = nsFileOutputStream::Write(buf, count, result);
     832            1253 :     if (NS_SUCCEEDED(mWriteResult)) {
     833            1253 :         if (NS_FAILED(rv))
     834               2 :             mWriteResult = rv;
     835            1251 :         else if (count != *result)
     836               0 :             mWriteResult = NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
     837                 : 
     838            1253 :         if (NS_FAILED(mWriteResult) && count > 0)
     839               2 :             NS_WARNING("writing to output stream failed! data may be lost");
     840                 :     } 
     841            1253 :     return rv;
     842                 : }
     843                 : 
     844                 : ////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.7