Windows NT 4.0 source code leak
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.

3263 lines
64 KiB

4 years ago
  1. /***********************************************************************
  2. * Microsoft (R) 32-Bit Incremental Linker
  3. *
  4. * Copyright (C) Microsoft Corp 1992-95. All rights reserved.
  5. *
  6. * File: bufio.cpp
  7. *
  8. * File Comments:
  9. *
  10. * Functions which are common to the COFF Linker/Librarian/Dumper.
  11. *
  12. ***********************************************************************/
  13. #include "link.h"
  14. #include <share.h>
  15. #define MAX_WRITEABLE_FILES 16
  16. static PFI pfiCloseOnBadExit[MAX_WRITEABLE_FILES];
  17. // value in buffer map table signifying something
  18. // has previously been to this range
  19. #define pbufPreviousWrite ((PBUF) 0x1)
  20. // default size of writeable files
  21. #define cbDefaultFileSize (4096L * 1024L) // 4Meg
  22. /* buffered i/o routines */
  23. STATIC INT BufferedOpen(PFI, INT, INT, BOOL);
  24. STATIC INT BufferedCloseHard(PFI);
  25. STATIC LONG BufferedSeek(PFI, LONG, INT);
  26. STATIC DWORD BufferedWrite(PFI, const void *, DWORD);
  27. STATIC DWORD BufferedRead(PFI, PVOID, DWORD);
  28. STATIC INT BufferedChSize (PFI, LONG);
  29. /* mapped i/o routines */
  30. INT MappedOpen(PFI, LONG, BOOL, DWORD *);
  31. INT MappedCloseHard(PFI);
  32. LONG MappedSeek(PFI, LONG, INT, DWORD *);
  33. STATIC DWORD MappedWrite(PFI, const void *, DWORD);
  34. STATIC DWORD MappedRead(PFI, PVOID, DWORD);
  35. BOOL ExtendMapView(PFI pfi, DWORD ibNeeded, DWORD *);
  36. BOOL FMapPfi(PFI pfi, BOOL, DWORD *pdwrc);
  37. STATIC INT MappedChSize(PFI, LONG);
  38. /* logical file descriptor manipulators */
  39. STATIC PFI LookupCachedFiles(const char *, INT, INT, BOOL *);
  40. STATIC PFI PfiClosedCached(const char *);
  41. STATIC PFI PfiNew(VOID);
  42. STATIC PFI PfiAlloc(VOID);
  43. STATIC VOID TransitionPFI(PFI, PPFI, PPFI, PPFI, PPFI, BOOL);
  44. STATIC VOID GrowMapTable(PFI);
  45. STATIC VOID CloseSoft(PFI);
  46. /* buffer manipulators */
  47. STATIC BOOL FDeactivateBuf(PBUF);
  48. STATIC BOOL FActivateBuf(PFI, PBUF);
  49. STATIC PBUF PbufNew(VOID);
  50. STATIC PBUF PbufAlloc(PFI, LONG);
  51. STATIC PBUF PbufLRU(VOID);
  52. STATIC VOID MoveToHeadLRU(PBUF);
  53. STATIC VOID SlidePbufCur(PFI);
  54. STATIC VOID FlushBuffer(PBUF);
  55. STATIC VOID ReadpbufCur(PFI);
  56. /* debug routines */
  57. #if DBG
  58. STATIC BOOL FBufListCheck(VOID);
  59. STATIC BOOL FNoDupBuf(PBUF);
  60. STATIC BOOL FPfiInList(PFI, PFI);
  61. STATIC BOOL FPfiCheck(VOID);
  62. #endif // DBG
  63. /* buffer containers */
  64. static PBUF pbufLRUHead; // LRU buffer chain head (MRU)
  65. static PBUF pbufLRUTail; // LRU buffer chain tail (LRU)
  66. static PBUF pbufFree; // free file buffers
  67. static PBUF pbufActive; // active file buffers
  68. /* statistics */
  69. static DWORD crereads; // number of buffer re-reads
  70. static DWORD cfiTot; // total number of logical file descriptors
  71. static DWORD cfiCacheClosed; // current size of closed/cached pool
  72. static DWORD cfiCacheClosedMax; // maximum size of closed/cached pool
  73. /* logical file descriptor containers */
  74. static PFI pfiFree; // free logical file handles
  75. static PFI pfiOpen; // active logical file handles
  76. static PFI pfiClosedHead; // head of list of closed file handles
  77. static PFI pfiClosedTail; // tail of list of closed file handles
  78. PFI *rgpfi; // map of cached file handles
  79. /* error handlers */
  80. static BOOL fMappedIO;
  81. /* State transitions for logical file descriptors. */
  82. /* There are 3 states, open, closed/cached, and free. */
  83. /* The following macros are atomic state transitions. It is likely */
  84. /* cheaper to change states with inline linked list code, however */
  85. /* it becomes difficult to track file handles and the probability of */
  86. /* loosing them increases. */
  87. #define TR_Free_To_Open(pfi) { \
  88. DBEXEC(DB_BUFVERBOSE, DBPRINT(" - pfi = 0x%p free to open (%s)\n", \
  89. (pfi), (pfi)->szFileName)); \
  90. TransitionPFI((pfi), &pfiFree, NULL, &pfiOpen, NULL, 0); }
  91. #define TR_Open_To_Free(pfi) { \
  92. DBEXEC(DB_BUFVERBOSE, DBPRINT(" - pfi = 0x%p open to free (%s)\n", \
  93. (pfi), (pfi)->szFileName)); \
  94. TransitionPFI((pfi), &pfiOpen, NULL, &pfiFree, NULL, 0); }
  95. #define TR_Open_To_Cache(pfi) { \
  96. cfiCacheClosed++; \
  97. DBEXEC(DB_BUFVERBOSE, DBPRINT(" - pfi = 0x%p open to cached (%s)\n", \
  98. (pfi), (pfi)->szFileName)); \
  99. TransitionPFI((pfi), &pfiOpen, NULL, &pfiClosedHead, &pfiClosedTail, 1); }
  100. #define TR_Cache_To_Open(pfi) { \
  101. cfiCacheClosed--; \
  102. DBEXEC(DB_BUFVERBOSE, DBPRINT(" - pfi = 0x%p cached to open (%s)\n", \
  103. (pfi), (pfi)->szFileName)); \
  104. TransitionPFI((pfi), &pfiClosedHead, &pfiClosedTail, &pfiOpen, NULL, 0); }
  105. #define TR_Cache_To_Free(pfi) { \
  106. cfiCacheClosed--; \
  107. DBEXEC(DB_BUFVERBOSE, DBPRINT(" - pfi = 0x%p cached to open (%s)\n", \
  108. (pfi), (pfi)->szFileName)); \
  109. TransitionPFI((pfi), &pfiClosedHead, &pfiClosedTail, &pfiFree, NULL, 0); }
  110. VOID
  111. FileInit(
  112. DWORD cfiNT,
  113. DWORD cfiCacheableNT,
  114. DWORD cfiTNT,
  115. DWORD cfiCacheableTNT)
  116. /*++
  117. Routine Description:
  118. Initialize the buffered i/o package.
  119. Arguments:
  120. Return Value:
  121. None.
  122. --*/
  123. {
  124. HINSTANCE hLib;
  125. DWORD cfi;
  126. DWORD cfiCacheable;
  127. DWORD ifi;
  128. int i;
  129. // Check for TNT. Don't use mapped I/O under TNT.
  130. hLib = GetModuleHandle("kernel32.dll");
  131. fMappedIO = (hLib == 0) || (GetProcAddress(hLib, "IsTNT") == 0);
  132. DBEXEC_REL(DB_NO_FILE_MAP, fMappedIO = FALSE);
  133. DBEXEC(DB_BUFVERBOSE, DBPRINT(fMappedIO ?
  134. "Using NT I/O parameters (file mapping)\n" :
  135. "Using TNT I/O parameters (no mapping, fewer handles)\n"));
  136. if (fMappedIO) {
  137. cfi = cfiNT;
  138. cfiCacheable = cfiCacheableNT;
  139. } else {
  140. cfi = cfiTNT;
  141. cfiCacheable = cfiCacheableTNT;
  142. }
  143. // Allocate logical file handle map
  144. rgpfi = (PFI *) PvAllocZ(cfi * sizeof(PFI));
  145. // Allocate buffered file handles
  146. for (ifi = 0; ifi < cfi; ifi++) {
  147. PFI pfi;
  148. pfi = PfiNew();
  149. pfi->ifi = ifi;
  150. if (pfiFree == NULL) {
  151. pfiFree = pfi;
  152. } else {
  153. pfi->pfiNext = pfiFree;
  154. pfiFree = pfi;
  155. }
  156. rgpfi[ifi] = pfi;
  157. }
  158. // Set the maximum cache size
  159. cfiCacheClosedMax = cfiCacheable;
  160. // Initialize the CloseOnBadExit array
  161. for (i = 1; i < MAX_WRITEABLE_FILES; i++) {
  162. pfiCloseOnBadExit[i] = NULL;
  163. }
  164. #if DBG
  165. assert(FPfiCheck());
  166. #endif
  167. }
  168. VOID
  169. BufferedIOInit (
  170. VOID)
  171. /*++
  172. Routine Description:
  173. Initialize for buffered i/o.
  174. UNDONE: we should just alloc buffers as needed
  175. Arguments:
  176. None.
  177. Return Value:
  178. None.
  179. --*/
  180. {
  181. static BOOL fBufIoInit = FALSE;
  182. DWORD ibuf;
  183. if (fBufIoInit)
  184. return;
  185. else
  186. fBufIoInit = TRUE;
  187. // Allocate buffers and add them to the free list
  188. for (ibuf = 0; ibuf < cbufTot; ibuf++) {
  189. PBUF pbuf;
  190. pbuf = PbufNew();
  191. if (pbufFree == NULL) {
  192. pbufFree = pbuf;
  193. } else {
  194. pbuf->pbufNext = pbufFree;
  195. pbufFree = pbuf;
  196. }
  197. }
  198. }
  199. STATIC PFI
  200. PfiNew(
  201. VOID)
  202. /*++
  203. Routine Description:
  204. Create a new logical file handle.
  205. Arguments:
  206. None.
  207. Return Value:
  208. None.
  209. --*/
  210. {
  211. PFI pfi;
  212. pfi = (PFI) PvAllocZ(sizeof(FI));
  213. cfiTot++;
  214. return(pfi);
  215. }
  216. STATIC VOID
  217. GrowMapTable(
  218. PFI pfi)
  219. /*++
  220. Routine Description:
  221. Grow a the file buffer map table and set *pl to the new size. This
  222. routine assumes pfi->cbMap % cbIOBuf == 0.
  223. Arguments:
  224. pfi - logical file descriptor
  225. Return Value:
  226. None.
  227. --*/
  228. {
  229. LONG cbufNew;
  230. LONG cbufOld;
  231. // get the old buffer table size
  232. cbufOld = pfi->cbMap / cbIOBuf;
  233. // double the size of the old table
  234. cbufNew = cbufOld << 1;
  235. assert(cbufNew > cbufOld);
  236. // grow the table
  237. pfi->rgpbuf = (PPBUF) PvRealloc(pfi->rgpbuf, cbufNew * sizeof(PBUF));
  238. // zero the enties
  239. memset(&(pfi->rgpbuf[cbufOld]), '\0', sizeof(PBUF) * (cbufNew - cbufOld));
  240. // set the new size
  241. pfi->cbMap = cbufNew * cbIOBuf;
  242. }
  243. STATIC PFI
  244. PfiAlloc(
  245. VOID)
  246. /*++
  247. Routine Description:
  248. Allocate a logical file descriptor.
  249. Arguments:
  250. None.
  251. Return Value:
  252. None.
  253. --*/
  254. {
  255. PFI pfi;
  256. if (!pfiFree) {
  257. // no free logical file descriptors, hard close
  258. pfi = pfiClosedHead;
  259. TR_Cache_To_Free(pfi);
  260. if (pfi->flags & FI_Mapped) {
  261. MappedCloseHard(pfi);
  262. } else {
  263. BufferedCloseHard(pfi);
  264. }
  265. }
  266. pfi = pfiFree;
  267. assert(pfi);
  268. TR_Free_To_Open(pfi);
  269. return(pfi);
  270. }
  271. STATIC PFI
  272. PfiClosedCached (
  273. const char *szFileName)
  274. /*++
  275. Routine Description:
  276. Check for a cached pfi in the closed chain.
  277. Arguments:
  278. szFileName - file name to find a cached pfi for
  279. Return Value:
  280. pointer to a logical file descriptor if found, NULL otherwise
  281. --*/
  282. {
  283. PFI pfiLast = pfiClosedHead;
  284. PFI pfi = pfiClosedHead;
  285. assert(szFileName);
  286. // loop through the closed chain loooking for the file
  287. while (pfi) {
  288. if (!strcmp(pfi->szFileName, szFileName)) {
  289. // found file, move from closed list to open list
  290. TR_Cache_To_Open(pfi);
  291. assert(pfi->flags & FI_Closed);
  292. pfi->flags &= ~FI_Closed;
  293. return(pfi);
  294. }
  295. pfiLast = pfi;
  296. pfi = pfi->pfiNext;
  297. }
  298. return(NULL);
  299. }
  300. INT
  301. FileChSize (
  302. INT fd,
  303. LONG cbSizeNew)
  304. /*++
  305. Routine Description:
  306. Change the file size.
  307. Arguments:
  308. fd - file descriptor
  309. cbSizeNew - new size of file
  310. Return Value:
  311. 0 on success, -1 otherwise
  312. --*/
  313. {
  314. assert(rgpfi[fd]);
  315. assert(rgpfi[fd]->flags & FI_Write);
  316. if (fCtrlCSignal) {
  317. BadExitCleanup();
  318. }
  319. if (cbSizeNew == rgpfi[fd]->cbSoFar) {
  320. // no change in size
  321. return(0);
  322. }
  323. if (rgpfi[fd]->flags & FI_Mapped) {
  324. return(MappedChSize(rgpfi[fd], cbSizeNew));
  325. }
  326. return(BufferedChSize(rgpfi[fd], cbSizeNew));
  327. }
  328. STATIC INT
  329. MappedChSize (
  330. PFI pfi,
  331. LONG cbSizeNew)
  332. /*++
  333. Routine Description:
  334. Change the file size. Same as _chsize() in the crt. This only operates
  335. on buffered files, the code will assert on mapped files.
  336. Arguments:
  337. fd - file descriptor
  338. cbSizeNew - new size of file
  339. Return Value:
  340. 0 on success, -1 otherwise
  341. --*/
  342. {
  343. BOOL f = TRUE;
  344. DWORD dwErr = 0;
  345. assert(pfi->flags & FI_Mapped);
  346. if (cbSizeNew > pfi->cbMapView) {
  347. // Grow file
  348. if (!ExtendMapView(pfi, cbSizeNew, &dwErr)) {
  349. Fatal(pfi->szFileName, CANTSEEKFILE, cbSizeNew);
  350. }
  351. } else {
  352. // Shrink file
  353. if (pfi->ibCur > cbSizeNew) {
  354. pfi->ibCur = cbSizeNew;
  355. }
  356. }
  357. pfi->cbSoFar = cbSizeNew;
  358. return(0);
  359. }
  360. STATIC INT
  361. BufferedChSize (
  362. PFI pfi,
  363. LONG cbSizeNew)
  364. /*++
  365. Routine Description:
  366. Change the file size. Same as _chsize() in the crt. This only operates
  367. on buffered files, the code will assert on mapped files.
  368. Arguments:
  369. pfi - logical file descriptor
  370. cbSizeNew - new size of file
  371. Return Value:
  372. 0 on success, -1 otherwise
  373. --*/
  374. {
  375. PBUF pbuf;
  376. LONG ibuf;
  377. LONG cbuf;
  378. #if DBG
  379. BOOL f;
  380. #endif // DBG
  381. assert(!(pfi->flags & FI_Mapped));
  382. if (cbSizeNew > pfi->cbSoFar) {
  383. // grow file
  384. while (pfi->cbMap <= cbSizeNew) {
  385. GrowMapTable(pfi);
  386. }
  387. assert(cbSizeNew <= pfi->cbMap);
  388. } else {
  389. // shrink file
  390. cbuf = pfi->cbMap >> cshiftBuf;
  391. // make sure pfi->cbMap is cbIOBuf aligned
  392. assert((cbuf * cbIOBuf) == pfi->cbMap);
  393. for(ibuf = cbSizeNew >> cshiftBuf; ibuf < cbuf; ibuf++) {
  394. pbuf = pfi->rgpbuf[ibuf];
  395. if (pbuf != NULL && pbuf != pbufPreviousWrite) {
  396. assert(pbuf->flags & BUF_Active);
  397. #if DBG
  398. f =
  399. #endif // DBG
  400. FDeactivateBuf(pbuf);
  401. assert(f);
  402. }
  403. }
  404. }
  405. pfi->cb = cbSizeNew;
  406. pfi->cbSoFar = cbSizeNew;
  407. return(_chsize(pfi->fd, cbSizeNew));
  408. }
  409. STATIC PFI
  410. LookupCachedFiles (
  411. const char *szFileName,
  412. INT flags,
  413. INT /* mode */,
  414. OUT BOOL *pfNewPfi
  415. )
  416. /*++
  417. Routine Description:
  418. Looks up the cached list for the file
  419. Arguments:
  420. szFileName - A pointer to a file name.
  421. flags - open flags
  422. mode - open mode
  423. pfNewPfi - TRUE if new pfi had to be allocated
  424. Return Value:
  425. PFI
  426. --*/
  427. {
  428. PFI pfi;
  429. // get a file handle
  430. if (!(pfi = PfiClosedCached(szFileName))) {
  431. pfi = PfiAlloc();
  432. *pfNewPfi = 1;
  433. pfi->szFileName = SzDup(szFileName);
  434. pfi->flags = 0;
  435. pfi->cbSoFar = 0;
  436. pfi->hFile = NULL;
  437. pfi->pvMapView = NULL;
  438. pfi->cbMapView = 0;
  439. pfi->ibCur = 0;
  440. pfi->MapAddr = 0;
  441. // set read flags
  442. if ((flags & 0x000f) == O_RDONLY ||
  443. flags & O_RDWR) {
  444. pfi->flags |= FI_Read;
  445. }
  446. // set write flags
  447. if (flags & O_WRONLY ||
  448. flags & O_RDWR) {
  449. pfi->flags |= FI_Write;
  450. }
  451. // set the create flag
  452. if (flags & O_CREAT) {
  453. pfi->flags |= FI_Create;
  454. }
  455. }
  456. assert(pfi);
  457. return(pfi);
  458. }
  459. INT
  460. FileOpen (
  461. const char *szFileName,
  462. INT flags,
  463. INT mode
  464. )
  465. /*++
  466. Routine Description:
  467. Opens a file. Prints an error if can't open file. Do rudementary
  468. file handle caching.
  469. Arguments:
  470. szFileName - A pointer to a file name.
  471. flags - open flags
  472. mode - open mode
  473. Return Value:
  474. Physical file descriptor.
  475. --*/
  476. {
  477. BOOL fNewPfi = 0;
  478. PFI pfi;
  479. INT i = -1;
  480. DWORD dwErr = 0;
  481. if (fCtrlCSignal) {
  482. BadExitCleanup();
  483. }
  484. pfi = LookupCachedFiles(szFileName, flags, mode, &fNewPfi);
  485. assert(pfi);
  486. if (fMappedIO) {
  487. i = MappedOpen(pfi, flags, fNewPfi, &dwErr);
  488. }
  489. if (i == -1) {
  490. BufferedIOInit();
  491. BufferedOpen(pfi, flags, mode, fNewPfi);
  492. }
  493. return(pfi->ifi);
  494. }
  495. DWORD
  496. RoundUpToNextPowerOf2 (
  497. DWORD cb,
  498. DWORD cbHigh
  499. )
  500. /*++
  501. Routine Description:
  502. Arguments:
  503. Return Value:
  504. --*/
  505. {
  506. if (cb < cbHigh) {
  507. return cbHigh;
  508. }
  509. return RoundUpToNextPowerOf2(cb, (cbHigh << 1));
  510. }
  511. INT
  512. FileOpenMapped (
  513. const char *szFileName,
  514. INT flags,
  515. INT mode,
  516. DWORD *pMapAddr,
  517. DWORD *pcb,
  518. DWORD *pdwErr
  519. )
  520. /*++
  521. Routine Description:
  522. Opens and maps a file to a specific address.
  523. Arguments:
  524. szFileName - name of file.
  525. flags - open flags
  526. mode - open mode
  527. pMapAddr - address to map the file to. On return has actual address.
  528. pcb - pointer to file size. On return has free space.
  529. pdwErr - ptr to store error code in case of failure
  530. Return Value:
  531. file handle.
  532. --*/
  533. {
  534. BOOL fNewPfi = 0;
  535. PFI pfi;
  536. INT i = -1;
  537. if (fCtrlCSignal) {
  538. BadExitCleanup();
  539. }
  540. // got to have mapped i/o
  541. if (!fMappedIO) {
  542. return i;
  543. }
  544. // lookup the cache first
  545. pfi = LookupCachedFiles(szFileName, flags, mode, &fNewPfi);
  546. assert(pfi);
  547. pfi->MapAddr = *pMapAddr;
  548. pfi->cbSoFar = *pcb;
  549. // set the file size
  550. if (flags & O_CREAT) {
  551. // 256K is starting size of map (bufio.h)
  552. pfi->cbMapView = cbInitialILKMapSize;
  553. } else {
  554. // Round up to 256K/512K/...etc for an open
  555. pfi->cbMapView = RoundUpToNextPowerOf2(pfi->cbSoFar, cbInitialILKMapSize);
  556. }
  557. // Open the file
  558. i = MappedOpen(pfi, flags, fNewPfi, pdwErr);
  559. if (i == -1) {
  560. // failed to map to specified address;
  561. // insuffcient disk space OR couldn't allocate map at req. addr.
  562. TR_Open_To_Free(pfi);
  563. if (!_access(pfi->szFileName, 0)) {
  564. _unlink(pfi->szFileName);
  565. }
  566. FreePv(pfi->szFileName);
  567. return i;
  568. }
  569. *pcb = (flags & O_CREAT) ? pfi->cbMapView : pfi->cbMapView - pfi->cbSoFar;
  570. *pMapAddr = pfi->MapAddr = (DWORD)pfi->pvMapView;
  571. return(pfi->ifi);
  572. }
  573. STATIC INT
  574. BufferedOpen (
  575. PFI pfi,
  576. INT flags,
  577. INT mode,
  578. BOOL fNewPfi)
  579. /*++
  580. Routine Description:
  581. Opens a file. Prints an error if can't open file. Do rudementary
  582. file handle caching.
  583. Arguments:
  584. pfi - logical file descriptor
  585. flags - open flags
  586. mode - open mode
  587. Return Value:
  588. Logical file descriptor.
  589. --*/
  590. {
  591. struct _stat statFile;
  592. LONG cbuf;
  593. LONG ibuf;
  594. assert(pfi);
  595. // if no cached logical file handle
  596. if (fNewPfi) {
  597. // open the file
  598. if ((pfi->fd = _sopen(pfi->szFileName, flags,
  599. ((flags & (_O_RDWR|_O_WRONLY)) ? _SH_DENYRW : _SH_DENYWR), mode)) == -1)
  600. {
  601. PFI pfiTmp;
  602. if (pfi == pfiOpen) {
  603. pfiOpen = pfi->pfiNext;
  604. cfiTot--;
  605. } else {
  606. for (pfiTmp = pfiOpen; pfiTmp; pfiTmp = pfiTmp->pfiNext) {
  607. if (pfiTmp->pfiNext == pfi) {
  608. pfiTmp->pfiNext = pfi->pfiNext;
  609. cfiTot--;
  610. break;
  611. }
  612. }
  613. }
  614. if (_doserrno == ERROR_DISK_FULL) {
  615. Fatal(pfi->szFileName, DISKFULL);
  616. }
  617. Fatal(NULL, CANTOPENFILE, pfi->szFileName);
  618. }
  619. // we don't support O_APPEND
  620. assert(!(flags & O_APPEND));
  621. pfi->cbSoFar = 0L;
  622. // get size of file, or set to default
  623. // note this is !FI_Write because an opened .exe is readable, but
  624. // its size is not defined yet
  625. if (!(pfi->flags & FI_Write) ||
  626. ((pfi->flags & (FI_Read | FI_Write)) &&
  627. !(pfi->flags & FI_Create))) {
  628. if (_stat(pfi->szFileName, &statFile) == -1) {
  629. Fatal(NULL, CANTOPENFILE, pfi->szFileName);
  630. }
  631. // Test for files of size 0 (mapped open will fall through in this case)
  632. if (!statFile.st_size) {
  633. // UNDONE: Why allocate before calling Fatal?
  634. pfi->rgpbuf = (PPBUF) PvAllocZ(sizeof(PBUF));
  635. Fatal(pfi->szFileName, BAD_FILE);
  636. }
  637. pfi->cb = statFile.st_size;
  638. pfi->cbSoFar = statFile.st_size;
  639. } else {
  640. pfi->cb = cbDefaultFileSize;
  641. }
  642. cbuf = (pfi->cb + cbIOBuf) / cbIOBuf;
  643. pfi->cbMap = cbuf * cbIOBuf;
  644. // allocate file buffer map table
  645. pfi->rgpbuf = (PPBUF) PvAllocZ(cbuf * sizeof(PBUF));
  646. // blast previous writes into buffer map table if required
  647. if ((pfi->flags & (FI_Read | FI_Write)) & !(pfi->flags & FI_Create)) {
  648. for (ibuf = 0; ibuf < cbuf; ibuf++) {
  649. pfi->rgpbuf[ibuf] = pbufPreviousWrite;
  650. }
  651. }
  652. }
  653. BufferedSeek(pfi, 0L, SEEK_SET);
  654. assert(rgpfi[pfi->ifi]->ifi == rgpfi[pfi->ifi]->pbufCur->ifi);
  655. return(0);
  656. }
  657. INT
  658. FileClose (
  659. INT fd,
  660. BOOL fUnCache)
  661. /*++
  662. Routine Description:
  663. Closes a file. Prints an error if can't close file.
  664. Arguments:
  665. pfi - logical file descriptor
  666. fUnCache - hard close the file
  667. Return Value:
  668. Same as close();
  669. --*/
  670. {
  671. PFI pfi;
  672. INT i;
  673. pfi = rgpfi[fd];
  674. assert(pfi);
  675. assert(!(pfi->flags & FI_Closed));
  676. if (fCtrlCSignal) {
  677. BadExitCleanup();
  678. }
  679. // either close the file hard if specified or if writable or
  680. // virtually close the file and cache the logical and physical handle
  681. if (fUnCache || (pfi->flags & FI_Write)) {
  682. TR_Open_To_Free(pfi);
  683. if (pfi->flags & FI_Mapped) {
  684. i = MappedCloseHard(pfi);
  685. } else {
  686. i = BufferedCloseHard(pfi);
  687. }
  688. } else {
  689. TR_Open_To_Cache(pfi);
  690. CloseSoft(pfi);
  691. i = 0;
  692. }
  693. return(i);
  694. }
  695. STATIC INT
  696. BufferedCloseHard (
  697. PFI pfi)
  698. /*++
  699. Routine Description:
  700. Close logical and physical file handles for a file. Does not manipulate
  701. PFI pools.
  702. Arguments:
  703. pfi - logical file descriptor
  704. Return Value:
  705. Same as close();
  706. --*/
  707. {
  708. PBUF pbufN;
  709. PBUF pbuf;
  710. INT i;
  711. #if DBG
  712. BOOL f;
  713. #endif // DBG
  714. assert(pfi);
  715. // delete active buffers from file
  716. pbuf = pbufActive;
  717. while (pbuf) {
  718. assert(pbuf->flags & BUF_Active);
  719. pbufN = pbuf->pbufNext;
  720. if (pbuf->ifi == pfi->ifi) {
  721. if (pbuf == pfi->pbufCur) {
  722. pfi->pbufCur->flags &= ~BUF_Current;
  723. }
  724. #if DBG
  725. f =
  726. #endif //DBG
  727. FDeactivateBuf(pbuf);
  728. assert(f);
  729. }
  730. pbuf = pbufN;
  731. }
  732. // close the physical handle
  733. if ((i = _close(pfi->fd)) == -1) {
  734. Fatal(NULL, CANTCLOSEFILE, pfi->szFileName);
  735. }
  736. assert(pfi->szFileName);
  737. FreePv(pfi->szFileName);
  738. assert(pfi->rgpbuf);
  739. FreePv(pfi->rgpbuf);
  740. // return the result of the low level close
  741. return(i);
  742. }
  743. STATIC VOID
  744. CloseSoft (
  745. PFI pfi)
  746. /*++
  747. Routine Description:
  748. Close a logical file handle and cache it.
  749. Arguments:
  750. pfi - logical file descriptor
  751. Return Value:
  752. Same as close();
  753. --*/
  754. {
  755. PFI pfiToFree;
  756. assert(pfi);
  757. assert(!(pfi->flags & FI_Closed));
  758. // set logical file descriptor to closed
  759. pfi->flags |= FI_Closed;
  760. if (!(pfi->flags & FI_Mapped)) {
  761. // set the current pbuf to not current and remove it from the
  762. // logical file descriptor, this is safe since when the file
  763. // is re-opened (logically) there is an immediate seek to offset
  764. // 0 which can potentially reactivate or reallocate the buffer,
  765. // this also frees up the buffer to be reallocated if need be
  766. assert(pfi->pbufCur);
  767. assert(pfi->pbufCur->flags & BUF_Current);
  768. pfi->pbufCur->flags &= ~BUF_Current;
  769. pfi->pbufCur = NULL;
  770. }
  771. // if cache is full, toss the last guy out
  772. if (cfiCacheClosed == cfiCacheClosedMax) {
  773. pfiToFree = pfiClosedHead;
  774. assert(pfiToFree);
  775. assert(pfiToFree);
  776. TR_Cache_To_Free(pfiToFree);
  777. (pfiToFree->flags & FI_Mapped) ?
  778. MappedCloseHard(pfiToFree) :
  779. BufferedCloseHard(pfiToFree);
  780. }
  781. }
  782. VOID
  783. FileCloseAll (
  784. VOID
  785. )
  786. /*++
  787. Routine Description:
  788. Closes all cached handles.
  789. Arguments:
  790. None.
  791. Return Value:
  792. None.
  793. --*/
  794. {
  795. PFI pfiT;
  796. PFI pfi;
  797. #if DBG
  798. assert(FPfiCheck());
  799. #endif
  800. // hard close all open files
  801. pfi = pfiOpen;
  802. while (pfi) {
  803. // move open PFI to free PFI pool
  804. assert(!(pfi->flags & FI_Closed));
  805. pfiT = pfi->pfiNext;
  806. TR_Open_To_Free(pfi);
  807. (pfi->flags & FI_Mapped) ?
  808. MappedCloseHard(pfi) :
  809. BufferedCloseHard(pfi);
  810. pfi = pfiT;
  811. }
  812. // hard close all closed/cached files
  813. pfi = pfiClosedHead;
  814. while (pfi) {
  815. assert(pfi->flags & FI_Closed);
  816. pfiT = pfi->pfiNext;
  817. // move closed/cached PFI to free PFI pool
  818. TR_Cache_To_Free(pfi);
  819. (pfi->flags & FI_Mapped) ?
  820. MappedCloseHard(pfi) :
  821. BufferedCloseHard(pfi);
  822. pfi = pfiT;
  823. }
  824. DBEXEC(DB_BUFVERBOSE, DBPRINT("Buffer summary\n"));
  825. DBEXEC(DB_BUFVERBOSE, DBPRINT("--------------\n"));
  826. DBEXEC(DB_BUFVERBOSE, DBPRINT("size of buffers = %lu\n", cbIOBuf));
  827. DBEXEC(DB_BUFVERBOSE, DBPRINT("buffer re-reads = %lu\n", crereads));
  828. #if DBG
  829. assert(FPfiCheck());
  830. #endif
  831. }
  832. STATIC VOID
  833. FlushBuffer (
  834. PBUF pbuf)
  835. /*++
  836. Routine Description:
  837. Flush a buffer.
  838. Arguments:
  839. pbuf - buffer to flush
  840. Return Value:
  841. None.
  842. --*/
  843. {
  844. LONG cb;
  845. PFI pfi;
  846. assert(pbuf);
  847. // get the buffered file descriptor
  848. pfi = rgpfi[pbuf->ifi];
  849. assert(pfi);
  850. if (pbuf->flags & BUF_Dirty) {
  851. // calculate how much to flush
  852. cb = pbuf->ibLast - pbuf->ibStart;
  853. DBEXEC(DB_IO_FLUSH,
  854. Trans_LOG(LOG_FlushBuffer, pfi->fd, pbuf->ibCur, cb, 0, NULL));
  855. // seek to buffers beginning
  856. if (_lseek(pfi->fd, pbuf->ibStart, SEEK_SET) == -1L) {
  857. Fatal(pfi->szFileName, CANTSEEKFILE, pbuf->ibStart);
  858. }
  859. // flush buffer
  860. if (_write(pfi->fd, pbuf->rgbBuf, cb) != cb) {
  861. if (_doserrno == ERROR_DISK_FULL) {
  862. Fatal(pfi->szFileName, DISKFULL);
  863. }
  864. Fatal(pfi->szFileName, CANTWRITEFILE, _tell(pfi->fd));
  865. }
  866. // set the buffer to written to
  867. pfi->rgpbuf[pbuf->ibStart >> cshiftBuf] = pbufPreviousWrite;
  868. // set file size so far
  869. if ((pfi->flags & FI_Write) &&
  870. (pbuf->ibLast > pfi->cbSoFar)) {
  871. pfi->cbSoFar = pbuf->ibLast;
  872. }
  873. } else {
  874. // remove the buffer from the buffer map table
  875. if (pbuf->flags & BUF_PreviousWrite) {
  876. pfi->rgpbuf[pbuf->ibStart >> cshiftBuf] = pbufPreviousWrite;
  877. } else {
  878. pfi->rgpbuf[pbuf->ibStart >> cshiftBuf] = NULL;
  879. }
  880. }
  881. #if DBG
  882. assert(FBufListCheck());
  883. #endif
  884. }
  885. STATIC LONG
  886. BufferedSeek (
  887. PFI pfi,
  888. LONG ib,
  889. INT origin
  890. )
  891. /*++
  892. Routine Description:
  893. Seeks a file that is buffered. Prints an error if can't seek file.
  894. Arguments:
  895. pfi - buffered file descriptor
  896. ib - Number of bytes to seek.
  897. origin - SEEK_SET, SEEK_CUR, or SEEK_END.
  898. Return Value:
  899. Same as lseek().
  900. --*/
  901. {
  902. LONG ibFile;
  903. PBUF pbuf;
  904. assert(pfi);
  905. #if DBG
  906. assert(FBufListCheck());
  907. #endif
  908. DBEXEC(DB_IO_SEEK,
  909. Trans_LOG(LOG_BufSeek, pfi->ifi, ib, 0, origin, NULL));
  910. // calculate SEEK_SET offset
  911. switch (origin) {
  912. case SEEK_SET: // already non-relative offset
  913. ibFile = ib;
  914. break;
  915. case SEEK_CUR: // relative offset
  916. assert(pfi->pbufCur);
  917. // base off of current buffer
  918. ibFile = pfi->pbufCur->ibCur + ib;
  919. break;
  920. default:
  921. case SEEK_END:
  922. ibFile = pfi->cbSoFar + ib;
  923. break;
  924. }
  925. // check if we need to grow the buffer map table
  926. while (ibFile >= pfi->cbMap) {
  927. GrowMapTable(pfi);
  928. }
  929. // get buffer entry
  930. assert(ibFile <= pfi->cbMap);
  931. pbuf = pfi->rgpbuf[ibFile >> cshiftBuf];
  932. // set current buffer to no buffer
  933. if (pfi->pbufCur) {
  934. assert(pfi->pbufCur->flags & BUF_Current);
  935. pfi->pbufCur->flags &= ~BUF_Current;
  936. pfi->pbufCur = NULL;
  937. }
  938. if ((DWORD) pbuf <= 1) {
  939. // no buffer or previously buffered, attempt to allocate a buffer
  940. pfi->pbufCur = PbufAlloc(pfi, ibFile);
  941. assert(!(pfi->pbufCur->flags & BUF_Current));
  942. pfi->pbufCur->flags |= BUF_Current;
  943. assert(pfi->pbufCur);
  944. assert(pfi->ifi == pfi->pbufCur->ifi);
  945. }
  946. // if the file has been previously written to at this range
  947. // then read in buffer
  948. if (pbuf == pbufPreviousWrite) {
  949. ReadpbufCur(pfi);
  950. crereads++;
  951. DBEXEC(DB_BUFVERBOSE,
  952. DBPRINT("re-read @%0x\n", pfi->pbufCur->ibStart));
  953. // set the buffer to previously written out
  954. pfi->pbufCur->flags |= BUF_PreviousWrite;
  955. }
  956. // found an entry in the buffer map table
  957. if ((DWORD) pbuf > 1) {
  958. pfi->pbufCur = pbuf;
  959. assert(!(pbuf->flags & BUF_Current));
  960. pfi->pbufCur->flags |= BUF_Current;
  961. }
  962. // set offset in buffer
  963. assert(ibFile >= pfi->pbufCur->ibStart);
  964. pfi->pbufCur->ibCur = ibFile;
  965. pfi->pbufCur->pbCur = pfi->pbufCur->rgbBuf +
  966. (ibFile - pfi->pbufCur->ibStart);
  967. // update highest valid buffer access on writes
  968. if ((pfi->flags & FI_Write) &&
  969. (pfi->pbufCur->ibCur > pfi->pbufCur->ibLast)) {
  970. pfi->pbufCur->ibLast = pfi->pbufCur->ibCur;
  971. }
  972. assert((ibFile - pfi->pbufCur->ibStart) < cbIOBuf);
  973. assert(pfi->ifi == pfi->pbufCur->ifi);
  974. #if DBG
  975. assert(FBufListCheck());
  976. #endif
  977. // update LRU list
  978. MoveToHeadLRU(pfi->pbufCur);
  979. #if DBG
  980. assert(FBufListCheck());
  981. #endif
  982. return(ibFile);
  983. }
  984. LONG
  985. FileSeekEx (
  986. INT fd,
  987. LONG ib,
  988. INT origin,
  989. DWORD *pdwErr
  990. )
  991. /*++
  992. Routine Description:
  993. Seeks a file. Prints an error if can't seek file.
  994. Arguments:
  995. fd - fd in which file was open.
  996. ib - Number of bytes to seek.
  997. origin - SEEK_SET, SEEK_CUR, or SEEK_END.
  998. pdwErr- ptr to store error code in case of an error.
  999. Return Value:
  1000. Same as lseek().
  1001. --*/
  1002. {
  1003. if (fCtrlCSignal) {
  1004. BadExitCleanup();
  1005. }
  1006. if (rgpfi[fd]->flags & FI_Mapped) {
  1007. return(MappedSeek(rgpfi[fd], ib, origin, pdwErr));
  1008. }
  1009. return(BufferedSeek(rgpfi[fd], ib, origin));
  1010. }
  1011. // the error code of is of no interest
  1012. LONG
  1013. FileSeek (
  1014. INT fd,
  1015. LONG ib,
  1016. INT origin
  1017. )
  1018. {
  1019. DWORD dwErr = 0;
  1020. return FileSeekEx(fd, ib, origin, &dwErr);
  1021. }
  1022. LONG
  1023. FileLength (
  1024. INT fd
  1025. )
  1026. /*++
  1027. Routine Description:
  1028. Returns a file's length in bytes.
  1029. Arguments:
  1030. fd - handle in which file was open.
  1031. Return Value:
  1032. Number of bytes in file.
  1033. --*/
  1034. {
  1035. LONG cbFile;
  1036. LONG ibHere;
  1037. if (fCtrlCSignal) {
  1038. BadExitCleanup();
  1039. }
  1040. // save current file pointer
  1041. ibHere = FileSeek(fd, 0L, SEEK_CUR);
  1042. // seek to the end of the file
  1043. cbFile = FileSeek(fd, 0L, SEEK_END);
  1044. // if where we are now is not the end of the file,
  1045. // set us back to where we were originally
  1046. if (cbFile != ibHere) {
  1047. FileSeek(fd, ibHere, SEEK_SET);
  1048. }
  1049. // return the size
  1050. return(cbFile);
  1051. }
  1052. STATIC DWORD
  1053. BufferedRead (
  1054. PFI pfi,
  1055. PVOID pvBuf,
  1056. DWORD cb)
  1057. /*++
  1058. Routine Description:
  1059. Read file which is buffered.
  1060. Arguments:
  1061. pvBuf - buffer to read into
  1062. cb - number of bytes to read
  1063. Return Value:
  1064. number of bytes read
  1065. --*/
  1066. {
  1067. LONG cbLeft;
  1068. LONG cbRead;
  1069. PVOID pvT = pvBuf;
  1070. assert(pfi);
  1071. assert(pfi->flags & FI_Read);
  1072. assert(pvBuf);
  1073. assert(pfi->pbufCur);
  1074. DBEXEC(DB_IO_READ,
  1075. Trans_LOG(LOG_BufRead, pfi->ifi, pfi->pbufCur->ibCur, cb, 0, NULL));
  1076. // check for reading past end of file
  1077. if ((pfi->pbufCur->ibCur + cb) > (DWORD)pfi->cbMap) {
  1078. Fatal(pfi->szFileName, CANTREADFILE, pfi->pbufCur->ibCur + cb);
  1079. }
  1080. // perform the read
  1081. for(cbLeft = cb;
  1082. cbLeft;
  1083. cbLeft -= cbRead, pvBuf = (PVOID) ((PCHAR) pvBuf + cbRead)) {
  1084. assert(pfi->ifi == pfi->pbufCur->ifi);
  1085. // check if buffer is random, if so read in the buffer
  1086. if (pfi->pbufCur->flags & BUF_Random) {
  1087. ReadpbufCur(pfi);
  1088. }
  1089. // bytes to read is the minimum of the total bytes to read or the
  1090. // bytes in the buffer
  1091. cbRead = __min(cbLeft, pfi->pbufCur->ibEnd - pfi->pbufCur->ibCur);
  1092. assert((LONG) (pfi->pbufCur->pbCur) <
  1093. (LONG) ((LONG) (pfi->pbufCur->rgbBuf) + cbIOBuf));
  1094. assert((LONG) pvBuf < (LONG) ((LONG) pvT + (LONG) cb));
  1095. assert((cbRead <= pfi->pbufCur->ibLast - pfi->pbufCur->ibStart) ||
  1096. (pfi->pbufCur->flags & BUF_PreviousWrite) ||
  1097. (pfi->pbufCur->flags & BUF_Active));
  1098. assert((DWORD) cbRead <= cb);
  1099. memcpy(pvBuf, pfi->pbufCur->pbCur, (DWORD) cbRead);
  1100. // adjust buffer pointers
  1101. pfi->pbufCur->ibCur += cbRead;
  1102. pfi->pbufCur->pbCur += cbRead;
  1103. if (pfi->pbufCur->ibCur == pfi->pbufCur->ibEnd) {
  1104. SlidePbufCur(pfi);
  1105. }
  1106. }
  1107. #if DBG
  1108. assert(FBufListCheck());
  1109. #endif
  1110. return(cb);
  1111. }
  1112. DWORD
  1113. FileRead (
  1114. INT fd,
  1115. PVOID pvBuf,
  1116. DWORD cb)
  1117. /*++
  1118. Routine Description:
  1119. Reads a file. Prints an error if can't read file.
  1120. Arguments:
  1121. fd - fd in which file was open.
  1122. pvBuf - Location to receive bytes.
  1123. cb - Number of bytes to read into Buffer.
  1124. Return Value:
  1125. Same as read().
  1126. --*/
  1127. {
  1128. if (fCtrlCSignal) {
  1129. BadExitCleanup();
  1130. }
  1131. if (rgpfi[fd]->flags & FI_Mapped) {
  1132. return(MappedRead(rgpfi[fd], pvBuf, cb));
  1133. }
  1134. return(BufferedRead(rgpfi[fd], pvBuf, cb));
  1135. }
  1136. DWORD
  1137. FileTell (
  1138. INT fd
  1139. )
  1140. /*++
  1141. Routine Description:
  1142. Give position of file pointer.
  1143. Arguments:
  1144. fd - file handle
  1145. Return Value:
  1146. position of file pointer
  1147. --*/
  1148. {
  1149. if (fCtrlCSignal) {
  1150. BadExitCleanup();
  1151. }
  1152. if (rgpfi[fd]->flags & FI_Mapped) {
  1153. return(rgpfi[fd]->ibCur);
  1154. } else {
  1155. assert(rgpfi[fd]);
  1156. assert(rgpfi[fd]->pbufCur);
  1157. return(rgpfi[fd]->pbufCur->ibCur);
  1158. }
  1159. }
  1160. STATIC DWORD
  1161. BufferedWrite (
  1162. PFI pfi,
  1163. const void *pvBuf,
  1164. DWORD cb)
  1165. /*++
  1166. Routine Description:
  1167. Write to a buffer if possible, otherwise write to low io.
  1168. Arguments:
  1169. pvBuf - buffer for bytes to write
  1170. cb - count of bytes
  1171. Return Value:
  1172. number of bytes written
  1173. --*/
  1174. {
  1175. const void *pvT;
  1176. LONG cbLeft;
  1177. LONG cbWrite;
  1178. assert(pfi);
  1179. assert(pfi->flags & FI_Write);
  1180. assert(pfi->pbufCur);
  1181. assert(pfi->ifi == pfi->pbufCur->ifi);
  1182. assert(pvBuf);
  1183. // writes of zero bytes don't do anything
  1184. if (!cb) {
  1185. return(cb);
  1186. }
  1187. // check if we need to grow the buffer map table
  1188. while ((pfi->pbufCur->ibCur + (LONG) cb) >= pfi->cbMap) {
  1189. GrowMapTable(pfi);
  1190. }
  1191. DBEXEC(DB_IO_WRITE,
  1192. Trans_LOG(LOG_BufWrite, pfi->ifi, pfi->pbufCur->ibCur, cb, 0, NULL));
  1193. pvT = pvBuf;
  1194. // mark the buffer as dirty
  1195. pfi->pbufCur->flags |= BUF_Dirty;
  1196. // perform the write
  1197. for(cbLeft = cb;
  1198. cbLeft;
  1199. cbLeft -= cbWrite, pvBuf = (PVOID) ((PCHAR) pvBuf + cbWrite)) {
  1200. assert(pfi->ifi == pfi->pbufCur->ifi);
  1201. // bytes to write is the minimum of the bytes to write or the
  1202. // bytes that fit in the buffer
  1203. cbWrite = __min(cbLeft, pfi->pbufCur->ibEnd - pfi->pbufCur->ibCur);
  1204. assert((LONG) (pfi->pbufCur->pbCur) <
  1205. (LONG) ((LONG) (pfi->pbufCur->rgbBuf) + cbIOBuf));
  1206. assert((LONG) pvBuf < (LONG) ((LONG) pvT + (LONG) cb));
  1207. assert((DWORD) cbWrite <= cb);
  1208. memcpy(pfi->pbufCur->pbCur, pvBuf, (DWORD) cbWrite);
  1209. // adjust buffer pointers
  1210. pfi->pbufCur->ibCur += cbWrite;
  1211. pfi->pbufCur->pbCur += cbWrite;
  1212. // update highest valid buffer write
  1213. if (pfi->pbufCur->ibCur > pfi->pbufCur->ibLast) {
  1214. pfi->pbufCur->ibLast = pfi->pbufCur->ibCur;
  1215. }
  1216. if (pfi->pbufCur->ibCur == pfi->pbufCur->ibEnd) {
  1217. SlidePbufCur(pfi);
  1218. }
  1219. if (cbLeft) {
  1220. pfi->pbufCur->flags |= BUF_Dirty;
  1221. }
  1222. }
  1223. #if DBG
  1224. assert(FBufListCheck());
  1225. #endif
  1226. return(cb);
  1227. }
  1228. STATIC VOID
  1229. ReadpbufCur(
  1230. PFI pfi)
  1231. /*++
  1232. Routine Description:
  1233. Read in a buffer from disk.
  1234. Arguments:
  1235. None.
  1236. Return Value:
  1237. None.
  1238. --*/
  1239. {
  1240. LONG cbReRead;
  1241. LONG ibSeek;
  1242. LONG cbRead;
  1243. assert(pfi);
  1244. assert(pfi->pbufCur);
  1245. assert(pfi->pbufCur->ibStart <= pfi->cbSoFar);
  1246. assert(pfi->ifi == pfi->pbufCur->ifi);
  1247. // seek to buffer region on disk
  1248. if ((ibSeek = (LONG)_lseek(pfi->fd,
  1249. pfi->pbufCur->ibStart, SEEK_SET)) == -1L) {
  1250. Fatal(pfi->szFileName, CANTSEEKFILE, ibSeek);
  1251. }
  1252. assert(ibSeek == pfi->pbufCur->ibStart);
  1253. // calculate bytes to read
  1254. cbReRead = __min(cbIOBuf, pfi->cbSoFar - pfi->pbufCur->ibStart);
  1255. assert((pfi->pbufCur->ibStart + cbReRead) <= pfi->cbSoFar);
  1256. // read in buffer
  1257. if ((cbRead = _read(pfi->fd, pfi->pbufCur->rgbBuf,
  1258. (DWORD) cbReRead)) != cbReRead) {
  1259. Fatal(pfi->szFileName, CANTREADFILE, _tell(pfi->fd));
  1260. }
  1261. // set the buffer to not containing random bits
  1262. pfi->pbufCur->flags &= ~BUF_Random;
  1263. }
  1264. STATIC VOID
  1265. SlidePbufCur(
  1266. PFI pfi)
  1267. /*++
  1268. Routine Description:
  1269. Slide down the current buffer in a file one region. Write the contents
  1270. of the buffer to disk if the buffer was written to and the file was
  1271. opened as writeable. Read the contents of the buffer from disk if the
  1272. file was readable.
  1273. Arguments:
  1274. pfi - file descriptor of file to slide current buffer in
  1275. Return Value:
  1276. None.
  1277. --*/
  1278. {
  1279. PBUF pbuf;
  1280. LONG ibuf;
  1281. PPBUF rgpbuf;
  1282. #if DBG
  1283. BOOL f;
  1284. #endif // DBG
  1285. assert(pfi);
  1286. assert(pfi->pbufCur);
  1287. assert(pfi->rgpbuf);
  1288. assert(pfi->ifi == pfi->pbufCur->ifi);
  1289. DBEXEC(
  1290. DB_BUFVERBOSE,
  1291. DBPRINT(" - slide pbuf = 0x%p from 0x%8lX to 0x%8lX in %s\n",
  1292. pfi->pbufCur, pfi->pbufCur->ibStart,
  1293. pfi->pbufCur->ibStart + 0x1000, pfi->szFileName));
  1294. // get buffer table entry
  1295. ibuf = pfi->pbufCur->ibStart >> cshiftBuf;
  1296. assert(((ibuf + 1) * cbIOBuf) < (pfi->cbMap));
  1297. // get the buffer table
  1298. rgpbuf = pfi->rgpbuf;
  1299. assert(rgpbuf[ibuf]);
  1300. pbuf = rgpbuf[ibuf + 1];
  1301. if ((pbuf == NULL) || (pbuf == pbufPreviousWrite)) {
  1302. // flush the current buffer, if the buffer is not dirty
  1303. // FlushBuffer will not write anything
  1304. FlushBuffer(pfi->pbufCur);
  1305. // move the buffer along in the buffer table
  1306. rgpbuf[ibuf + 1] = pfi->pbufCur;
  1307. // set the buffers new range
  1308. pfi->pbufCur->ibStart += cbIOBuf;
  1309. pfi->pbufCur->ibEnd += cbIOBuf;
  1310. pfi->pbufCur->ibLast = pfi->pbufCur->ibStart;
  1311. // set the buffer to containing random bits
  1312. // HELP: this might have to be done for !FI_Write only
  1313. if (!(pfi->flags & FI_Write)) {
  1314. pfi->pbufCur->flags |= BUF_Random;
  1315. }
  1316. // if the file has been previously written to at this range
  1317. // then read in buffer
  1318. if (pbuf == pbufPreviousWrite) {
  1319. ReadpbufCur(pfi);
  1320. crereads++;
  1321. DBEXEC(DB_BUFVERBOSE,
  1322. DBPRINT("re-read @%0x\n", pfi->pbufCur->ibStart));
  1323. // set the buffer to previously written out
  1324. pfi->pbufCur->flags |= BUF_PreviousWrite;
  1325. }
  1326. } else {
  1327. // we ran into an existing buffer, deactivate the current
  1328. // buffer, this causes the buffer to be flushed and updates
  1329. // the buffer table
  1330. assert(pfi->pbufCur->flags & BUF_Current);
  1331. pfi->pbufCur->flags &= ~BUF_Current;
  1332. #if DBG
  1333. f =
  1334. #endif //DBG
  1335. FDeactivateBuf(pfi->pbufCur);
  1336. assert(f);
  1337. // set the current buffer to the one we ran into,
  1338. // this assumes there will be no more writes to the
  1339. // previous file offset in this buffer
  1340. assert(((ibuf + 1) * cbIOBuf) <= pfi->cbMap);
  1341. pfi->pbufCur = rgpbuf[ibuf + 1];
  1342. assert(!(pfi->pbufCur->flags & BUF_Current));
  1343. pfi->pbufCur->flags |= BUF_Current;
  1344. }
  1345. // set the current offsets to the beginning of the buffer
  1346. pfi->pbufCur->ibCur = pfi->pbufCur->ibStart;
  1347. pfi->pbufCur->pbCur = pfi->pbufCur->rgbBuf;
  1348. assert(pfi->ifi == pfi->pbufCur->ifi);
  1349. }
  1350. DWORD
  1351. FileWrite (
  1352. INT fd,
  1353. const void *pvBuf,
  1354. DWORD cb)
  1355. /*++
  1356. Routine Description:
  1357. Write a file. Prints an error if can't write file.
  1358. Arguments:
  1359. fd - file handle
  1360. pvBuf - location to receive bytes
  1361. cb - number of bytes to write from pvBuf
  1362. Return Value:
  1363. Same as write().
  1364. --*/
  1365. {
  1366. if (fCtrlCSignal) {
  1367. BadExitCleanup();
  1368. }
  1369. if (rgpfi[fd]->flags & FI_Mapped) {
  1370. return(MappedWrite(rgpfi[fd], pvBuf, cb));
  1371. }
  1372. return(BufferedWrite(rgpfi[fd], pvBuf, cb));
  1373. }
  1374. STATIC VOID
  1375. MoveToHeadLRU(
  1376. PBUF pbuf
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. Move a buffer to the head of the LRU chain.
  1381. Arguments:
  1382. pbuf - buffer to move to the head of the LRU chain
  1383. Return Value:
  1384. None.
  1385. --*/
  1386. {
  1387. BOOL fActive = 0;
  1388. PBUF pbufT;
  1389. assert(pbuf);
  1390. for (pbufT = pbufLRUHead;
  1391. pbufT && (pbufT != pbuf);
  1392. pbufT = pbufT->pbufLRURight);
  1393. // delete old links if the buffer is active
  1394. if (pbufT) {
  1395. assert(pbuf->flags & BUF_Active);
  1396. if (pbuf->pbufLRULeft) {
  1397. // left entry is not head
  1398. pbuf->pbufLRULeft->pbufLRURight = pbuf->pbufLRURight;
  1399. } else {
  1400. // left entry is head
  1401. pbufLRUHead = pbuf->pbufLRURight;
  1402. }
  1403. if (pbuf->pbufLRURight) {
  1404. // right entry is not tail
  1405. pbuf->pbufLRURight->pbufLRULeft = pbuf->pbufLRULeft;
  1406. } else {
  1407. // right entry is tail
  1408. pbufLRUTail = pbuf->pbufLRULeft;
  1409. }
  1410. }
  1411. // set the new LRU links
  1412. if ((!pbufLRUHead) && (!pbufLRUTail)) {
  1413. // add to empty list case
  1414. pbufLRUHead = pbuf;
  1415. pbufLRUTail = pbuf;
  1416. pbuf->pbufLRURight = NULL;
  1417. pbuf->pbufLRULeft = NULL;
  1418. } else {
  1419. // add to non-empty list
  1420. pbuf->pbufLRURight = pbufLRUHead;
  1421. pbuf->pbufLRULeft = NULL;
  1422. pbufLRUHead->pbufLRULeft = pbuf;
  1423. pbufLRUHead = pbuf;
  1424. }
  1425. }
  1426. STATIC PBUF
  1427. PbufLRU(
  1428. VOID)
  1429. /*++
  1430. Routine Description:
  1431. Return the LRU seeked buffer which isn't any PFI's current buffer.
  1432. Arguments:
  1433. None.
  1434. Return Value:
  1435. Pointer a buffer.
  1436. --*/
  1437. {
  1438. PBUF pbuf;
  1439. assert(pbufLRUHead);
  1440. assert(pbufLRUTail);
  1441. // find the buffer
  1442. pbuf = pbufLRUTail;
  1443. while (pbuf) {
  1444. if (!(pbuf->flags & BUF_Current)) {
  1445. break;
  1446. } else {
  1447. pbuf = pbuf->pbufLRULeft;
  1448. }
  1449. }
  1450. assert(pbuf);
  1451. if (pbuf == pbufLRUTail) {
  1452. pbufLRUTail = pbuf->pbufLRULeft;
  1453. } else {
  1454. pbuf->pbufLRURight->pbufLRULeft = pbuf->pbufLRULeft;
  1455. }
  1456. if (pbuf == pbufLRUHead) {
  1457. pbufLRUHead = pbuf->pbufLRURight;
  1458. } else {
  1459. pbuf->pbufLRULeft->pbufLRURight = pbuf->pbufLRURight;
  1460. }
  1461. pbuf->pbufLRURight = NULL;
  1462. pbuf->pbufLRULeft = NULL;
  1463. return(pbuf);
  1464. }
  1465. STATIC BOOL
  1466. FActivateBuf(
  1467. PFI pfi,
  1468. PBUF pbuf
  1469. )
  1470. /*++
  1471. Routine Description:
  1472. Activate a buffer by removing the first buffer from the free list,
  1473. inserting it to the active list and setting its status to active.
  1474. Arguments:
  1475. pfi - file descriptor to bind buffer to
  1476. pbuf - buffer to activate
  1477. Return Value:
  1478. !0 on success, 0 otherwise
  1479. --*/
  1480. {
  1481. assert(pbuf);
  1482. assert(!(pbuf->flags & BUF_Active));
  1483. assert(pbuf->ifi == -1);
  1484. assert(!(pbuf->flags & BUF_Dirty));
  1485. // if no free bufferes, cannot activate a buffer
  1486. if (!pbufFree) {
  1487. return(FALSE);
  1488. }
  1489. // removed buffer from free list
  1490. assert(pbuf == pbufFree);
  1491. pbufFree = pbuf->pbufNext;
  1492. // bind buffer to physical file handle
  1493. pbuf->ifi = pfi->ifi;
  1494. // make sure there isn't an active buffer on this range
  1495. #if DBG
  1496. assert(FNoDupBuf(pbuf));
  1497. #endif
  1498. // insert buffer into active list
  1499. pbuf->pbufNext = pbufActive;
  1500. pbufActive = pbuf;
  1501. assert(pbufActive);
  1502. // activate the buffer
  1503. pbuf->flags |= BUF_Active;
  1504. assert(
  1505. pfi->rgpbuf[pbuf->ibStart >> cshiftBuf] == NULL ||
  1506. pfi->rgpbuf[pbuf->ibStart >> cshiftBuf] == pbufPreviousWrite);
  1507. assert(pbuf->ibStart <= pfi->cbMap);
  1508. pfi->rgpbuf[pbuf->ibStart >> cshiftBuf] = pbuf;
  1509. DBEXEC(DB_BUFVERBOSE,
  1510. DBPRINT(" - activated pbuf = 0x%p at offset %8lX on file %s\n",
  1511. pbuf, pbuf->ibStart, pfi->szFileName));
  1512. // success
  1513. return 1;
  1514. }
  1515. STATIC BOOL
  1516. FDeactivateBuf(
  1517. PBUF pbuf
  1518. )
  1519. /*++
  1520. Routine Description:
  1521. Deactivate a buffer by flushing it, setting the buffer status to inactive,
  1522. deleting the buffer from the active list and adding the buffer to the
  1523. free list.
  1524. Arguments:
  1525. pbuf - buffer to deactivate
  1526. Return Value:
  1527. !0 on success, 0 otherwise
  1528. --*/
  1529. {
  1530. PBUF pbufT;
  1531. PBUF pbufLast;
  1532. assert(pbuf);
  1533. assert(pbuf->flags & BUF_Active);
  1534. assert(pbuf->ifi != -1);
  1535. assert(pbufActive);
  1536. assert(rgpfi[pbuf->ifi]);
  1537. assert(rgpfi[pbuf->ifi]->rgpbuf);
  1538. assert(rgpfi[pbuf->ifi]->rgpbuf[pbuf->ibStart >> cshiftBuf]);
  1539. assert(!(pbuf->flags & BUF_Current));
  1540. if (!fErr) // don't flush if we had an error
  1541. FlushBuffer(pbuf);
  1542. DBEXEC(DB_BUFVERBOSE,
  1543. DBPRINT(" - deactivated pbuf = 0x%p at offset %8lX on file %s\n",
  1544. pbuf, pbuf->ibStart, rgpfi[pbuf->ifi]->szFileName));
  1545. // make the buffer inactive
  1546. pbuf->flags = 0;
  1547. pbuf->ifi = -1;
  1548. // removed buffer from active list
  1549. if (pbufActive == pbuf) {
  1550. pbufActive = pbufActive->pbufNext;
  1551. } else {
  1552. pbufLast = pbufActive;
  1553. for (pbufT = pbufActive->pbufNext; pbufT; pbufT = pbufT->pbufNext) {
  1554. assert(pbufT);
  1555. if (pbuf == pbufT) {
  1556. pbufLast->pbufNext = pbufT->pbufNext;
  1557. break;
  1558. }
  1559. pbufLast = pbufT;
  1560. }
  1561. }
  1562. // add the buffer to the free list
  1563. pbuf->pbufNext = pbufFree;
  1564. pbufFree = pbuf;
  1565. // success
  1566. return 1;
  1567. }
  1568. STATIC PBUF
  1569. PbufNew(
  1570. VOID)
  1571. /*++
  1572. Routine Description:
  1573. Create a new buffer. Print an error if we run out of memory.
  1574. Arguments:
  1575. None.
  1576. Return Value:
  1577. pointer to a buffer
  1578. --*/
  1579. {
  1580. PBUF pbuf;
  1581. // allocate the buffer structure
  1582. pbuf = (PBUF) PvAllocZ(sizeof(BUF));
  1583. pbuf->ifi = -1;
  1584. assert(pbuf);
  1585. return(pbuf);
  1586. }
  1587. STATIC PBUF
  1588. PbufAlloc(
  1589. PFI pfi,
  1590. LONG ib)
  1591. /*++
  1592. Routine Description:
  1593. Allocate a new buffer. Print an error if we run out of memory.
  1594. Arguments:
  1595. pfi - file descriptor to bind buffer to
  1596. ib - file offset to map buffer to
  1597. Return Value:
  1598. pointer to a buffer
  1599. --*/
  1600. {
  1601. PBUF pbuf;
  1602. #if DBG
  1603. BOOL f;
  1604. #endif //DBG
  1605. assert(FBufListCheck());
  1606. // get a buffer from the free list
  1607. pbuf = pbufFree;
  1608. // if no free buffers
  1609. if (!pbuf) {
  1610. // get LRU seeked buffer
  1611. pbuf = PbufLRU();
  1612. // this assumes more > 0 buffers in the system
  1613. assert(pbuf);
  1614. // deactivate buffer
  1615. #if DBG
  1616. f =
  1617. #endif // DBG
  1618. FDeactivateBuf(pbuf);
  1619. assert(f);
  1620. }
  1621. assert(pbuf);
  1622. // set the buffer range
  1623. pbuf->ibStart = (ib / cbIOBuf) * cbIOBuf;
  1624. pbuf->ibEnd = pbuf->ibStart + cbIOBuf;
  1625. pbuf->ibCur = ib;
  1626. pbuf->ibLast = pbuf->ibStart;
  1627. assert((ib >= pbuf->ibStart) && (ib <= pbuf->ibEnd));
  1628. pbuf->pbCur = (BYTE *) ((LONG) pbuf->rgbBuf + (ib - pbuf->ibStart));
  1629. // if file is writable, clear the buffer
  1630. if (pfi->flags & FI_Write) {
  1631. memset(pbuf->rgbBuf, '\0', cbIOBuf);
  1632. }
  1633. // if file is readable, set the random contents flag
  1634. if (!(pfi->flags & FI_Write)) {
  1635. pbuf->flags |= BUF_Random;
  1636. }
  1637. // activate buffer
  1638. #if DBG
  1639. f =
  1640. #endif // DBG
  1641. FActivateBuf(pfi, pbuf);
  1642. assert(f);
  1643. assert(FBufListCheck());
  1644. // return the buffer
  1645. return(pbuf);
  1646. }
  1647. STATIC VOID
  1648. TransitionPFI(
  1649. PFI pfi,
  1650. PPFI ppfiFromHead,
  1651. PPFI ppfiFromTail,
  1652. PPFI ppfiToHead,
  1653. PPFI ppfiToTail,
  1654. BOOL fAddToTail)
  1655. /*++
  1656. Routine Description:
  1657. Move a logical file descriptor from one pool to another.
  1658. Arguments:
  1659. pfi - logical file descriptor to move
  1660. ppfiFromHead - head of pool to remove pfi from
  1661. ppfiFromTail - tail of pool to remove pfi from, update if ppfiFromTail
  1662. ppfiToHead - head of pool to put pfi in
  1663. ppfiToTail - tail of pool to put pfi in, update if ppfiToTail
  1664. fAddToTail - add pfi to tail of ppfiTo
  1665. Return Value:
  1666. !0 on success, 0 otherwise
  1667. --*/
  1668. {
  1669. PFI pfiT; // current
  1670. PFI pfiL; // last
  1671. assert(pfi);
  1672. assert(ppfiFromHead);
  1673. assert(ppfiToHead);
  1674. #if DBG
  1675. assert(FPfiInList(pfi, *ppfiFromHead));
  1676. assert(!FPfiInList(pfi, *ppfiToHead));
  1677. #endif // DBG
  1678. // remove pfi from ppfiFromHead
  1679. if (pfi == *ppfiFromHead) {
  1680. // pfi is the first element
  1681. *ppfiFromHead = (*ppfiFromHead)->pfiNext;
  1682. if (ppfiFromTail && ((*ppfiFromTail) == pfi)) {
  1683. *ppfiFromTail = NULL;
  1684. }
  1685. } else {
  1686. pfiL = *ppfiFromHead;
  1687. for (pfiT = (*ppfiFromHead)->pfiNext; pfiT; pfiT = pfiT->pfiNext) {
  1688. if (pfi == pfiT) {
  1689. pfiL->pfiNext = pfiT->pfiNext;
  1690. break;
  1691. } else {
  1692. pfiL = pfiT;
  1693. }
  1694. }
  1695. if (ppfiFromTail && ((*ppfiFromTail) == pfi)) {
  1696. *ppfiFromTail = pfiL;
  1697. }
  1698. }
  1699. // add pfi to ppfiTo
  1700. if (!(*ppfiToHead)) {
  1701. // list is empty
  1702. *ppfiToHead = pfi;
  1703. pfi->pfiNext = NULL;
  1704. if (ppfiToTail) {
  1705. assert(!(*ppfiToTail));
  1706. *ppfiToTail = pfi;
  1707. }
  1708. } else {
  1709. if (fAddToTail) {
  1710. // add pfi to tail
  1711. assert(ppfiToTail);
  1712. pfi->pfiNext = NULL;
  1713. (*ppfiToTail)->pfiNext = pfi;
  1714. *ppfiToTail = pfi;
  1715. } else {
  1716. pfi->pfiNext = *ppfiToHead;
  1717. *ppfiToHead = pfi;
  1718. }
  1719. }
  1720. }
  1721. #if DBG
  1722. STATIC BOOL
  1723. FBufListCheck(
  1724. VOID)
  1725. /*++
  1726. Routine Description:
  1727. Check the active, free and LRU list for errors. This is a debug routine.
  1728. Arguments:
  1729. None.
  1730. Return Value:
  1731. None.
  1732. --*/
  1733. {
  1734. PBUF pbuf;
  1735. LONG cbuf;
  1736. // ensure the correct number of buffers in the lists
  1737. for(cbuf = 0, pbuf = pbufFree;
  1738. pbuf && cbuf < cbufTot;
  1739. pbuf = pbuf->pbufNext) {
  1740. cbuf++;
  1741. }
  1742. for(pbuf = pbufActive;
  1743. pbuf && cbuf < cbufTot;
  1744. pbuf = pbuf->pbufNext) {
  1745. cbuf++;
  1746. }
  1747. if (cbuf != cbufTot) {
  1748. return(FALSE);
  1749. }
  1750. // walk down the LRU list counting members, walk back and see
  1751. // if we get to the same place
  1752. for(cbuf = 0, pbuf = pbufLRUHead;
  1753. pbuf && cbuf < cbufTot;
  1754. pbuf = pbuf->pbufLRURight) {
  1755. cbuf++;
  1756. }
  1757. for(pbuf = pbufLRUTail;
  1758. pbuf && cbuf > 0;
  1759. pbuf = pbuf->pbufLRULeft) {
  1760. cbuf--;
  1761. }
  1762. return(cbuf == 0);
  1763. }
  1764. #endif // DBG
  1765. #if DBG
  1766. STATIC BOOL
  1767. FNoDupBuf(
  1768. PBUF pbuf)
  1769. /*++
  1770. Routine Description:
  1771. Scan the active list to see if pbuf's range is covered by another buffer.
  1772. Arguments:
  1773. pbuf - buffer to check for duplicates ranges of
  1774. Return Value:
  1775. !0 if no duplicates, 0 if duplicates
  1776. --*/
  1777. {
  1778. PBUF pbufT;
  1779. assert(pbuf);
  1780. for (pbufT = pbufActive; pbufT; pbufT = pbufT->pbufNext) {
  1781. assert(pbufT);
  1782. if ((pbuf->ifi == pbufT->ifi) &&
  1783. (pbuf->ibStart == pbufT->ibStart)) {
  1784. return(FALSE);
  1785. }
  1786. }
  1787. return 1;
  1788. }
  1789. #endif // DBG
  1790. #if DBG
  1791. STATIC BOOL
  1792. FPfiInList(
  1793. PFI pfi,
  1794. PFI pfiList)
  1795. /*++
  1796. Routine Description:
  1797. Check if pfi is in pfiList.
  1798. Arguments:
  1799. pfi - logical file descriptor to check for
  1800. pfiList - list to look for logical file descriptor in
  1801. Return Value:
  1802. !0 if found, 0 if not found
  1803. --*/
  1804. {
  1805. PFI pfiT;
  1806. DWORD ifi = 0;
  1807. for (pfiT = pfiList, ifi = 0; pfiT; pfiT = pfiT->pfiNext, ifi++) {
  1808. if (pfiT == pfi) {
  1809. return(TRUE);
  1810. }
  1811. if (ifi > cfiTot) {
  1812. assert(FALSE);
  1813. return(FALSE);
  1814. }
  1815. }
  1816. return(FALSE);
  1817. }
  1818. #endif // DBG
  1819. #if DBG
  1820. STATIC BOOL
  1821. FPfiCheck(
  1822. VOID)
  1823. /*++
  1824. Routine Description:
  1825. Check the pfi lists.
  1826. Arguments:
  1827. None.
  1828. Return Value:
  1829. !0 if found, 0 if not found
  1830. --*/
  1831. {
  1832. DWORD ifi = 0;
  1833. PFI pfi;
  1834. pfi = pfiFree;
  1835. while (pfi) {
  1836. ifi++;
  1837. if (ifi > cfiTot) {
  1838. return(FALSE);
  1839. }
  1840. pfi = pfi->pfiNext;
  1841. }
  1842. pfi = pfiOpen;
  1843. while (pfi) {
  1844. ifi++;
  1845. if (ifi > cfiTot) {
  1846. return(FALSE);
  1847. }
  1848. if (!(pfi->flags & FI_Mapped) && pfi->pbufCur != NULL) {
  1849. if (pfi->ifi != pfi->pbufCur->ifi) {
  1850. return(FALSE);
  1851. }
  1852. }
  1853. pfi = pfi->pfiNext;
  1854. }
  1855. pfi = pfiClosedHead;
  1856. while (pfi) {
  1857. ifi++;
  1858. if (ifi > cfiTot) {
  1859. return(FALSE);
  1860. }
  1861. if (!(pfi->flags & FI_Mapped) && pfi->pbufCur != NULL) {
  1862. if (pfi->ifi != pfi->pbufCur->ifi) {
  1863. return(FALSE);
  1864. }
  1865. }
  1866. pfi = pfi->pfiNext;
  1867. }
  1868. return(cfiTot == ifi);
  1869. }
  1870. #endif // DBG
  1871. INT
  1872. MappedOpen(
  1873. PFI pfi,
  1874. LONG flags,
  1875. BOOL fNewPfi,
  1876. DWORD *pdwErr)
  1877. /*++
  1878. Routine Description:
  1879. NT mapped i/o open.
  1880. Arguments:
  1881. pfi - logical file descriptor
  1882. flags - flags to open file with
  1883. fNewPfi - !0 if pfi is new
  1884. pdwErr - ptr to store error code in case of failure.
  1885. Return Value:
  1886. 0 on success, !0 otherwise
  1887. --*/
  1888. {
  1889. BOOL fWriteable, fCreate;
  1890. int i;
  1891. DWORD dwSize;
  1892. if (fNewPfi) {
  1893. // open the file through win32
  1894. fWriteable = flags & (O_WRONLY | O_RDWR);
  1895. fCreate = flags & O_CREAT;
  1896. if (fWriteable) {
  1897. for (i = 0; i < MAX_WRITEABLE_FILES; i++) {
  1898. if (pfiCloseOnBadExit[i] == NULL) {
  1899. pfiCloseOnBadExit[i] = pfi;
  1900. break;
  1901. }
  1902. }
  1903. pfi->hFile = CreateFile(pfi->szFileName,
  1904. GENERIC_READ | GENERIC_WRITE, // access
  1905. 0, // share
  1906. NULL, // security
  1907. fCreate ? CREATE_ALWAYS : OPEN_EXISTING,
  1908. FILE_ATTRIBUTE_NORMAL,
  1909. NULL);
  1910. } else {
  1911. assert(!fCreate); // no read-only create
  1912. pfi->hFile = CreateFile(pfi->szFileName,
  1913. GENERIC_READ, // access
  1914. FILE_SHARE_READ, // share
  1915. NULL, // security
  1916. OPEN_EXISTING,
  1917. 0,
  1918. NULL);
  1919. }
  1920. // abort on error
  1921. if (pfi->hFile == INVALID_HANDLE_VALUE) {
  1922. (*pdwErr) = GetLastError();
  1923. pfi->hFile = NULL;
  1924. if (!fWriteable &&
  1925. ((*pdwErr) == ERROR_PATH_NOT_FOUND ||
  1926. (*pdwErr) == ERROR_FILE_NOT_FOUND) ) {
  1927. TR_Open_To_Free(pfi);
  1928. Fatal(NULL, CANTOPENINPUTFILE, pfi->szFileName);
  1929. } else {
  1930. return -1;
  1931. }
  1932. }
  1933. if (fCreate) {
  1934. dwSize = 0;
  1935. } else {
  1936. dwSize = GetFileSize(pfi->hFile, NULL);
  1937. if (dwSize == 0xFFFFFFFF) {
  1938. Fatal(NULL, CANTOPENFILE, pfi->szFileName);
  1939. }
  1940. }
  1941. pfi->cbSoFar = dwSize;
  1942. if (fWriteable) {
  1943. if (pfi->cbMapView == 0) { // Set in the case of FileOpenMapped()
  1944. pfi->cbMapView = __max(cbMapViewDefault, pfi->cbSoFar);
  1945. }
  1946. } else {
  1947. pfi->cbMapView = pfi->cbSoFar;
  1948. }
  1949. if (!FMapPfi(pfi, FALSE, pdwErr)) {
  1950. return -1;
  1951. }
  1952. pfi->flags |= FI_Mapped;
  1953. } else {
  1954. MappedSeek(pfi, 0, SEEK_SET, pdwErr);
  1955. }
  1956. return(0);
  1957. }
  1958. LONG
  1959. MappedSeek(
  1960. PFI pfi,
  1961. LONG ib,
  1962. INT origin,
  1963. DWORD *pdwErr)
  1964. /*++
  1965. Routine Description:
  1966. NT mapped i/o seek.
  1967. Arguments:
  1968. pfi - logical file descriptor
  1969. if - offset
  1970. origin - type of seek
  1971. pdwErr - ptr to store error code in.
  1972. Return Value:
  1973. offset seek to
  1974. --*/
  1975. {
  1976. switch (origin) {
  1977. #if DBG
  1978. default:
  1979. assert(FALSE);
  1980. break;
  1981. #endif
  1982. case SEEK_CUR:
  1983. assert((pfi->ibCur + ib) >= 0 );
  1984. pfi->ibCur += ib;
  1985. break;
  1986. case SEEK_END:
  1987. assert(pfi->cbSoFar + ib >= 0);
  1988. pfi->ibCur = pfi->cbSoFar + ib;
  1989. break;
  1990. case SEEK_SET:
  1991. assert(ib >= 0 );
  1992. pfi->ibCur = ib;
  1993. break;
  1994. }
  1995. if (pfi->ibCur > pfi->cbMapView) {
  1996. if (!ExtendMapView(pfi, pfi->ibCur, pdwErr)) {
  1997. if (pfi->MapAddr == 0) { // not the ILK file
  1998. if ((*pdwErr) == ERROR_DISK_FULL) {
  1999. Fatal(pfi->szFileName, DISKFULL);
  2000. }
  2001. Fatal(pfi->szFileName, CANTSEEKFILE, pfi->ibCur);
  2002. }
  2003. return(-1);
  2004. }
  2005. }
  2006. DBEXEC(DB_IO_SEEK,
  2007. Trans_LOG(LOG_MapSeek, pfi->ifi, ib, 0, origin, NULL));
  2008. return(pfi->ibCur);
  2009. }
  2010. STATIC DWORD
  2011. MappedRead(
  2012. PFI pfi,
  2013. PVOID pv,
  2014. DWORD cb)
  2015. /*++
  2016. Routine Description:
  2017. NT mapped i/o read.
  2018. Arguments:
  2019. pfi - logical file descriptor
  2020. pv - buffer to read into
  2021. cb - bytes to read
  2022. Return Value:
  2023. bytes read
  2024. --*/
  2025. {
  2026. PVOID pvT;
  2027. DWORD dwErr = 0;
  2028. assert(pfi);
  2029. assert(pv);
  2030. DBEXEC(DB_IO_READ,
  2031. Trans_LOG(LOG_MapRead, pfi->ifi, pfi->ibCur, cb, 0, NULL));
  2032. // extend map view only for writeable files
  2033. if ((pfi->ibCur + (LONG) cb) > pfi->cbMapView) {
  2034. if (pfi->flags & FI_Write) {
  2035. if (!ExtendMapView(pfi, pfi->ibCur + (LONG) cb, &dwErr)) {
  2036. Fatal(pfi->szFileName, CANTSEEKFILE, pfi->ibCur + (LONG) cb);
  2037. }
  2038. } else {
  2039. return(0);
  2040. }
  2041. }
  2042. pvT = (PVOID) ((DWORD) (pfi->pvMapView) + (DWORD) (pfi->ibCur));
  2043. memcpy(pv, pvT, cb);
  2044. pfi->ibCur += cb;
  2045. return(cb);
  2046. }
  2047. /*++
  2048. Routine Description:
  2049. NT mapped i/o tell.
  2050. Arguments:
  2051. pfi - logical file descriptor
  2052. Return Value:
  2053. file offset
  2054. --*/
  2055. #if DBG
  2056. LONG WriteBreakAddress = (LONG) -1;
  2057. #endif
  2058. STATIC DWORD
  2059. MappedWrite(
  2060. PFI pfi,
  2061. const void *pv,
  2062. DWORD cb)
  2063. {
  2064. PVOID pvT;
  2065. DWORD dwErr = 0;
  2066. assert(pfi);
  2067. assert(pfi->ibCur >= 0);
  2068. DBEXEC(DB_IO_WRITE,
  2069. Trans_LOG(LOG_MapWrite, pfi->ifi, pfi->ibCur, cb, 0, NULL));
  2070. if ((pfi->ibCur + (LONG) cb) > pfi->cbMapView) {
  2071. if (!ExtendMapView(pfi, pfi->ibCur + cb, &dwErr)) {
  2072. Fatal(pfi->szFileName, CANTSEEKFILE, pfi->ibCur + (LONG) cb);
  2073. }
  2074. }
  2075. pvT = (PVOID) ((DWORD) (pfi->pvMapView) + (DWORD) (pfi->ibCur));
  2076. if ((pfi->ibCur + (LONG) cb) > pfi->cbSoFar) {
  2077. pfi->cbSoFar = pfi->ibCur + (LONG) cb;
  2078. }
  2079. #if DBG
  2080. if (((DWORD) pfi->ibCur <= (DWORD) WriteBreakAddress) && ((DWORD) (pfi->ibCur + cb) >= (DWORD) WriteBreakAddress)) {
  2081. DebugBreak();
  2082. }
  2083. #endif
  2084. memcpy(pvT, pv, cb);
  2085. pfi->ibCur += cb;
  2086. return(cb);
  2087. }
  2088. INT
  2089. MappedCloseHard (
  2090. PFI pfi)
  2091. /*++
  2092. Routine Description:
  2093. NT mapped i/o hard close.
  2094. Arguments:
  2095. pfi - logical file descriptor
  2096. Return Value:
  2097. file offset
  2098. --*/
  2099. {
  2100. INT i, retval;
  2101. assert(pfi);
  2102. assert(pfi->flags & FI_Mapped);
  2103. // already closed
  2104. if (!pfi->hFile) {
  2105. return TRUE;
  2106. }
  2107. if (!UnmapViewOfFile(pfi->pvMapView)) {
  2108. Fatal(NULL, CANTCLOSEFILE, pfi->szFileName);
  2109. }
  2110. if (pfi->flags & FI_Write) {
  2111. // If writeable, set the end of file pointer to the last place we
  2112. // wrote. This prevents the file from being created with the full
  2113. // size of the mapping.
  2114. if ((pfi->cbSoFar != (LONG)SetFilePointer(pfi->hFile, pfi->cbSoFar, NULL, FILE_BEGIN)) ||
  2115. !SetEndOfFile(pfi->hFile)) {
  2116. Fatal(NULL, CANTCLOSEFILE, pfi->szFileName);
  2117. }
  2118. }
  2119. if (!(retval = CloseHandle(pfi->hFile))) {
  2120. Fatal(NULL, CANTCLOSEFILE, pfi->szFileName);
  2121. }
  2122. for (i = 0; i < MAX_WRITEABLE_FILES; i++) {
  2123. if (pfi == pfiCloseOnBadExit[i]) {
  2124. pfiCloseOnBadExit[i] = NULL;
  2125. }
  2126. }
  2127. FreePv(pfi->szFileName);
  2128. return(retval);
  2129. }
  2130. BOOL
  2131. ExtendMapView(PFI pfi, DWORD ibNeeded, DWORD *pdwErr)
  2132. // Makes the memory-map bigger for a mapped file. This only makes sense
  2133. // for writeable files, not readable files.
  2134. {
  2135. // Free the existing map.
  2136. if (!UnmapViewOfFile(pfi->pvMapView)) {
  2137. *pdwErr = GetLastError();
  2138. CloseHandle(pfi->hFile);
  2139. pfi->hFile = NULL;
  2140. return FALSE;
  2141. }
  2142. // Set the new size (it must grow by at least a factor of 2).
  2143. pfi->cbMapView = __max((LONG) ibNeeded, pfi->cbMapView * 2);
  2144. if (!FMapPfi(pfi, TRUE, pdwErr)) {
  2145. return(FALSE);
  2146. }
  2147. return(TRUE);
  2148. }
  2149. BOOL
  2150. FMapPfi(PFI pfi, BOOL fExtend, DWORD *pdwErr)
  2151. {
  2152. HANDLE hMap;
  2153. if (pfi->flags & FI_Write && fExtend) {
  2154. // Extend file to size specified. This works around a problem in
  2155. // NT 3.10 where the cache isn't flushed to disk properly.
  2156. if ((pfi->cbMapView != (LONG)SetFilePointer(pfi->hFile, pfi->cbMapView, NULL, FILE_BEGIN)) ||
  2157. !SetEndOfFile(pfi->hFile)) {
  2158. (*pdwErr) = GetLastError();
  2159. CloseHandle(pfi->hFile);
  2160. pfi->hFile = NULL;
  2161. return FALSE;
  2162. }
  2163. }
  2164. hMap = CreateFileMapping(pfi->hFile,
  2165. NULL,
  2166. (pfi->flags & FI_Write)
  2167. ? PAGE_READWRITE
  2168. : PAGE_READONLY,
  2169. 0,
  2170. pfi->cbMapView,
  2171. NULL);
  2172. if (hMap == NULL) {
  2173. (*pdwErr) = GetLastError();
  2174. CloseHandle(pfi->hFile);
  2175. pfi->hFile = NULL;
  2176. return FALSE;
  2177. }
  2178. pfi->pvMapView = MapViewOfFileEx(hMap,
  2179. (pfi->flags & FI_Write)
  2180. ? FILE_MAP_ALL_ACCESS
  2181. : FILE_MAP_READ,
  2182. 0,
  2183. 0,
  2184. 0,
  2185. (LPVOID) pfi->MapAddr);
  2186. if (!pfi->pvMapView) {
  2187. (*pdwErr) = GetLastError();
  2188. CloseHandle(hMap);
  2189. CloseHandle(pfi->hFile);
  2190. pfi->hFile = NULL;
  2191. return FALSE;
  2192. }
  2193. // The handle to the mapping object isn't needed any more
  2194. if (!CloseHandle(hMap)) {
  2195. (*pdwErr) = GetLastError();
  2196. return FALSE;
  2197. }
  2198. return TRUE;
  2199. }
  2200. VOID
  2201. MoveToFreeListPfi (PFI pfi)
  2202. {
  2203. PFI pfiT;
  2204. pfiT = pfiOpen;
  2205. while (pfiT) {
  2206. if (pfiT == pfi) {
  2207. TR_Open_To_Free(pfi);
  2208. return;
  2209. } else {
  2210. pfiT = pfiT->pfiNext;
  2211. }
  2212. } // end while
  2213. pfiT = pfiClosedHead;
  2214. while (pfiT) {
  2215. if (pfiT == pfi) {
  2216. TR_Cache_To_Free(pfi);
  2217. return;
  2218. } else {
  2219. pfiT = pfiT->pfiNext;
  2220. }
  2221. } // end while
  2222. // should have been in one of the lists
  2223. Fatal(NULL, INTERNAL_ERR);
  2224. }
  2225. VOID
  2226. BadExitCleanup(VOID)
  2227. // Warning ... may be called asynchronously by the control-C handler thread.
  2228. {
  2229. int i;
  2230. // on an ilink free up ILK space and close file
  2231. if (fINCR) {
  2232. FreeHeap();
  2233. if (!_access(szIncrDbFilename, 0)) {
  2234. _unlink(szIncrDbFilename);
  2235. }
  2236. }
  2237. for (i = 0; i < MAX_WRITEABLE_FILES; i++) {
  2238. if (pfiCloseOnBadExit[i] != NULL) {
  2239. // remove pfi from list of open/cached pfi (otherwise we will try to close it again in FileCloseAll()).
  2240. MoveToFreeListPfi(pfiCloseOnBadExit[i]);
  2241. if (!UnmapViewOfFile(pfiCloseOnBadExit[i]->pvMapView)) {
  2242. Fatal(NULL, CANTCLOSEFILE, pfiCloseOnBadExit[i]->szFileName);
  2243. }
  2244. if (pfiCloseOnBadExit[i]->flags & FI_Write) {
  2245. // Set end of file to 0, this speeds up the close
  2246. if ((SetFilePointer(pfiCloseOnBadExit[i]->hFile, 0, NULL, FILE_BEGIN) != 0) ||
  2247. !SetEndOfFile(pfiCloseOnBadExit[i]->hFile))
  2248. Fatal(NULL, CANTCLOSEFILE, pfiCloseOnBadExit[i]->szFileName);
  2249. }
  2250. if (!CloseHandle(pfiCloseOnBadExit[i]->hFile)) {
  2251. Fatal(NULL, CANTCLOSEFILE, pfiCloseOnBadExit[i]->szFileName);
  2252. }
  2253. if (!DeleteFile(pfiCloseOnBadExit[i]->szFileName)) {
  2254. Fatal(NULL, CANTREMOVEFILE, pfiCloseOnBadExit[i]->szFileName);
  2255. }
  2256. }
  2257. }
  2258. FileCloseAll();
  2259. RemoveConvertTempFiles();
  2260. // Close the pdb w/o committing.
  2261. if (fPdb) {
  2262. DBG_ClosePDB();
  2263. }
  2264. ExitProcess(1);
  2265. }
  2266. // PbMappedRegion: if possible, returns a pointer to a memory-mapped region
  2267. // of an open file. If the file is writeable, its size is extended to
  2268. // the end of the region if necessary.
  2269. //
  2270. // Returns NULL if mapping is not available.
  2271. //
  2272. // The "current position" in the file is not changed.
  2273. //
  2274. // Caveats:
  2275. // * caller must handle NULL return value
  2276. // * return value is invalidated by subsequent operations on the same
  2277. // file handle.
  2278. BYTE *
  2279. PbMappedRegion(INT fd, DWORD ibStart, DWORD cb)
  2280. {
  2281. PFI pfi;
  2282. DWORD dwErr = 0;
  2283. pfi = rgpfi[fd];
  2284. if (!(pfi->flags & FI_Mapped)) {
  2285. return NULL;
  2286. }
  2287. DBEXEC(DB_IO_WRITE,
  2288. Trans_LOG(LOG_MapWrite, pfi->ifi, pfi->ibCur, cb, 0, NULL));
  2289. if (ibStart + cb > (DWORD)pfi->cbMapView) {
  2290. if (!ExtendMapView(pfi, ibStart + cb, &dwErr)) {
  2291. if (dwErr == ERROR_DISK_FULL) {
  2292. Fatal(pfi->szFileName, DISKFULL);
  2293. }
  2294. Fatal(pfi->szFileName, CANTSEEKFILE, ibStart + cb);
  2295. }
  2296. }
  2297. if ((ibStart + cb) > (DWORD) pfi->cbSoFar) {
  2298. pfi->cbSoFar = ibStart + cb;
  2299. }
  2300. return((BYTE *) pfi->pvMapView + ibStart);
  2301. }
  2302. VOID
  2303. FileSetSize (
  2304. INT fd
  2305. )
  2306. /*++
  2307. Routine Description:
  2308. This API is used in conjunction with Malloc() to set the
  2309. current size of file since the writes don't go through
  2310. the file API.
  2311. Arguments:
  2312. fd - hanlde to file
  2313. Return Value:
  2314. None
  2315. --*/
  2316. {
  2317. // file better be mapped
  2318. assert(rgpfi[fd]->flags & FI_Mapped);
  2319. // update cbSoFar
  2320. rgpfi[fd]->cbSoFar = rgpfi[fd]->ibCur;
  2321. }
  2322. VOID
  2323. FileCloseMap (
  2324. INT fd
  2325. )
  2326. /*++
  2327. Routine Description:
  2328. Closes the map and file without writing out anything.
  2329. Arguments:
  2330. fd - hanlde to file
  2331. Return Value:
  2332. None
  2333. --*/
  2334. {
  2335. // don't look at interrupts here
  2336. // file must be a mapped file
  2337. assert(rgpfi[fd]->flags & FI_Mapped);
  2338. // set the size to zero
  2339. rgpfi[fd]->cbSoFar = 0;
  2340. // remove pfi from open list
  2341. TR_Open_To_Free(rgpfi[fd]);
  2342. // close the map & file
  2343. MappedCloseHard(rgpfi[fd]);
  2344. }