Back to index

lightning-sunbird  0.9+nobinonly
nsIFileStream.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsIFileStream.h"
00040 #include "nsFileSpec.h"
00041 #include "nsCOMPtr.h"
00042 
00043 #include "prerror.h"
00044 
00045 #include "nsSegmentedBuffer.h"
00046 #include "nsInt64.h"
00047 
00048 #ifdef XP_MAC
00049 #include "pprio.h" // To get PR_ImportFile
00050 #else
00051 #include "prio.h"
00052 #endif
00053 
00054 #ifdef XP_MAC
00055 #include <Errors.h>
00056 #include <iostream>
00057 #endif
00058 
00059 //========================================================================================
00060 class FileImpl
00061     : public nsIRandomAccessStore
00062     , public nsIFileSpecOutputStream
00063     , public nsIFileSpecInputStream
00064     , public nsIOpenFile
00065 //========================================================================================
00066 {
00067     public:
00068                                         FileImpl(PRFileDesc* inDesc);
00069                                         FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode);
00070 
00071         // nsISupports interface
00072                                         NS_DECL_ISUPPORTS
00073 
00074         // nsIOpenFile interface
00075         NS_IMETHOD                      Open(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode);
00076         NS_IMETHOD                      Close();
00077         NS_IMETHOD                      GetIsOpen(PRBool* outOpen);
00078 
00079         // nsIInputStream interface
00080         NS_IMETHOD                      Available(PRUint32 *aLength);
00081         NS_IMETHOD                      Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount);
00082         NS_IMETHOD                      ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval);
00083         NS_IMETHOD                      IsNonBlocking(PRBool *aNonBlocking);
00084 
00085         // nsIOutputStream interface
00086         NS_IMETHOD                      Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount);
00087         NS_IMETHOD                      Flush();
00088         NS_IMETHOD                      WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval);
00089         NS_IMETHOD                      WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval);
00090 
00091         // nsIRandomAccessStore interface
00092         NS_DECL_NSISEEKABLESTREAM
00093         NS_IMETHOD                      GetAtEOF(PRBool* outAtEOF);
00094         NS_IMETHOD                      SetAtEOF(PRBool inAtEOF);
00095 
00096     private:
00097 
00098                                         ~FileImpl();        
00099 
00100     protected:
00101     
00102         enum {
00103             kOuputBufferSegmentSize    = 4096,
00104             kOuputBufferMaxSize        = 4096
00105         };
00106         
00107         nsresult                        InternalFlush(PRBool syncFile);
00108         nsresult                        AllocateBuffers(PRUint32 segmentSize, PRUint32 maxSize);
00109 
00110         PRFileDesc*                     mFileDesc;
00111         int                             mNSPRMode;
00112         PRBool                          mFailed;
00113         PRBool                          mEOF;
00114         PRInt32                         mLength;
00115 
00116         PRBool                          mGotBuffers;
00117         nsSegmentedBuffer               mOutBuffer;
00118         char*                           mWriteCursor;
00119         char*                           mWriteLimit;
00120 
00121 }; // class FileImpl
00122 
00123 NS_IMPL_RELEASE(FileImpl)
00124 NS_IMPL_ADDREF(FileImpl)
00125 
00126 NS_IMPL_QUERY_HEAD(FileImpl)
00127   NS_IMPL_QUERY_BODY(nsIOpenFile)
00128   NS_IMPL_QUERY_BODY(nsISeekableStream)
00129   NS_IMPL_QUERY_BODY(nsIRandomAccessStore)
00130   NS_IMPL_QUERY_BODY(nsIOutputStream)
00131   NS_IMPL_QUERY_BODY(nsIInputStream)
00132   NS_IMPL_QUERY_BODY(nsIFileSpecInputStream)
00133   NS_IMPL_QUERY_BODY(nsIFileSpecOutputStream)
00134 NS_IMPL_QUERY_TAIL(nsIOutputStream)
00135 
00136 
00137 //----------------------------------------------------------------------------------------
00138 FileImpl::FileImpl(PRFileDesc* inDesc)
00139 //----------------------------------------------------------------------------------------
00140 : mFileDesc(inDesc)
00141 , mNSPRMode(0)
00142 , mFailed(PR_FALSE)
00143 , mEOF(PR_FALSE)
00144 , mLength(-1)
00145 , mGotBuffers(PR_FALSE)
00146 {
00147     mWriteCursor = nsnull;
00148     mWriteLimit  = nsnull;
00149 }
00150 
00151 
00152 //----------------------------------------------------------------------------------------
00153 FileImpl::FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode)
00154 //----------------------------------------------------------------------------------------
00155 : mFileDesc(nsnull)
00156 , mNSPRMode(-1)
00157 , mEOF(PR_FALSE)
00158 , mLength(-1)
00159 , mGotBuffers(PR_FALSE)
00160 {
00161     mWriteCursor = nsnull;
00162     mWriteLimit  = nsnull;
00163 
00164     nsresult rv = Open(inFile, nsprMode, accessMode);          // this sets nsprMode
00165     
00166     if (NS_FAILED(rv))
00167     {
00168         mFailed = PR_TRUE;
00169 #if DEBUG
00170         char *fileName = inFile.GetLeafName();
00171         printf("Opening file %s failed\n", fileName);
00172         nsCRT::free(fileName);
00173 #endif
00174     }
00175     else
00176     {
00177         mFailed = PR_FALSE;
00178     }
00179 }
00180 
00181 //----------------------------------------------------------------------------------------
00182 FileImpl::~FileImpl()
00183 //----------------------------------------------------------------------------------------
00184 {
00185     nsresult  rv = Close();
00186     NS_ASSERTION(NS_SUCCEEDED(rv), "Close failed");
00187 }
00188 
00189 
00190 //----------------------------------------------------------------------------------------
00191 NS_IMETHODIMP FileImpl::Open(
00192     const nsFileSpec& inFile,
00193     int nsprMode,
00194     PRIntn accessMode)
00195 //----------------------------------------------------------------------------------------
00196 {
00197     if (mFileDesc)
00198         if ((nsprMode & mNSPRMode) == nsprMode)
00199             return NS_OK;
00200         else
00201             return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR);
00202         
00203     const int nspr_modes[]={
00204         PR_WRONLY | PR_CREATE_FILE,
00205         PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
00206         PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
00207         PR_RDONLY,
00208         PR_RDONLY | PR_APPEND,
00209         PR_RDWR | PR_CREATE_FILE,
00210         PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
00211 //      "wb",
00212 //      "ab", 
00213 //      "wb",
00214 //      "rb",
00215 //      "r+b",
00216 //      "w+b",
00217         0 };
00218     const int* currentLegalMode = nspr_modes;
00219     while (*currentLegalMode && nsprMode != *currentLegalMode)
00220         ++currentLegalMode;
00221     if (!*currentLegalMode) 
00222         return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR);
00223 
00224 #ifdef XP_MAC
00225      // Use the file spec to open the file, because one path can be common to
00226      // several files on the Macintosh (you can have several volumes with the
00227      // same name, see).
00228     mFileDesc = 0;
00229     OSErr err = inFile.Error();
00230     if (err != noErr)
00231       if (err != fnfErr || !(nsprMode & PR_CREATE_FILE))
00232           return NS_FILE_RESULT(inFile.Error());
00233     err = noErr;
00234 #if DEBUG
00235     const OSType kCreator = 'CWIE';
00236 #else
00237     const OSType kCreator = 'MOSS';
00238 #endif
00239     // Resolve the alias to the original file.
00240     nsFileSpec original = inFile;
00241     PRBool ignoredResult;
00242     original.ResolveSymlink(ignoredResult);
00243     const FSSpec& spec = original.operator const FSSpec&();
00244     if (nsprMode & PR_CREATE_FILE) {
00245         // In order to get the right file type/creator, do it with an nsILocalFileMac
00246         // Don't propagate any errors in doing this. If any error, just use FSpCreate.
00247         FSSpec nonConstSpec = spec;
00248         nsCOMPtr<nsILocalFileMac> macFile;
00249         nsresult res = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_FALSE, getter_AddRefs(macFile));
00250         if (NS_SUCCEEDED(res)) {
00251             nsCOMPtr<nsIFile> asFile(do_QueryInterface(macFile, &res));
00252             if (NS_SUCCEEDED(res)) {
00253                 res = asFile->Create(nsIFile::NORMAL_FILE_TYPE, 0);
00254                 if (res == NS_ERROR_FILE_ALREADY_EXISTS)
00255                     res = NS_OK;
00256             }
00257         }
00258         if (NS_FAILED(res))
00259             err = FSpCreate(&spec, kCreator, 'TEXT', 0);
00260     }
00261 
00262     if (err == dupFNErr)
00263         err = noErr;
00264     if (err != noErr)
00265         return NS_FILE_RESULT(err);
00266     
00267     SInt8 perm;
00268     if (nsprMode & PR_RDWR)
00269        perm = fsRdWrPerm;
00270     else if (nsprMode & PR_WRONLY)
00271        perm = fsWrPerm;
00272     else
00273        perm = fsRdPerm;
00274 
00275     short refnum;
00276     err = FSpOpenDF(&spec, perm, &refnum);
00277 
00278     if (err == noErr && (nsprMode & PR_TRUNCATE))
00279         err = ::SetEOF(refnum, 0);
00280     if (err == noErr && (nsprMode & PR_APPEND))
00281         err = SetFPos(refnum, fsFromLEOF, 0);
00282     if (err != noErr)
00283         return NS_FILE_RESULT(err);
00284 
00285     if ((mFileDesc = PR_ImportFile(refnum)) == 0)
00286         return NS_FILE_RESULT(PR_GetError());
00287 #else
00288     //    Platforms other than Macintosh...
00289     //  Another bug in NSPR: Mac PR_Open assumes a unix style path, but Win PR_Open assumes
00290     //  a windows path.
00291     if ((mFileDesc = PR_Open((const char*)nsFileSpec(inFile), nsprMode, accessMode)) == 0)
00292         return NS_FILE_RESULT(PR_GetError());
00293 #endif
00294      mNSPRMode = nsprMode;
00295      mLength = PR_Available(mFileDesc);
00296      return NS_OK;
00297 } // FileImpl::Open
00298 
00299 
00300 //----------------------------------------------------------------------------------------
00301 NS_IMETHODIMP FileImpl::Available(PRUint32 *aLength)
00302 //----------------------------------------------------------------------------------------
00303 {
00304     NS_PRECONDITION(aLength != nsnull, "null ptr");
00305     if (!aLength)
00306         return NS_ERROR_NULL_POINTER;
00307     if (mLength < 0)
00308         return NS_ERROR_UNEXPECTED;
00309     *aLength = mLength;
00310     return NS_OK;
00311 }
00312 
00313 //----------------------------------------------------------------------------------------
00314 NS_IMETHODIMP FileImpl::GetIsOpen(PRBool* outOpen)
00315 //----------------------------------------------------------------------------------------
00316 {
00317     *outOpen = (mFileDesc != nsnull && !mFailed);
00318     return NS_OK;
00319 }
00320 
00321 //----------------------------------------------------------------------------------------
00322 NS_IMETHODIMP FileImpl::Seek(PRInt32 whence, PRInt64 offset)
00323 //----------------------------------------------------------------------------------------
00324 {
00325     if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) 
00326        return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
00327     mFailed = PR_FALSE; // reset on a seek.
00328     mEOF = PR_FALSE; // reset on a seek.
00329     
00330     // To avoid corruption, we flush during a seek. see bug number 18949
00331     InternalFlush(PR_FALSE);
00332 
00333     nsInt64 position = PR_Seek64(mFileDesc, 0, PR_SEEK_CUR);
00334     nsInt64 available = PR_Available64(mFileDesc);
00335     nsInt64 fileSize = position + available;
00336     nsInt64 newPosition = offset;
00337     switch (whence)
00338     {
00339         case NS_SEEK_CUR: newPosition += position; break;
00340         case NS_SEEK_SET: ; break;
00341         case NS_SEEK_END: newPosition += fileSize; break;
00342     }
00343     const nsInt64 zero = 0;
00344     if (newPosition < zero)
00345     {
00346         newPosition = 0;
00347         mFailed = PR_TRUE;
00348     }
00349     if (newPosition >= fileSize) // nb: not "else if".
00350     {
00351         newPosition = fileSize;
00352         mEOF = PR_TRUE;
00353     }
00354     if (PR_Seek64(mFileDesc, newPosition, PR_SEEK_SET) < 0)
00355         mFailed = PR_TRUE;
00356     return NS_OK;
00357 } // FileImpl::Seek
00358 
00359 
00360 //----------------------------------------------------------------------------------------
00361 NS_IMETHODIMP FileImpl::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount)
00362 //----------------------------------------------------------------------------------------
00363 {
00364     NS_PRECONDITION(aBuf != nsnull, "null ptr");
00365     if (!aBuf)
00366         return NS_ERROR_NULL_POINTER;
00367     NS_PRECONDITION(aReadCount != nsnull, "null ptr");
00368     if (!aReadCount)
00369         return NS_ERROR_NULL_POINTER;
00370     if (!mFileDesc)
00371         return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
00372     if (mFailed)
00373         return NS_ERROR_FAILURE;
00374     PRInt32 bytesRead = PR_Read(mFileDesc, aBuf, aCount);
00375     if (bytesRead < 0)
00376     {
00377         *aReadCount = 0;
00378         mFailed = PR_TRUE;
00379         return NS_FILE_RESULT(PR_GetError());
00380     }
00381     else if (bytesRead == 0)
00382     {
00383         mEOF = PR_TRUE;
00384     }
00385     *aReadCount = bytesRead;
00386     return NS_OK;
00387 }
00388 
00389 NS_IMETHODIMP
00390 FileImpl::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval)
00391 {
00392     NS_NOTREACHED("ReadSegments");
00393     return NS_ERROR_NOT_IMPLEMENTED;
00394 }
00395 
00396 //----------------------------------------------------------------------------------------
00397 NS_IMETHODIMP FileImpl::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount)
00398 //----------------------------------------------------------------------------------------
00399 {
00400     NS_PRECONDITION(aBuf != nsnull, "null ptr");
00401     NS_PRECONDITION(aWriteCount != nsnull, "null ptr");
00402                     
00403     *aWriteCount = 0;
00404 
00405 #ifdef XP_MAC
00406     // Calling PR_Write on stdout is sure suicide.
00407     if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR)
00408     {
00409         std::cout.write(aBuf, aCount);
00410         *aWriteCount = aCount;
00411         return NS_OK;
00412     }
00413 #endif
00414     if (!mFileDesc)
00415         return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
00416     if (mFailed)
00417        return NS_ERROR_FAILURE;
00418 
00419     if (!mGotBuffers)
00420     {
00421         nsresult rv = AllocateBuffers(kOuputBufferSegmentSize, kOuputBufferMaxSize);
00422         if (NS_FAILED(rv))
00423           return rv;        // try to write non-buffered?
00424     }
00425     
00426     PRUint32 bufOffset = 0;
00427     PRUint32 currentWrite = 0;
00428     while (aCount > 0) 
00429     {
00430         if (mWriteCursor == nsnull || mWriteCursor == mWriteLimit)
00431         {
00432             char* seg = mOutBuffer.AppendNewSegment();
00433             if (seg == nsnull) 
00434             {
00435                 // buffer is full, try again
00436                 InternalFlush(PR_FALSE);
00437                 seg = mOutBuffer.AppendNewSegment();
00438                 if (seg == nsnull)
00439                     return NS_ERROR_OUT_OF_MEMORY;
00440             }
00441             mWriteCursor = seg;
00442             mWriteLimit  = seg + mOutBuffer.GetSegmentSize();
00443         }
00444         
00445         // move
00446         currentWrite = mWriteLimit - mWriteCursor;
00447         
00448         if (aCount < currentWrite)
00449             currentWrite = aCount;
00450 
00451         memcpy(mWriteCursor, (aBuf + bufOffset), currentWrite);
00452         
00453         mWriteCursor += currentWrite;  
00454         
00455         aCount    -= currentWrite;
00456         bufOffset += currentWrite;
00457         *aWriteCount += currentWrite;
00458     }
00459     
00460     return NS_OK;
00461 }
00462 
00463 static NS_METHOD
00464 nsWriteSegmentToFile(nsIInputStream* in,
00465                      void* closure,
00466                      const char* fromRawSegment,
00467                      PRUint32 toOffset,
00468                      PRUint32 count,
00469                      PRUint32 *writeCount)
00470 {
00471     NS_NOTREACHED("nsWriteSegmentToFile");
00472     return NS_ERROR_NOT_IMPLEMENTED;
00473 }
00474 
00475 NS_IMETHODIMP 
00476 FileImpl::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *result)
00477 {
00478     return inStr->ReadSegments(nsWriteSegmentToFile, nsnull, count, result);
00479 }
00480 
00481 NS_IMETHODIMP 
00482 FileImpl::WriteSegments(nsReadSegmentFun reader, void * closure, 
00483                         PRUint32 count, PRUint32 *result)
00484 {
00485     NS_NOTREACHED("WriteSegments");
00486     return NS_ERROR_NOT_IMPLEMENTED;
00487 }
00488 
00489 NS_IMETHODIMP
00490 FileImpl::IsNonBlocking(PRBool *aNonBlocking)
00491 {
00492     *aNonBlocking = PR_FALSE;
00493     return NS_OK;
00494 }
00495 
00496 //----------------------------------------------------------------------------------------
00497 NS_IMETHODIMP FileImpl::Tell(PRInt64* outWhere)
00498 //----------------------------------------------------------------------------------------
00499 {
00500     if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) 
00501        return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
00502     *outWhere = PR_Seek64(mFileDesc, 0, PR_SEEK_CUR);
00503     return NS_OK;
00504 } // FileImpl::Tell
00505 
00506 //----------------------------------------------------------------------------------------
00507 NS_IMETHODIMP FileImpl::Close()
00508 //----------------------------------------------------------------------------------------
00509 {
00510     if ((mNSPRMode & PR_RDONLY) == 0)
00511         InternalFlush(PR_FALSE);
00512 
00513     if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) 
00514        return NS_OK;
00515     if (PR_Close(mFileDesc) == PR_SUCCESS)
00516         mFileDesc = 0;
00517     else
00518         return NS_FILE_RESULT(PR_GetError());
00519     return NS_OK;
00520 } // FileImpl::close
00521 
00522 //----------------------------------------------------------------------------------------
00523 NS_IMETHODIMP FileImpl::Flush()
00524 //----------------------------------------------------------------------------------------
00525 {
00526   // for external callers, this will do a Sync as well as flush buffers.
00527   return InternalFlush(PR_TRUE);
00528 } // FileImpl::flush
00529 
00530 
00531 //----------------------------------------------------------------------------------------
00532 NS_IMETHODIMP FileImpl::GetAtEOF(PRBool* outAtEOF)
00533 //----------------------------------------------------------------------------------------
00534 {
00535   *outAtEOF = mEOF;
00536   return NS_OK;
00537 }
00538 
00539 
00540 //----------------------------------------------------------------------------------------
00541 NS_IMETHODIMP FileImpl::SetAtEOF(PRBool inAtEOF)
00542 //----------------------------------------------------------------------------------------
00543 {
00544     mEOF = inAtEOF;
00545     return NS_OK;
00546 }
00547 
00548 //----------------------------------------------------------------------------------------
00549 NS_IMETHODIMP FileImpl::SetEOF()
00550 //----------------------------------------------------------------------------------------
00551 {
00552     NS_NOTYETIMPLEMENTED("FileImpl::SetEOF");
00553     return NS_ERROR_NOT_IMPLEMENTED;
00554 }
00555 
00556 //----------------------------------------------------------------------------------------
00557 nsresult FileImpl::AllocateBuffers(PRUint32 segmentSize, PRUint32 maxBufSize)
00558 //----------------------------------------------------------------------------------------
00559 {
00560     nsresult rv = mOutBuffer.Init(segmentSize, maxBufSize);
00561     if (NS_SUCCEEDED(rv))
00562       mGotBuffers = PR_TRUE;
00563 
00564     return rv;
00565 }
00566 
00567 // external callers of Flush will have sync get called,
00568 // but internal callers just want to flush the buffers to disk.
00569 nsresult FileImpl::InternalFlush(PRBool syncFile)
00570 {
00571 #ifdef XP_MAC
00572     if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR)
00573     {
00574         std::cout.flush();
00575         return NS_OK;
00576     }
00577 #endif
00578     if (!mFileDesc) 
00579         return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
00580     
00581     PRInt32 segCount = mOutBuffer.GetSegmentCount();
00582     PRUint32 segSize = mOutBuffer.GetSegmentSize();
00583 
00584     for (PRInt32 i = 0; i < segCount; i++) 
00585     {
00586         char* seg = mOutBuffer.GetSegment(i);
00587 
00588         // if it is the last buffer, it may not be completely full.  
00589         if(i == (segCount-1))
00590             segSize = (mWriteCursor - seg);
00591 
00592         PRInt32 bytesWrit = PR_Write(mFileDesc, seg, segSize);
00593         if (bytesWrit != (PRInt32)segSize)
00594         {
00595           mFailed = PR_TRUE;
00596           return NS_FILE_RESULT(PR_GetError());
00597         }
00598     }
00599 
00600     if (mGotBuffers)
00601         mOutBuffer.Empty();
00602     mWriteCursor = nsnull;
00603     mWriteLimit  = nsnull;
00604 
00605     // On unix, it seems to fail always.
00606     if (syncFile && PR_Sync(mFileDesc) != PR_SUCCESS)
00607         mFailed = PR_TRUE;
00608                                                 
00609     return NS_OK;
00610 }
00611 //----------------------------------------------------------------------------------------
00612 nsresult NS_NewTypicalInputFileStream(
00613     nsISupports** aResult,
00614     const nsFileSpec& inFile
00615     /*Default nsprMode == PR_RDONLY*/
00616     /*Default accessmode = 0666 (octal)*/)
00617 // Factory method to get an nsInputStream from a file, using most common options
00618 //----------------------------------------------------------------------------------------
00619 {
00620   // This QueryInterface was needed because NS_NewIOFileStream
00621   // does a cast from (void *) to (nsISupports *) thus causing a 
00622   // vtable problem on Windows, where we really didn't have the proper pointer
00623   // to an nsIInputStream, this ensures that we do 
00624     nsISupports    * supports;
00625     nsIInputStream * inStr;
00626 
00627     nsresult rv = NS_NewIOFileStream(&supports, inFile, PR_RDONLY, 0666);
00628 
00629     *aResult = nsnull;
00630     if (NS_SUCCEEDED(rv)) {
00631       if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIInputStream), (void**)&inStr))) {
00632         *aResult = inStr;
00633       }
00634       NS_RELEASE(supports);
00635     }
00636     return rv;
00637 }
00638 
00639 //----------------------------------------------------------------------------------------
00640 nsresult NS_NewTypicalOutputFileStream(
00641     nsISupports** aResult,
00642     const nsFileSpec& inFile
00643     /*default nsprMode= (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/
00644     /*Default accessMode= 0666 (octal)*/)
00645 // Factory method to get an nsOutputStream to a file - most common case.
00646 //----------------------------------------------------------------------------------------
00647 {
00648   // This QueryInterface was needed because NS_NewIOFileStream
00649   // does a cast from (void *) to (nsISupports *) thus causing a 
00650   // vtable problem on Windows, where we really didn't have the proper pointer
00651   // to an nsIOutputStream, this ensures that we do 
00652 #if 1
00653 /*    nsISupports     * supports;
00654     nsIOutputStream * outStr;
00655 
00656     nsresult rv = NS_NewIOFileStream(
00657         &supports,
00658         inFile,
00659         (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
00660         0666);
00661 
00662     *aResult = nsnull;
00663     if (NS_SUCCEEDED(rv)) { 
00664       if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) {
00665         *aResult = outStr;
00666       }
00667       NS_RELEASE(supports);
00668     }
00669     return rv;
00670     */
00671 
00672     nsCOMPtr<nsISupports> supports;
00673     nsIOutputStream * outStr;
00674 
00675     nsresult rv = NS_NewIOFileStream(
00676         getter_AddRefs(supports),
00677         inFile,
00678         (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
00679         0666);
00680 
00681     *aResult = nsnull;
00682     if (NS_SUCCEEDED(rv)) { 
00683       if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) {
00684         *aResult = outStr;
00685       }
00686     }
00687     return rv;
00688 #else
00689     return NS_NewIOFileStream(
00690         aResult,
00691         inFile,
00692         (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
00693         0666);
00694 #endif
00695 }
00696 
00697 //----------------------------------------------------------------------------------------
00698 NS_COM_OBSOLETE nsresult NS_NewIOFileStream(
00699     nsISupports** aResult,
00700     const nsFileSpec& inFile,
00701     PRInt32 nsprMode /*default = (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/,
00702     PRInt32 accessMode /*Default = 0666 (octal)*/)
00703     // Factory method to get an object that implements both nsIInputStream
00704     // and nsIOutputStream, associated with a file.
00705 //----------------------------------------------------------------------------------------
00706 {
00707     NS_PRECONDITION(aResult != nsnull, "null ptr");
00708     if (!aResult)
00709         return NS_ERROR_NULL_POINTER;
00710 
00711     FileImpl* stream = new FileImpl(inFile, nsprMode, accessMode);
00712     if (! stream)
00713         return NS_ERROR_OUT_OF_MEMORY;
00714 
00715     NS_ADDREF(stream);
00716     PRBool isOpened = PR_FALSE;
00717     stream->GetIsOpen(&isOpened);
00718     if (!isOpened)
00719     {
00720         NS_RELEASE(stream);
00721         return NS_ERROR_FAILURE;
00722     }
00723 
00724     *aResult = (nsISupports*)(void*)stream;
00725     return NS_OK;
00726 }
00727