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

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