Source code of Windows XP (NT5)
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.

1001 lines
26 KiB

  1. /*****************************************************************************
  2. * *
  3. * BTREE.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1989 - 1994. *
  6. * All Rights reserved. *
  7. * *
  8. ******************************************************************************
  9. * *
  10. * Module Intent *
  11. * *
  12. * Btree manager general functions: open, close, etc. *
  13. * *
  14. ******************************************************************************
  15. * *
  16. * Current Owner: BinhN *
  17. * *
  18. *****************************************************************************/
  19. /*****************************************************************************
  20. *
  21. * Revision History: Created 02/10/89 by JohnSc
  22. *
  23. * 2/10/89 johnsc created: stub version
  24. * 3/10/89 johnsc use FS files
  25. * 8/21/89 johnsc autodocified
  26. * 11/08/90 JohnSc added a parameter to RcGetBtreeInfo() to get block size
  27. * 11/29/90 RobertBu #ifdef'ed out a dead routine
  28. * 12/14/90 JohnSc added VerifyHbt()
  29. * 3/05/97 erinfox Change errors to HRESULTS
  30. *
  31. *****************************************************************************/
  32. static char s_aszModule[] = __FILE__; /* For error report */
  33. #include <mvopsys.h>
  34. #include <string.h>
  35. #include <orkin.h>
  36. #include <misc.h>
  37. #include <iterror.h>
  38. #include <wrapstor.h>
  39. #include <mvsearch.h>
  40. #include <_mvutil.h>
  41. #include "common.h"
  42. /***************************************************************************
  43. *
  44. - Function: RcMakeCache(qbthr)
  45. -
  46. * Purpose: Allocate a btree cache with one block per level.
  47. *
  48. * ASSUMES
  49. * args IN: qbthr - no cache
  50. *
  51. * PROMISES
  52. * returns: S_OK, or errors
  53. * args OUT: qbthr->ghCache is allocated; qbthr->qCache is NULL
  54. *
  55. ***************************************************************************/
  56. HRESULT PASCAL FAR RcMakeCache(QBTHR qbthr)
  57. {
  58. SHORT i;
  59. /* Sanity check */
  60. if (qbthr == NULL)
  61. return (E_INVALIDARG);
  62. /* Allocate the memory */
  63. if (qbthr->bth.cLevels > 0)
  64. {
  65. // would it work to just alloc 0 bytes???
  66. qbthr->ghCache = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
  67. (LONG)qbthr->bth.cLevels * CbCacheBlock(qbthr) );
  68. if (qbthr->ghCache == NULL)
  69. return (E_OUTOFMEMORY);
  70. qbthr->qCache = (QB) _GLOBALLOCK(qbthr->ghCache);
  71. /* Initialize the flags */
  72. for (i = 0; i < qbthr->bth.cLevels; i++)
  73. QCacheBlock(qbthr, i)->bFlags = (BYTE)0;
  74. _GLOBALUNLOCK(qbthr->ghCache);
  75. }
  76. else {
  77. qbthr->ghCache = NULL;
  78. }
  79. qbthr->qCache = NULL;
  80. return (S_OK);
  81. }
  82. /***************************************************************************
  83. *
  84. * Public Routines
  85. *
  86. ***************************************************************************/
  87. /***************************************************************************
  88. *
  89. - Function: HbtCreateBtreeSz(sz, qbtp)
  90. -
  91. * Purpose: Create and open a btree.
  92. *
  93. * ASSUMES
  94. * args IN: sz - name of the btree
  95. * qbtp - pointer to btree params: NO default because we
  96. * need an HFS.
  97. * The bFlags param contains HFILE_SYSTEM for the
  98. * system btree, but none of the btree code should
  99. * care whether or not it is a system file.
  100. *
  101. * PROMISES
  102. * returns: handle to the new btree
  103. *
  104. * Note: KT supported: KT_SZ, KT_LONG, KT_SZI, KT_SZISCAND.
  105. * +++
  106. *
  107. * Method: Btrees are files inside a FS. The FS directory is a
  108. * special file in the FS.
  109. *
  110. ***************************************************************************/
  111. HBT FAR PASCAL HbtCreateBtreeSz(LPSTR sz,BTREE_PARAMS FAR *qbtp, PHRESULT phr)
  112. {
  113. HF hf;
  114. HBT hbt;
  115. QBTHR qbthr;
  116. /* see if we support key type */
  117. if (qbtp == NULL ||
  118. (
  119. #ifdef FULL_BTREE // {
  120. qbtp->rgchFormat[0] != KT_SZ
  121. &&
  122. qbtp->rgchFormat[0] != KT_VSTI
  123. &&
  124. qbtp->rgchFormat[0] != KT_SZI
  125. &&
  126. qbtp->rgchFormat[0] != KT_SZMAP
  127. &&
  128. qbtp->rgchFormat[0] != KT_SZISCAND
  129. &&
  130. #endif // }
  131. qbtp->rgchFormat[0] != KT_LONG
  132. &&
  133. qbtp->rgchFormat[0] != KT_EXTSORT) )
  134. {
  135. SetErrCode(phr, E_INVALIDARG);
  136. return NULL;
  137. }
  138. /* allocate btree handle struct */
  139. if (( hbt = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
  140. (LONG)sizeof( BTH_RAM) ) ) == NULL ) {
  141. SetErrCode(phr, E_OUTOFMEMORY);
  142. return NULL;
  143. }
  144. qbthr = (QBTHR) _GLOBALLOCK(hbt);
  145. /* initialize bthr struct */
  146. qbtp->rgchFormat[ wMaxFormat ] = '\0';
  147. lstrcpy(qbthr->bth.rgchFormat, qbtp->rgchFormat[0] == '\0'
  148. ? rgchBtreeFormatDefault : qbtp->rgchFormat);
  149. switch (qbtp->rgchFormat[ 0 ])
  150. {
  151. #ifdef FULL_BTREE // {
  152. case KT_SZ:
  153. qbthr->BkScanInternal = BkScanSzInternal;
  154. qbthr->RcScanLeaf = RcScanSzLeaf;
  155. break;
  156. case KT_VSTI:
  157. qbthr->BkScanInternal = BkScanVstiInternal;
  158. qbthr->RcScanLeaf = RcScanVstiLeaf;
  159. break;
  160. case KT_SZI:
  161. qbthr->BkScanInternal = BkScanSziInternal;
  162. qbthr->RcScanLeaf = RcScanSziLeaf;
  163. break;
  164. case KT_SZISCAND:
  165. qbthr->BkScanInternal = BkScanSziScandInternal;
  166. qbthr->RcScanLeaf = RcScanSziScandLeaf;
  167. break;
  168. case KT_SZMAP:
  169. qbthr->BkScanInternal = BkScanCMapInternal ;
  170. qbthr->RcScanLeaf = RcScanCMapLeaf;
  171. break;
  172. #endif // }
  173. case KT_LONG:
  174. qbthr->BkScanInternal = BkScanLInternal;
  175. qbthr->RcScanLeaf = RcScanLLeaf;
  176. break;
  177. case KT_EXTSORT:
  178. qbthr->BkScanInternal = BkScanExtSortInternal ;
  179. qbthr->RcScanLeaf = RcScanExtSortLeaf;
  180. break;
  181. default:
  182. /* unsupported KT */
  183. SetErrCode(phr, E_INVALIDARG);
  184. goto error_return;
  185. break;
  186. }
  187. /* create the btree file */
  188. if (!FHfValid(hf = HfCreateFileHfs(qbtp->hfs, sz, qbtp->bFlags, phr)))
  189. {
  190. goto error_return;
  191. }
  192. qbthr->bth.wMagic = wBtreeMagic;
  193. qbthr->bth.bVersion = bBtreeVersion;
  194. qbthr->bth.bFlags = qbtp->bFlags | fFSDirty;
  195. qbthr->bth.cbBlock = qbtp->cbBlock ? qbtp->cbBlock : cbBtreeBlockDefault;
  196. qbthr->bth.bkFirst =
  197. qbthr->bth.bkLast =
  198. qbthr->bth.bkRoot =
  199. qbthr->bth.bkFree = bkNil;
  200. qbthr->bth.bkEOF = (BK)0;
  201. qbthr->bth.cLevels = 0;
  202. qbthr->bth.lcEntries = (LONG)0;
  203. qbthr->bth.dwCodePageID = qbtp->dwCodePageID;
  204. qbthr->bth.lcid = qbtp->lcid;
  205. qbthr->bth.dwExtSortInstID = qbtp->dwExtSortInstID;
  206. qbthr->bth.dwExtSortKeyType = qbtp->dwExtSortKeyType;
  207. qbthr->hf = hf;
  208. qbthr->cbRecordSize = 0;
  209. qbthr->ghCache = NULL;
  210. qbthr->qCache = NULL;
  211. qbthr->lrglpCharTab = NULL;
  212. qbthr->pITSortKey = NULL;
  213. LcbWriteHf(qbthr->hf, &(qbthr->bth), (LONG)sizeof(BTH), phr ); /* why??? */
  214. _GLOBALUNLOCK(hbt);
  215. return hbt;
  216. error_return:
  217. _GLOBALUNLOCK(hbt);
  218. _GLOBALFREE(hbt);
  219. return NULL;
  220. }
  221. /***************************************************************************
  222. *
  223. - Function: RcDestroyBtreeSz(sz, hfs)
  224. -
  225. * Purpose: destroy an existing btree
  226. *
  227. * Method: look for file and unlink it
  228. *
  229. * ASSUMES
  230. * args IN: sz - name of btree file
  231. * hfs - file system btree lives in
  232. * state IN: btree is closed (if not data will be lost)
  233. *
  234. * PROMISES
  235. * returns: S_OK or errors
  236. *
  237. * Notes: FS directory btree never gets destroyed: you just get rid
  238. * of the whole fs.
  239. *
  240. ***************************************************************************/
  241. HRESULT FAR PASCAL RcDestroyBtreeSz(LPSTR sz, HFS hfs)
  242. {
  243. return (RcUnlinkFileHfs(hfs, sz));
  244. }
  245. /***************************************************************************
  246. *
  247. * Function: HbtOpenBtreeSz(sz, hfs, bFlags)
  248. *
  249. * Purpose: open an existing btree
  250. *
  251. * ASSUMES
  252. * args IN: sz - name of the btree (ignored if isdir is set)
  253. * hfs - hfs btree lives in
  254. * bFlags - open mode, isdir flag
  255. * args OUT:
  256. * phr - error code
  257. *
  258. * PROMISES
  259. * returns: handle to the open btree or NULL on failure
  260. * isdir flag set in qbthr->bth.bFlags if indicated
  261. *
  262. ***************************************************************************/
  263. HBT FAR PASCAL HbtOpenBtreeSz(LPWSTR sz, HFS hfs, BYTE bFlags, PHRESULT phr)
  264. {
  265. HF hf;
  266. QBTHR qbthr;
  267. HBT hbt;
  268. LONG lcb;
  269. HRESULT rc;
  270. /* allocate struct */
  271. if ((hbt = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
  272. (LONG)sizeof(BTH_RAM))) == NULL)
  273. {
  274. SetErrCode(phr, E_OUTOFMEMORY);
  275. return NULL;
  276. }
  277. qbthr = (QBTHR) _GLOBALLOCK(hbt);
  278. /* open btree file */
  279. if (!FHfValid(hf = HfOpenHfs(hfs, sz, bFlags, phr)))
  280. {
  281. exit0:
  282. _GLOBALUNLOCK (hbt);
  283. _GLOBALFREE(hbt);
  284. return 0;
  285. }
  286. /* read header from file */
  287. lcb = LcbReadHf(hf, &(qbthr->bth), (LONG)sizeof( BTH), phr);
  288. /* MAC swapping stuffs */
  289. if (qbthr->bth.wMagic == SWAPWORD(wBtreeMagic))
  290. {
  291. qbthr->bth.wMagic = SWAPWORD(qbthr->bth.wMagic);
  292. qbthr->bth.cbBlock = SWAPWORD(qbthr->bth.cbBlock);
  293. qbthr->bth.bkFirst = SWAPLONG(qbthr->bth.bkFirst);
  294. qbthr->bth.bkLast = SWAPLONG(qbthr->bth.bkLast);
  295. qbthr->bth.bkRoot = SWAPLONG(qbthr->bth.bkRoot);
  296. qbthr->bth.bkFree = SWAPLONG(qbthr->bth.bkFree);
  297. qbthr->bth.bkEOF = SWAPLONG(qbthr->bth.bkEOF);
  298. qbthr->bth.cLevels = SWAPWORD(qbthr->bth.cLevels);
  299. qbthr->bth.lcEntries = SWAPLONG(qbthr->bth.lcEntries);
  300. qbthr->bth.dwCodePageID = SWAPLONG(qbthr->bth.dwCodePageID);
  301. qbthr->bth.lcid = SWAPLONG(qbthr->bth.lcid);
  302. qbthr->bth.dwExtSortInstID = SWAPLONG(qbthr->bth.dwExtSortInstID);
  303. qbthr->bth.dwExtSortKeyType = SWAPLONG(qbthr->bth.dwExtSortKeyType);
  304. }
  305. if (lcb != (LONG)sizeof(BTH))
  306. {
  307. exit1:
  308. RcCloseHf(hf);
  309. goto exit0;
  310. }
  311. if (qbthr->bth.wMagic != wBtreeMagic)
  312. {
  313. // check magic number
  314. SetErrCode(phr, E_FILEINVALID);
  315. goto exit1;
  316. }
  317. if (qbthr->bth.bVersion != bBtreeVersion)
  318. {
  319. // support >1 vers someday
  320. SetErrCode(phr, E_BADVERSION);
  321. goto exit1;
  322. }
  323. /* initialize stuff */
  324. if ((rc = RcMakeCache(qbthr)) != S_OK)
  325. {
  326. SetErrCode (phr, rc);
  327. goto exit1;
  328. }
  329. qbthr->hf = hf;
  330. qbthr->cbRecordSize = 0;
  331. switch (qbthr->bth.rgchFormat[0])
  332. {
  333. #ifdef FULL_BTREE // {
  334. case KT_SZ:
  335. qbthr->BkScanInternal = BkScanSzInternal;
  336. qbthr->RcScanLeaf = RcScanSzLeaf;
  337. break;
  338. case KT_SZI:
  339. qbthr->BkScanInternal = BkScanSziInternal;
  340. qbthr->RcScanLeaf = RcScanSziLeaf;
  341. break;
  342. case KT_VSTI:
  343. qbthr->BkScanInternal = BkScanVstiInternal;
  344. qbthr->RcScanLeaf = RcScanVstiLeaf;
  345. break;
  346. case KT_SZISCAND:
  347. qbthr->BkScanInternal = BkScanSziScandInternal;
  348. qbthr->RcScanLeaf = RcScanSziScandLeaf;
  349. break;
  350. case KT_SZMAP:
  351. qbthr->BkScanInternal = BkScanCMapInternal ;
  352. qbthr->RcScanLeaf = RcScanCMapLeaf;
  353. break;
  354. #endif // }
  355. case KT_LONG:
  356. qbthr->BkScanInternal = BkScanLInternal;
  357. qbthr->RcScanLeaf = RcScanLLeaf;
  358. break;
  359. case KT_EXTSORT:
  360. qbthr->BkScanInternal = BkScanExtSortInternal ;
  361. qbthr->RcScanLeaf = RcScanExtSortLeaf;
  362. break;
  363. default: // unsupported KT
  364. SetErrCode(phr, E_INVALIDARG);
  365. goto exit1;
  366. break;
  367. }
  368. assert(! ( qbthr->bth.bFlags & ( fFSDirty) ) );
  369. if ((bFlags | qbthr->bth.bFlags) & ( fFSReadOnly | fFSOpenReadOnly ))
  370. {
  371. qbthr->bth.bFlags |= fFSOpenReadOnly;
  372. }
  373. _GLOBALUNLOCK(hbt);
  374. return hbt;
  375. }
  376. /***************************************************************************
  377. *
  378. * Function: GetBtreeParams(hbt, qbtp)
  379. *
  380. * Purpose: open an existing btree
  381. *
  382. * ASSUMES
  383. * args IN: hbt - handle to btree info
  384. * args OUT:
  385. * qbtp - Btree params (key type info, etc.). All members
  386. * of the structure are set EXCEPT for the hfs.
  387. *
  388. * PROMISES
  389. * returns: nothing
  390. *
  391. ***************************************************************************/
  392. VOID FAR PASCAL GetBtreeParams(HBT hbt, BTREE_PARAMS FAR *qbtp)
  393. {
  394. if (hbt != NULL && qbtp != NULL)
  395. {
  396. QBTHR qbthr;
  397. qbthr = (QBTHR) _GLOBALLOCK(hbt);
  398. // Copy btree info to BTREE_PARMS.
  399. qbtp->cbBlock = qbthr->bth.cbBlock;
  400. qbtp->dwCodePageID = qbthr->bth.dwCodePageID;
  401. qbtp->lcid = qbthr->bth.lcid;
  402. qbtp->dwExtSortInstID = qbthr->bth.dwExtSortInstID;
  403. qbtp->dwExtSortKeyType = qbthr->bth.dwExtSortKeyType;
  404. qbtp->bFlags = qbthr->bth.bFlags;
  405. lstrcpy(qbtp->rgchFormat, qbthr->bth.rgchFormat);
  406. _GLOBALUNLOCK(hbt);
  407. }
  408. else
  409. {
  410. ITASSERT(FALSE);
  411. }
  412. }
  413. /***************************************************************************
  414. *
  415. - Function: RcCloseOrFlushHbt(hbt, fClose)
  416. -
  417. * Purpose: Close or flush the btree. Flush only works for directory
  418. * btree. (Is this true? If so, why?)
  419. *
  420. * ASSUMES
  421. * args IN: hbt
  422. * fClose - TRUE to close the btree, FALSE to flush it
  423. *
  424. * PROMISES
  425. * returns: rc
  426. * args OUT: hbt - the btree is still open and cache still exists
  427. *
  428. * NOTE: This function gets called by RcCloseOrFlushHfs() even if
  429. * there was an error (just to clean up memory.)
  430. *
  431. ***************************************************************************/
  432. HRESULT FAR PASCAL RcCloseOrFlushHbt(HBT hbt, BOOL fClose)
  433. {
  434. QBTHR qbthr;
  435. HF hf;
  436. int fRet;
  437. HANDLE hnd;
  438. HRESULT errb;
  439. if (hbt == 0)
  440. return (E_INVALIDARG);
  441. qbthr = (QBTHR) _GLOBALLOCK(hbt);
  442. fRet = S_OK;
  443. hf = qbthr->hf;
  444. if (qbthr->ghCache != NULL)
  445. {
  446. qbthr->qCache = (QB) _GLOBALLOCK(qbthr->ghCache);
  447. }
  448. fRet = S_OK;
  449. if (qbthr->bth.bFlags & fFSDirty)
  450. {
  451. assert(!( qbthr->bth.bFlags & ( fFSReadOnly | fFSOpenReadOnly) ) );
  452. if (qbthr->ghCache != NULL &&
  453. (fRet = RcFlushCache(qbthr)) != S_OK)
  454. {
  455. exit0:
  456. /* Close/flush the B-tree */
  457. // Previously
  458. //if ((fRet = RcCloseOrFlushHf(hf, fClose,
  459. // qbthr->bth.bFlags & fFSOptCdRom ? sizeof(BTH):0))!= S_OK)
  460. if (fClose)
  461. fRet=RcCloseHf(hf);
  462. else
  463. fRet=RcFlushHf(hf);
  464. if ((fRet!=S_OK) || (fClose))
  465. /* Release the memory */
  466. { if ((hnd = qbthr->ghCache) != NULL)
  467. {
  468. while ((GlobalFlags(hnd) & GMEM_LOCKCOUNT) > 0)
  469. _GLOBALUNLOCK(hnd);
  470. if (fClose)
  471. {
  472. _GLOBALFREE(hnd);
  473. qbthr->ghCache = 0;
  474. }
  475. }
  476. }
  477. else
  478. {
  479. if (qbthr->ghCache)
  480. { _GLOBALUNLOCK(qbthr->ghCache);
  481. qbthr->qCache=NULL;
  482. }
  483. }
  484. // Before we free the BTHR, we need to release any sort object we're
  485. // holding onto.
  486. if (fClose && qbthr->pITSortKey != NULL)
  487. {
  488. qbthr->pITSortKey->Release();
  489. qbthr->pITSortKey = NULL;
  490. }
  491. _GLOBALUNLOCK(hbt);
  492. if (fClose)
  493. _GLOBALFREE(hbt);
  494. return fRet;
  495. }
  496. qbthr->bth.bFlags &= ~(fFSDirty);
  497. if (!FoEquals(FoSeekHf(hf, foNil, wFSSeekSet, &errb),foNil))
  498. goto exit0;
  499. LcbWriteHf(hf, &(qbthr->bth), (LONG)sizeof(BTH), &errb);
  500. }
  501. goto exit0;
  502. }
  503. /***************************************************************************
  504. *
  505. - Function: RcCloseBtreeHbt(hbt)
  506. -
  507. * Purpose: Close an open btree. If it's been modified, save changes.
  508. *
  509. * ASSUMES
  510. * args IN: hbt
  511. *
  512. * PROMISES
  513. * returns: S_OK or error
  514. *
  515. ***************************************************************************/
  516. HRESULT FAR PASCAL RcCloseBtreeHbt(HBT hbt)
  517. {
  518. return RcCloseOrFlushHbt(hbt, TRUE);
  519. }
  520. #ifdef DEADROUTINE
  521. /***************************************************************************
  522. *
  523. - Function: RcFlushHbt(hbt)
  524. -
  525. * Purpose: Write any btree changes to disk.
  526. * Btree stays open, cache remains.
  527. *
  528. * ASSUMES
  529. * args IN: hbt
  530. *
  531. * PROMISES
  532. * returns: rc
  533. *
  534. ***************************************************************************/
  535. HRESULT FAR PASCAL RcFlushHbt(HBT hbt)
  536. {
  537. return RcCloseOrFlushHbt(hbt, FALSE);
  538. }
  539. #endif
  540. /***************************************************************************
  541. *
  542. - Function: HRESULT RcFreeCacheHbt(hbt)
  543. -
  544. * Purpose: Free the btree cache.
  545. *
  546. * ASSUMES
  547. * args IN: hbt - ghCache is NULL or allocated; qCache not locked
  548. *
  549. * PROMISES
  550. * returns: S_OK or errors
  551. * args OUT: hbt - ghCache is NULL; qCache is NULL
  552. *
  553. ***************************************************************************/
  554. HRESULT FAR PASCAL RcFreeCacheHbt(HBT hbt)
  555. {
  556. QBTHR qbthr;
  557. HRESULT rc = S_OK;
  558. if (hbt == NULL)
  559. {
  560. return E_INVALIDARG;
  561. }
  562. qbthr = (QBTHR) _GLOBALLOCK(hbt);
  563. if (qbthr->ghCache != NULL) {
  564. qbthr->qCache = (QB) _GLOBALLOCK(qbthr->ghCache);
  565. rc = RcFlushCache(qbthr);
  566. _GLOBALUNLOCK(qbthr->ghCache);
  567. _GLOBALFREE(qbthr->ghCache);
  568. qbthr->ghCache = NULL;
  569. qbthr->qCache = NULL;
  570. }
  571. _GLOBALUNLOCK(hbt);
  572. return rc;
  573. }
  574. /***************************************************************************
  575. *
  576. - Function: RcGetBtreeInfo(hbt, qchFormat, qlcKeys)
  577. -
  578. * Purpose: Return btree info: format string and/or number of keys
  579. *
  580. * ASSUMES
  581. * args IN: hbt
  582. * qchFormat - pointer to buffer for fmt string or NULL
  583. * qlcKeys - pointer to long for key count or NULL
  584. * qcbBlock - pointer to int for block size in bytes or NULL
  585. *
  586. * PROMISES
  587. * returns: rc
  588. * args OUT: qchFormat - btree format string copied here
  589. * qlcKeys - gets number of keys in btree
  590. * qcbBlock - gets number of bytes in a block
  591. *
  592. ***************************************************************************/
  593. HRESULT FAR PASCAL RcGetBtreeInfo(HBT hbt, LPBYTE qchFormat,
  594. QL qlcKeys, QW qcbBlock)
  595. {
  596. QBTHR qbthr;
  597. if ((qbthr = (QBTHR) _GLOBALLOCK(hbt)) == NULL)
  598. return(E_INVALIDARG);
  599. if (qchFormat != NULL)
  600. STRCPY ((char *) qchFormat, qbthr->bth.rgchFormat);
  601. if (qlcKeys != NULL)
  602. *(LPUL)qlcKeys = qbthr->bth.lcEntries;
  603. if (qcbBlock != NULL)
  604. *qcbBlock = qbthr->bth.cbBlock;
  605. _GLOBALUNLOCK(hbt);
  606. return S_OK;
  607. }
  608. /***************************************************************************
  609. *
  610. - Function: RcAbandonHbt(hbt)
  611. -
  612. * Purpose: Abandon an open btree. All changes since btree was opened
  613. * will be lost. If btree was opened with a create, it is
  614. * as if the create never happened.
  615. *
  616. * ASSUMES
  617. * args IN: hbt
  618. *
  619. * PROMISES
  620. * returns: rc
  621. * +++
  622. *
  623. * Method: Just abandon the file and free memory.
  624. *
  625. ***************************************************************************/
  626. PUBLIC HRESULT PASCAL FAR EXPORT_API RcAbandonHbt(HBT hbt)
  627. {
  628. QBTHR qbthr;
  629. int fRet;
  630. /* Sanity check */
  631. if ((qbthr = (QBTHR) _GLOBALLOCK(hbt)) == NULL)
  632. return(E_INVALIDARG);
  633. if (qbthr->ghCache != NULL)
  634. _GLOBALFREE(qbthr->ghCache);
  635. fRet = RcAbandonHf(qbthr->hf);
  636. _GLOBALUNLOCK(hbt);
  637. _GLOBALFREE(hbt);
  638. return fRet;
  639. }
  640. #if 0
  641. /*************************************************************************
  642. * @doc API
  643. *
  644. * @func PASCAL FAR | DiskBtreeCreate |
  645. * Given a pointer to the B-tree ofthe file system, the fucntion
  646. * will copy it to a disk file.
  647. *
  648. * @parm QBTHR | qbt |
  649. * Pointer to the B-tree structure
  650. *
  651. * @parm LPSTR | szFilename |
  652. * Disk filename
  653. *
  654. * @rdesc S_OK if succeeded, else various Rc errors
  655. *
  656. * @comm The current assumption is that the whole B-tree is less
  657. * 64K. It is assume that the whole structure will reside
  658. * in memory at runtime.
  659. *************************************************************************/
  660. HRESULT EXPORT_API PASCAL FAR DiskBtreeCreate (QBTHR qbt, LPSTR szFilename)
  661. {
  662. #ifdef MOSMAP // {
  663. // Disable function
  664. return ERR_FAILED;
  665. #else // } {
  666. DWORD dwbtSize; /* Total size of B-tree */
  667. WORD wBlockSize; /* Size of a B-tree block */
  668. int fRet; /* Return error value */
  669. HANDLE hbtBuf; /* Handle to B-tree memory buffer */
  670. QB qbtBuf; /* pointer to B-tree memory buffer */
  671. int hFile; /* temp file handle */
  672. /* Calculate the size of the B-tree buffer */
  673. wBlockSize = qbt->bth.cbBlock;
  674. dwbtSize = qbt->bth.bkEOF * wBlockSize;
  675. if (dwbtSize >= 0xffff)
  676. return ERR_FAILED;
  677. /* Allocate a buffer to hold the data */
  678. if ((hbtBuf = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE | GMEM_MOVEABLE, dwbtSize)) == NULL) {
  679. return E_OUTOFMEMORY;
  680. }
  681. qbtBuf = (QB)_GLOBALLOCK (hbtBuf);
  682. /* We can read everything at once into memory. First seek to the
  683. * correct position
  684. */
  685. if (DwSeekHf(qbt->hf, (LONG)sizeof(BTH), wFSSeekSet) != sizeof(BTH)) {
  686. fRet = ERR_SEEK_FAILED;
  687. exit0:
  688. _GLOBALUNLOCK (hbtBuf);
  689. _GLOBALFREE (hbtBuf);
  690. return fRet;
  691. }
  692. /* Read in the whole B-tree */
  693. if (LcbReadHf(qbt->hf, qbtBuf, dwbtSize) != (LONG)dwbtSize) {
  694. fRet = ERR_FAILED;
  695. goto exit0;
  696. }
  697. /* Open the disk file */
  698. if ((hFile = _lcreat (szFilename, 0)) == HFILE_ERROR) {
  699. fRet = ERR_FILECREAT_FAILED;
  700. goto exit0;
  701. }
  702. /* Write the B-tree file header. Set bFlags = !fCompressed */
  703. qbt->bth.bFlags = 0;
  704. if ((_lwrite (hFile, (QB)&qbt->bth, sizeof(BTH))) != sizeof(BTH)) {
  705. fRet = ERR_CANTWRITE;
  706. exit1:
  707. _lclose (hFile);
  708. goto exit0;
  709. }
  710. /* Write the whole B-tree */
  711. if ((_lwrite (hFile, qbtBuf, (WORD)dwbtSize)) != (WORD)dwbtSize) {
  712. fRet = ERR_CANTWRITE;
  713. goto exit1;
  714. }
  715. fRet = S_OK;
  716. goto exit0;
  717. #endif //}
  718. }
  719. /*************************************************************************
  720. * @doc API
  721. *
  722. * @func HBT PASCAL FAR | DiskBtreeLoad |
  723. * :Load a B-tree structure saved on disk into memroy
  724. *
  725. * @parm LPSTR | szFilename |
  726. * Disk filename
  727. *
  728. * @rdesc The function returns a handle to the B-tree in memory
  729. * if succeeded, 0 otherwise
  730. *
  731. * @comm The current assumption is that the whole B-tree is less
  732. * 64K. It is assume that the whole structure will reside
  733. * in memory at runtime.
  734. *************************************************************************/
  735. HBT EXPORT_API PASCAL FAR DiskBtreeLoad (LPSTR szFilename)
  736. {
  737. int hFile; /* File handle */
  738. BTH btHeader; /* B-tree header */
  739. HANDLE hbt = 0; /* Handle to B-tree structure */
  740. DWORD dwbtSize; /* Size of B-tree */
  741. QBTHR qbt; /* Pointer to B-tree structure */
  742. HRESULT fRet; /* Error return code */
  743. /* Open the file */
  744. if ((hFile = _lopen ((QB)szFilename, OF_READ)) == HFILE_ERROR) {
  745. SetErrCode (ERR_NOTEXIST);
  746. return NULL;
  747. }
  748. /* Read in the header */
  749. if ((_lread (hFile, (QB)&btHeader, sizeof (BTH))) != sizeof (BTH)) {
  750. fRet = ERR_CANTREAD;
  751. exit0:
  752. SetErrCode (fRet);
  753. _lclose (hFile);
  754. return hbt;
  755. }
  756. /* MAC swapping stuffs */
  757. btHeader.wMagic = SWAPWORD(btHeader.wMagic);
  758. btHeader.cbBlock = SWAPWORD(btHeader.cbBlock);
  759. btHeader.bkFirst = SWAPLONG(btHeader.bkFirst);
  760. btHeader.bkLast = SWAPLONG(btHeader.bkLast);
  761. btHeader.bkRoot = SWAPLONG(btHeader.bkRoot);
  762. btHeader.bkFree = SWAPLONG(btHeader.bkFree);
  763. btHeader.bkEOF = SWAPLONG(btHeader.bkEOF);
  764. btHeader.lcEntries = SWAPLONG(btHeader.lcEntries);
  765. btHeader.dwCodePageID = SWAPLONG(btHeader.dwCodePageID);
  766. btHeader.lcid = SWAPLONG(btHeader.lcid);
  767. btHeader.dwExtSortInstID = SWAPLONG(btHeader.dwExtSortInstID);
  768. btHeader.dwExtSortKeyType = SWAPLONG(btHeader.dwExtSortKeyType);
  769. /* Check for validity */
  770. if (btHeader.wMagic != wBtreeMagic) { // check magic number
  771. fRet = ERR_INVALID;
  772. goto exit0;
  773. }
  774. if (btHeader.bVersion != bBtreeVersion) {// Check version
  775. fRet = E_BADVERSION;
  776. goto exit0;
  777. }
  778. dwbtSize = btHeader.bkEOF * btHeader.cbBlock;
  779. /* Currently we do not support a B-tree larger than 64K */
  780. if (dwbtSize >= 0xffff) {
  781. fRet = ERR_NOTSUPPORTED;
  782. goto exit0;
  783. }
  784. /* Allocate the block of memory for the B-tree */
  785. if ((hbt = _GLOBALALLOC (GMEM_ZEROINIT | GMEM_SHARE | GMEM_MOVEABLE, sizeof (BTH_RAM) + dwbtSize)) == NULL) {
  786. fRet = E_OUTOFMEMORY;
  787. goto exit0;
  788. }
  789. qbt = (QBTHR)_GLOBALLOCK (hbt);
  790. /* Initialize the structure */
  791. qbt->bth = btHeader;
  792. qbt->ghCache = hbt;
  793. qbt->qCache = (QB)qbt + sizeof (BTH_RAM);
  794. /* Read in the B-tree */
  795. if ((_lread (hFile, qbt->qCache, (WORD)dwbtSize)) != dwbtSize) {
  796. fRet = ERR_CANTREAD;
  797. _GLOBALUNLOCK (hbt);
  798. _GLOBALFREE (hbt);
  799. hbt = 0;
  800. goto exit0;
  801. }
  802. _GLOBALUNLOCK (hbt);
  803. fRet = S_OK;
  804. goto exit0;
  805. }
  806. /*************************************************************************
  807. * @doc API
  808. *
  809. * @func VOID PASCAL FAR | DiskBtreeFree |
  810. * Free the in-memroy B-tree
  811. *
  812. * @parm HBT | hbt |
  813. * Handle to the B-tree structure
  814. *
  815. *************************************************************************/
  816. VOID EXPORT_API PASCAL FAR DiskBtreeFree (HBT hbt)
  817. {
  818. if (hbt) {
  819. _GLOBALUNLOCK (hbt);
  820. _GLOBALFREE (hbt);
  821. }
  822. }
  823. #endif // if 0
  824. #ifdef _DEBUG
  825. /***************************************************************************
  826. *
  827. - Function: VerifyHbt(hbt)
  828. -
  829. * Purpose: Verify the consistency of an HBT. The main criterion
  830. * is whether an RcAbandonHbt() would succeed.
  831. *
  832. * ASSUMES
  833. * args IN: hbt
  834. *
  835. * PROMISES
  836. * state OUT: Asserts on failure.
  837. *
  838. * Note: hbt == NULL is considered OK.
  839. * +++
  840. *
  841. * Method: Check the qfshr and cache memory. Check the HF.
  842. *
  843. ***************************************************************************/
  844. PUBLIC VOID PASCAL FAR EXPORT_API VerifyHbt(HBT hbt)
  845. {
  846. QBTHR qbthr;
  847. if (hbt == NULL) return;
  848. qbthr = (QBTHR) _GLOBALLOCK(hbt);
  849. assert(qbthr != NULL);
  850. VerifyHf(qbthr->hf);
  851. _GLOBALUNLOCK(hbt);
  852. }
  853. #endif // _DEBUG
  854. /* EOF */