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
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/
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
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1999
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or 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.
36 * ***** END LICENSE BLOCK ***** */
63 // #define MORK_CONFIG_USE_ORKINFILE 1
65 #ifdef MORK_CONFIG_USE_ORKINFILE
67 #include "orkinFile.h"
69 #endif /*MORK_CONFIG_USE_ORKINFILE*/
71 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
74 // ````` ````` ````` ````` `````
75 // { ===== begin morkNode interface =====
77 /*public virtual*/ void
78 morkFile::CloseMorkNode(morkEnv
* ev
) // CloseFile() only if open
80 if ( this->IsOpenNode() )
89 morkFile::~morkFile() // assert CloseFile() executed earlier
91 MORK_ASSERT(mFile_Frozen
==0);
92 MORK_ASSERT(mFile_DoTrace
==0);
93 MORK_ASSERT(mFile_IoOpen
==0);
94 MORK_ASSERT(mFile_Active
==0);
98 morkFile::morkFile(morkEnv
* ev
, const morkUsage
& inUsage
,
99 nsIMdbHeap
* ioHeap
, nsIMdbHeap
* ioSlotHeap
)
100 : morkObject(ev
, inUsage
, ioHeap
, morkColor_kNone
, (morkHandle
*) 0)
106 , mFile_SlotHeap( 0 )
114 nsIMdbHeap_SlotStrongHeap(ioSlotHeap
, ev
, &mFile_SlotHeap
);
116 mNode_Derived
= morkDerived_kFile
;
119 ev
->NilPointerError();
123 NS_IMPL_ISUPPORTS_INHERITED1(morkFile
, morkObject
, nsIMdbFile
)
124 /*public non-poly*/ void
125 morkFile::CloseFile(morkEnv
* ev
) // called by CloseMorkNode();
129 if ( this->IsNode() )
137 this->SetFileName(ev
, (const char*) 0);
139 nsIMdbHeap_SlotStrongHeap((nsIMdbHeap
*) 0, ev
, &mFile_SlotHeap
);
140 nsIMdbFile_SlotStrongFile((nsIMdbFile
*) 0, ev
, &mFile_Thief
);
145 this->NonNodeError(ev
);
148 ev
->NilPointerError();
151 // } ===== end morkNode methods =====
152 // ````` ````` ````` ````` `````
155 morkFile::AcquireFileHandle(morkEnv
* ev
)
157 nsIMdbFile
* outFile
= 0;
159 #ifdef MORK_CONFIG_USE_ORKINFILE
161 #endif /*MORK_CONFIG_USE_ORKINFILE*/
168 morkFile::OpenOldFile(morkEnv
* ev
, nsIMdbHeap
* ioHeap
,
169 const char* inFilePath
, mork_bool inFrozen
)
170 // Choose some subclass of morkFile to instantiate, in order to read
171 // (and write if not frozen) the file known by inFilePath. The file
172 // returned should be open and ready for use, and presumably positioned
173 // at the first byte position of the file. The exact manner in which
174 // files must be opened is considered a subclass specific detail, and
175 // other portions or Mork source code don't want to know how it's done.
177 return morkStdioFile::OpenOldStdioFile(ev
, ioHeap
, inFilePath
, inFrozen
);
181 morkFile::CreateNewFile(morkEnv
* ev
, nsIMdbHeap
* ioHeap
,
182 const char* inFilePath
)
183 // Choose some subclass of morkFile to instantiate, in order to read
184 // (and write if not frozen) the file known by inFilePath. The file
185 // returned should be created and ready for use, and presumably positioned
186 // at the first byte position of the file. The exact manner in which
187 // files must be opened is considered a subclass specific detail, and
188 // other portions or Mork source code don't want to know how it's done.
190 return morkStdioFile::CreateNewStdioFile(ev
, ioHeap
, inFilePath
);
194 morkFile::NewMissingIoError(morkEnv
* ev
) const
196 ev
->NewError("file missing io");
200 morkFile::NonFileTypeError(morkEnv
* ev
)
202 ev
->NewError("non morkFile");
206 morkFile::NilSlotHeapError(morkEnv
* ev
)
208 ev
->NewError("nil mFile_SlotHeap");
212 morkFile::NilFileNameError(morkEnv
* ev
)
214 ev
->NewError("nil mFile_Name");
218 morkFile::SetThief(morkEnv
* ev
, nsIMdbFile
* ioThief
)
220 nsIMdbFile_SlotStrongFile(ioThief
, ev
, &mFile_Thief
);
224 morkFile::SetFileName(morkEnv
* ev
, const char* inName
) // inName can be nil
226 nsIMdbHeap
* heap
= mFile_SlotHeap
;
229 char* name
= mFile_Name
;
233 ev
->FreeString(heap
, name
);
235 if ( ev
->Good() && inName
)
236 mFile_Name
= ev
->CopyString(heap
, inName
);
239 this->NilSlotHeapError(ev
);
243 morkFile::NewFileDownError(morkEnv
* ev
) const
244 // call NewFileDownError() when either IsOpenAndActiveFile()
245 // is false, or when IsOpenActiveAndMutableFile() is false.
247 if ( this->IsOpenNode() )
249 if ( this->FileActive() )
251 if ( this->FileFrozen() )
253 ev
->NewError("file frozen");
256 ev
->NewError("unknown file problem");
259 ev
->NewError("file not active");
262 ev
->NewError("file not open");
266 morkFile::NewFileErrnoError(morkEnv
* ev
) const
267 // call NewFileErrnoError() to convert std C errno into AB fault
269 const char* errnoString
= strerror(errno
);
270 ev
->NewError(errnoString
); // maybe pass value of strerror() instead
273 // ````` ````` ````` ````` newlines ````` ````` ````` `````
275 #if defined(MORK_MAC)
276 static const char morkFile_kNewlines
[] =
277 "\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015";
278 # define morkFile_kNewlinesCount 16
280 # if defined(MORK_WIN) || defined(MORK_OS2)
281 static const char morkFile_kNewlines
[] =
282 "\015\012\015\012\015\012\015\012\015\012\015\012\015\012\015\012";
283 # define morkFile_kNewlinesCount 8
285 # if defined(MORK_UNIX) || defined(MORK_BEOS)
286 static const char morkFile_kNewlines
[] =
287 "\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012";
288 # define morkFile_kNewlinesCount 16
289 # endif /* MORK_UNIX || MORK_BEOS */
290 # endif /* MORK_WIN */
291 #endif /* MORK_MAC */
294 morkFile::WriteNewlines(morkEnv
* ev
, mork_count inNewlines
)
295 // WriteNewlines() returns the number of bytes written.
297 mork_size outSize
= 0;
298 while ( inNewlines
&& ev
->Good() ) // more newlines to write?
300 mork_u4 quantum
= inNewlines
;
301 if ( quantum
> morkFile_kNewlinesCount
)
302 quantum
= morkFile_kNewlinesCount
;
304 mork_size quantumSize
= quantum
* mork_kNewlineSize
;
305 mdb_size bytesWritten
;
306 this->Write(ev
->AsMdbEnv(), morkFile_kNewlines
, quantumSize
, &bytesWritten
);
307 outSize
+= quantumSize
;
308 inNewlines
-= quantum
;
314 morkFile::Eof(nsIMdbEnv
* mev
, mdb_pos
* outPos
)
318 morkEnv
*ev
= morkEnv::FromMdbEnv(mev
);
320 outErr
= ev
->AsErr();
327 morkFile::Get(nsIMdbEnv
* mev
, void* outBuf
, mdb_size inSize
,
328 mdb_pos inPos
, mdb_size
* outActualSize
)
331 morkEnv
*ev
= morkEnv::FromMdbEnv(mev
);
335 Seek(mev
, inPos
, &outPos
);
337 rv
= Read(mev
, outBuf
, inSize
, outActualSize
);
343 morkFile::Put(nsIMdbEnv
* mev
, const void* inBuf
, mdb_size inSize
,
344 mdb_pos inPos
, mdb_size
* outActualSize
)
348 morkEnv
*ev
= morkEnv::FromMdbEnv(mev
);
353 Seek(mev
, inPos
, &outPos
);
355 Write(mev
, inBuf
, inSize
, outActualSize
);
356 outErr
= ev
->AsErr();
361 // { ----- begin path methods -----
363 morkFile::Path(nsIMdbEnv
* mev
, mdbYarn
* outFilePath
)
367 outFilePath
->mYarn_Fill
= 0;
368 morkEnv
*ev
= morkEnv::FromMdbEnv(mev
);
371 ev
->StringToYarn(GetFileNameString(), outFilePath
);
372 outErr
= ev
->AsErr();
377 // } ----- end path methods -----
379 // { ----- begin replacement methods -----
383 morkFile::Thief(nsIMdbEnv
* mev
, nsIMdbFile
** acqThief
)
386 nsIMdbFile
* outThief
= 0;
387 morkEnv
*ev
= morkEnv::FromMdbEnv(mev
);
390 outThief
= GetThief();
391 NS_IF_ADDREF(outThief
);
392 outErr
= ev
->AsErr();
395 *acqThief
= outThief
;
399 // } ----- end replacement methods -----
401 // { ----- begin versioning methods -----
403 // ````` ````` ````` ````` `````
404 // { ===== begin morkNode interface =====
406 /*public virtual*/ void
407 morkStdioFile::CloseMorkNode(morkEnv
* ev
) // CloseStdioFile() only if open
409 if ( this->IsOpenNode() )
412 this->CloseStdioFile(ev
);
418 morkStdioFile::~morkStdioFile() // assert CloseStdioFile() executed earlier
421 CloseStdioFile(mMorkEnv
);
422 MORK_ASSERT(mStdioFile_File
==0);
425 /*public non-poly*/ void
426 morkStdioFile::CloseStdioFile(morkEnv
* ev
) // called by CloseMorkNode();
430 if ( this->IsNode() )
432 if ( mStdioFile_File
&& this->FileActive() && this->FileIoOpen() )
434 this->CloseStdio(ev
);
443 this->NonNodeError(ev
);
446 ev
->NilPointerError();
449 // } ===== end morkNode methods =====
450 // ````` ````` ````` ````` `````
452 // compatible with the morkFile::MakeFile() entry point
454 /*static*/ morkStdioFile
*
455 morkStdioFile::OpenOldStdioFile(morkEnv
* ev
, nsIMdbHeap
* ioHeap
,
456 const char* inFilePath
, mork_bool inFrozen
)
458 morkStdioFile
* outFile
= 0;
459 if ( ioHeap
&& inFilePath
)
461 const char* mode
= (inFrozen
)? "rb" : "rb+";
462 outFile
= new(*ioHeap
, ev
)
463 morkStdioFile(ev
, morkUsage::kHeap
, ioHeap
, ioHeap
, inFilePath
, mode
);
467 outFile
->SetFileFrozen(inFrozen
);
471 ev
->NilPointerError();
476 /*static*/ morkStdioFile
*
477 morkStdioFile::CreateNewStdioFile(morkEnv
* ev
, nsIMdbHeap
* ioHeap
,
478 const char* inFilePath
)
480 morkStdioFile
* outFile
= 0;
481 if ( ioHeap
&& inFilePath
)
483 const char* mode
= "wb+";
484 outFile
= new(*ioHeap
, ev
)
485 morkStdioFile(ev
, morkUsage::kHeap
, ioHeap
, ioHeap
, inFilePath
, mode
);
488 ev
->NilPointerError();
496 morkStdioFile::BecomeTrunk(nsIMdbEnv
* ev
)
497 // If this file is a file version branch created by calling AcquireBud(),
498 // BecomeTrunk() causes this file's content to replace the original
499 // file's content, typically by assuming the original file's identity.
505 morkStdioFile::AcquireBud(nsIMdbEnv
* mdbev
, nsIMdbHeap
* ioHeap
, nsIMdbFile
**acquiredFile
)
506 // AcquireBud() starts a new "branch" version of the file, empty of content,
507 // so that a new version of the file can be written. This new file
508 // can later be told to BecomeTrunk() the original file, so the branch
509 // created by budding the file will replace the original file. Some
510 // file subclasses might initially take the unsafe but expedient
511 // approach of simply truncating this file down to zero length, and
512 // then returning the same morkFile pointer as this, with an extra
513 // reference count increment. Note that the caller of AcquireBud() is
514 // expected to eventually call CutStrongRef() on the returned file
515 // in order to release the strong reference. High quality versions
516 // of morkFile subclasses will create entirely new files which later
517 // are renamed to become the old file, so that better transactional
518 // behavior is exhibited by the file, so crashes protect old files.
519 // Note that AcquireBud() is an illegal operation on readonly files.
521 NS_ENSURE_ARG(acquiredFile
);
524 morkFile
* outFile
= 0;
525 morkEnv
*ev
= morkEnv::FromMdbEnv(mdbev
);
527 if ( this->IsOpenAndActiveFile() )
529 FILE* file
= (FILE*) mStdioFile_File
;
533 // truncate(file, /*eof*/ 0);
535 char* name
= mFile_Name
;
538 if ( MORK_FILECLOSE(file
) >= 0 )
540 this->SetFileActive(morkBool_kFalse
);
541 this->SetFileIoOpen(morkBool_kFalse
);
544 file
= MORK_FILEOPEN(name
, "wb+"); // open for write, discarding old content
547 mStdioFile_File
= file
;
548 this->SetFileActive(morkBool_kTrue
);
549 this->SetFileIoOpen(morkBool_kTrue
);
550 this->SetFileFrozen(morkBool_kFalse
);
553 this->new_stdio_file_fault(ev
);
556 this->new_stdio_file_fault(ev
);
559 this->NilFileNameError(ev
);
561 //#endif /*MORK_WIN*/
563 if ( ev
->Good() && this->AddStrongRef(ev
->AsMdbEnv()) )
569 else if ( mFile_Thief
)
571 rv
= mFile_Thief
->AcquireBud(ev
->AsMdbEnv(), ioHeap
, acquiredFile
);
574 this->NewMissingIoError(ev
);
576 else this->NewFileDownError(ev
);
578 *acquiredFile
= outFile
;
583 morkStdioFile::Length(morkEnv
* ev
) const
587 if ( this->IsOpenAndActiveFile() )
589 FILE* file
= (FILE*) mStdioFile_File
;
592 long start
= MORK_FILETELL(file
);
595 long fore
= MORK_FILESEEK(file
, 0, SEEK_END
);
598 long eof
= MORK_FILETELL(file
);
601 long back
= MORK_FILESEEK(file
, start
, SEEK_SET
);
605 this->new_stdio_file_fault(ev
);
607 else this->new_stdio_file_fault(ev
);
609 else this->new_stdio_file_fault(ev
);
611 else this->new_stdio_file_fault(ev
);
613 else if ( mFile_Thief
)
614 mFile_Thief
->Eof(ev
->AsMdbEnv(), &outPos
);
616 this->NewMissingIoError(ev
);
618 else this->NewFileDownError(ev
);
624 morkStdioFile::Tell(nsIMdbEnv
* ev
, mork_pos
*outPos
) const
627 NS_ENSURE_ARG(outPos
);
628 morkEnv
* mev
= morkEnv::FromMdbEnv(ev
);
629 if ( this->IsOpenAndActiveFile() )
631 FILE* file
= (FILE*) mStdioFile_File
;
634 long where
= MORK_FILETELL(file
);
638 this->new_stdio_file_fault(mev
);
640 else if ( mFile_Thief
)
641 mFile_Thief
->Tell(ev
, outPos
);
643 this->NewMissingIoError(mev
);
645 else this->NewFileDownError(mev
);
651 morkStdioFile::Read(nsIMdbEnv
* ev
, void* outBuf
, mork_size inSize
, mork_num
*outCount
)
654 morkEnv
* mev
= morkEnv::FromMdbEnv(ev
);
655 if ( this->IsOpenAndActiveFile() )
657 FILE* file
= (FILE*) mStdioFile_File
;
660 long count
= (long) MORK_FILEREAD(outBuf
, inSize
, file
);
663 *outCount
= (mork_num
) count
;
665 else this->new_stdio_file_fault(mev
);
667 else if ( mFile_Thief
)
668 mFile_Thief
->Read(ev
, outBuf
, inSize
, outCount
);
670 this->NewMissingIoError(mev
);
672 else this->NewFileDownError(mev
);
678 morkStdioFile::Seek(nsIMdbEnv
* mdbev
, mork_pos inPos
, mork_pos
*aOutPos
)
682 morkEnv
*ev
= morkEnv::FromMdbEnv(mdbev
);
684 if ( this->IsOpenOrClosingNode() && this->FileActive() )
686 FILE* file
= (FILE*) mStdioFile_File
;
689 long where
= MORK_FILESEEK(file
, inPos
, SEEK_SET
);
693 this->new_stdio_file_fault(ev
);
695 else if ( mFile_Thief
)
696 mFile_Thief
->Seek(mdbev
, inPos
, aOutPos
);
698 this->NewMissingIoError(ev
);
700 else this->NewFileDownError(ev
);
707 morkStdioFile::Write(nsIMdbEnv
* mdbev
, const void* inBuf
, mork_size inSize
, mork_size
*aOutSize
)
709 mork_num outCount
= 0;
711 morkEnv
*ev
= morkEnv::FromMdbEnv(mdbev
);
712 if ( this->IsOpenActiveAndMutableFile() )
714 FILE* file
= (FILE*) mStdioFile_File
;
717 fwrite(inBuf
, 1, inSize
, file
);
721 this->new_stdio_file_fault(ev
);
723 else if ( mFile_Thief
)
724 mFile_Thief
->Write(mdbev
, inBuf
, inSize
, &outCount
);
726 this->NewMissingIoError(ev
);
728 else this->NewFileDownError(ev
);
730 *aOutSize
= outCount
;
735 morkStdioFile::Flush(nsIMdbEnv
* mdbev
)
737 morkEnv
*ev
= morkEnv::FromMdbEnv(mdbev
);
738 if ( this->IsOpenOrClosingNode() && this->FileActive() )
740 FILE* file
= (FILE*) mStdioFile_File
;
743 MORK_FILEFLUSH(file
);
746 else if ( mFile_Thief
)
747 mFile_Thief
->Flush(mdbev
);
749 this->NewMissingIoError(ev
);
751 else this->NewFileDownError(ev
);
755 // ````` ````` ````` ````` ````` ````` ````` `````
756 //protected: // protected non-poly morkStdioFile methods
759 morkStdioFile::new_stdio_file_fault(morkEnv
* ev
) const
761 FILE* file
= (FILE*) mStdioFile_File
;
763 int copyErrno
= errno
; // facilitate seeing error in debugger
765 // bunch of stuff not ported here
766 if ( !copyErrno
&& file
)
768 copyErrno
= ferror(file
);
772 this->NewFileErrnoError(ev
);
775 // ````` ````` ````` ````` ````` ````` ````` `````
776 //public: // public non-poly morkStdioFile methods
780 morkStdioFile::morkStdioFile(morkEnv
* ev
,
781 const morkUsage
& inUsage
, nsIMdbHeap
* ioHeap
, nsIMdbHeap
* ioSlotHeap
)
782 : morkFile(ev
, inUsage
, ioHeap
, ioSlotHeap
)
783 , mStdioFile_File( 0 )
786 mNode_Derived
= morkDerived_kStdioFile
;
789 morkStdioFile::morkStdioFile(morkEnv
* ev
, const morkUsage
& inUsage
,
790 nsIMdbHeap
* ioHeap
, nsIMdbHeap
* ioSlotHeap
,
791 const char* inName
, const char* inMode
)
792 // calls OpenStdio() after construction
793 : morkFile(ev
, inUsage
, ioHeap
, ioSlotHeap
)
794 , mStdioFile_File( 0 )
797 this->OpenStdio(ev
, inName
, inMode
);
800 morkStdioFile::morkStdioFile(morkEnv
* ev
, const morkUsage
& inUsage
,
801 nsIMdbHeap
* ioHeap
, nsIMdbHeap
* ioSlotHeap
,
802 void* ioFile
, const char* inName
, mork_bool inFrozen
)
803 // calls UseStdio() after construction
804 : morkFile(ev
, inUsage
, ioHeap
, ioSlotHeap
)
805 , mStdioFile_File( 0 )
808 this->UseStdio(ev
, ioFile
, inName
, inFrozen
);
812 morkStdioFile::OpenStdio(morkEnv
* ev
, const char* inName
, const char* inMode
)
813 // Open a new FILE with name inName, using mode flags from inMode.
820 mork_bool frozen
= (*inMode
== 'r'); // cursory attempt to note readonly
822 if ( this->IsOpenNode() )
824 if ( !this->FileActive() )
826 this->SetFileIoOpen(morkBool_kFalse
);
827 if ( inName
&& *inName
)
829 this->SetFileName(ev
, inName
);
832 FILE* file
= MORK_FILEOPEN(inName
, inMode
);
835 mStdioFile_File
= file
;
836 this->SetFileActive(morkBool_kTrue
);
837 this->SetFileIoOpen(morkBool_kTrue
);
838 this->SetFileFrozen(frozen
);
841 this->new_stdio_file_fault(ev
);
844 else ev
->NewError("no file name");
846 else ev
->NewError("file already active");
848 else this->NewFileDownError(ev
);
853 morkStdioFile::UseStdio(morkEnv
* ev
, void* ioFile
, const char* inName
,
855 // Use an existing file, like stdin/stdout/stderr, which should not
856 // have the io stream closed when the file is closed. The ioFile
857 // parameter must actually be of type FILE (but we don't want to make
858 // this header file include the stdio.h header file).
862 if ( this->IsOpenNode() )
864 if ( !this->FileActive() )
868 this->SetFileIoOpen(morkBool_kFalse
);
869 this->SetFileName(ev
, inName
);
872 mStdioFile_File
= ioFile
;
873 this->SetFileActive(morkBool_kTrue
);
874 this->SetFileFrozen(inFrozen
);
878 ev
->NilPointerError();
880 else ev
->NewError("file already active");
882 else this->NewFileDownError(ev
);
887 morkStdioFile::CloseStdio(morkEnv
* ev
)
888 // Close the stream io if both and FileActive() and FileIoOpen(), but
889 // this does not close this instances (like CloseStdioFile() does).
890 // If stream io was made active by means of calling UseStdio(),
891 // then this method does little beyond marking the stream inactive
892 // because FileIoOpen() is false.
894 if ( mStdioFile_File
&& this->FileActive() && this->FileIoOpen() )
896 FILE* file
= (FILE*) mStdioFile_File
;
897 if ( MORK_FILECLOSE(file
) < 0 )
898 this->new_stdio_file_fault(ev
);
901 this->SetFileActive(morkBool_kFalse
);
902 this->SetFileIoOpen(morkBool_kFalse
);
908 morkStdioFile::Steal(nsIMdbEnv
* ev
, nsIMdbFile
* ioThief
)
909 // If this file is a file version branch created by calling AcquireBud(),
910 // BecomeTrunk() causes this file's content to replace the original
911 // file's content, typically by assuming the original file's identity.
913 morkEnv
*mev
= morkEnv::FromMdbEnv(ev
);
914 if ( mStdioFile_File
&& FileActive() && FileIoOpen() )
916 FILE* file
= (FILE*) mStdioFile_File
;
917 if ( MORK_FILECLOSE(file
) < 0 )
918 new_stdio_file_fault(mev
);
922 SetThief(mev
, ioThief
);
927 #if defined(MORK_WIN)
929 void mork_fileflush(FILE * file
)
933 OSVERSIONINFOA vi
= { sizeof(OSVERSIONINFOA
) };
934 if ((GetVersionExA(&vi
) && vi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
))
937 int fd
= fileno(file
);
938 HANDLE fh
= (HANDLE
)_get_osfhandle(fd
);
939 FlushFileBuffers(fh
);
947 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789