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.

1233 lines
30 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. write.c
  5. Abstract:
  6. This module implements low level primitives that are win32 compatible.
  7. Author:
  8. dmunsil created sometime in 1999
  9. Revision History:
  10. --*/
  11. #include "sdbp.h"
  12. #define ALLOCATION_INCREMENT 65536 // 64K bytes
  13. BOOL
  14. SdbpWriteBufferedData(
  15. PDB pdb,
  16. DWORD dwOffset,
  17. const PVOID pBuffer,
  18. DWORD dwSize)
  19. /*++
  20. Return: TRUE on success, FALSE otherwise.
  21. Desc: Appends the specified buffer to the mapped view of the db.
  22. --*/
  23. {
  24. if (!pdb->bWrite) {
  25. DBGPRINT((sdlError, "SdbpWriteBufferedData", "Invalid parameter.\n"));
  26. return FALSE;
  27. }
  28. //
  29. // Reallocate the buffer if necessary
  30. //
  31. if (dwOffset + dwSize > pdb->dwAllocatedSize) {
  32. DWORD dwNewAllocation;
  33. PVOID* pNewBase;
  34. dwNewAllocation = dwOffset + dwSize + ALLOCATION_INCREMENT;
  35. pNewBase = SdbAlloc(dwNewAllocation);
  36. if (pNewBase == NULL) {
  37. DBGPRINT((sdlError,
  38. "SdbpWriteBufferedData",
  39. "Failed to allocate %d bytes.\n",
  40. dwNewAllocation));
  41. return FALSE;
  42. }
  43. if (pdb->pBase) {
  44. memcpy(pNewBase, pdb->pBase, pdb->dwAllocatedSize);
  45. SdbFree(pdb->pBase);
  46. }
  47. pdb->pBase = pNewBase;
  48. pdb->dwAllocatedSize = dwNewAllocation;
  49. }
  50. //
  51. // Copy in the new bytes.
  52. //
  53. memcpy((PBYTE)pdb->pBase + dwOffset, pBuffer, dwSize);
  54. //
  55. // Adjust the size.
  56. //
  57. if (dwOffset + dwSize > pdb->dwSize) {
  58. pdb->dwSize = dwOffset + dwSize;
  59. }
  60. return TRUE;
  61. }
  62. HANDLE
  63. SdbpCreateFile(
  64. IN LPCWSTR szPath, // the full path to the database file to be created
  65. IN PATH_TYPE eType // DOS_PATH for the popular DOS paths or NT_PATH for
  66. // nt internal paths.
  67. )
  68. /*++
  69. Return: The handle to the created file or INVALID_HANDLE_VALUE if it fails.
  70. Desc: Creates a file with the path specified.
  71. --*/
  72. {
  73. OBJECT_ATTRIBUTES ObjectAttributes;
  74. IO_STATUS_BLOCK IoStatusBlock;
  75. UNICODE_STRING UnicodeString;
  76. HANDLE hFile = INVALID_HANDLE_VALUE;
  77. HRESULT status;
  78. RTL_RELATIVE_NAME RelativeName;
  79. RtlInitUnicodeString(&UnicodeString, szPath);
  80. if (eType == DOS_PATH) {
  81. if (!RtlDosPathNameToNtPathName_U(UnicodeString.Buffer,
  82. &UnicodeString,
  83. NULL,
  84. &RelativeName)) {
  85. DBGPRINT((sdlError,
  86. "SdbpCreateFile",
  87. "Failed to convert DOS path \"%s\"\n",
  88. szPath));
  89. return INVALID_HANDLE_VALUE;
  90. }
  91. }
  92. InitializeObjectAttributes(&ObjectAttributes,
  93. &UnicodeString,
  94. OBJ_CASE_INSENSITIVE,
  95. NULL,
  96. NULL);
  97. status = NtCreateFile(&hFile,
  98. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  99. &ObjectAttributes,
  100. &IoStatusBlock,
  101. 0,
  102. FILE_ATTRIBUTE_NORMAL,
  103. 0,
  104. FILE_OVERWRITE_IF,
  105. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  106. NULL,
  107. 0);
  108. if (eType == DOS_PATH) {
  109. RtlFreeUnicodeString(&UnicodeString);
  110. }
  111. if (!NT_SUCCESS(status)) {
  112. DBGPRINT((sdlError,
  113. "SdbpCreateFile",
  114. "Failed to create the file \"%s\". Status 0x%x\n",
  115. szPath,
  116. status));
  117. return INVALID_HANDLE_VALUE;
  118. }
  119. return hFile;
  120. }
  121. void
  122. SdbpDeleteFile(
  123. IN LPCWSTR szPath, // the full path to the database file to be deleted.
  124. IN PATH_TYPE eType // DOS_PATH for the popular DOS paths or NT_PATH for
  125. // nt internal paths.
  126. )
  127. /*++
  128. Return: ?
  129. Desc: ?.
  130. --*/
  131. {
  132. OBJECT_ATTRIBUTES ObjectAttributes;
  133. UNICODE_STRING UnicodeString;
  134. RTL_RELATIVE_NAME RelativeName;
  135. NTSTATUS status;
  136. RtlInitUnicodeString(&UnicodeString, szPath);
  137. if (eType == DOS_PATH) {
  138. if (!RtlDosPathNameToNtPathName_U(UnicodeString.Buffer,
  139. &UnicodeString,
  140. NULL,
  141. &RelativeName)) {
  142. DBGPRINT((sdlError,
  143. "SdbpDeleteFile",
  144. "Failed to convert DOS path \"%s\"\n",
  145. szPath));
  146. return;
  147. }
  148. }
  149. InitializeObjectAttributes(&ObjectAttributes,
  150. &UnicodeString,
  151. OBJ_CASE_INSENSITIVE,
  152. NULL,
  153. NULL);
  154. status = NtDeleteFile(&ObjectAttributes);
  155. if (DOS_PATH == eType) {
  156. RtlFreeUnicodeString(&UnicodeString);
  157. }
  158. if (!NT_SUCCESS(status)) {
  159. DBGPRINT((sdlError,
  160. "SdbpDeleteFile",
  161. "Failed to delete the file \"%s\". Status 0x%x\n",
  162. szPath,
  163. status));
  164. }
  165. }
  166. PDB
  167. SdbCreateDatabase(
  168. IN LPCWSTR szPath,
  169. IN PATH_TYPE eType
  170. )
  171. /*++
  172. Return: A pointer to the created database.
  173. Desc: Self explanatory.
  174. --*/
  175. {
  176. HANDLE hFile;
  177. DB_HEADER DBHeader;
  178. PDB pdb;
  179. SYSTEMTIME time;
  180. hFile = SdbpCreateFile(szPath, eType);
  181. if (hFile == INVALID_HANDLE_VALUE) {
  182. DBGPRINT((sdlError, "SdbCreateDatabase", "Failed to create the database.\n"));
  183. return NULL;
  184. }
  185. pdb = SdbAlloc(sizeof(DB));
  186. if (pdb == NULL) {
  187. DBGPRINT((sdlError,
  188. "SdbCreateDatabase",
  189. "Failed to allocate %d bytes.\n",
  190. sizeof(DB)));
  191. goto err1;
  192. }
  193. ZeroMemory(pdb, sizeof(DB));
  194. pdb->hFile = hFile;
  195. pdb->bWrite = TRUE;
  196. //
  197. // Create the initial header
  198. //
  199. DBHeader.dwMagic = SHIMDB_MAGIC;
  200. DBHeader.dwMajorVersion = SHIMDB_MAJOR_VERSION;
  201. SdbpGetCurrentTime(&time);
  202. DBHeader.dwMinorVersion = time.wDay + time.wMonth * 100 + (time.wYear - 2000) * 10000;
  203. if (!SdbpWriteBufferedData(pdb, 0, &DBHeader, sizeof(DB_HEADER))) {
  204. DBGPRINT((sdlError,
  205. "SdbCreateDatabase",
  206. "Failed to write the header to disk.\n"));
  207. goto err2;
  208. }
  209. return pdb;
  210. err2:
  211. SdbFree(pdb);
  212. err1:
  213. SdbpCloseFile(hFile);
  214. return NULL;
  215. }
  216. //
  217. // WRITE functions
  218. //
  219. TAGID
  220. SdbBeginWriteListTag(
  221. IN PDB pdb,
  222. IN TAG tTag
  223. )
  224. /*++
  225. Return: BUGBUG: ?
  226. Desc: BUGBUG: ?
  227. --*/
  228. {
  229. TAGID tiReturn;
  230. assert(pdb);
  231. //
  232. // The tagid is just the file offset to the tag
  233. //
  234. tiReturn = pdb->dwSize;
  235. if (GETTAGTYPE(tTag) != TAG_TYPE_LIST) {
  236. DBGPRINT((sdlError, "SdbBeginWriteListTag", "This is not a list tag.\n"));
  237. return TAGID_NULL;
  238. }
  239. if (!SdbpWriteTagData(pdb, tTag, NULL, TAG_SIZE_UNFINISHED)) {
  240. DBGPRINT((sdlError, "SdbBeginWriteListTag", "Failed to write the data.\n"));
  241. return TAGID_NULL;
  242. }
  243. return tiReturn;
  244. }
  245. BOOL
  246. SdbEndWriteListTag(
  247. IN PDB pdb,
  248. IN TAGID tiList
  249. )
  250. /*++
  251. Return: BUGBUG: ?
  252. Desc: BUGBUG: ?
  253. --*/
  254. {
  255. DWORD dwSize;
  256. DWORD i;
  257. assert(pdb);
  258. if (GETTAGTYPE(SdbGetTagFromTagID(pdb, tiList)) != TAG_TYPE_LIST) {
  259. DBGPRINT((sdlError, "SdbEndWriteListTag", "This is not a list tag.\n"));
  260. return FALSE;
  261. }
  262. //
  263. // The size of this tag is the offset from the beginning to the end of the
  264. // file, minus the tag and size itself.
  265. //
  266. dwSize = pdb->dwSize - tiList - sizeof(TAG) - sizeof(DWORD);
  267. if (!SdbpWriteBufferedData(pdb, tiList + sizeof(TAG), &dwSize, sizeof(DWORD))) {
  268. DBGPRINT((sdlError, "SdbEndWriteListTag", "Failed to write the data.\n"));
  269. return FALSE;
  270. }
  271. //
  272. // Check if we need to add index entries
  273. //
  274. for (i = 0; i < pdb->dwIndexes; i++) {
  275. //
  276. // Is there an index of this type, that is currently active?
  277. //
  278. if (pdb->aIndexes[i].tWhich == SdbGetTagFromTagID(pdb, tiList) &&
  279. pdb->aIndexes[i].bActive) {
  280. //
  281. // We have an index on this tag, check for a key.
  282. //
  283. TAGID tiKey;
  284. INDEX_RECORD IndexRecord;
  285. BOOL bWrite = TRUE; // this is the variable that determines
  286. // whether we actually write an index entry,
  287. // used for "uniqueKey" indexes
  288. PINDEX_INFO pIndex = &pdb->aIndexes[i];
  289. //
  290. // Find the key value and fill out INDEX_RECORD structure.
  291. //
  292. tiKey = SdbFindFirstTag(pdb, tiList, pIndex->tKey);
  293. //
  294. // If we don't have a key, that's OK. This tag will get indexed with key 0
  295. //
  296. if (tiKey) {
  297. IndexRecord.ullKey = SdbpTagToKey(pdb, tiKey);
  298. } else {
  299. IndexRecord.ullKey = (ULONGLONG)0;
  300. }
  301. IndexRecord.tiRef = tiList;
  302. //
  303. // If the index is of "UniqueKey" type we don't write anything at
  304. // this time, we just collect the info and write it all out at the end.
  305. //
  306. if (pIndex->bUniqueKey) {
  307. //
  308. // Use the buffer
  309. //
  310. // has the last written key been the same as this one?
  311. //
  312. if (pIndex->ullLastKey == IndexRecord.ullKey) {
  313. bWrite = FALSE;
  314. } else {
  315. //
  316. // Actually write the key, store the buffer
  317. //
  318. pIndex->ullLastKey = IndexRecord.ullKey;
  319. }
  320. }
  321. if (bWrite) {
  322. //
  323. // Check for walking off the end of the index
  324. //
  325. if (pIndex->dwIndexEntry == pIndex->dwIndexEnd) {
  326. DBGPRINT((sdlError,
  327. "SdbEndWriteListTag",
  328. "Too many index entries for tag %04x, key %04x.\n",
  329. pdb->aIndexes[i].tWhich,
  330. pdb->aIndexes[i].tKey));
  331. return FALSE;
  332. }
  333. //
  334. // Stick in the new entry, and increment
  335. //
  336. SdbpWriteBufferedData(pdb,
  337. pIndex->dwIndexEntry,
  338. &IndexRecord,
  339. sizeof(INDEX_RECORD));
  340. pIndex->dwIndexEntry += sizeof(INDEX_RECORD);
  341. }
  342. }
  343. }
  344. return TRUE;
  345. }
  346. BOOL
  347. SdbWriteNULLTag(
  348. IN PDB pdb,
  349. IN TAG tTag
  350. )
  351. /*++
  352. Return: BUGBUG: ?
  353. Desc: BUGBUG: ?
  354. --*/
  355. {
  356. assert(pdb);
  357. if (GETTAGTYPE(tTag) != TAG_TYPE_NULL) {
  358. return FALSE;
  359. }
  360. if (!SdbpWriteTagData(pdb, tTag, NULL, 0)) {
  361. return FALSE;
  362. }
  363. return TRUE;
  364. }
  365. #define WRITETYPEDTAG(ttype, type) \
  366. { \
  367. assert(pdb); \
  368. \
  369. if (GETTAGTYPE(tTag) != ttype) { \
  370. return FALSE; \
  371. } \
  372. \
  373. if (!SdbpWriteTagData(pdb, tTag, &xData, sizeof(type))) { \
  374. return FALSE; \
  375. } \
  376. \
  377. return TRUE; \
  378. }
  379. BOOL SdbWriteBYTETag(PDB pdb, TAG tTag, BYTE xData)
  380. {
  381. WRITETYPEDTAG(TAG_TYPE_BYTE, BYTE);
  382. }
  383. BOOL SdbWriteWORDTag(PDB pdb, TAG tTag, WORD xData)
  384. {
  385. WRITETYPEDTAG(TAG_TYPE_WORD, WORD);
  386. }
  387. BOOL SdbWriteDWORDTag(PDB pdb, TAG tTag, DWORD xData)
  388. {
  389. WRITETYPEDTAG(TAG_TYPE_DWORD, DWORD);
  390. }
  391. BOOL SdbWriteQWORDTag(PDB pdb, TAG tTag, ULONGLONG xData)
  392. {
  393. WRITETYPEDTAG(TAG_TYPE_QWORD, ULONGLONG);
  394. }
  395. BOOL
  396. SdbWriteStringTag(
  397. IN PDB pdb,
  398. IN TAG tTag,
  399. IN LPCWSTR pwszData
  400. )
  401. /*++
  402. Return: BUGBUG: ?
  403. Desc: BUGBUG: ?
  404. --*/
  405. {
  406. TAG_TYPE ttThis;
  407. assert(pdb);
  408. ttThis = GETTAGTYPE(tTag);
  409. //
  410. // It must be either a STRING type, in which case we
  411. // write it directly, or a STRINGREF, in which case we
  412. // put it in the string table and add a string table reference
  413. // in place here.
  414. //
  415. if (ttThis == TAG_TYPE_STRINGREF) {
  416. STRINGREF srThis;
  417. srThis = SdbpAddStringToTable(pdb, pwszData);
  418. if (srThis == STRINGREF_NULL) {
  419. return FALSE;
  420. }
  421. return SdbWriteStringRefTag(pdb, tTag, srThis);
  422. } else if (ttThis == TAG_TYPE_STRING) {
  423. return SdbWriteStringTagDirect(pdb, tTag, pwszData);
  424. }
  425. return FALSE;
  426. }
  427. BOOL
  428. SdbWriteBinaryTag(
  429. IN PDB pdb,
  430. IN TAG tTag,
  431. IN PBYTE pBuffer,
  432. IN DWORD dwSize
  433. )
  434. /*++
  435. Return: BUGBUG: ?
  436. Desc: BUGBUG: ?
  437. --*/
  438. {
  439. assert(pdb);
  440. if (GETTAGTYPE(tTag) != TAG_TYPE_BINARY) {
  441. return FALSE;
  442. }
  443. if (!SdbpWriteTagData(pdb, tTag, pBuffer, dwSize)) {
  444. return FALSE;
  445. }
  446. return TRUE;
  447. }
  448. BOOL
  449. SdbWriteBinaryTagFromFile(
  450. IN PDB pdb,
  451. IN TAG tTag,
  452. IN LPCWSTR pwszPath
  453. )
  454. /*++
  455. Return: BUGBUG: ?
  456. Desc: BUGBUG: ?
  457. --*/
  458. {
  459. HANDLE hTempFile;
  460. DWORD dwSize;
  461. BOOL bSuccess = FALSE;
  462. PBYTE pBuffer;
  463. LARGE_INTEGER liOffset;
  464. IO_STATUS_BLOCK IoStatusBlock;
  465. NTSTATUS status;
  466. assert(pdb && pwszPath);
  467. hTempFile = SdbpOpenFile(pwszPath, DOS_PATH);
  468. if (hTempFile == INVALID_HANDLE_VALUE) {
  469. return FALSE;
  470. }
  471. dwSize = SdbpGetFileSize(hTempFile);
  472. pBuffer = SdbAlloc(dwSize);
  473. if (pBuffer == NULL) {
  474. bSuccess = FALSE;
  475. goto err1;
  476. }
  477. liOffset.LowPart = 0;
  478. liOffset.HighPart = 0;
  479. status = NtReadFile(hTempFile,
  480. NULL,
  481. NULL,
  482. NULL,
  483. &IoStatusBlock,
  484. pBuffer,
  485. dwSize,
  486. &liOffset,
  487. NULL);
  488. if (!NT_SUCCESS(status)) {
  489. DBGPRINT((sdlError,
  490. "SdbWriteBinaryTagFromFile",
  491. "Failed to read data. Status: 0x%x.\n",
  492. status));
  493. goto err2;
  494. }
  495. bSuccess = SdbWriteBinaryTag(pdb, tTag, pBuffer, dwSize);
  496. err2:
  497. SdbFree(pBuffer);
  498. err1:
  499. SdbpCloseFile(hTempFile);
  500. return bSuccess;
  501. }
  502. BOOL
  503. SdbpWriteTagData(
  504. PDB pdb,
  505. TAG tTag,
  506. const PVOID pBuffer,
  507. DWORD dwSize
  508. )
  509. /*++
  510. Return: BUGBUG: ?
  511. Desc: BUGBUG: ?
  512. --*/
  513. {
  514. BYTE bPadding = 0xDB;
  515. assert(pdb);
  516. //
  517. // Write the tag.
  518. //
  519. if (!SdbpWriteBufferedData(pdb, pdb->dwSize, &tTag, sizeof(TAG))) {
  520. return FALSE;
  521. }
  522. //
  523. // Write the size.
  524. //
  525. if (GETTAGTYPE(tTag) >= TAG_TYPE_LIST) {
  526. if (!SdbpWriteBufferedData(pdb, pdb->dwSize, &dwSize, sizeof(DWORD))) {
  527. return FALSE;
  528. }
  529. }
  530. //
  531. // Write the data.
  532. //
  533. if (pBuffer) {
  534. if (!SdbpWriteBufferedData(pdb, pdb->dwSize, pBuffer, dwSize)) {
  535. return FALSE;
  536. }
  537. //
  538. // Align the tag.
  539. //
  540. if (dwSize & 1) {
  541. if (!SdbpWriteBufferedData(pdb, pdb->dwSize, &bPadding, 1)) {
  542. DBGPRINT((sdlError, "SdbpWriteTagData", "Failed to write padding data 1 byte\n"));
  543. return FALSE;
  544. }
  545. }
  546. }
  547. return TRUE;
  548. }
  549. BOOL
  550. SdbWriteStringRefTag(
  551. IN PDB pdb,
  552. IN TAG tTag,
  553. IN STRINGREF srData
  554. )
  555. {
  556. assert(pdb);
  557. if (GETTAGTYPE(tTag) != TAG_TYPE_STRINGREF) {
  558. return FALSE;
  559. }
  560. if (!SdbpWriteTagData(pdb, tTag, &srData, sizeof(srData))) {
  561. return FALSE;
  562. }
  563. return TRUE;
  564. }
  565. BOOL
  566. SdbWriteStringTagDirect(
  567. IN PDB pdb,
  568. IN TAG tTag,
  569. IN LPCWSTR pwszData
  570. )
  571. {
  572. DWORD dwSize;
  573. assert(pdb && pwszData);
  574. dwSize = (wcslen(pwszData) + 1) * sizeof(WCHAR);
  575. if (GETTAGTYPE(tTag) != TAG_TYPE_STRING) {
  576. return FALSE;
  577. }
  578. if (!SdbpWriteTagData(pdb, tTag, (const PVOID)pwszData, dwSize)) {
  579. return FALSE;
  580. }
  581. return TRUE;
  582. }
  583. void
  584. SdbCloseDatabase(
  585. IN PDB pdb // IN - DB to close
  586. )
  587. /*++
  588. Params: described above.
  589. Return: void.
  590. Desc: Closes a database and frees all memory and file handles associated with it.
  591. --*/
  592. {
  593. assert(pdb != NULL);
  594. // copy the string table and indexes onto the end of the file
  595. if (pdb->bWrite && pdb->pdbStringTable != NULL) {
  596. TAGID tiString;
  597. tiString = SdbFindFirstTag(pdb->pdbStringTable, TAGID_ROOT, TAG_STRINGTABLE_ITEM);
  598. if (tiString != TAGID_NULL) {
  599. TAGID tiTable;
  600. tiTable = SdbBeginWriteListTag(pdb, TAG_STRINGTABLE);
  601. while (tiString != TAGID_NULL) {
  602. TCHAR* pszTemp;
  603. pszTemp = SdbGetStringTagPtr(pdb->pdbStringTable, tiString);
  604. if (pszTemp == NULL) {
  605. DBGPRINT((sdlWarning,
  606. "SdbCloseDatabase",
  607. "Failed to read a string.\n"));
  608. break;
  609. }
  610. if (!SdbWriteStringTagDirect(pdb, TAG_STRINGTABLE_ITEM, pszTemp)) {
  611. DBGPRINT((sdlError,
  612. "SdbCloseDatabase",
  613. "Failed to write stringtable item\n"));
  614. break;
  615. }
  616. tiString = SdbFindNextTag(pdb->pdbStringTable, TAGID_ROOT, tiString);
  617. }
  618. if (!SdbEndWriteListTag(pdb, tiTable)) {
  619. DBGPRINT((sdlError,
  620. "SdbCloseDatabase",
  621. "Failed to write end list tag for the string table\n"));
  622. goto err1;
  623. }
  624. }
  625. }
  626. //
  627. // Now sort all the indexes if necessary.
  628. //
  629. if (pdb->bWrite) {
  630. DWORD i;
  631. for (i = 0; i < pdb->dwIndexes; ++i) {
  632. if (!SdbpSortIndex(pdb, pdb->aIndexes[i].tiIndex)) {
  633. DBGPRINT((sdlError,
  634. "SdbCloseDatabase",
  635. "Failed to sort index.\n"));
  636. goto err1;
  637. }
  638. }
  639. }
  640. err1:
  641. if (pdb->pdbStringTable != NULL) {
  642. SdbCloseDatabase(pdb->pdbStringTable);
  643. pdb->pdbStringTable = NULL;
  644. //
  645. // Delete the file
  646. //
  647. if (pdb->ustrTempStringtable.Buffer) {
  648. SdbpDeleteFile(pdb->ustrTempStringtable.Buffer, DOS_PATH);
  649. }
  650. FREE_TEMP_STRINGTABLE(pdb);
  651. }
  652. //
  653. // The string hash is used when writing to the database for the purpose of
  654. // caching the string table.
  655. //
  656. if (pdb->pStringHash != NULL) {
  657. HashFree(pdb->pStringHash);
  658. pdb->pStringHash = NULL;
  659. }
  660. if (pdb->pBase != NULL) {
  661. if (pdb->bWrite) {
  662. LARGE_INTEGER liOffset;
  663. IO_STATUS_BLOCK IoStatusBlock;
  664. HRESULT status;
  665. liOffset.LowPart = 0;
  666. liOffset.HighPart = 0;
  667. //
  668. // Flush the buffer to disk.
  669. //
  670. status = NtWriteFile(pdb->hFile,
  671. NULL,
  672. NULL,
  673. NULL,
  674. &IoStatusBlock,
  675. pdb->pBase,
  676. pdb->dwSize,
  677. &liOffset,
  678. NULL);
  679. if (!NT_SUCCESS(status)) {
  680. DBGPRINT((sdlError, "SdbCloseDatabase", "Failed to write the sdb.\n"));
  681. }
  682. SdbFree(pdb->pBase);
  683. pdb->pBase = NULL;
  684. // BUGBUG: should we call SdbpUnmapAndCloseDB in this case ?
  685. } else {
  686. SdbpUnmapAndCloseDB(pdb);
  687. }
  688. }
  689. if (pdb->hFile != INVALID_HANDLE_VALUE) {
  690. SdbpCloseFile(pdb->hFile);
  691. pdb->hFile = INVALID_HANDLE_VALUE;
  692. }
  693. SdbFree(pdb);
  694. }
  695. //
  696. // INDEX functions (used during write)
  697. //
  698. BOOL
  699. SdbDeclareIndex(
  700. IN PDB pdb,
  701. IN TAG tWhich,
  702. IN TAG tKey,
  703. IN DWORD dwEntries,
  704. IN BOOL bUniqueKey,
  705. OUT INDEXID* piiIndex
  706. )
  707. {
  708. BOOL bReturn = FALSE;
  709. DWORD dwSize = 0;
  710. TAGID tiIndex = TAGID_NULL;
  711. PVOID pFiller = NULL;
  712. TAGID tiIndexBits = TAGID_NULL;
  713. DWORD dwFlags = 0;
  714. if (bUniqueKey) {
  715. // this is a special unique-key index which we will write out
  716. dwFlags |= SHIMDB_INDEX_UNIQUE_KEY;
  717. }
  718. if (GETTAGTYPE(tWhich) != TAG_TYPE_LIST) {
  719. DBGPRINT((sdlError, "SdbDeclareIndex", "Illegal to index non-LIST tag.\n"));
  720. goto err1;
  721. }
  722. if (GETTAGTYPE(tKey) == TAG_TYPE_LIST) {
  723. DBGPRINT((sdlError, "SdbDeclareIndex", "Illegal to use LIST type as a key.\n"));
  724. goto err1;
  725. }
  726. if (!pdb->bWritingIndexes) {
  727. if (pdb->dwSize != sizeof(DB_HEADER)) {
  728. DBGPRINT((sdlError,
  729. "SdbDeclareIndex",
  730. "Began declaring indexes after writing other data.\n"));
  731. goto err1;
  732. }
  733. pdb->bWritingIndexes = TRUE;
  734. pdb->tiIndexes = SdbBeginWriteListTag(pdb, TAG_INDEXES);
  735. if (!pdb->tiIndexes) {
  736. DBGPRINT((sdlError, "SdbDeclareIndex", "Error beginning TAG_INDEXES.\n"));
  737. goto err1;
  738. }
  739. }
  740. if (pdb->dwIndexes == MAX_INDEXES) {
  741. DBGPRINT((sdlError,
  742. "SdbDeclareIndex",
  743. "Hit limit of %d indexes. Increase MAX_INDEXES and recompile.\n",
  744. MAX_INDEXES));
  745. goto err1;
  746. }
  747. tiIndex = SdbBeginWriteListTag(pdb, TAG_INDEX);
  748. if (!tiIndex) {
  749. DBGPRINT((sdlError, "SdbDeclareIndex", "Error beginning TAG_INDEX.\n"));
  750. goto err1;
  751. }
  752. if (!SdbWriteWORDTag(pdb, TAG_INDEX_TAG, tWhich)) {
  753. DBGPRINT((sdlError, "SdbDeclareIndex", "Error writing TAG_INDEX_TAG.\n"));
  754. goto err1;
  755. }
  756. if (!SdbWriteWORDTag(pdb, TAG_INDEX_KEY, tKey)) {
  757. DBGPRINT((sdlError, "SdbDeclareIndex", "Error writing TAG_INDEX_KEY.\n"));
  758. goto err1;
  759. }
  760. if (dwFlags && !SdbWriteDWORDTag(pdb, TAG_INDEX_FLAGS, dwFlags)) {
  761. DBGPRINT((sdlError, "SdbDeclareIndex", "Error writing TAG_INDEX_FLAGS.\n"));
  762. goto err1;
  763. }
  764. //
  765. // allocate and write out space-filler garbage, which
  766. // will be filled in with the real index later.
  767. //
  768. dwSize = dwEntries * sizeof(INDEX_RECORD);
  769. pFiller = SdbAlloc(dwSize);
  770. if (!pFiller) {
  771. goto err1;
  772. }
  773. tiIndexBits = pdb->dwSize;
  774. if (!SdbWriteBinaryTag(pdb, TAG_INDEX_BITS, pFiller, dwSize)) {
  775. DBGPRINT((sdlError, "SdbDeclareIndex", "Error writing TAG_INDEX_BITS.\n"));
  776. goto err1;
  777. }
  778. SdbFree(pFiller);
  779. pFiller = NULL;
  780. if (!SdbEndWriteListTag(pdb, tiIndex)) {
  781. DBGPRINT((sdlError, "SdbDeclareIndex", "Error ending TAG_INDEX.\n"));
  782. goto err1;
  783. }
  784. pdb->aIndexes[pdb->dwIndexes].tWhich = tWhich;
  785. pdb->aIndexes[pdb->dwIndexes].tKey = tKey;
  786. pdb->aIndexes[pdb->dwIndexes].tiIndex = tiIndexBits;
  787. pdb->aIndexes[pdb->dwIndexes].dwIndexEntry = tiIndexBits + sizeof(TAG) + sizeof(DWORD);
  788. pdb->aIndexes[pdb->dwIndexes].dwIndexEnd = pdb->aIndexes[pdb->dwIndexes].dwIndexEntry + dwSize;
  789. pdb->aIndexes[pdb->dwIndexes].ullLastKey = 0;
  790. pdb->aIndexes[pdb->dwIndexes].bUniqueKey = bUniqueKey;
  791. *piiIndex = pdb->dwIndexes;
  792. pdb->dwIndexes++;
  793. bReturn = TRUE;
  794. err1:
  795. if (pFiller) {
  796. SdbFree(pFiller);
  797. pFiller = NULL;
  798. }
  799. return bReturn;
  800. }
  801. BOOL
  802. SdbCommitIndexes(
  803. IN PDB pdb
  804. )
  805. {
  806. pdb->bWritingIndexes = FALSE;
  807. if (!SdbEndWriteListTag(pdb, pdb->tiIndexes)) {
  808. DBGPRINT((sdlError, "SdbDeclareIndex", "Error ending TAG_INDEXES.\n"));
  809. return FALSE;
  810. }
  811. return TRUE;
  812. }
  813. BOOL
  814. SdbStartIndexing(
  815. IN PDB pdb,
  816. IN INDEXID iiWhich
  817. )
  818. {
  819. if (iiWhich >= pdb->dwIndexes) {
  820. return FALSE;
  821. }
  822. pdb->aIndexes[iiWhich].bActive = TRUE;
  823. return TRUE;
  824. }
  825. BOOL
  826. SdbStopIndexing(
  827. IN PDB pdb,
  828. IN INDEXID iiWhich
  829. )
  830. {
  831. if (iiWhich >= pdb->dwIndexes) {
  832. return FALSE;
  833. }
  834. pdb->aIndexes[iiWhich].bActive = FALSE;
  835. return TRUE;
  836. }
  837. int __cdecl
  838. CompareIndexRecords(
  839. const void* p1,
  840. const void* p2
  841. )
  842. /*++
  843. Params: BUGBUG: comments ?
  844. Return: TRUE if successful, FALSE otherwise.
  845. Desc: Callback used by qsort.
  846. --*/
  847. {
  848. ULONGLONG ullKey1;
  849. ULONGLONG ullKey2;
  850. ullKey1 = ((INDEX_RECORD UNALIGNED*)p1)->ullKey;
  851. ullKey2 = ((INDEX_RECORD UNALIGNED*)p2)->ullKey;
  852. if (ullKey1 == ullKey2) {
  853. TAGID ti1, ti2;
  854. //
  855. // Secondary sort on TAGID, so we'll always walk
  856. // the exe records from the beginning to the end, and
  857. // take advantage of cache read-ahead
  858. //
  859. ti1 = ((INDEX_RECORD UNALIGNED*)p1)->tiRef;
  860. ti2 = ((INDEX_RECORD UNALIGNED*)p2)->tiRef;
  861. if (ti1 == ti2) {
  862. return 0;
  863. } else if (ti1 < ti2) {
  864. return -1;
  865. } else {
  866. return 1;
  867. }
  868. } else if (ullKey1 < ullKey2) {
  869. return -1;
  870. } else {
  871. return 1;
  872. }
  873. }
  874. BOOL
  875. SdbpSortIndex(
  876. PDB pdb,
  877. TAGID tiIndexBits
  878. )
  879. /*++
  880. Params: BUGBUG: comments ?
  881. Return: TRUE if successful, FALSE otherwise.
  882. Desc: Sorts an index.
  883. --*/
  884. {
  885. INDEX_RECORD* pIndexRecords = NULL;
  886. DWORD dwRecords = 0;
  887. if (SdbGetTagFromTagID(pdb, tiIndexBits) != TAG_INDEX_BITS) {
  888. DBGPRINT((sdlError, "SdbpSortIndex", "Not an index.\n"));
  889. return FALSE;
  890. }
  891. pIndexRecords = SdbpGetMappedTagData(pdb, tiIndexBits);
  892. if (pIndexRecords == NULL) {
  893. DBGPRINT((sdlError,
  894. "SdbpSortIndex",
  895. "Index referenced by 0x%x is not valid\n",
  896. tiIndexBits));
  897. return FALSE;
  898. }
  899. dwRecords = SdbGetTagDataSize(pdb, tiIndexBits) / sizeof(INDEX_RECORD);
  900. qsort(pIndexRecords, dwRecords, sizeof(INDEX_RECORD), CompareIndexRecords);
  901. return TRUE;
  902. }
  903. ////////////////////////////////////////////////////////////////////////////////
  904. //
  905. // String writing routine
  906. //
  907. STRINGREF
  908. SdbpAddStringToTable(
  909. PDB pdb,
  910. LPCTSTR szData)
  911. {
  912. STRINGREF srReturn = STRINGREF_NULL;
  913. BOOL bSuccess;
  914. TAGID tiTemp;
  915. assert(pdb);
  916. //
  917. // Add a string table if one doesn't exist
  918. //
  919. if (!pdb->pdbStringTable) {
  920. DWORD dwLength;
  921. TCHAR szBuffer[MAX_PATH];
  922. TCHAR szTempFile[MAX_PATH];
  923. //
  924. // Create temp string table db
  925. //
  926. dwLength = GetTempPath(CHARCOUNT(szBuffer), szBuffer);
  927. if (!dwLength || dwLength > CHARCOUNT(szBuffer)) {
  928. DBGPRINT((sdlError,
  929. "SdbpAddStringToTable",
  930. "Error Gettting temp path 0x%lx\n",
  931. GetLastError()));
  932. goto err1;
  933. }
  934. //
  935. // We got the directory, generate the file now
  936. //
  937. dwLength = GetTempFileName(szBuffer, TEXT("SDB"), 0, szTempFile);
  938. if (!dwLength) {
  939. DBGPRINT((sdlError,
  940. "SdbpAddStringToTable",
  941. "Error Gettting temp filename 0x%lx\n",
  942. GetLastError()));
  943. goto err1;
  944. }
  945. //
  946. // If we are successful, we'd have a string table file now.
  947. //
  948. pdb->pdbStringTable = SdbCreateDatabase(szTempFile, DOS_PATH);
  949. if (!pdb->pdbStringTable) {
  950. goto err1;
  951. }
  952. //
  953. // success !!! set the name of the file into the pdb so we could remove it later
  954. //
  955. if (!COPY_TEMP_STRINGTABLE(pdb, szTempFile)) {
  956. DBGPRINT((sdlError,
  957. "SdbpAddStringToTable",
  958. "Error copying string table temp filename\n"));
  959. goto err1;
  960. }
  961. }
  962. if (!pdb->pStringHash) {
  963. pdb->pStringHash = HashCreate();
  964. if (pdb->pStringHash == NULL) {
  965. DBGPRINT((sdlError,
  966. "SdbpAddStringToTable",
  967. "Error creating hash table\n"));
  968. goto err1;
  969. }
  970. }
  971. srReturn = HashFindString((PSTRHASH)pdb->pStringHash, szData);
  972. if (!srReturn) {
  973. //
  974. // A stringref is the offset from the beginning of the string table to
  975. // the string tag itself. We have to adjust for the header of the temporary
  976. // DB, and the tag and size that will be written later.
  977. //
  978. srReturn = pdb->pdbStringTable->dwSize - sizeof (DB_HEADER) + sizeof(TAG) + sizeof(DWORD);
  979. bSuccess = SdbWriteStringTagDirect(pdb->pdbStringTable, TAG_STRINGTABLE_ITEM, szData);
  980. if (!bSuccess) {
  981. DBGPRINT((sdlError,
  982. "SdbpAddStringToTable",
  983. "Failed to write stringtableitem into the string table\n"));
  984. srReturn = STRINGREF_NULL;
  985. }
  986. HashAddString((PSTRHASH)pdb->pStringHash, szData, srReturn);
  987. }
  988. err1:
  989. return srReturn;
  990. }