1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef _MDB_
7 # include "mdb.h"
8 #endif
9
10 #ifndef _MORK_
11 # include "mork.h"
12 #endif
13
14 #ifndef _MORKNODE_
15 # include "morkNode.h"
16 #endif
17
18 #ifndef _MORKENV_
19 # include "morkEnv.h"
20 #endif
21
22 #ifndef _MORKFILE_
23 # include "morkFile.h"
24 #endif
25
26 #ifdef MORK_WIN
27 # include "io.h"
28 # include <windows.h>
29 #endif
30
31 #include "mozilla/Unused.h"
32 #include "nsString.h"
33
34 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
35
36 // ````` ````` ````` ````` `````
37 // { ===== begin morkNode interface =====
38
CloseMorkNode(morkEnv * ev)39 /*public virtual*/ void morkFile::CloseMorkNode(
40 morkEnv* ev) // CloseFile() only if open
41 {
42 if (this->IsOpenNode()) {
43 this->MarkClosing();
44 this->CloseFile(ev);
45 this->MarkShut();
46 }
47 }
48
49 /*public virtual*/
~morkFile()50 morkFile::~morkFile() // assert CloseFile() executed earlier
51 {
52 MORK_ASSERT(mFile_Frozen == 0);
53 MORK_ASSERT(mFile_DoTrace == 0);
54 MORK_ASSERT(mFile_IoOpen == 0);
55 MORK_ASSERT(mFile_Active == 0);
56 }
57
58 /*public non-poly*/
morkFile(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,nsIMdbHeap * ioSlotHeap)59 morkFile::morkFile(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
60 nsIMdbHeap* ioSlotHeap)
61 : morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*)0),
62 mFile_Frozen(0),
63 mFile_DoTrace(0),
64 mFile_IoOpen(0),
65 mFile_Active(0)
66
67 ,
68 mFile_SlotHeap(0),
69 mFile_Name(0),
70 mFile_Thief(0) {
71 if (ev->Good()) {
72 if (ioSlotHeap) {
73 nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mFile_SlotHeap);
74 if (ev->Good()) mNode_Derived = morkDerived_kFile;
75 } else
76 ev->NilPointerError();
77 }
78 }
79
NS_IMPL_ISUPPORTS_INHERITED(morkFile,morkObject,nsIMdbFile)80 NS_IMPL_ISUPPORTS_INHERITED(morkFile, morkObject, nsIMdbFile)
81 /*public non-poly*/ void morkFile::CloseFile(
82 morkEnv* ev) // called by CloseMorkNode();
83 {
84 if (this->IsNode()) {
85 mFile_Frozen = 0;
86 mFile_DoTrace = 0;
87 mFile_IoOpen = 0;
88 mFile_Active = 0;
89
90 if (mFile_Name) this->SetFileName(ev, nullptr);
91
92 nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*)0, ev, &mFile_SlotHeap);
93 nsIMdbFile_SlotStrongFile((nsIMdbFile*)0, ev, &mFile_Thief);
94
95 this->MarkShut();
96 } else
97 this->NonNodeError(ev);
98 }
99
100 // } ===== end morkNode methods =====
101 // ````` ````` ````` ````` `````
102
OpenOldFile(morkEnv * ev,nsIMdbHeap * ioHeap,const PathChar * inFilePath,mork_bool inFrozen)103 /*static*/ morkFile* morkFile::OpenOldFile(morkEnv* ev, nsIMdbHeap* ioHeap,
104 const PathChar* inFilePath,
105 mork_bool inFrozen)
106 // Choose some subclass of morkFile to instantiate, in order to read
107 // (and write if not frozen) the file known by inFilePath. The file
108 // returned should be open and ready for use, and presumably positioned
109 // at the first byte position of the file. The exact manner in which
110 // files must be opened is considered a subclass specific detail, and
111 // other portions or Mork source code don't want to know how it's done.
112 {
113 return morkStdioFile::OpenOldStdioFile(ev, ioHeap, inFilePath, inFrozen);
114 }
115
CreateNewFile(morkEnv * ev,nsIMdbHeap * ioHeap,const PathChar * inFilePath)116 /*static*/ morkFile* morkFile::CreateNewFile(morkEnv* ev, nsIMdbHeap* ioHeap,
117 const PathChar* inFilePath)
118 // Choose some subclass of morkFile to instantiate, in order to read
119 // (and write if not frozen) the file known by inFilePath. The file
120 // returned should be created and ready for use, and presumably positioned
121 // at the first byte position of the file. The exact manner in which
122 // files must be opened is considered a subclass specific detail, and
123 // other portions or Mork source code don't want to know how it's done.
124 {
125 return morkStdioFile::CreateNewStdioFile(ev, ioHeap, inFilePath);
126 }
127
NewMissingIoError(morkEnv * ev) const128 void morkFile::NewMissingIoError(morkEnv* ev) const {
129 ev->NewError("file missing io");
130 }
131
NonFileTypeError(morkEnv * ev)132 /*static*/ void morkFile::NonFileTypeError(morkEnv* ev) {
133 ev->NewError("non morkFile");
134 }
135
NilSlotHeapError(morkEnv * ev)136 /*static*/ void morkFile::NilSlotHeapError(morkEnv* ev) {
137 ev->NewError("nil mFile_SlotHeap");
138 }
139
NilFileNameError(morkEnv * ev)140 /*static*/ void morkFile::NilFileNameError(morkEnv* ev) {
141 ev->NewError("nil mFile_Name");
142 }
143
SetThief(morkEnv * ev,nsIMdbFile * ioThief)144 void morkFile::SetThief(morkEnv* ev, nsIMdbFile* ioThief) {
145 nsIMdbFile_SlotStrongFile(ioThief, ev, &mFile_Thief);
146 }
147
SetFileName(morkEnv * ev,const PathChar * inName)148 void morkFile::SetFileName(morkEnv* ev,
149 const PathChar* inName) // inName can be nil
150 {
151 nsIMdbHeap* heap = mFile_SlotHeap;
152 if (heap) {
153 PathChar* name = mFile_Name;
154 if (name) {
155 mFile_Name = 0;
156 ev->FreeString(heap, name);
157 }
158 if (ev->Good() && inName) mFile_Name = ev->CopyString(heap, inName);
159 } else
160 this->NilSlotHeapError(ev);
161 }
162
NewFileDownError(morkEnv * ev) const163 void morkFile::NewFileDownError(morkEnv* ev) const
164 // call NewFileDownError() when either IsOpenAndActiveFile()
165 // is false, or when IsOpenActiveAndMutableFile() is false.
166 {
167 if (this->IsOpenNode()) {
168 if (this->FileActive()) {
169 if (this->FileFrozen()) {
170 ev->NewError("file frozen");
171 } else
172 ev->NewError("unknown file problem");
173 } else
174 ev->NewError("file not active");
175 } else
176 ev->NewError("file not open");
177 }
178
NewFileErrnoError(morkEnv * ev) const179 void morkFile::NewFileErrnoError(morkEnv* ev) const
180 // call NewFileErrnoError() to convert std C errno into AB fault
181 {
182 const char* errnoString = strerror(errno);
183 ev->NewError(errnoString); // maybe pass value of strerror() instead
184 }
185
186 // ````` ````` ````` ````` newlines ````` ````` ````` `````
187
188 #if defined(MORK_MAC)
189 static const char morkFile_kNewlines[] =
190 "\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015";
191 # define morkFile_kNewlinesCount 16
192 #else
193 # if defined(MORK_WIN)
194 static const char morkFile_kNewlines[] =
195 "\015\012\015\012\015\012\015\012\015\012\015\012\015\012\015\012";
196 # define morkFile_kNewlinesCount 8
197 # else
198 # ifdef MORK_UNIX
199 static const char morkFile_kNewlines[] =
200 "\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012";
201 # define morkFile_kNewlinesCount 16
202 # endif /* MORK_UNIX */
203 # endif /* MORK_WIN */
204 #endif /* MORK_MAC */
205
WriteNewlines(morkEnv * ev,mork_count inNewlines)206 mork_size morkFile::WriteNewlines(morkEnv* ev, mork_count inNewlines)
207 // WriteNewlines() returns the number of bytes written.
208 {
209 mork_size outSize = 0;
210 while (inNewlines && ev->Good()) // more newlines to write?
211 {
212 mork_u4 quantum = inNewlines;
213 if (quantum > morkFile_kNewlinesCount) quantum = morkFile_kNewlinesCount;
214
215 mork_size quantumSize = quantum * mork_kNewlineSize;
216 mdb_size bytesWritten;
217 this->Write(ev->AsMdbEnv(), morkFile_kNewlines, quantumSize, &bytesWritten);
218 outSize += quantumSize;
219 inNewlines -= quantum;
220 }
221 return outSize;
222 }
223
224 NS_IMETHODIMP
Eof(nsIMdbEnv * mev,mdb_pos * outPos)225 morkFile::Eof(nsIMdbEnv* mev, mdb_pos* outPos) {
226 nsresult outErr = NS_OK;
227 mdb_pos pos = -1;
228 morkEnv* ev = morkEnv::FromMdbEnv(mev);
229 pos = Length(ev);
230 outErr = ev->AsErr();
231 if (outPos) *outPos = pos;
232 return outErr;
233 }
234
235 NS_IMETHODIMP
Get(nsIMdbEnv * mev,void * outBuf,mdb_size inSize,mdb_pos inPos,mdb_size * outActualSize)236 morkFile::Get(nsIMdbEnv* mev, void* outBuf, mdb_size inSize, mdb_pos inPos,
237 mdb_size* outActualSize) {
238 nsresult rv = NS_OK;
239 morkEnv* ev = morkEnv::FromMdbEnv(mev);
240 if (ev) {
241 mdb_pos outPos;
242 Seek(mev, inPos, &outPos);
243 if (ev->Good()) rv = Read(mev, outBuf, inSize, outActualSize);
244 }
245 return rv;
246 }
247
248 NS_IMETHODIMP
Put(nsIMdbEnv * mev,const void * inBuf,mdb_size inSize,mdb_pos inPos,mdb_size * outActualSize)249 morkFile::Put(nsIMdbEnv* mev, const void* inBuf, mdb_size inSize, mdb_pos inPos,
250 mdb_size* outActualSize) {
251 nsresult outErr = NS_OK;
252 *outActualSize = 0;
253 morkEnv* ev = morkEnv::FromMdbEnv(mev);
254 if (ev) {
255 mdb_pos outPos;
256
257 Seek(mev, inPos, &outPos);
258 if (ev->Good()) Write(mev, inBuf, inSize, outActualSize);
259 outErr = ev->AsErr();
260 }
261 return outErr;
262 }
263
264 // { ----- begin path methods -----
265 NS_IMETHODIMP
Path(nsIMdbEnv * mev,mdbYarn * outFilePath)266 morkFile::Path(nsIMdbEnv* mev, mdbYarn* outFilePath) {
267 nsresult outErr = NS_OK;
268 if (outFilePath) outFilePath->mYarn_Fill = 0;
269 morkEnv* ev = morkEnv::FromMdbEnv(mev);
270 if (ev) {
271 ev->StringToYarn(GetFileNameString(), outFilePath);
272 outErr = ev->AsErr();
273 }
274 return outErr;
275 }
276
277 // } ----- end path methods -----
278
279 // { ----- begin replacement methods -----
280
281 NS_IMETHODIMP
Thief(nsIMdbEnv * mev,nsIMdbFile ** acqThief)282 morkFile::Thief(nsIMdbEnv* mev, nsIMdbFile** acqThief) {
283 nsresult outErr = NS_OK;
284 nsIMdbFile* outThief = 0;
285 morkEnv* ev = morkEnv::FromMdbEnv(mev);
286 if (ev) {
287 outThief = GetThief();
288 NS_IF_ADDREF(outThief);
289 outErr = ev->AsErr();
290 }
291 if (acqThief) *acqThief = outThief;
292 return outErr;
293 }
294
295 // } ----- end replacement methods -----
296
297 // { ----- begin versioning methods -----
298
299 // ````` ````` ````` ````` `````
300 // { ===== begin morkNode interface =====
301
CloseMorkNode(morkEnv * ev)302 /*public virtual*/ void morkStdioFile::CloseMorkNode(
303 morkEnv* ev) // CloseStdioFile() only if open
304 {
305 if (this->IsOpenNode()) {
306 this->MarkClosing();
307 this->CloseStdioFile(ev);
308 this->MarkShut();
309 }
310 }
311
312 /*public virtual*/
~morkStdioFile()313 morkStdioFile::~morkStdioFile() // assert CloseStdioFile() executed earlier
314 {
315 if (mStdioFile_File) CloseStdioFile(mMorkEnv);
316 MORK_ASSERT(mStdioFile_File == 0);
317 }
318
CloseStdioFile(morkEnv * ev)319 /*public non-poly*/ void morkStdioFile::CloseStdioFile(
320 morkEnv* ev) // called by CloseMorkNode();
321 {
322 if (this->IsNode()) {
323 if (mStdioFile_File && this->FileActive() && this->FileIoOpen()) {
324 this->CloseStdio(ev);
325 }
326
327 mStdioFile_File = 0;
328
329 this->CloseFile(ev);
330 this->MarkShut();
331 } else
332 this->NonNodeError(ev);
333 }
334
335 // } ===== end morkNode methods =====
336 // ````` ````` ````` ````` `````
337
338 // compatible with the morkFile::MakeFile() entry point
339
OpenOldStdioFile(morkEnv * ev,nsIMdbHeap * ioHeap,const PathChar * inFilePath,mork_bool inFrozen)340 /*static*/ morkStdioFile* morkStdioFile::OpenOldStdioFile(
341 morkEnv* ev, nsIMdbHeap* ioHeap, const PathChar* inFilePath,
342 mork_bool inFrozen) {
343 morkStdioFile* outFile = 0;
344 if (ioHeap && inFilePath) {
345 const char* mode = (inFrozen) ? "rb" : "rb+";
346 outFile = new (*ioHeap, ev)
347 morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode);
348
349 if (outFile) {
350 outFile->SetFileFrozen(inFrozen);
351 }
352 } else
353 ev->NilPointerError();
354
355 return outFile;
356 }
357
CreateNewStdioFile(morkEnv * ev,nsIMdbHeap * ioHeap,const PathChar * inFilePath)358 /*static*/ morkStdioFile* morkStdioFile::CreateNewStdioFile(
359 morkEnv* ev, nsIMdbHeap* ioHeap, const PathChar* inFilePath) {
360 morkStdioFile* outFile = 0;
361 if (ioHeap && inFilePath) {
362 const char* mode = "wb+";
363 outFile = new (*ioHeap, ev)
364 morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode);
365 } else
366 ev->NilPointerError();
367
368 return outFile;
369 }
370
371 NS_IMETHODIMP
BecomeTrunk(nsIMdbEnv * ev)372 morkStdioFile::BecomeTrunk(nsIMdbEnv* ev)
373 // If this file is a file version branch created by calling AcquireBud(),
374 // BecomeTrunk() causes this file's content to replace the original
375 // file's content, typically by assuming the original file's identity.
376 {
377 return Flush(ev);
378 }
379
380 NS_IMETHODIMP
AcquireBud(nsIMdbEnv * mdbev,nsIMdbHeap * ioHeap,nsIMdbFile ** acquiredFile)381 morkStdioFile::AcquireBud(nsIMdbEnv* mdbev, nsIMdbHeap* ioHeap,
382 nsIMdbFile** acquiredFile)
383 // AcquireBud() starts a new "branch" version of the file, empty of content,
384 // so that a new version of the file can be written. This new file
385 // can later be told to BecomeTrunk() the original file, so the branch
386 // created by budding the file will replace the original file. Some
387 // file subclasses might initially take the unsafe but expedient
388 // approach of simply truncating this file down to zero length, and
389 // then returning the same morkFile pointer as this, with an extra
390 // reference count increment. Note that the caller of AcquireBud() is
391 // expected to eventually call CutStrongRef() on the returned file
392 // in order to release the strong reference. High quality versions
393 // of morkFile subclasses will create entirely new files which later
394 // are renamed to become the old file, so that better transactional
395 // behavior is exhibited by the file, so crashes protect old files.
396 // Note that AcquireBud() is an illegal operation on readonly files.
397 {
398 NS_ENSURE_ARG(acquiredFile);
399 MORK_USED_1(ioHeap);
400 nsresult rv = NS_OK;
401 morkFile* outFile = 0;
402 morkEnv* ev = morkEnv::FromMdbEnv(mdbev);
403
404 if (this->IsOpenAndActiveFile()) {
405 FILE* file = (FILE*)mStdioFile_File;
406 if (file) {
407 //#ifdef MORK_WIN
408 // truncate(file, /*eof*/ 0);
409 //#else /*MORK_WIN*/
410 PathChar* name = mFile_Name;
411 if (name) {
412 if (MORK_FILECLOSE(file) >= 0) {
413 this->SetFileActive(morkBool_kFalse);
414 this->SetFileIoOpen(morkBool_kFalse);
415 mStdioFile_File = 0;
416
417 file = MORK_FILEOPEN(
418 name, "wb+"); // open for write, discarding old content
419 if (file) {
420 mStdioFile_File = file;
421 this->SetFileActive(morkBool_kTrue);
422 this->SetFileIoOpen(morkBool_kTrue);
423 this->SetFileFrozen(morkBool_kFalse);
424 } else
425 this->new_stdio_file_fault(ev);
426 } else
427 this->new_stdio_file_fault(ev);
428 } else
429 this->NilFileNameError(ev);
430
431 //#endif /*MORK_WIN*/
432
433 if (ev->Good() && this->AddStrongRef(ev->AsMdbEnv())) {
434 outFile = this;
435 AddRef();
436 }
437 } else if (mFile_Thief) {
438 rv = mFile_Thief->AcquireBud(ev->AsMdbEnv(), ioHeap, acquiredFile);
439 } else
440 this->NewMissingIoError(ev);
441 } else
442 this->NewFileDownError(ev);
443
444 *acquiredFile = outFile;
445 return rv;
446 }
447
Length(morkEnv * ev) const448 mork_pos morkStdioFile::Length(morkEnv* ev) const {
449 mork_pos outPos = 0;
450
451 if (this->IsOpenAndActiveFile()) {
452 FILE* file = (FILE*)mStdioFile_File;
453 if (file) {
454 long start = MORK_FILETELL(file);
455 if (start >= 0) {
456 long fore = MORK_FILESEEK(file, 0, SEEK_END);
457 if (fore >= 0) {
458 long eof = MORK_FILETELL(file);
459 if (eof >= 0) {
460 long back = MORK_FILESEEK(file, start, SEEK_SET);
461 if (back >= 0)
462 outPos = eof;
463 else
464 this->new_stdio_file_fault(ev);
465 } else
466 this->new_stdio_file_fault(ev);
467 } else
468 this->new_stdio_file_fault(ev);
469 } else
470 this->new_stdio_file_fault(ev);
471 } else if (mFile_Thief)
472 mFile_Thief->Eof(ev->AsMdbEnv(), &outPos);
473 else
474 this->NewMissingIoError(ev);
475 } else
476 this->NewFileDownError(ev);
477
478 return outPos;
479 }
480
481 NS_IMETHODIMP
Tell(nsIMdbEnv * ev,mork_pos * outPos) const482 morkStdioFile::Tell(nsIMdbEnv* ev, mork_pos* outPos) const {
483 nsresult rv = NS_OK;
484 NS_ENSURE_ARG(outPos);
485 morkEnv* mev = morkEnv::FromMdbEnv(ev);
486 if (this->IsOpenAndActiveFile()) {
487 FILE* file = (FILE*)mStdioFile_File;
488 if (file) {
489 long where = MORK_FILETELL(file);
490 if (where >= 0)
491 *outPos = where;
492 else
493 this->new_stdio_file_fault(mev);
494 } else if (mFile_Thief)
495 mFile_Thief->Tell(ev, outPos);
496 else
497 this->NewMissingIoError(mev);
498 } else
499 this->NewFileDownError(mev);
500
501 return rv;
502 }
503
504 NS_IMETHODIMP
Read(nsIMdbEnv * ev,void * outBuf,mork_size inSize,mork_num * outCount)505 morkStdioFile::Read(nsIMdbEnv* ev, void* outBuf, mork_size inSize,
506 mork_num* outCount) {
507 nsresult rv = NS_OK;
508 morkEnv* mev = morkEnv::FromMdbEnv(ev);
509 if (this->IsOpenAndActiveFile()) {
510 FILE* file = (FILE*)mStdioFile_File;
511 if (file) {
512 long count = (long)MORK_FILEREAD(outBuf, inSize, file);
513 if (count >= 0) {
514 *outCount = (mork_num)count;
515 } else
516 this->new_stdio_file_fault(mev);
517 } else if (mFile_Thief)
518 mFile_Thief->Read(ev, outBuf, inSize, outCount);
519 else
520 this->NewMissingIoError(mev);
521 } else
522 this->NewFileDownError(mev);
523
524 return rv;
525 }
526
527 NS_IMETHODIMP
Seek(nsIMdbEnv * mdbev,mork_pos inPos,mork_pos * aOutPos)528 morkStdioFile::Seek(nsIMdbEnv* mdbev, mork_pos inPos, mork_pos* aOutPos) {
529 mork_pos outPos = 0;
530 nsresult rv = NS_OK;
531 morkEnv* ev = morkEnv::FromMdbEnv(mdbev);
532
533 if (this->IsOpenOrClosingNode() && this->FileActive()) {
534 FILE* file = (FILE*)mStdioFile_File;
535 if (file) {
536 long where = MORK_FILESEEK(file, inPos, SEEK_SET);
537 if (where >= 0)
538 outPos = inPos;
539 else
540 this->new_stdio_file_fault(ev);
541 } else if (mFile_Thief)
542 mFile_Thief->Seek(mdbev, inPos, aOutPos);
543 else
544 this->NewMissingIoError(ev);
545 } else
546 this->NewFileDownError(ev);
547
548 *aOutPos = outPos;
549 return rv;
550 }
551
552 NS_IMETHODIMP
Write(nsIMdbEnv * mdbev,const void * inBuf,mork_size inSize,mork_size * aOutSize)553 morkStdioFile::Write(nsIMdbEnv* mdbev, const void* inBuf, mork_size inSize,
554 mork_size* aOutSize) {
555 mork_num outCount = 0;
556 nsresult rv = NS_OK;
557 morkEnv* ev = morkEnv::FromMdbEnv(mdbev);
558 if (this->IsOpenActiveAndMutableFile()) {
559 FILE* file = (FILE*)mStdioFile_File;
560 if (file) {
561 mozilla::Unused << fwrite(inBuf, 1, inSize, file);
562 if (!ferror(file))
563 outCount = inSize;
564 else
565 this->new_stdio_file_fault(ev);
566 } else if (mFile_Thief)
567 mFile_Thief->Write(mdbev, inBuf, inSize, &outCount);
568 else
569 this->NewMissingIoError(ev);
570 } else
571 this->NewFileDownError(ev);
572
573 *aOutSize = outCount;
574 return rv;
575 }
576
577 NS_IMETHODIMP
Flush(nsIMdbEnv * mdbev)578 morkStdioFile::Flush(nsIMdbEnv* mdbev) {
579 morkEnv* ev = morkEnv::FromMdbEnv(mdbev);
580 if (this->IsOpenOrClosingNode() && this->FileActive()) {
581 FILE* file = (FILE*)mStdioFile_File;
582 if (file) {
583 MORK_FILEFLUSH(file);
584
585 } else if (mFile_Thief)
586 mFile_Thief->Flush(mdbev);
587 else
588 this->NewMissingIoError(ev);
589 } else
590 this->NewFileDownError(ev);
591 return NS_OK;
592 }
593
594 // ````` ````` ````` ````` ````` ````` ````` `````
595 // protected: // protected non-poly morkStdioFile methods
596
new_stdio_file_fault(morkEnv * ev) const597 void morkStdioFile::new_stdio_file_fault(morkEnv* ev) const {
598 FILE* file = (FILE*)mStdioFile_File;
599
600 int copyErrno = errno; // facilitate seeing error in debugger
601
602 // bunch of stuff not ported here
603 if (!copyErrno && file) {
604 copyErrno = ferror(file);
605 errno = copyErrno;
606 }
607
608 this->NewFileErrnoError(ev);
609 }
610
611 // ````` ````` ````` ````` ````` ````` ````` `````
612 // public: // public non-poly morkStdioFile methods
613
614 /*public non-poly*/
morkStdioFile(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,nsIMdbHeap * ioSlotHeap)615 morkStdioFile::morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
616 nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
617 : morkFile(ev, inUsage, ioHeap, ioSlotHeap), mStdioFile_File(0) {
618 if (ev->Good()) mNode_Derived = morkDerived_kStdioFile;
619 }
620
morkStdioFile(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,nsIMdbHeap * ioSlotHeap,const PathChar * inName,const char * inMode)621 morkStdioFile::morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
622 nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
623 const PathChar* inName, const char* inMode)
624 // calls OpenStdio() after construction
625 : morkFile(ev, inUsage, ioHeap, ioSlotHeap), mStdioFile_File(0) {
626 if (ev->Good()) this->OpenStdio(ev, inName, inMode);
627 }
628
morkStdioFile(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,nsIMdbHeap * ioSlotHeap,void * ioFile,const PathChar * inName,mork_bool inFrozen)629 morkStdioFile::morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
630 nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
631 void* ioFile, const PathChar* inName,
632 mork_bool inFrozen)
633 // calls UseStdio() after construction
634 : morkFile(ev, inUsage, ioHeap, ioSlotHeap), mStdioFile_File(0) {
635 if (ev->Good()) this->UseStdio(ev, ioFile, inName, inFrozen);
636 }
637
OpenStdio(morkEnv * ev,const PathChar * inName,const char * inMode)638 void morkStdioFile::OpenStdio(morkEnv* ev, const PathChar* inName,
639 const char* inMode)
640 // Open a new FILE with name inName, using mode flags from inMode.
641 {
642 if (ev->Good()) {
643 if (!inMode) inMode = "";
644
645 mork_bool frozen = (*inMode == 'r'); // cursory attempt to note readonly
646
647 if (this->IsOpenNode()) {
648 if (!this->FileActive()) {
649 this->SetFileIoOpen(morkBool_kFalse);
650 if (inName && *inName) {
651 this->SetFileName(ev, inName);
652 if (ev->Good()) {
653 FILE* file = MORK_FILEOPEN(inName, inMode);
654 if (file) {
655 mStdioFile_File = file;
656 this->SetFileActive(morkBool_kTrue);
657 this->SetFileIoOpen(morkBool_kTrue);
658 this->SetFileFrozen(frozen);
659 } else
660 this->new_stdio_file_fault(ev);
661 }
662 } else
663 ev->NewError("no file name");
664 } else
665 ev->NewError("file already active");
666 } else
667 this->NewFileDownError(ev);
668 }
669 }
670
UseStdio(morkEnv * ev,void * ioFile,const PathChar * inName,mork_bool inFrozen)671 void morkStdioFile::UseStdio(morkEnv* ev, void* ioFile, const PathChar* inName,
672 mork_bool inFrozen)
673 // Use an existing file, like stdin/stdout/stderr, which should not
674 // have the io stream closed when the file is closed. The ioFile
675 // parameter must actually be of type FILE (but we don't want to make
676 // this header file include the stdio.h header file).
677 {
678 if (ev->Good()) {
679 if (this->IsOpenNode()) {
680 if (!this->FileActive()) {
681 if (ioFile) {
682 this->SetFileIoOpen(morkBool_kFalse);
683 this->SetFileName(ev, inName);
684 if (ev->Good()) {
685 mStdioFile_File = ioFile;
686 this->SetFileActive(morkBool_kTrue);
687 this->SetFileFrozen(inFrozen);
688 }
689 } else
690 ev->NilPointerError();
691 } else
692 ev->NewError("file already active");
693 } else
694 this->NewFileDownError(ev);
695 }
696 }
697
CloseStdio(morkEnv * ev)698 void morkStdioFile::CloseStdio(morkEnv* ev)
699 // Close the stream io if both and FileActive() and FileIoOpen(), but
700 // this does not close this instances (like CloseStdioFile() does).
701 // If stream io was made active by means of calling UseStdio(),
702 // then this method does little beyond marking the stream inactive
703 // because FileIoOpen() is false.
704 {
705 if (mStdioFile_File && this->FileActive() && this->FileIoOpen()) {
706 FILE* file = (FILE*)mStdioFile_File;
707 if (MORK_FILECLOSE(file) < 0) this->new_stdio_file_fault(ev);
708
709 mStdioFile_File = 0;
710 this->SetFileActive(morkBool_kFalse);
711 this->SetFileIoOpen(morkBool_kFalse);
712 }
713 }
714
715 NS_IMETHODIMP
Steal(nsIMdbEnv * ev,nsIMdbFile * ioThief)716 morkStdioFile::Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief)
717 // If this file is a file version branch created by calling AcquireBud(),
718 // BecomeTrunk() causes this file's content to replace the original
719 // file's content, typically by assuming the original file's identity.
720 {
721 morkEnv* mev = morkEnv::FromMdbEnv(ev);
722 if (mStdioFile_File && FileActive() && FileIoOpen()) {
723 FILE* file = (FILE*)mStdioFile_File;
724 if (MORK_FILECLOSE(file) < 0) new_stdio_file_fault(mev);
725
726 mStdioFile_File = 0;
727 }
728 SetThief(mev, ioThief);
729 return NS_OK;
730 }
731
732 #if defined(MORK_WIN)
733
mork_fileflush(FILE * file)734 void mork_fileflush(FILE* file) { fflush(file); }
735
736 #endif /*MORK_WIN*/
737
738 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
739