Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1487 lines
37 KiB

  1. /************************************************************/
  2. /* Windows Write, Copyright 1985-1992 Microsoft Corporation */
  3. /************************************************************/
  4. /* file.c -- WRITE file interface functions */
  5. /* It is important that the external interface to this module be entirely
  6. at the level of "fn's", not "osfn's" and/or "rfn's". An intermodule call
  7. may cause our files to be closed, and this is the only module internally
  8. capable of compensating for this */
  9. #define NOGDICAPMASKS
  10. #define NOVIRTUALKEYCODES
  11. #define NOWINMESSAGES
  12. #define NOWINSTYLES
  13. #define NOSYSMETRICS
  14. #define NOMENUS
  15. #define NOICON
  16. #define NOKEYSTATE
  17. #define NOSYSCOMMANDS
  18. #define NORASTEROPS
  19. #define NOSHOWWINDOW
  20. #define NOSYSMETRICS
  21. #define NOATOM
  22. #define NOBITMAP
  23. #define NOBRUSH
  24. #define NOCLIPBOARD
  25. #define NOCOLOR
  26. #define NOCREATESTRUCT
  27. #define NOCTLMGR
  28. #define NODRAWTEXT
  29. #define NOFONT
  30. #define NOGDI
  31. #define NOHDC
  32. #define NOMEMMGR
  33. #define NOMENUS
  34. #define NOMETAFILE
  35. #define NOMSG
  36. #define NOPEN
  37. #define NOPOINT
  38. #define NORECT
  39. #define NOREGION
  40. #define NOSCROLL
  41. #define NOSOUND
  42. #define NOTEXTMETRIC
  43. #define NOWH
  44. #define NOWINOFFSETS
  45. #define NOWNDCLASS
  46. #define NOCOMM
  47. #include <windows.h>
  48. #include "mw.h"
  49. #include "doslib.h"
  50. #include "docdefs.h"
  51. #include "filedefs.h"
  52. #define NOSTRUNDO
  53. #include "str.h"
  54. #include "debug.h"
  55. extern int vfDiskFull;
  56. extern int vfSysFull;
  57. extern int vfnWriting;
  58. extern CHAR (*rgbp)[cbSector];
  59. extern typeTS tsMruRfn;
  60. extern struct BPS *mpibpbps;
  61. extern int ibpMax;
  62. extern struct FCB (**hpfnfcb)[];
  63. extern typeTS tsMruBps;
  64. extern struct ERFN dnrfn[rfnMax];
  65. extern int iibpHashMax;
  66. extern CHAR *rgibpHash;
  67. extern int rfnMac;
  68. extern int ferror;
  69. extern CHAR szWriteDocPrompt[];
  70. extern CHAR szScratchFilePrompt[];
  71. extern CHAR szSaveFilePrompt[];
  72. #ifdef CKSM
  73. #ifdef DEBUG
  74. extern unsigned (**hpibpcksm) [];
  75. extern int ibpCksmMax;
  76. #endif
  77. #endif
  78. #define IibpHash(fn,pn) ((int) ((fn + 1) * (pn + 1)) & 077777) % iibpHashMax
  79. #ifdef DEBUG
  80. #define STATIC
  81. #else
  82. #define STATIC static
  83. #define ErrorWithMsg( idpmt, szModule ) Error( idpmt )
  84. #define DiskErrorWithMsg( idpmt, szModule ) DiskError( idpmt )
  85. #endif
  86. #define osfnNil (-1)
  87. STATIC int near RfnGrab( void );
  88. STATIC int near FpeSeekFnPn( int, typePN );
  89. STATIC typeOSFN near OsfnEnsureValid( int );
  90. STATIC typeOSFN near OsfnReopenFn( int );
  91. STATIC CHAR *(near SzPromptFromFn( int ));
  92. /* The following debug flags are used to initiate, during debug, specific
  93. low-level disk errors */
  94. #ifdef DEBUG
  95. int vfFakeReadErr = 0;
  96. int vfFakeWriteErr = 0;
  97. int vfFakeOpenErr = 0;
  98. #endif
  99. #ifdef CKSM
  100. #ifdef DEBUG
  101. unsigned CksmFromIbp( ibp )
  102. int ibp;
  103. {
  104. int cb = mpibpbps [ibp].cch;
  105. unsigned cksm = 0;
  106. CHAR *pb;
  107. Assert( ibp >= 0 && ibp < ibpCksmMax );
  108. Assert( mpibpbps [ibp].fn != fnNil );
  109. Assert( !mpibpbps [ibp].fDirty );
  110. pb = rgbp [ibp];
  111. while (cb-- > 0)
  112. cksm += *(pb++);
  113. return cksm;
  114. }
  115. #endif
  116. #endif
  117. typeFC FcMacFromUnformattedFn( fn )
  118. int fn;
  119. { /* Obtain fcMac for passed unformatted fn by seeking to the file's end.
  120. If it fails, return -1
  121. If it succeeds, return the fcMac */
  122. typeFC fcMac;
  123. typeOSFN osfn;
  124. Assert( (fn != fnNil) && (!(**hpfnfcb) [fn].fFormatted) );
  125. if ((osfn = OsfnEnsureValid( fn )) == osfnNil)
  126. return (typeFC) -1;
  127. else
  128. {
  129. if ( FIsErrDwSeek( fcMac=DwSeekDw( osfn, 0L, SF_END )))
  130. {
  131. if (fcMac == fpeBadHndError)
  132. { /* Windows closed the file for us */
  133. if ( ((osfn = OsfnReopenFn( fn )) != osfnNil) &&
  134. !FIsErrDwSeek( fcMac = DwSeekDw( osfn, 0L, SF_END )) )
  135. /* Successfully re-opened file */
  136. return fcMac;
  137. }
  138. if (FIsCaughtDwSeekErr( fcMac ))
  139. /* Suppress reporting of error -- Windows did it */
  140. ferror = TRUE;
  141. DiskErrorWithMsg(IDPMTSDE, " FcMacFromUnformattedFn");
  142. return (typeFC) -1;
  143. }
  144. }
  145. return fcMac;
  146. }
  147. IbpLru(ibpStarting)
  148. int ibpStarting;
  149. /*
  150. Description: Find least recently used BPS (Buffer page) starting
  151. at slot ibpStarting.
  152. Returns: Number of the least recently used buffer slot.
  153. */
  154. {
  155. int ibp, ibpLru = 0;
  156. typeTS ts, tsLru;
  157. struct BPS *pbps = &mpibpbps[ibpStarting];
  158. tsLru = -1; /* Since time stamps are unsigned ints, -1 */
  159. /* is largest time stamp. */
  160. for(ibp = ibpStarting; ibp < ibpMax; ibp++, pbps++)
  161. {
  162. ts = pbps->ts - (tsMruBps + 1);
  163. /* The time stamp can conceivably wrap around and thus a */
  164. /* simple < or > comparison between time stamps cannot be */
  165. /* used to determine which is more or less recently used. */
  166. /* The above statement normalizes time stamps so that the */
  167. /* most recently used is FFFF and the others fall between */
  168. /* 0 and FFFE. This method makes the assumption that */
  169. /* time stamps older than 2^16 clicks of the time stamp */
  170. /* counter have long since disappeared. Otherwise, such */
  171. /* ancients would appear to be what they are not. */
  172. if (ts <= tsLru) {tsLru = ts; ibpLru = ibp;}
  173. }
  174. return(ibpLru);
  175. }
  176. int IbpMakeValid(fn, pn)
  177. int fn;
  178. typePN pn;
  179. { /*
  180. Description: Get page pn of file fn into memory.
  181. Assume not already in memory.
  182. Returns: Bp index (buffer slot #) where the page resides
  183. in memory.
  184. */
  185. #define cbpClump 4
  186. #define cpnAlign 4
  187. #define ALIGN
  188. int ibpT, cbpRead;
  189. int ibp, iibpHash, ibpPrev;
  190. typePN pnT;
  191. register struct BPS *pbps;
  192. int ibpNew;
  193. int cch;
  194. int fFileFlushed;
  195. #ifdef ALIGN
  196. int dibpAlign;
  197. #endif
  198. #ifdef DEBUG
  199. int cbpReadT;
  200. CheckIbp();
  201. #endif /* DEBUG */
  202. Assert(fn != fnNil);
  203. /* page is not currently in memory */
  204. /* We will try to read in cbpClump Buffer Pages beginning with the
  205. least recently used */
  206. /* Pick best starting slot for read based on a least-recently-used scheme */
  207. if (vfnWriting != fnNil)
  208. /* Currently saving file, favor adjacent slots for fn being written */
  209. ibpNew = IbpWriting( fn );
  210. else
  211. /* If reading from the scratch file, do not use the first
  212. cpbMustKeep slots. This is necessary to prevent a disk full
  213. condition from being catastrophic. */
  214. ibpNew = IbpLru( (fn == fnScratch) ? cbpMustKeep : 0 );
  215. /* Empty the slots by flushing out ALL buffers holding pieces of their fn's */
  216. /* Compute cbpRead */
  217. pbps = &mpibpbps[ ibpNew ];
  218. for ( cbpRead = 0; cbpRead < min( cbpClump, ibpMax - ibpNew );
  219. cbpRead++, pbps++ )
  220. {
  221. #ifdef CKSM
  222. #ifdef DEBUG
  223. int ibpT = pbps - mpibpbps;
  224. if (!pbps->fDirty && pbps->fn != fnNil)
  225. Assert( (**hpibpcksm) [ibpT] == CksmFromIbp( ibpT ) );
  226. #endif
  227. #endif
  228. if (pbps->fDirty && pbps->fn != fnNil)
  229. if (!FFlushFn( pbps->fn ))
  230. break;
  231. }
  232. /* If a flush failed, cbpRead was reduced. If it was reduced to 0, this
  233. is serious. If the file was not fnScratch, we can consider it flushed
  234. even though the flush failed, because upper-level procedures will detect
  235. the error and cancel the operation. If it was fnScratch, we must obtain
  236. a new slot for the page we are trying to read */
  237. if (cbpRead == 0)
  238. {
  239. if (pbps->fn == fnScratch)
  240. ibpNew = IbpFindSlot( fn );
  241. cbpRead++;
  242. }
  243. else
  244. { /* Restrict cbpRead according to the following:
  245. (1) If we are reading in the text area, we don't want to
  246. free pages for stuff past the end of the text area
  247. that we know CchPageIn won't give us
  248. (2) If we are reading in the properties area, we only want to
  249. read one page, because FetchCp depends on us not trashing
  250. the MRU page */
  251. struct FCB *pfcb = &(**hpfnfcb)[fn];
  252. if (pfcb->fFormatted && fn != fnScratch && pn >= pfcb->pnChar)
  253. cbpRead = 1;
  254. else
  255. {
  256. typePN cbpValid = (pfcb->fcMac - (pn * cfcPage)) / cfcPage;
  257. cbpRead = min( cbpRead, max( 1, cbpValid ) );
  258. }
  259. }
  260. #ifdef ALIGN
  261. /* Align the read request on an even sector boundary, for speed */
  262. dibpAlign = (pn % cpnAlign);
  263. if (cbpRead > dibpAlign)
  264. /* We are reading enough pages to cover the desired one */
  265. pn -= dibpAlign;
  266. else
  267. dibpAlign = 0;
  268. #endif
  269. /* Remove flushed slots from their hash chains */
  270. for ( pbps = &mpibpbps[ ibpT = ibpNew + cbpRead - 1 ];
  271. ibpT >= ibpNew;
  272. ibpT--, pbps-- )
  273. if (pbps->fn != fnNil)
  274. FreeBufferPage( pbps->fn, pbps->pn );
  275. /* Free slots holding any existing copies of pages to be read */
  276. #ifdef DBCS /* was in KKBUGFIX */
  277. /* In #else code ,If pn= 8000H(= -32768), pnT can not be littler than pn */
  278. for ( pnT = pn + cbpRead; pnT > pn; pnT-- ) // Assume cbpRead > 0
  279. FreeBufferPage( fn, pnT-1 );
  280. #else
  281. for ( pnT = pn + cbpRead - 1; (int)pnT >= (int)pn; pnT-- )
  282. FreeBufferPage( fn, pnT );
  283. #endif
  284. /* Read contents of file page(s) into buffer slot(s) */
  285. cch = CchPageIn( fn, pn, rgbp[ibpNew], cbpRead );
  286. #ifdef DEBUG
  287. cbpReadT = cbpRead;
  288. #endif
  289. /* Fill in bps records for as many bytes as were read, but always
  290. at least one record (to support PnAlloc). If we reached the end of the
  291. file, the unfilled bps slots are left free */
  292. pbps = &mpibpbps[ ibpT = ibpNew ];
  293. do
  294. {
  295. pbps->fn = fn;
  296. pbps->pn = pn;
  297. pbps->ts = ++tsMruBps; /* mark page as MRUsed */
  298. pbps->fDirty = false;
  299. pbps->cch = min( cch, cbSector );
  300. pbps->ibpHashNext = ibpNil;
  301. cch = max( cch - cbSector, 0 );
  302. /* put in new hash table entry for fn,pn */
  303. iibpHash = IibpHash(fn, pn);
  304. ibp = rgibpHash[iibpHash];
  305. ibpPrev = ibpNil;
  306. while (ibp != ibpNil)
  307. {
  308. ibpPrev = ibp;
  309. ibp = mpibpbps[ibp].ibpHashNext;
  310. }
  311. if (ibpPrev == ibpNil)
  312. rgibpHash[iibpHash] = ibpT;
  313. else
  314. mpibpbps[ibpPrev].ibpHashNext = ibpT;
  315. pn++; ibpT++; pbps++;
  316. } while ( (--cbpRead > 0) && (cch > 0) );
  317. #ifdef CKSM
  318. #ifdef DEBUG
  319. /* Compute checksums for newly read pages */
  320. {
  321. int ibp;
  322. for ( ibp = ibpNew; ibp < ibpNew + cbpReadT; ibp++ )
  323. if (mpibpbps [ibp].fn != fnNil && !mpibpbps [ibp].fDirty)
  324. (**hpibpcksm) [ibp] = CksmFromIbp( ibp );
  325. }
  326. CheckIbp();
  327. #endif /* DEBUG */
  328. #endif
  329. #ifdef ALIGN
  330. return (ibpNew + dibpAlign);
  331. #else
  332. return (ibpNew);
  333. #endif
  334. } /* end of I b p M a k e V a l i d */
  335. FreeBufferPage( fn, pn )
  336. int fn;
  337. int pn;
  338. { /* Free buffer page holding page pn of file fn if there is one */
  339. /* Flushes fn if page is dirty */
  340. int iibp = IibpHash( fn, pn );
  341. int ibp = rgibpHash[ iibp ];
  342. int ibpPrev = ibpNil;
  343. Assert( fn != fnNil );
  344. while (ibp != ibpNil)
  345. {
  346. struct BPS *pbps=&mpibpbps[ ibp ];
  347. if ( (pbps->fn == fn) && (pbps->pn == pn ) )
  348. { /* Found it. Remove this page from the chain & mark it free */
  349. if (pbps->fDirty)
  350. FFlushFn( fn );
  351. #ifdef CKSM
  352. #ifdef DEBUG
  353. else /* Page has not been trashed while in memory */
  354. {
  355. Assert( (**hpibpcksm) [ibp] == CksmFromIbp( ibp ) );
  356. }
  357. #endif
  358. #endif
  359. if (ibpPrev == ibpNil)
  360. /* First entry in hash chain */
  361. rgibpHash [ iibp ] = pbps->ibpHashNext;
  362. else
  363. mpibpbps[ ibpPrev ].ibpHashNext = pbps->ibpHashNext;
  364. pbps->fn = fnNil;
  365. pbps->fDirty = FALSE;
  366. /* Mark the page not recently used */
  367. pbps->ts = tsMruBps - (ibpMax * 4);
  368. /* Mark pages that are on even clump boundaries a bit less recently
  369. used so they are favored in new allocations */
  370. if (ibp % cbpClump == 0)
  371. --(pbps->ts);
  372. pbps->ibpHashNext = ibpNil;
  373. }
  374. ibpPrev = ibp;
  375. ibp = pbps->ibpHashNext;
  376. }
  377. #ifdef DEBUG
  378. CheckIbp();
  379. #endif
  380. }
  381. int CchPageIn(fn, pn, rgbBuf, cpnRead)
  382. int fn;
  383. typePN pn;
  384. CHAR rgbBuf[];
  385. int cpnRead;
  386. { /*
  387. Description: Read a cpnRead pages of file fn from disk into rgbBuf.
  388. Have already determined that page is not resident
  389. in the buffer.
  390. Returns: Number of valid chars read (zero or positive #).
  391. */
  392. struct FCB *pfcb = &(**hpfnfcb)[fn];
  393. typeFC fcMac = pfcb->fcMac;
  394. typeFC fcPage = pn * cfcPage;
  395. int dfc;
  396. int fCharFormatInfo; /* if reading Format info part of */
  397. /* file then = TRUE, text part of */
  398. /* file then = FALSE; */
  399. /* No reads > 32767 bytes, so dfc can be int */
  400. Assert( cpnRead <= 32767 / cbSector );
  401. /* Don't try to read beyond pnMac */
  402. if (cpnRead > pfcb->pnMac - pn)
  403. cpnRead = pfcb->pnMac - pn;
  404. dfc = cpnRead * (int)cfcPage;
  405. if (pn >= pfcb->pnMac) /* are we trying to read beyond eof? */
  406. {
  407. return 0; /* Nothing to read */
  408. }
  409. else if (pfcb->fFormatted && fn != fnScratch
  410. && fn != vfnWriting /* Since pnChar is zero in this case */
  411. && pn >= pfcb->pnChar)
  412. { /* reading character format info portion of file */
  413. fCharFormatInfo = TRUE;
  414. }
  415. else /* reading text portion of file */
  416. { /* get dfc (cch) from fcMac */
  417. typeFC dfcT = fcMac - fcPage;
  418. fCharFormatInfo = FALSE;
  419. if (dfcT < dfc)
  420. dfc = (int) dfcT;
  421. else if (dfc <= fc0) /* Nothing to read, so let's avoid disk access. */
  422. {
  423. return 0;
  424. }
  425. }
  426. return CchReadAtPage( fn, pn, rgbBuf, (int)dfc, fCharFormatInfo );
  427. }
  428. CchReadAtPage( fn, pn, rgb, dfc, fSeriousErr )
  429. int fn;
  430. typePN pn;
  431. CHAR rgb[];
  432. int dfc;
  433. int fSeriousErr;
  434. { /*
  435. Description: Read dfc bytes of file fn starting at page pn
  436. into rgb
  437. Returns: Number of valid chars read (zero or positive #)
  438. Errors: Returns # of chars read; ferror & vfDiskFull are
  439. set (in DiskError) if an error occurs.
  440. Notes: Caller is responsible for assuring that the page
  441. range read is reasonable wrt the fn
  442. */
  443. typeOSFN osfn;
  444. int fpeSeek;
  445. int fpeRead;
  446. int fCaught; /* Whether error was reported by DOS */
  447. #ifdef DEBUG
  448. if (vfFakeReadErr)
  449. {
  450. dfc = 0;
  451. goto ReportErr;
  452. }
  453. #endif
  454. if (!FIsErrFpe( fpeSeek = FpeSeekFnPn( fn, pn )))
  455. {
  456. osfn = OsfnEnsureValid( fn );
  457. #ifdef DEBUG
  458. #ifdef DFILE
  459. CommSzSz( "Read from file: ", &(**(**hpfnfcb)[fn].hszFile)[0] );
  460. #endif
  461. #endif
  462. if ((fpeRead = CchReadDoshnd( osfn, (CHAR FAR *)rgb, dfc )) == dfc)
  463. { /* Read succeeded */
  464. return dfc;
  465. }
  466. else
  467. {
  468. /* Should be guaranteed that file was not closed because of seek */
  469. Assert( fpeRead != fpeBadHndError );
  470. fCaught = FIsCaughtFpe( fpeRead );
  471. }
  472. }
  473. else
  474. fCaught = FIsCaughtFpe( fpeSeek );
  475. /* unable to set position or read */
  476. if ((fn == fnScratch) || (fSeriousErr))
  477. { /* unrecoverable error: either can't read from scratch */
  478. /* file or unable to read format info (FIB or format pages) part of */
  479. /* of some file. */
  480. dfc = 0;
  481. goto ReportErr;
  482. }
  483. else /* serious disk error on file (recoverable).*/
  484. {
  485. int cchRead = (FIsErrFpe(fpeSeek) || FIsErrFpe(fpeRead)) ? 0 : fpeRead;
  486. CHAR *pch = &rgb[cchRead];
  487. int cch = dfc - cchRead;
  488. /* If the positioning failed or the read failed
  489. for a reason other than disk full, completely
  490. fill the buffer with 'X's. Otherwise, just
  491. fill the disputed portion (diff between #char
  492. requested and #char read) with 'X's */
  493. while (cch-- > 0)
  494. *pch++ = 'X';
  495. ReportErr:
  496. if (fCaught)
  497. /* Suppress reporting of the error -- Windows reported it */
  498. ferror = TRUE;
  499. if (pn != 0)
  500. /* Report error if not reading FIB */
  501. DiskErrorWithMsg(IDPMTSDE, " CchReadAtPage");
  502. return (int)dfc;
  503. /* recovery is accomplished: 1) Upper level procedures do not
  504. see any change in the world, 2) the worst thing that
  505. happens is that the user sees some 'X's on the screen. */
  506. }
  507. }
  508. AlignFn(fn, cch, fEven)
  509. int fn, cch;
  510. { /* Make sure we have cch contiguous chars in fn */
  511. /* if fEven, make sure fcMac is even */
  512. struct FCB *pfcb = &(**hpfnfcb)[fn];
  513. typeFC fcMac = pfcb->fcMac;
  514. typePN pn;
  515. typeFC fcFirstPage;
  516. pn = fcMac / cfcPage;
  517. fcFirstPage = (pn + 1) * cfcPage;
  518. Assert(cch <= cfcPage);
  519. if (fEven && (fcMac & 1) != 0)
  520. ++cch;
  521. if (fcFirstPage - fcMac < cch)
  522. {
  523. struct BPS *pbps = &mpibpbps[IbpEnsureValid(fn, pn++)];
  524. pbps->cch = cfcPage;
  525. pbps->fDirty = true;
  526. fcMac = pfcb->fcMac = fcFirstPage;
  527. }
  528. if (fEven && (fcMac & 1) != 0)
  529. {
  530. struct BPS *pbps = &mpibpbps[IbpEnsureValid(fn, pn)];
  531. pbps->cch++;
  532. pbps->fDirty = true;
  533. pfcb->fcMac++;
  534. }
  535. } /* end of A l i g n F n */
  536. /*** OsfnEnsureValid - ensure that file fn is open
  537. *
  538. *
  539. */
  540. STATIC typeOSFN near OsfnEnsureValid(fn)
  541. int fn;
  542. { /*
  543. Description: Ensure that file fn is open (really)
  544. Returns: operating system file number (osfnNil if error)
  545. */
  546. struct FCB *pfcb = &(**hpfnfcb)[fn];
  547. int rfn = pfcb->rfn;
  548. if (rfn == rfnNil)
  549. { /* file doesn't have a rfn - ie. it is not opened */
  550. #ifdef DEBUG
  551. #ifdef DFILE
  552. CommSzSz( pfcb->fOpened ? "Re-opening file " :
  553. "Opening file", **pfcb->hszFile );
  554. #endif
  555. if (vfFakeOpenErr || !FAccessFn( fn, dtyNormal ))
  556. #else
  557. if (!FAccessFn( fn, dtyNormal ))
  558. #endif
  559. { /* unrecoverable error - unable to open file */
  560. DiskErrorWithMsg(IDPMTSDE, " OsfnEnsureValid");
  561. return osfnNil;
  562. }
  563. rfn = pfcb->rfn;
  564. Assert( (rfn >= 0) && (rfn < rfnMac) );
  565. }
  566. return dnrfn[rfn].osfn;
  567. }
  568. /* end of O s F n E n s u r e V a l i d */
  569. STATIC int near FpeSeekFnPn( fn, pn )
  570. int fn;
  571. typePN pn;
  572. { /* Seek to page pn of file fn
  573. return err code on failure, fpeNoErr on success
  574. Leaves file open (if no error occurs)
  575. Recovers from the case in which windows closed the file for us
  576. */
  577. typeOSFN osfn;
  578. long dwSeekReq;
  579. long dwSeekAct;
  580. #ifdef DEBUG
  581. #ifdef DFILE
  582. CommSzSz( "Seeking within file ", **(**hpfnfcb)[fn].hszFile );
  583. #endif
  584. #endif
  585. //osfn = OsfnEnsureValid( fn );
  586. if ((osfn = OsfnEnsureValid( fn )) == osfnNil)
  587. return fpeNoAccError;
  588. dwSeekReq = (long) pn * (long) cbSector;
  589. dwSeekAct = DwSeekDw( osfn, dwSeekReq, SF_BEGINNING);
  590. if ( ((int) dwSeekAct) == fpeBadHndError )
  591. { /* Windows closed the file for us -- must reopen it */
  592. if ((osfn = OsfnReopenFn( fn )) == osfnNil)
  593. return fpeNoAccError;
  594. else
  595. dwSeekAct = DwSeekDw( osfn, dwSeekReq, SF_BEGINNING );
  596. }
  597. return (dwSeekAct >= 0) ? fpeNoErr : (int) dwSeekAct;
  598. }
  599. int FFlushFn(fn)
  600. int fn;
  601. { /*
  602. Description: Write all dirty pages of fn to disk.
  603. Sets vfSysFull = TRUE if disk full error occurred
  604. while flushing fnScratch. Otherwise, a disk full
  605. error causes vfDiskFull = TRUE.
  606. Serious disk errors cause vfDiskError = TRUE
  607. Only the pages which actually made it to disk are
  608. marked as non-dirty.
  609. Returns: TRUE if successful, FALSE if Disk full error
  610. while writing pages to disk. Any other error
  611. is unrecoverable, ie. go back to main loop.
  612. To avoid extraneous error messages, the following
  613. two entry conditions cause FFlush to immediately
  614. return FALSE:
  615. - If vfSysFull = TRUE and fn = fnScratch
  616. - If vfDiskFull = TRUE and fn = vfnWriting
  617. */
  618. int ibp;
  619. typeOSFN osfn;
  620. int fpe;
  621. int cchWritten;
  622. int cchAskWrite;
  623. struct BPS *pbps;
  624. Assert( fn != fnNil );
  625. if ((vfSysFull) && (fn == fnScratch)) return (FALSE);
  626. if ((vfDiskFull) && (fn == vfnWriting)) return (FALSE);
  627. for (ibp = 0, pbps = mpibpbps; ibp < ibpMax; )
  628. {
  629. if (pbps->fn == fn && pbps->fDirty)
  630. {
  631. typePN pn = pbps->pn;
  632. int cbp = 0;
  633. CHAR *pch = (CHAR *)rgbp[ibp];
  634. struct BPS *pbpsStart = &mpibpbps[ibp];
  635. /* Coalesce all consecutive pages for a single write */
  636. do
  637. {
  638. /* taken out 11/7/84 - can't mark scratch file
  639. page as non dirty if chance that it will never
  640. get written out (write fails - disk full)
  641. pbps->fDirty = false; mark page as clean */
  642. ++ibp, ++cbp, ++pbps;
  643. } while (ibp < ibpMax && pbps->fn == fn && pbps->pn == pn + cbp);
  644. /* Now do the write, checking for out of disk space */
  645. Scribble(3, 'W');
  646. cchAskWrite = (int)cbSector * (cbp - 1) + (pbps - 1)->cch;
  647. cchWritten = cchDiskHardError; /* assure hard error if seek fails */
  648. #ifdef DEBUG
  649. if (vfFakeWriteErr)
  650. goto SeriousError;
  651. else
  652. #endif
  653. if ( FIsErrFpe( FpeSeekFnPn( fn, pn )) ||
  654. ((osfn = OsfnEnsureValid( fn )) == osfnNil) ||
  655. #ifdef DEBUG
  656. #ifdef DFILE
  657. (CommSzSz( "Writing to file: ", &(**(**hpfnfcb)[fn].hszFile)[0] ),
  658. #endif
  659. #endif
  660. (( cchWritten = CchWriteDoshnd( osfn, (CHAR FAR *)pch,
  661. cchAskWrite )) != cchAskWrite))
  662. #ifdef DEBUG
  663. #ifdef DFILE
  664. )
  665. #endif
  666. #endif
  667. {
  668. /* Should be guaranteed that windows did not close the file
  669. since we have not called intermodule since the seek */
  670. Assert( cchWritten != fpeBadHndError );
  671. /* Seek or Write error */
  672. if ( !FIsErrCchDisk(cchWritten) )
  673. { /* serious but recoverable disk error */
  674. /* Ran out of disk space; write failed */
  675. if (fn == fnScratch)
  676. vfSysFull = fTrue;
  677. vfDiskFull = fTrue;
  678. DiskErrorWithMsg(IDPMTDFULL, " FFlushFn");
  679. return(FALSE);
  680. }
  681. else /* cause of error is not disk full */
  682. { /* unrecov. disk error */
  683. #ifdef DEBUG
  684. SeriousError:
  685. #endif
  686. DiskErrorWithMsg(IDPMTSDE2, " FFlushFn");
  687. return FALSE;
  688. }
  689. }
  690. Diag(CommSzNumNum(" cchWritten, cchAskWrite ",cchWritten,cchAskWrite));
  691. /* ---- write was successful ---- */
  692. Scribble(3, ' ');
  693. while (cbp-- > 0)
  694. { /* mark pages actually copied to disk as non dirty */
  695. (pbpsStart++)->fDirty = false;
  696. #ifdef CKSM
  697. #ifdef DEBUG
  698. {
  699. int ibpT = pbpsStart - 1 - mpibpbps;
  700. /* Recompute checksums for pages which are now clean */
  701. (**hpibpcksm) [ibpT] = CksmFromIbp( ibpT );
  702. }
  703. #endif
  704. #endif
  705. }
  706. }
  707. else
  708. {
  709. ++ibp;
  710. ++pbps;
  711. }
  712. }
  713. return (TRUE);
  714. }
  715. #ifdef DEBUG
  716. CheckIbp()
  717. {
  718. /* Walk through the rgibpHash and the mpibpbps structure to make sure all of
  719. the links are right. */
  720. /* 10/11/85 - Added extra Assert ( FALSE ) so we get the messages instead
  721. of a freeze-up on systems not connected to a COM port.
  722. Ignoring the assertion will produce the RIP with the ibp info */
  723. extern int fIbpCheck;
  724. int rgfibp[255];
  725. int ibp;
  726. int ibpHash;
  727. int iibp;
  728. static BOOL bAsserted=FALSE;
  729. if (fIbpCheck && !bAsserted)
  730. {
  731. if (!(ibpMax < 256))
  732. {
  733. Assert(0);
  734. bAsserted=TRUE;
  735. return;
  736. }
  737. bltc(rgfibp, false, ibpMax);
  738. /* Are there any circular links in mpibpbps? */
  739. for (iibp = 0; iibp < iibpHashMax; iibp++)
  740. {
  741. if ((ibpHash = rgibpHash[iibp]) != ibpNil)
  742. {
  743. if (!(ibpHash < ibpMax))
  744. {
  745. Assert(0);
  746. bAsserted=TRUE;
  747. return;
  748. }
  749. if (rgfibp[ibpHash])
  750. {
  751. /* Each entry in rgibpHash should point to an unique chain.
  752. */
  753. Assert(0);
  754. bAsserted=TRUE;
  755. #if DUGSTUB
  756. FatalExit(0x100 | ibp);
  757. #endif
  758. return;
  759. }
  760. else
  761. {
  762. rgfibp[ibpHash] = true;
  763. while ((ibpHash = mpibpbps[ibpHash].ibpHashNext) != ibpNil)
  764. {
  765. if (!(ibpHash < ibpMax))
  766. {
  767. Assert(0);
  768. bAsserted=TRUE;
  769. return;
  770. }
  771. if (rgfibp[ibpHash])
  772. {
  773. /* The chain should be non-circular and unique. */
  774. Assert( FALSE );
  775. bAsserted=TRUE;
  776. #if DUGSTUB
  777. FatalExit(0x200 | ibpHash);
  778. #endif
  779. return;
  780. }
  781. rgfibp[ibpHash] = true;
  782. }
  783. }
  784. }
  785. }
  786. /* All chains not pointed to by rgibpHash should be nil. */
  787. for (ibp = 0; ibp < ibpMax; ibp++)
  788. {
  789. if (!rgfibp[ibp])
  790. {
  791. if (mpibpbps[ibp].fn != fnNil)
  792. {
  793. Assert( FALSE );
  794. bAsserted=TRUE;
  795. #if DUGSTUB
  796. FatalExit(0x400 | mpibpbps[ibp].fn);
  797. #endif
  798. return;
  799. }
  800. if (mpibpbps[ibp].ibpHashNext != ibpNil)
  801. {
  802. Assert( FALSE );
  803. bAsserted=TRUE;
  804. #if DUGSTUB
  805. FatalExit(0x300 | ibp);
  806. #endif
  807. return;
  808. }
  809. }
  810. }
  811. }
  812. }
  813. #endif /* DEBUG */
  814. /* Formerly fileOC.c -- file open and close routines */
  815. /*** SetRfnMac - set usable # of rfn slots
  816. *
  817. * ENTRY: crfn - desired # of rfn slots
  818. * EXIT: (global) rfnMac - set to crfn, if possible
  819. *
  820. * The ability to adjust the usable # of rfn slots is a new addition in
  821. * Windows Word. The two things that it accomplishes are:
  822. *
  823. * (1) Gives the ability for Word to scale back its need for
  824. * DOS file handles if not enough are available
  825. * (2) Permits Word to attempt to grab more file handles than usual
  826. * when this would help performance (in particular, during
  827. * Transfer Save, when the original, scratch, and write files
  828. * are most commonly open)
  829. *
  830. */
  831. SetRfnMac( crfn )
  832. int crfn;
  833. {
  834. int rfn;
  835. Assert( (crfn > 0) && (crfn <= rfnMax) );
  836. Assert( (sizeof (struct ERFN) & 1) == 0); /* ERFN must be even for blt */
  837. if (crfn > rfnMac)
  838. { /* Add rfn slots */
  839. for ( rfn = rfnMac; rfn < crfn; rfn++ )
  840. dnrfn [rfn].fn = fnNil; /* These will get used next (see RfnGrab)*/
  841. rfnMac = crfn;
  842. }
  843. else /* Lose Rfn slots (keep the most recently used one(s)) */
  844. while ( rfnMac > crfn )
  845. {
  846. int rfnLru=RfnGrab();
  847. int fn;
  848. if ( (rfnLru != --rfnMac) && ((fn = dnrfn [rfnMac].fn) != fnNil) )
  849. {
  850. extern int fnMac;
  851. Assert( fn >= 0 && fn < fnMac );
  852. (**hpfnfcb) [fn].rfn = rfnLru;
  853. blt( &dnrfn [rfnMac], &dnrfn [rfnLru],
  854. sizeof(struct ERFN)/sizeof(int) );
  855. }
  856. }
  857. }
  858. /*========================================================*/
  859. STATIC int near RfnGrab()
  860. { /*
  861. Description: Allocate the least recently used rfn (real file #)
  862. slot for a new file.
  863. Returns: rfn slot number. */
  864. int rfn = 0, rfnLru = 0;
  865. typeTS ts, tsLru;
  866. struct ERFN *perfn = &dnrfn[rfn];
  867. /* Time stamp algorithm akin to method used with Bps. */
  868. /* See IbpLru in file.c for comments. */
  869. tsLru = -1; /* max unsigned number */
  870. for ( rfn = 0; rfn < rfnMac ; rfn++, perfn++ )
  871. {
  872. ts = perfn->ts - (tsMruRfn + 1);
  873. if (perfn->fn == fnNil)
  874. ts = ts - rfnMac;
  875. /* cluge: If slot is unused, give it a lower ts. */
  876. /* This ensures that an occupied slot can never be */
  877. /* swapped out if a empty one exists. */
  878. if (ts <= tsLru)
  879. {
  880. tsLru = ts;
  881. rfnLru = rfn;
  882. }
  883. }
  884. if (dnrfn [rfnLru].fn != fnNil)
  885. CloseRfn( rfnLru );
  886. return rfnLru;
  887. }
  888. CloseFn( fn )
  889. int fn;
  890. { /* Close file fn if it is currently open */
  891. int rfn;
  892. if (fn == fnNil)
  893. return;
  894. if (((rfn = (**hpfnfcb)[fn].rfn) != rfnNil) && (rfn != rfnFree))
  895. CloseRfn( rfn );
  896. }
  897. OpenEveryHardFn()
  898. { /* For each fn representing a file on nonremoveable media,
  899. try to open it. It is not guaranteed that any or all such files
  900. will be open on return from this routine -- we are merely attempting
  901. to assert our ownership of these files on a network by keeping them open */
  902. extern int fnMac;
  903. int fn;
  904. struct FCB *pfcb;
  905. #ifdef DFILE
  906. extern int docCur;
  907. CommSzNum("OpenEveryHardFn: docCur ", docCur);
  908. #endif
  909. for ( fn = 0, pfcb = &(**hpfnfcb) [0] ; fn < fnMac; fn++, pfcb++ )
  910. {
  911. /* Bryanl 3/26/87: only call FAccessFn if rfn == rfnNil, to prevent
  912. multiple opens of the same file, which fail if the sharer is loaded */
  913. #ifdef DFILE
  914. {
  915. char rgch[100];
  916. if (pfcb->rfn == rfnNil && ((POFSTRUCT)(pfcb->rgbOpenFileBuf))->fFixedDisk)
  917. {
  918. wsprintf(rgch," fn %d, hszFile %s \n\r",fn,(LPSTR)(**pfcb->hszFile));
  919. CommSz(rgch);
  920. wsprintf(rgch," OFSTR %s \n\r", (LPSTR)(((POFSTRUCT)pfcb->rgbOpenFileBuf)->szPathName));
  921. CommSz(rgch);
  922. }
  923. else
  924. {
  925. wsprintf(rgch," fn %d, not accessing, sz %s\n\r", fn, (LPSTR) (LPSTR)(**pfcb->hszFile));
  926. CommSz(rgch);
  927. wsprintf(rgch," OFSTR %s \n\r", (LPSTR)(((POFSTRUCT)pfcb->rgbOpenFileBuf)->szPathName));
  928. CommSz(rgch);
  929. }
  930. }
  931. #endif
  932. if (pfcb->rfn == rfnNil && ((POFSTRUCT)(pfcb->rgbOpenFileBuf))->fFixedDisk)
  933. { /* fn refers to a file on nonremoveable media */
  934. FAccessFn( fn, dtyNormal );
  935. }
  936. }
  937. }
  938. STATIC typeOSFN near OsfnReopenFn( fn )
  939. int fn;
  940. { /* Reopen file fn after it was automatically closed by Windows due
  941. to disk swap. State is: fn has an rfn but rfn's osfn has been
  942. made a "bad handle" */
  943. struct FCB *pfcb = &(**hpfnfcb) [fn];
  944. int rfn = pfcb->rfn;
  945. typeOSFN osfn;
  946. WORD wOpen;
  947. Assert( fn != fnNil );
  948. Assert( rfn != rfnNil );
  949. Assert( pfcb->fOpened);
  950. /* Only files on floppies are automatically closed */
  951. Assert( ! ((POFSTRUCT)(pfcb->rgbOpenFileBuf))->fFixedDisk );
  952. #ifdef DEBUG
  953. #ifdef DFILE
  954. CommSzSz( "Opening after WINDOWS close: ", **pfcb->hszFile );
  955. #endif
  956. #endif
  957. wOpen = OF_REOPEN | OF_PROMPT | OF_CANCEL | OF_SHARE_DENY_WRITE |
  958. ((pfcb->mdFile == mdBinary) ? OF_READWRITE : OF_READ );
  959. SetErrorMode(1);
  960. osfn = OpenFile( (LPSTR) SzPromptFromFn( fn ),
  961. (LPOFSTRUCT) pfcb->rgbOpenFileBuf, wOpen );
  962. SetErrorMode(0);
  963. if (osfn == -1)
  964. return osfnNil;
  965. else
  966. {
  967. dnrfn[ rfn ].osfn = osfn;
  968. }
  969. return osfn;
  970. }
  971. FAccessFn( fn, dty)
  972. int fn;
  973. int dty;
  974. { /* Description: Access file which is not currently opened.
  975. Open file and make an appropriate entry in the
  976. rfn table. Put the rfn into (**hpfnfcb)[fn].rfn.
  977. Returns: TRUE on success, FALSE on failure
  978. */
  979. extern int vwDosVersion;
  980. extern HANDLE hParentWw;
  981. extern HWND vhWndMsgBoxParent;
  982. int rfn;
  983. register struct FCB *pfcb = &(**hpfnfcb)[fn];
  984. typeOSFN osfn;
  985. int wOpen;
  986. #ifdef DEBUG
  987. int junk;
  988. Assert(FValidFile(**pfcb->hszFile, CchSz(**pfcb->hszFile)-1, &junk));
  989. #ifdef DFILE
  990. {
  991. char rgch[100];
  992. CommSzSz("FAccessFn: ", pfcb->fOpened ? SzPromptFromFn( fn ) : &(**pfcb->hszFile)[0]);
  993. wsprintf(rgch, " * OFSTR before %s \n\r", (LPSTR)(((POFSTRUCT)pfcb->rgbOpenFileBuf)->szPathName));
  994. CommSz(rgch);
  995. }
  996. #endif
  997. #endif /*DEBUG*/
  998. if ((**pfcb->hszFile)[0] == 0) /* if file name field is blank, */
  999. return FALSE; /* unable to open file */
  1000. wOpen = /*OF_PROMPT + OF_CANCEL + (6.21.91) v-dougk bug #6910 */
  1001. (((pfcb->mdFile == mdBinary) ?
  1002. OF_READWRITE : OF_READ) |
  1003. OF_SHARE_DENY_WRITE);
  1004. if (pfcb->fOpened)
  1005. wOpen += OF_REOPEN;
  1006. else if (pfcb->fSearchPath)
  1007. wOpen += OF_VERIFY;
  1008. if ((vwDosVersion & 0x7F) >= 2)
  1009. {
  1010. WORD da;
  1011. if ((vwDosVersion & 0x7F) >= 3)
  1012. /* Above DOS 3, set attributes to deny access if the sharer is in */
  1013. wOpen += bSHARE_DENYRDWR;
  1014. if ( ( (pfcb->mdFile == mdBinary) && (!pfcb->fOpened)) &&
  1015. ((da = DaGetFileModeSz( &(**pfcb->hszFile) [0] )) != DA_NIL) &&
  1016. (da & DA_READONLY) )
  1017. { /* This is here because the Novell net does not allow us to test
  1018. for read-only files by opening in read/write mode -- it lets
  1019. us open them anyway! */
  1020. goto TryReadOnly;
  1021. }
  1022. }
  1023. for ( ;; )
  1024. {
  1025. /* OpenFile's first parm is a filename when opening for the
  1026. first time, a prompt on successive occasions (OF_REOPEN) */
  1027. SetErrorMode(1);
  1028. osfn = OpenFile( pfcb->fOpened ?
  1029. (LPSTR) SzPromptFromFn( fn ) :
  1030. (LPSTR) &(**pfcb->hszFile)[0],
  1031. (LPOFSTRUCT) &pfcb->rgbOpenFileBuf[0],
  1032. wOpen );
  1033. SetErrorMode(0);
  1034. if (osfn != -1) /* Note != -1: osfn is unsigned */
  1035. { /* Opened file OK */
  1036. #ifdef DFILE
  1037. {
  1038. char rgch[100];
  1039. wsprintf(rgch, " * OFSTR now %s \n\r", (LPSTR)(((POFSTRUCT)(**hpfnfcb) [fn].rgbOpenFileBuf)->szPathName));
  1040. CommSz(rgch);
  1041. }
  1042. #endif
  1043. if (!pfcb->fOpened)
  1044. { /* First time through: OpenFile may have given us a
  1045. different name for the file */
  1046. CHAR szT [cchMaxFile];
  1047. CHAR (**hsz) [];
  1048. #if WINVER >= 0x300
  1049. /* Currently: FNormSzFile *TAKES* an OEM sz, and
  1050. *RETURNS* an ANSI sz ..pault */
  1051. #endif
  1052. if (FNormSzFile( szT, ((POFSTRUCT)pfcb->rgbOpenFileBuf)->szPathName,
  1053. dty ) &&
  1054. WCompSz( szT, &(**pfcb->hszFile) [0] ) != 0 &&
  1055. FnFromSz( szT ) == fnNil &&
  1056. !FNoHeap( hsz = HszCreate( szT )))
  1057. {
  1058. /* Yes, indeed, the name OpenFile gave us was different.
  1059. Put the normalized version into the fcb entry */
  1060. FreeH( (**hpfnfcb) [fn].hszFile ); /* HEAP MOVEMENT */
  1061. (**hpfnfcb) [fn].hszFile = hsz;
  1062. }
  1063. }
  1064. break; /* We succeeded; break out of the loop */
  1065. }
  1066. else
  1067. { /* Open failed -- try read-only; don't prompt this time */
  1068. if ( (pfcb->mdFile == mdBinary) && (!pfcb->fOpened) )
  1069. { /* Failed as read/write; try read-only */
  1070. /* Check for sharing violation */
  1071. if (((vwDosVersion & 0x7F) >= 3) &&
  1072. (((POFSTRUCT) pfcb->rgbOpenFileBuf)->nErrCode == nErrNoAcc))
  1073. {
  1074. if ( DosxError() == dosxSharing )
  1075. {
  1076. extern int vfInitializing;
  1077. int fT = vfInitializing;
  1078. vfInitializing = FALSE; /* Report this err, even during inz */
  1079. {
  1080. char szMsg[cchMaxSz];
  1081. MergeStrings (IDPMTCantShare, **pfcb->hszFile, szMsg);
  1082. IdPromptBoxSz(vhWndMsgBoxParent ? vhWndMsgBoxParent : hParentWw, szMsg, MB_OK|MB_ICONEXCLAMATION);
  1083. }
  1084. vfInitializing = fT;
  1085. return FALSE;
  1086. }
  1087. }
  1088. TryReadOnly:
  1089. pfcb->mdFile = mdBinRO;
  1090. wOpen = OF_READ;
  1091. if (pfcb->fOpened)
  1092. wOpen += OF_REOPEN;
  1093. #ifdef ENABLE
  1094. else if (pfcb->fSearchPath)
  1095. wOpen += OF_VERIFY;
  1096. #endif
  1097. }
  1098. else
  1099. {
  1100. if ((**hpfnfcb)[fn].fDisableRead)
  1101. /* already reported */
  1102. {
  1103. ferror = TRUE;
  1104. return FALSE;
  1105. }
  1106. else
  1107. { /* Could not find file in place specified */
  1108. char szMsg[cchMaxSz];
  1109. extern int ferror;
  1110. extern int vfInitializing;
  1111. int fT = vfInitializing;
  1112. BOOL bRetry=TRUE;
  1113. extern struct DOD (**hpdocdod)[];
  1114. extern int docCur;
  1115. /* get user to put file back */
  1116. MergeStrings (IDPMTFileNotFound, **pfcb->hszFile, szMsg);
  1117. vfInitializing = FALSE; /* Report this err, even during inz */
  1118. /*
  1119. This is frippin insidious. MessageBox yields and allows us to get
  1120. into here again before it has even been issued!
  1121. */
  1122. (**hpdocdod)[docCur].fDisplayable = FALSE; // block redraws
  1123. /* if we're being called from a message box, then use it
  1124. as the parent window, otherwise use main write window */
  1125. if (IdPromptBoxSz(vhWndMsgBoxParent ? vhWndMsgBoxParent : hParentWw,
  1126. szMsg, MB_OKCANCEL | MB_ICONEXCLAMATION | MB_APPLMODAL)
  1127. == IDCANCEL)
  1128. {
  1129. vfInitializing = fT;
  1130. (**hpfnfcb)[fn].fDisableRead = TRUE;
  1131. ferror = TRUE; /* need to flag */
  1132. bRetry = FALSE;
  1133. }
  1134. (**hpdocdod)[docCur].fDisplayable = TRUE; // unblock redraws
  1135. vfInitializing = fT;
  1136. if (!bRetry)
  1137. return FALSE;
  1138. }
  1139. }
  1140. }
  1141. }
  1142. pfcb->fOpened = TRUE;
  1143. rfn = RfnGrab();
  1144. {
  1145. struct ERFN *perfn = &dnrfn [rfn];
  1146. perfn->osfn = osfn;
  1147. perfn->fn = fn;
  1148. perfn->ts = ++tsMruRfn; /* mark Rfn as MRused */
  1149. }
  1150. (**hpfnfcb) [fn].rfn = rfn;
  1151. (**hpfnfcb) [fn].fDisableRead = FALSE;
  1152. return TRUE;
  1153. }
  1154. FCreateFile( szFile, fn ) /* returns szFile in ANSI ..pault */
  1155. CHAR *szFile;
  1156. int fn;
  1157. { /* Create a new, unique file.
  1158. Return the name in szFile.
  1159. Returns TRUE on success, FALSE on failure.
  1160. Leaves the filename in (**hpfnfcb)[fn].hszFile (if successful),
  1161. the rfn in (**hpfnfcb)[fn].rfn.
  1162. If szFile begins "X:...", creates the file on the specified drive;
  1163. otherwise, creates the file on a drive of Windows' choice */
  1164. extern CHAR szExtDoc[];
  1165. CHAR (**hsz)[];
  1166. CHAR szFileT [cchMaxFile];
  1167. if (!GetTempFileName(szFile[0] | ((szFile[1] == ':') ? TF_FORCEDRIVE : 0),
  1168. (LPSTR)(szExtDoc+1), 0, (LPSTR)szFileT) )
  1169. { /* can't create file */
  1170. DiskErrorWithMsg( IDPMTSDE, " RfnCreate" );
  1171. /* recovery is accomplished: only FnCreateSz calls FCreateFile.
  1172. FnCreateSz returns nil if FCreateFile returns FALSE. All of
  1173. FnCreateSz's callers check for nil */
  1174. return FALSE;
  1175. }
  1176. /* Succeeded in creating file */
  1177. FNormSzFile( szFile, szFileT, dtyNormal );
  1178. if ( FNoHeap( hsz = HszCreate( (PCH)szFile )))
  1179. return FALSE;
  1180. (**hpfnfcb) [fn].hszFile = hsz;
  1181. if ( !FAccessFn( fn, dtyNormal ) )
  1182. return FALSE;
  1183. return TRUE;
  1184. } /* end of F C r e a t e F i l e */
  1185. FEnsureOnLineFn( fn )
  1186. int fn;
  1187. { /* Ensure that file fn is on line (i.e. on a disk that is accessible).
  1188. Return TRUE if we were able to guarantee this, FALSE if not */
  1189. int rfn;
  1190. Assert( fn != fnNil );
  1191. if ( ((POFSTRUCT)(**hpfnfcb) [fn].rgbOpenFileBuf)->fFixedDisk )
  1192. /* If it's on nonremovable media, we know it's on line */
  1193. return TRUE;
  1194. /* If it's open, must close and re-open, cause windows might have closed it */
  1195. if ((rfn = (**hpfnfcb) [fn].rfn) != rfnNil)
  1196. CloseRfn( rfn );
  1197. return FAccessFn( fn, dtyNormal );
  1198. }
  1199. typePN PnAlloc(fn)
  1200. int fn;
  1201. { /* Allocate the next page of file fn */
  1202. typePN pn;
  1203. struct BPS *pbps;
  1204. struct FCB *pfcb = &(**hpfnfcb)[fn];
  1205. AlignFn(fn, (int)cfcPage, false);
  1206. pn = pfcb->fcMac / cfcPage;
  1207. pbps = &mpibpbps[IbpEnsureValid(fn, pn)];
  1208. pbps->cch = cfcPage;
  1209. pbps->fDirty = true;
  1210. pfcb->fcMac += cfcPage;
  1211. pfcb->pnMac = pn + 1;
  1212. return pn;
  1213. }
  1214. STATIC CHAR *(near SzPromptFromFn( fn ))
  1215. int fn;
  1216. {
  1217. extern int vfnSaving;
  1218. CHAR *pch;
  1219. Assert( fn != fnNil );
  1220. if (fn == vfnSaving)
  1221. pch = szSaveFilePrompt;
  1222. else if (fn == fnScratch)
  1223. pch = szScratchFilePrompt;
  1224. else
  1225. pch = szWriteDocPrompt;
  1226. return pch;
  1227. }
  1228.