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.

2215 lines
56 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. recchk.c
  5. Abstract:
  6. This file implements the record database checking code. There are two types of
  7. persistent data structures, the priority Q (or our version of Master FIle Table)
  8. and the hierarchy of files and directories that starts with the superroot which
  9. contains all the shares connected to. The truth is considered to be in the
  10. hierarchy. The Priority Q is supposed to mirror some critical data from the
  11. hierarchy. When fixing the database, we traverse the hierarchy
  12. recursively and build an in memory PQ. We then write that out as the new PQ.
  13. This file gets linked in the usermode and in the kernlemode so that for NT this
  14. can execute in kernel mode while for win9x it can execute in usermode
  15. Author:
  16. Shishir Pardikar [Shishirp] 10-30-1997
  17. Revision History:
  18. split up from usermode.
  19. --*/
  20. #include "precomp.h"
  21. #pragma hdrstop
  22. #pragma code_seg("PAGE")
  23. #include "record.h"
  24. #include "string.h"
  25. #include "stdlib.h"
  26. // Record Buffer Array (RBA). This holds an entire inode file in memory
  27. // It is made up of pointers to 1 or more Record Buffer Entries (RBE).
  28. // Each RBE is a chunk of memory that holds an integral number of records from
  29. // the file represented by ulidShadow entry in the structure
  30. typedef struct tagRBA
  31. {
  32. unsigned ulErrorFlags;
  33. unsigned ulidShadow; // Inode which is represented by this structure
  34. GENERICHEADER sGH; // it's header
  35. CSCHFILE hf; // open handle to the file
  36. DWORD cntRBE; // count of buffer entries in the array
  37. DWORD cntRecsPerRBE; // #of records per buffer entry
  38. DWORD cbRBE; // size in bytes of each buffer entry
  39. LPBYTE rgRBE[]; // Record Buffer Entry (RBE) array
  40. }
  41. RBA, *LPRBA; // stands for RecordBuffArray
  42. #define RBA_ERROR_INVALID_HEADER 0x00000001
  43. #define RAB_ERROR_INVALID_RECORD_COUNT 0x00000002
  44. #define RBA_ERROR_INVALID_OVF 0x00000004
  45. #define RBA_ERROR_INVALID_ENTRY 0x00000008
  46. #define RBA_ERROR_MISMATCHED_SIZE 0x00000010
  47. #define RBA_ERROR_MISALIGNED_RECORD 0x00000020
  48. #define RBA_ERROR_INVALID_INODE 0x00000040
  49. #define RBA_ERROR_LIMIT_EXCEEDED 0x00000080
  50. #define MAX_RECBUFF_ENTRY_SIZE (0x10000-0x100) // max size of an RBE
  51. #define MAX_RBES_EXPECTED 0x30 // Max number of RBEs of the above size in an RBA
  52. // we make provision for max possible # of RBEs, even beyond what the PQ currently
  53. // needs. The max set here is (MAX_RBES_EXPETCED * MAX_RECBUFF_ENTRY_SIZE)
  54. // which amounts to 48 * 65280 which is around 3M which at the current size of
  55. // QREC will hold ~100K entries in the hierarchy. This is far more than
  56. // the # of entries we ever expect to have in our database
  57. // As we allocate memory only as it is needed, it would'nt be a problem to
  58. // increase MAX_RBES_EXPECTED so it handles more inodes
  59. typedef struct tagCSE *LPCSE;
  60. typedef struct tagCSE // CSC Stack Entry
  61. {
  62. LPCSE lpcseNext;
  63. unsigned ulidShare; // server
  64. unsigned ulidParent; // parent of the directory
  65. unsigned ulidDir; // the directory itself
  66. unsigned ulRec;
  67. LPRBA lpRBA; // the contents of ulidDir
  68. }
  69. CSE;
  70. #pragma intrinsic (memcmp, memcpy, memset, strcat, strcmp, strcpy, strlen)
  71. #ifdef DEBUG
  72. //cshadow dbgprint interface
  73. #define RecchkKdPrint(__bit,__x) {\
  74. if (((RECCHK_KDP_##__bit)==0) || FlagOn(RecchkKdPrintVector,(RECCHK_KDP_##__bit))) {\
  75. KdPrint (__x);\
  76. }\
  77. }
  78. #define RECCHK_KDP_ALWAYS 0x00000000
  79. #define RECCHK_KDP_BADERRORS 0x00000001
  80. #define RECCHK_KDP_TRAVERSE 0x00000002
  81. #define RECCHK_KDP_PQ 0x00000004
  82. #define RECCHK_KDP_RBA 0x00000008
  83. ULONG RecchkKdPrintVector = RECCHK_KDP_BADERRORS;
  84. #else
  85. #define RecchkKdPrint(__bit,__x) ;
  86. #endif
  87. #define ValidShadowID(ulidShadow) ((ulidShadow & ~0x80000000) >=ULID_FIRST_USER_DIR)
  88. char vszTemp[] = "csc0.tmp";
  89. char vszTemp1[] = "csc1.tmp";
  90. AssertData;
  91. AssertError;
  92. RebuildPQInRBA(
  93. LPRBA lpRBA
  94. );
  95. BOOL
  96. TraverseDirectory(
  97. LPVOID lpdbID,
  98. unsigned ulidShare,
  99. unsigned ulidParent,
  100. unsigned ulidDir,
  101. LPRBA lpRBAPQ,
  102. BOOL fFix
  103. );
  104. BOOL
  105. AllocateRBA(
  106. DWORD cntRBE, // count of record buffer entries
  107. DWORD cbRBE, // size of each record buffer entry
  108. LPRBA *lplpRBA // result to be returned
  109. );
  110. VOID
  111. FreeRBA(
  112. LPRBA lpRBA
  113. );
  114. BOOL
  115. ReadShadowInRBA(
  116. LPVOID lpdbID,
  117. unsigned ulidShadow,
  118. DWORD cbMaxRBE, // max size of an RBE
  119. DWORD cntRBE, // # of RBEs to be allocated, calculated if 0
  120. LPRBA *lplpRBA
  121. );
  122. BOOL
  123. WriteRBA(
  124. LPVOID lpdbID,
  125. LPRBA lpRBA,
  126. LPSTR lpszFileName
  127. );
  128. LPVOID
  129. GetRecordPointerFromRBA(
  130. LPRBA lpRBA,
  131. unsigned ulRec
  132. );
  133. BOOL
  134. ReadRecordFromRBA(
  135. LPRBA lpRBA,
  136. unsigned ulRec,
  137. LPGENERICREC lpGH
  138. );
  139. BOOL
  140. WriteRecordToRBA(
  141. LPRBA lpRBA,
  142. unsigned ulRec,
  143. LPGENERICREC lpGH,
  144. BOOL fOverwrite,
  145. LPDWORD lpdwError
  146. );
  147. BOOL
  148. FillupRBAUptoThisRBE(
  149. LPRBA lpRBA,
  150. DWORD indxRBE
  151. );
  152. VOID
  153. InitializeRBE(
  154. LPRBA lpRBA,
  155. DWORD indxRBE
  156. );
  157. BOOL
  158. InsertRBAPQEntryFile(
  159. LPRBA lpRBAPQ,
  160. LPQREC lpPQDst,
  161. unsigned ulrecDst
  162. );
  163. BOOL
  164. InsertRBAPQEntryDir(
  165. LPRBA lpRBAPQ,
  166. LPQREC lpPQDst,
  167. unsigned ulrecDst
  168. );
  169. BOOL
  170. ValidateQrecFromFilerec(
  171. unsigned ulidShare,
  172. unsigned ulidDir,
  173. LPFILERECEXT lpFR,
  174. LPQREC lpQR,
  175. unsigned ulrecDirEntry
  176. );
  177. BOOL
  178. TraversePQ(
  179. LPVOID lpdbID
  180. )
  181. /*++
  182. Routine Description:
  183. This routine traverses the priority Q and verifies the consistency of the Q by verifying
  184. that the backward and the forward pointers are pointing correctly
  185. Parameters:
  186. lpdbID CSC database directory
  187. Return Value:
  188. Notes:
  189. --*/
  190. {
  191. QREC sQR, sPrev, sNext;
  192. unsigned ulRec;
  193. BOOL fRet = FALSE, fValidHead=FALSE, fValidTail=FALSE;
  194. LPRBA lpRBA = NULL;
  195. if (!ReadShadowInRBA(lpdbID, ULID_PQ, MAX_RECBUFF_ENTRY_SIZE, 0, &lpRBA))
  196. {
  197. RecchkKdPrint(BADERRORS, ("TraversePQ: Failed to read PQ in memory\r\n"));
  198. goto bailout;
  199. }
  200. if ((((LPQHEADER)&(lpRBA->sGH))->ulrecTail > lpRBA->sGH.ulRecords) ||
  201. (((LPQHEADER)&(lpRBA->sGH))->ulrecHead > lpRBA->sGH.ulRecords))
  202. {
  203. RecchkKdPrint(BADERRORS, ("Invalid head-tail pointers\r\n"));
  204. goto bailout;
  205. }
  206. if (!lpRBA->sGH.ulRecords)
  207. {
  208. fRet = TRUE;
  209. goto bailout;
  210. }
  211. for (ulRec = 1; ulRec <= lpRBA->sGH.ulRecords; ulRec++)
  212. {
  213. if(!ReadRecordFromRBA(lpRBA, ulRec, (LPGENERICREC)&sQR))
  214. {
  215. goto bailout;
  216. }
  217. if (sQR.uchType == REC_DATA)
  218. {
  219. if (sQR.ulrecNext)
  220. {
  221. if (sQR.ulrecNext > lpRBA->sGH.ulRecords)
  222. {
  223. RecchkKdPrint(BADERRORS, ("Invalid next pointer to %d\r\n", ulRec));
  224. goto bailout;
  225. }
  226. if (!ReadRecordFromRBA(lpRBA, sQR.ulrecNext, (LPGENERICREC)&sNext))
  227. {
  228. goto bailout;
  229. }
  230. if (sNext.ulrecPrev != ulRec)
  231. {
  232. RecchkKdPrint(BADERRORS, ("Prev pointer of %d doesn't equal %d\r\n", sNext.ulrecPrev, ulRec));
  233. goto bailout;
  234. }
  235. }
  236. else
  237. {
  238. if (((LPQHEADER)&(lpRBA->sGH))->ulrecTail != ulRec)
  239. {
  240. RecchkKdPrint(BADERRORS, ("Invalid tail pointer to %d\r\n", ulRec));
  241. goto bailout;
  242. }
  243. fValidTail = TRUE;
  244. }
  245. if (sQR.ulrecPrev)
  246. {
  247. if (sQR.ulrecPrev > lpRBA->sGH.ulRecords)
  248. {
  249. RecchkKdPrint(BADERRORS, ("Invalid prev pointer to %d\r\n", ulRec));
  250. goto bailout;
  251. }
  252. if (!ReadRecordFromRBA(lpRBA, sQR.ulrecPrev, (LPGENERICREC)&sPrev))
  253. {
  254. goto bailout;
  255. }
  256. if (sPrev.ulrecNext != ulRec)
  257. {
  258. RecchkKdPrint(BADERRORS, ("Next pointer of %d doesn't equal %d\r\n", sPrev.ulrecNext, ulRec));
  259. goto bailout;
  260. }
  261. }
  262. else
  263. {
  264. if (((LPQHEADER)&(lpRBA->sGH))->ulrecHead != ulRec)
  265. {
  266. RecchkKdPrint(BADERRORS, ("Invalid Head pointer to %d\r\n", ulRec));
  267. goto bailout;
  268. }
  269. fValidHead = TRUE;
  270. }
  271. }
  272. }
  273. if (!fValidHead || !fValidTail)
  274. {
  275. RecchkKdPrint(BADERRORS, ("Head or Tail invalid \r\n"));
  276. goto bailout;
  277. }
  278. fRet = TRUE;
  279. bailout:
  280. if (lpRBA)
  281. {
  282. FreeRBA(lpRBA);
  283. }
  284. return (fRet);
  285. }
  286. BOOL
  287. RebuildPQ(
  288. LPVOID lpdbID
  289. )
  290. /*++
  291. Routine Description:
  292. Parameters:
  293. Return Value:
  294. Notes:
  295. --*/
  296. {
  297. LPRBA lpRBA = NULL;
  298. BOOL fRet = FALSE;
  299. RecchkKdPrint(PQ, ("RebuildPQ: reading PQ \r\n"));
  300. if (!ReadShadowInRBA(lpdbID, ULID_PQ, MAX_RECBUFF_ENTRY_SIZE, 0, &lpRBA))
  301. {
  302. RecchkKdPrint(BADERRORS, ("TraversePQ: Failed to read PQ in memory\r\n"));
  303. goto bailout;
  304. }
  305. RecchkKdPrint(PQ, ("RebuildPQ: read PQ \r\n"));
  306. if (!RebuildPQInRBA(lpRBA))
  307. {
  308. RecchkKdPrint(BADERRORS, ("RebuildPQ: failed to rebuild PQ in RBA \r\n"));
  309. goto bailout;
  310. }
  311. RecchkKdPrint(PQ, ("RebuildPQ: writing PQ \r\n"));
  312. if (!WriteRBA(lpdbID, lpRBA, NULL))
  313. {
  314. RecchkKdPrint(BADERRORS, ("RebuildPQ:Failed to writeout the PQ\r\n"));
  315. goto bailout;
  316. }
  317. RecchkKdPrint(PQ, ("RebuildPQ: wrote PQ \r\n"));
  318. fRet = TRUE;
  319. bailout:
  320. if (lpRBA)
  321. {
  322. FreeRBA(lpRBA);
  323. }
  324. return (fRet);
  325. }
  326. BOOL
  327. RebuildPQInRBA(
  328. LPRBA lpRBA
  329. )
  330. /*++
  331. Routine Description:
  332. Parameters:
  333. Return Value:
  334. Notes:
  335. --*/
  336. {
  337. unsigned ulRec;
  338. LPQHEADER lpQH;
  339. LPQREC lpPQ;
  340. BOOL fRet = FALSE;
  341. lpQH = (LPQHEADER)&(lpRBA->sGH);
  342. // nuke the PQ
  343. lpQH->ulrecHead = lpQH->ulrecTail = 0;
  344. for (ulRec = 1; ulRec <= lpRBA->sGH.ulRecords; ulRec++)
  345. {
  346. if (!(lpPQ = GetRecordPointerFromRBA(lpRBA, ulRec)))
  347. {
  348. RecchkKdPrint(BADERRORS, ("InsertRBAPQEntry: failed reading q entry at %d\r\n", ulRec));
  349. goto bailout;
  350. }
  351. if (lpPQ->uchType != REC_DATA)
  352. {
  353. continue;
  354. }
  355. if (!(lpPQ->ulidShadow & 0x80000000))
  356. {
  357. if (!InsertRBAPQEntryDir(lpRBA, lpPQ, ulRec))
  358. {
  359. RecchkKdPrint(BADERRORS, ("RebuildPQ:Failed inserting %d \r\n", ulRec));
  360. goto bailout;
  361. }
  362. }
  363. else
  364. {
  365. if (!InsertRBAPQEntryFile(lpRBA, lpPQ, ulRec))
  366. {
  367. RecchkKdPrint(BADERRORS, ("RebuildPQ:Failed inserting %d \r\n", ulRec));
  368. goto bailout;
  369. }
  370. }
  371. }
  372. fRet = TRUE;
  373. bailout:
  374. return fRet;
  375. }
  376. BOOL
  377. TraverseHierarchy(
  378. LPVOID lpdbID,
  379. BOOL fFix
  380. )
  381. /*++
  382. Routine Description:
  383. Parameters:
  384. Return Value:
  385. Notes:
  386. --*/
  387. {
  388. unsigned ulRec;
  389. BOOL fRet = FALSE;
  390. LPRBA lpRBA = NULL, lpRBAPQ=NULL;
  391. SHAREREC sSR;
  392. QREC sQR;
  393. BOOL fErrors = FALSE;
  394. DWORD dwError;
  395. if (!ReadShadowInRBA(lpdbID, ULID_SHARE, MAX_RECBUFF_ENTRY_SIZE, 0, &lpRBA))
  396. {
  397. RecchkKdPrint(BADERRORS, ("TraverseHierarchy: Failed to read servers in memory\r\n"));
  398. goto bailout;
  399. }
  400. if (!fFix)
  401. {
  402. if (!ReadShadowInRBA( lpdbID,
  403. ULID_PQ,
  404. MAX_RECBUFF_ENTRY_SIZE,
  405. 0,
  406. &lpRBAPQ))
  407. {
  408. RecchkKdPrint(BADERRORS, ("TraverseHierarchy: Failed to read PQ in memory\r\n"));
  409. goto bailout;
  410. }
  411. }
  412. else
  413. {
  414. ULONG cbCountOfTotal= ((LPSHAREHEADER)&(lpRBA->sGH))->sCur.ucntDirs+((LPSHAREHEADER)&(lpRBA->sGH))->sCur.ucntFiles;
  415. ULONG cbMaxEntriesExpected,cbMaxRbesExpected;
  416. cbMaxEntriesExpected = (MAX_RECBUFF_ENTRY_SIZE * MAX_RBES_EXPECTED)/sizeof(QREC);
  417. RecchkKdPrint(BADERRORS, ("TraverseHierarchy: total count=%d\r\n",cbCountOfTotal));
  418. if (cbCountOfTotal >= cbMaxEntriesExpected)
  419. {
  420. fRet = TRUE;
  421. RecchkKdPrint(BADERRORS, ("TraverseHierarchy: Database too big skipping autocheck\r\n"));
  422. goto bailout;
  423. // cbMaxRbesExpected = (cbCountOfTotal*sizeof(QREC)/MAX_RECBUFF_ENTRY_SIZE)+1;
  424. }
  425. else
  426. {
  427. cbMaxRbesExpected = MAX_RBES_EXPECTED;
  428. }
  429. RecchkKdPrint(BADERRORS, ("TraverseHierarchy: MaxRBEs = %d\r\n",cbMaxRbesExpected));
  430. if (!AllocateRBA(cbMaxRbesExpected, MAX_RECBUFF_ENTRY_SIZE, &lpRBAPQ))
  431. {
  432. RecchkKdPrint(BADERRORS, ("TraverseHierarchy: Failed to Allocate PQ\r\n"));
  433. goto bailout;
  434. }
  435. InitQHeader((LPQHEADER)&(lpRBAPQ->sGH));
  436. lpRBAPQ->ulidShadow = ULID_PQ;
  437. lpRBAPQ->cntRecsPerRBE = MAX_RECBUFF_ENTRY_SIZE/lpRBAPQ->sGH.uRecSize;
  438. }
  439. for (ulRec=1; ulRec<=lpRBA->sGH.ulRecords; ++ulRec)
  440. {
  441. ReadRecordFromRBA(lpRBA, ulRec, (LPGENERICREC)&sSR);
  442. if (sSR.uchType != REC_DATA)
  443. {
  444. continue;
  445. }
  446. if(!ValidShadowID(sSR.ulidShadow))
  447. {
  448. fErrors = TRUE;
  449. sSR.uchType = REC_EMPTY;
  450. RecchkKdPrint(BADERRORS, ("Invalid Shadow ID %xh found in %xh \r\n", sSR.ulidShadow, sSR.ulShare));
  451. if (fFix)
  452. {
  453. if (!WriteRecordToRBA(lpRBA, ulRec, (LPGENERICREC)&sSR, TRUE, NULL))
  454. {
  455. RecchkKdPrint(BADERRORS, ("Couldn't write entry for Share Record %xh \r\n", sSR.ulShare));
  456. }
  457. }
  458. continue;
  459. }
  460. if (!fFix)
  461. {
  462. if (!ReadRecordFromRBA(lpRBAPQ, RecFromInode(sSR.ulidShadow), (LPGENERICREC)&sQR))
  463. {
  464. RecchkKdPrint(BADERRORS, ("No PQ entry for Inode %xh \r\n", sSR.ulidShadow));
  465. }
  466. }
  467. else
  468. {
  469. InitPriQRec(ulRec, 0, sSR.ulidShadow, SHADOW_SPARSE, 0, 0, 0, 0, ulRec, &sQR);
  470. if (!WriteRecordToRBA(lpRBAPQ, RecFromInode(sSR.ulidShadow), (LPGENERICREC)&sQR, FALSE, &dwError))
  471. {
  472. if (dwError == ERROR_NOT_ENOUGH_MEMORY)
  473. {
  474. RecchkKdPrint(BADERRORS, ("Couldn't write PQ entry for Inode %xh \r\n", sSR.ulidShadow));
  475. }
  476. fErrors = TRUE;
  477. sSR.uchType = REC_EMPTY;
  478. WriteRecordToRBA(lpRBA, ulRec, (LPGENERICREC)&sSR, TRUE, NULL);
  479. continue;
  480. }
  481. }
  482. if(!TraverseDirectory( lpdbID,
  483. ulRec, // ulidShare
  484. 0, // parent inode
  485. sSR.ulidShadow, // dir inode
  486. lpRBAPQ,
  487. fFix
  488. ))
  489. {
  490. goto bailout;
  491. }
  492. }
  493. if (fFix)
  494. {
  495. if (fErrors)
  496. {
  497. if (!WriteRBA(lpdbID, lpRBA, NULL))
  498. {
  499. RecchkKdPrint(BADERRORS, ("TraverseHierarchy:Failed to write Shares\r\n"));
  500. goto bailout;
  501. }
  502. }
  503. RecchkKdPrint(TRAVERSE, ("Total records %d \r\n", lpRBAPQ->sGH.ulRecords));
  504. if (lpRBAPQ->ulErrorFlags & RBA_ERROR_LIMIT_EXCEEDED)
  505. {
  506. RecchkKdPrint(BADERRORS, ("TraverseHierarchy: skipping rewriting of new PQ\r\n"));
  507. }
  508. else
  509. {
  510. if (!RebuildPQInRBA(lpRBAPQ))
  511. {
  512. RecchkKdPrint(BADERRORS, ("TraverseHierarchy:Failed to rebuild PQ\r\n"));
  513. goto bailout;
  514. }
  515. if (!WriteRBA(lpdbID, lpRBAPQ, NULL))
  516. {
  517. RecchkKdPrint(BADERRORS, ("TraverseHierarchy:Failed to write PQ\r\n"));
  518. goto bailout;
  519. }
  520. }
  521. }
  522. fRet = TRUE;
  523. bailout:
  524. if (lpRBA)
  525. {
  526. FreeRBA(lpRBA);
  527. }
  528. if (lpRBAPQ)
  529. {
  530. FreeRBA(lpRBAPQ);
  531. }
  532. return fRet;
  533. }
  534. BOOL
  535. TraverseDirectory(
  536. LPVOID lpdbID,
  537. unsigned ulidShare,
  538. unsigned ulidParent,
  539. unsigned ulidDir,
  540. LPRBA lpRBAPQ,
  541. BOOL fFix
  542. )
  543. /*++
  544. Routine Description:
  545. Parameters:
  546. Return Value:
  547. Notes:
  548. --*/
  549. {
  550. unsigned ulDepthLevel = 0, ulidCurParent, ulidCurDir;
  551. BOOL fRet = FALSE, fGoDeeper = TRUE;
  552. FILERECEXT *lpFR = NULL;
  553. QREC *lpQR = NULL;
  554. LPCSE lpcseNextDir = NULL;
  555. LPCSE lpcseHead = NULL, lpcseT;
  556. BOOL fErrors = FALSE;
  557. DWORD dwError;
  558. lpFR = AllocMemPaged(sizeof(FILERECEXT));
  559. lpQR = AllocMemPaged(sizeof(QREC));
  560. if (!lpFR || !lpQR)
  561. {
  562. RecchkKdPrint(BADERRORS, ("AllocMemPaged Failed \r\n"));
  563. goto bailout;
  564. }
  565. ulidCurParent = ulidParent;
  566. ulidCurDir = ulidDir;
  567. for (;;)
  568. {
  569. if (fGoDeeper)
  570. {
  571. // we are going deeper
  572. // allocate a stack entry for the directory which we want
  573. // to traverse
  574. lpcseT = AllocMemPaged(sizeof(CSE));
  575. if (!lpcseT)
  576. {
  577. RecchkKdPrint(BADERRORS, ("AllocMemPaged failed \r\n"));
  578. goto bailout;
  579. }
  580. // do appropriate inits
  581. lpcseT->ulidShare = ulidShare;
  582. lpcseT->ulidParent = ulidCurParent;
  583. lpcseT->ulidDir = ulidCurDir;
  584. lpcseT->ulRec = 1; // start for record # 1
  585. lpcseT->lpcseNext = NULL;
  586. // read the entire directory in memory
  587. if (!ReadShadowInRBA(lpdbID, ulidCurDir, MAX_RECBUFF_ENTRY_SIZE, 0, &(lpcseT->lpRBA)))
  588. {
  589. RecchkKdPrint(BADERRORS, ("TraverseDirectory: Failed to read directory in memory\r\n"));
  590. if (!fFix)
  591. {
  592. RecchkKdPrint(BADERRORS, ("TraverseDirectory: Aborting\r\n"));
  593. FreeMemPaged(lpcseT);
  594. goto bailout;
  595. }
  596. else
  597. {
  598. RecchkKdPrint(TRAVERSE, ("TraverseDirectory: attempting to heal\r\n"));
  599. if(CreateDirInode(lpdbID, ulidShare, ulidCurParent, ulidCurDir) < 0)
  600. {
  601. RecchkKdPrint(BADERRORS, ("TraverseDirectory: failed to heal\r\n"));
  602. }
  603. FreeMemPaged(lpcseT);
  604. fGoDeeper = FALSE;
  605. // continue if there are more things to do
  606. // else stop
  607. if (lpcseHead)
  608. {
  609. continue;
  610. }
  611. else
  612. {
  613. break;
  614. }
  615. }
  616. }
  617. // put it at the head of the queue
  618. lpcseT->lpcseNext = lpcseHead;
  619. lpcseHead = lpcseT;
  620. ulDepthLevel++;
  621. }
  622. fGoDeeper = FALSE;
  623. // we always operate on the head of the list
  624. Assert(lpcseHead != NULL);
  625. RecchkKdPrint(TRAVERSE, ("Processing %x at depth %d\r\n", ulidCurDir, ulDepthLevel));
  626. RecchkKdPrint(TRAVERSE, ("lpcseHead = %x, lpcseHead->lpcseNext = %x \r\n", lpcseHead, lpcseHead->lpcseNext));
  627. for (; lpcseHead->ulRec<=lpcseHead->lpRBA->sGH.ulRecords;)
  628. {
  629. ReadRecordFromRBA(lpcseHead->lpRBA, lpcseHead->ulRec, (LPGENERICREC)lpFR);
  630. if (lpFR->sFR.uchType == REC_DATA)
  631. {
  632. if(!ValidShadowID(lpFR->sFR.ulidShadow))
  633. {
  634. RecchkKdPrint(BADERRORS, ("Invalid Shadow ID %xh found in %xh \r\n", lpFR->sFR.ulidShadow, ulidCurDir));
  635. lpcseHead->lpRBA->ulErrorFlags |= RBA_ERROR_INVALID_INODE;
  636. if (fFix)
  637. {
  638. lpFR->sFR.uchType = REC_EMPTY;
  639. if (!WriteRecordToRBA(lpcseHead->lpRBA, lpcseHead->ulRec, (LPGENERICREC)lpFR, TRUE, NULL))
  640. {
  641. RecchkKdPrint(BADERRORS, ("Couldn't write entry for dir Record #%dh in dir %xh\r\n", lpcseHead->ulRec, ulidCurDir));
  642. }
  643. }
  644. }
  645. else
  646. {
  647. if (!fFix)
  648. {
  649. ReadRecordFromRBA(lpRBAPQ, RecFromInode(lpFR->sFR.ulidShadow), (LPGENERICREC)lpQR);
  650. if (!ValidateQrecFromFilerec(lpcseHead->ulidShare, lpcseHead->ulidDir, lpFR, lpQR, lpcseHead->ulRec))
  651. {
  652. RecchkKdPrint(BADERRORS, ("PQ entry for Inode %xh in directory=%xh doesn't match with filerec\r\n", lpFR->sFR.ulidShadow, lpcseHead->lpRBA->ulidShadow));
  653. }
  654. }
  655. else
  656. {
  657. InitPriQRec(lpcseHead->ulidShare,
  658. lpcseHead->ulidDir,
  659. lpFR->sFR.ulidShadow,
  660. lpFR->sFR.usStatus,
  661. lpFR->sFR.uchRefPri,
  662. lpFR->sFR.uchIHPri,
  663. lpFR->sFR.uchHintPri,
  664. lpFR->sFR.uchHintFlags,
  665. lpcseHead->ulRec,
  666. lpQR);
  667. if (!WriteRecordToRBA(lpRBAPQ, RecFromInode(lpFR->sFR.ulidShadow), (LPGENERICREC)lpQR, FALSE, &dwError))
  668. {
  669. if (dwError == ERROR_NOT_ENOUGH_MEMORY)
  670. {
  671. RecchkKdPrint(BADERRORS, ("Couldn't write PQ entry for Inode %xh \r\n", lpFR->sFR.ulidShadow));
  672. }
  673. lpFR->sFR.uchType = REC_EMPTY;
  674. lpcseHead->lpRBA->ulErrorFlags |= RBA_ERROR_INVALID_INODE;
  675. WriteRecordToRBA(lpcseHead->lpRBA, lpcseHead->ulRec, (LPGENERICREC)lpFR, TRUE, NULL);
  676. // go around one more time, when this entry will get skipped
  677. continue;
  678. }
  679. }
  680. }
  681. }
  682. // point to the next record
  683. lpcseHead->ulRec += (OvfCount(lpFR)+1);
  684. if ((lpFR->sFR.uchType == REC_DATA) && !(lpFR->sFR.ulidShadow & 0x80000000))
  685. {
  686. ulidCurParent = ulidCurDir;
  687. ulidCurDir = lpFR->sFR.ulidShadow;
  688. fGoDeeper = TRUE;
  689. break;
  690. }
  691. }
  692. if (fGoDeeper)
  693. {
  694. continue;
  695. }
  696. else
  697. {
  698. // we completed processing a directory
  699. Assert(fGoDeeper == FALSE);
  700. Assert(lpcseHead);
  701. RecchkKdPrint(TRAVERSE, ("Unwinding \r\n"));
  702. if (fFix && lpcseHead->lpRBA->ulErrorFlags)
  703. {
  704. if (!WriteRBA(lpdbID, lpcseHead->lpRBA, NULL))
  705. {
  706. RecchkKdPrint(BADERRORS, ("Cannot fix errors on %xh \n\r", lpcseHead->lpRBA->ulidShadow));
  707. }
  708. }
  709. // processing of a directory is complete, unwind the stack
  710. lpcseT = lpcseHead;
  711. lpcseHead = lpcseHead->lpcseNext;
  712. FreeRBA(lpcseT->lpRBA);
  713. FreeMemPaged(lpcseT);
  714. if (!lpcseHead)
  715. {
  716. break;
  717. }
  718. ulidCurDir = lpcseHead->ulidDir;
  719. ulidCurParent = lpcseHead->ulidParent;
  720. }
  721. }
  722. fRet = TRUE;
  723. bailout:
  724. if (lpFR)
  725. {
  726. FreeMemPaged(lpFR);
  727. }
  728. if (lpQR)
  729. {
  730. FreeMemPaged(lpQR);
  731. }
  732. Assert(!(fRet && lpcseHead));
  733. for (;lpcseHead;)
  734. {
  735. lpcseT = lpcseHead;
  736. lpcseHead = lpcseHead->lpcseNext;
  737. FreeRBA(lpcseT->lpRBA);
  738. FreeMemPaged(lpcseT);
  739. }
  740. return (fRet);
  741. }
  742. BOOL
  743. AllocateRBA(
  744. DWORD cntRBE, // count of record buffer entries
  745. DWORD cbRBE, // size of each record buffer entry
  746. LPRBA *lplpRBA // result to be returned
  747. )
  748. /*++
  749. Routine Description:
  750. Parameters:
  751. Return Value:
  752. Notes:
  753. --*/
  754. {
  755. LPRBA lpRBA = NULL;
  756. DWORD i;
  757. lpRBA = (LPRBA)AllocMemPaged(sizeof(RBA)+sizeof(LPBYTE)*cntRBE);
  758. if (lpRBA != NULL)
  759. {
  760. // initialize the guy
  761. lpRBA->cntRBE = cntRBE; // count of record buffer entries in rgRBE
  762. lpRBA->cbRBE = cbRBE; // size in bytes of each RBE buffer
  763. }
  764. else
  765. {
  766. RecchkKdPrint(BADERRORS, ("Failed memory allocation while getting RBA\r\n"));
  767. }
  768. if (lpRBA)
  769. {
  770. *lplpRBA = lpRBA;
  771. return (TRUE);
  772. }
  773. return FALSE;
  774. }
  775. VOID
  776. FreeRBA(
  777. LPRBA lpRBA
  778. )
  779. /*++
  780. Routine Description:
  781. Parameters:
  782. Return Value:
  783. Notes:
  784. --*/
  785. {
  786. DWORD i;
  787. RecchkKdPrint(RBA, ("FreeRBA:cntRBE=%d cbRBE=%d lpRBA=%xh\r\n", lpRBA->cntRBE, lpRBA->cbRBE, lpRBA));
  788. for (i=0; i<lpRBA->cntRBE; ++i)
  789. {
  790. if (lpRBA->rgRBE[i])
  791. {
  792. FreeMemPaged(lpRBA->rgRBE[i]);
  793. }
  794. }
  795. if (lpRBA->hf)
  796. {
  797. CloseFileLocal(lpRBA->hf);
  798. }
  799. FreeMemPaged(lpRBA);
  800. }
  801. BOOL
  802. ReadShadowInRBA(
  803. LPVOID lpdbID,
  804. unsigned ulidShadow,
  805. DWORD cbMaxRBEIn, // max size in bytes of an RBE
  806. DWORD cntRBEIn, // # of RBEs in this RBA, calculated if 0
  807. LPRBA *lplpRBA
  808. )
  809. /*++
  810. Routine Description:
  811. Parameters:
  812. Return Value:
  813. Notes:
  814. --*/
  815. {
  816. LPSTR lpszName = NULL;
  817. BOOL fRet = FALSE;
  818. DWORD dwFileSize, cntRBE, cntRecsPerRBE, cbRBE, i;
  819. unsigned ulRecords, ulPos, ulErrorFlags = 0;
  820. CSCHFILE hf = CSCHFILE_NULL;
  821. GENERICHEADER sGH;
  822. LPRBA lpRBA=NULL;
  823. if (lpszName = FormNameString(lpdbID, ulidShadow))
  824. {
  825. hf = OpenFileLocal(lpszName);
  826. if (hf)
  827. {
  828. if ((GetFileSizeLocal(hf, &dwFileSize))==0xffffffff)
  829. {
  830. RecchkKdPrint(BADERRORS, ("Failed to get filesize for %s\r\n", lpszName));
  831. goto bailout;
  832. }
  833. if (ReadHeader(hf, &sGH, sizeof(sGH))< 0)
  834. {
  835. RecchkKdPrint(BADERRORS, ("Failed to read header for %s\r\n", lpszName));
  836. goto bailout;
  837. }
  838. ulRecords = (dwFileSize-sGH.lFirstRec)/sGH.uRecSize;
  839. if (sGH.ulRecords != ulRecords)
  840. {
  841. RecchkKdPrint(BADERRORS, ("Count of total records inconsistent with the file size header=%d expected=%d\r\n",
  842. sGH.ulRecords,
  843. ulRecords
  844. ));
  845. ulErrorFlags |= RAB_ERROR_INVALID_RECORD_COUNT;
  846. }
  847. if (sGH.ulRecords > ulRecords)
  848. {
  849. sGH.ulRecords = ulRecords;
  850. }
  851. // integral # of records per RBE
  852. cntRecsPerRBE = cbMaxRBEIn/sGH.uRecSize;
  853. // corresponding size of memory allocation per RBE
  854. cbRBE = cntRecsPerRBE * sGH.uRecSize;
  855. if (!cntRBEIn)
  856. {
  857. // total count of RBEs. Add 1 to take care of partial RBE at the end
  858. cntRBE = sGH.ulRecords/cntRecsPerRBE + 1;
  859. }
  860. else
  861. {
  862. cntRBE = cntRBEIn;
  863. }
  864. if (!AllocateRBA(cntRBE, cbRBE, &lpRBA))
  865. {
  866. RecchkKdPrint(BADERRORS, ("Failed allocation of recbuff array of %d entries for %s\r\n", cntRBE, lpszName));
  867. goto bailout;
  868. }
  869. ulPos = sGH.lFirstRec;
  870. for (i=0; i<cntRBE; ++i)
  871. {
  872. int iRet;
  873. Assert(!lpRBA->rgRBE[i]);
  874. lpRBA->rgRBE[i] = (LPBYTE)AllocMemPaged(cbRBE);
  875. if (!lpRBA->rgRBE[i])
  876. {
  877. RecchkKdPrint(BADERRORS, ("Error allocating RBE for Inode file %s \r\n", lpszName));
  878. goto bailout;
  879. }
  880. iRet = ReadFileLocalEx2(hf, ulPos, lpRBA->rgRBE[i], cbRBE, FLAG_RW_OSLAYER_PAGED_BUFFER);
  881. if (iRet < 0)
  882. {
  883. RecchkKdPrint(BADERRORS, ("Error reading Inode file %s \r\n", lpszName));
  884. goto bailout;
  885. }
  886. if (iRet < (int)cbRBE)
  887. {
  888. break;
  889. }
  890. ulPos += cbRBE;
  891. }
  892. // initialize the guy
  893. lpRBA->ulidShadow = ulidShadow; // Inode
  894. lpRBA->sGH = sGH; // Inode file header
  895. lpRBA->hf = hf; // file handle
  896. lpRBA->cntRBE = cntRBE; // count of record buffer entries in rgRBE
  897. lpRBA->cntRecsPerRBE = cntRecsPerRBE; // count of records in each RBE buffer
  898. lpRBA->cbRBE = cbRBE; // size in bytes of each RBE buffer
  899. lpRBA->ulErrorFlags = ulErrorFlags; // errors found so far
  900. *lplpRBA = lpRBA;
  901. fRet = TRUE;
  902. }
  903. else
  904. {
  905. RecchkKdPrint(BADERRORS, ("Failed to open %s \r\n", lpszName));
  906. }
  907. }
  908. else
  909. {
  910. RecchkKdPrint(BADERRORS, ("Failed memory allocation\r\n"));
  911. }
  912. bailout:
  913. if (lpszName)
  914. {
  915. FreeNameString(lpszName);
  916. }
  917. if (hf)
  918. {
  919. CloseFileLocal(hf);
  920. if (lpRBA)
  921. {
  922. lpRBA->hf = CSCHFILE_NULL;
  923. }
  924. }
  925. if (!fRet)
  926. {
  927. if (lpRBA)
  928. {
  929. FreeRBA(lpRBA);
  930. }
  931. }
  932. return (fRet);
  933. }
  934. BOOL
  935. WriteRBA(
  936. LPVOID lpdbID,
  937. LPRBA lpRBA,
  938. LPSTR lpszFileName
  939. )
  940. /*++
  941. Routine Description:
  942. Parameters:
  943. Return Value:
  944. Notes:
  945. --*/
  946. {
  947. CSCHFILE hf = CSCHFILE_NULL;
  948. BOOL fRet = FALSE;
  949. LPSTR lpszName = NULL, lpszTempName = NULL, lpszTempName1 = NULL;
  950. DWORD i, cntRecsInLastRBE, cbLastRBE, cntRBEReal;
  951. unsigned long ulPos, ulT;
  952. if (!lpszFileName)
  953. {
  954. lpszName = FormNameString(lpdbID, lpRBA->ulidShadow);
  955. if (!lpszName)
  956. {
  957. RecchkKdPrint(BADERRORS, ("Failed to allocate memory\r\n"));
  958. goto bailout;
  959. }
  960. }
  961. else
  962. {
  963. lpszName = lpszFileName;
  964. }
  965. // create tempfilel names
  966. lpszTempName = AllocMemPaged(strlen((LPSTR)lpdbID) + strlen(vszTemp) + 4);
  967. if (!lpszTempName)
  968. {
  969. RecchkKdPrint(BADERRORS, ("Failed to allocate memory\r\n"));
  970. goto bailout;
  971. }
  972. strcpy(lpszTempName, (LPSTR)lpdbID);
  973. strcat(lpszTempName, "\\");
  974. strcat(lpszTempName, vszTemp);
  975. lpszTempName1 = AllocMemPaged(strlen((LPSTR)lpdbID) + strlen(vszTemp1) + 4);
  976. if (!lpszTempName1)
  977. {
  978. RecchkKdPrint(BADERRORS, ("Failed to allocate memory\r\n"));
  979. goto bailout;
  980. }
  981. strcpy(lpszTempName1, (LPSTR)lpdbID);
  982. strcat(lpszTempName1, "\\");
  983. strcat(lpszTempName1, vszTemp1);
  984. hf = R0OpenFileEx(ACCESS_READWRITE, ACTION_CREATEALWAYS, FILE_ATTRIBUTE_SYSTEM, lpszTempName, FALSE);
  985. if (!hf)
  986. {
  987. RecchkKdPrint(BADERRORS, ("Failed to open %s\r\n", lpszTempName));
  988. goto bailout;
  989. }
  990. // this is the real # of RBEs, there might be empty ones
  991. // after this
  992. cntRBEReal = lpRBA->sGH.ulRecords / lpRBA->cntRecsPerRBE;
  993. RecchkKdPrint(RBA, ("Writing %s\r\n", lpszTempName));
  994. // is there a partial RBE at the end?
  995. if (lpRBA->sGH.ulRecords % lpRBA->cntRecsPerRBE)
  996. {
  997. // yes, bump up the count of RBEs to write and caclulate the
  998. // # of bytes
  999. cntRBEReal++;
  1000. cntRecsInLastRBE = lpRBA->sGH.ulRecords - (cntRBEReal - 1) * lpRBA->cntRecsPerRBE;
  1001. cbLastRBE = cntRecsInLastRBE * lpRBA->sGH.uRecSize;
  1002. }
  1003. else
  1004. {
  1005. // records exactly fit in the last RBE.
  1006. // so the stats for the last RBE are trivial
  1007. cntRecsInLastRBE = lpRBA->cntRecsPerRBE;
  1008. cbLastRBE = lpRBA->cbRBE;
  1009. }
  1010. RecchkKdPrint(RBA, ("%d RBEs, %d bytes in last RBE\r\n", cntRBEReal, cbLastRBE));
  1011. Assert(cntRBEReal <= lpRBA->cntRBE);
  1012. if(WriteFileLocalEx2(hf, 0, &(lpRBA->sGH), sizeof(lpRBA->sGH), FLAG_RW_OSLAYER_PAGED_BUFFER)!=((int)sizeof(lpRBA->sGH)))
  1013. {
  1014. RecchkKdPrint(BADERRORS, ("Failed writing header \r\n"));
  1015. goto bailout;
  1016. }
  1017. ulPos = lpRBA->sGH.lFirstRec;
  1018. for (i=0; i<cntRBEReal; ++i)
  1019. {
  1020. DWORD dwSize;
  1021. // if last RBE, write the residual size calculated above
  1022. dwSize = (((i+1)==cntRBEReal)?cbLastRBE:lpRBA->cbRBE);
  1023. // there must be a corresponding RBE
  1024. Assert(lpRBA->rgRBE[i]);
  1025. if(WriteFileLocalEx2(hf, ulPos, lpRBA->rgRBE[i], dwSize, FLAG_RW_OSLAYER_PAGED_BUFFER)!=(int)dwSize)
  1026. {
  1027. RecchkKdPrint(BADERRORS, ("Error writing file\r\n"));
  1028. goto bailout;
  1029. }
  1030. ulPos += dwSize;
  1031. }
  1032. CloseFileLocal(hf);
  1033. hf = CSCHFILE_NULL;
  1034. if((GetAttributesLocal(lpszTempName1, &ulT)>=0)
  1035. && (DeleteFileLocal(lpszTempName1, ATTRIB_DEL_ANY) < 0))
  1036. {
  1037. RecchkKdPrint(BADERRORS, ("WriteRBA: failed to delete temp file %s\r\n", lpszTempName1));
  1038. goto bailout;
  1039. }
  1040. if(RenameFileLocal(lpszName, lpszTempName1) < 0)
  1041. {
  1042. RecchkKdPrint(BADERRORS, ("WriteRBA: failed to rename original %s to temp file %s\r\n", lpszName, lpszTempName1));
  1043. goto bailout;
  1044. }
  1045. if(RenameFileLocal(lpszTempName, lpszName) < 0)
  1046. {
  1047. RecchkKdPrint(BADERRORS, ("WriteRBA: failed to rename new file %s to the original %s\r\n", lpszTempName, lpszName));
  1048. if(RenameFileLocal(lpszTempName1, lpszTempName) < 0)
  1049. {
  1050. RecchkKdPrint(BADERRORS, ("WriteRBA: failed to rename back %s to the original %s\r\n", lpszTempName1, lpszName));
  1051. Assert(FALSE);
  1052. }
  1053. goto bailout;
  1054. }
  1055. fRet = TRUE;
  1056. bailout:
  1057. if (hf)
  1058. {
  1059. CloseFileLocal(hf);
  1060. }
  1061. // if a name wasn't sent in, we must have allocated it
  1062. if (!lpszFileName)
  1063. {
  1064. FreeNameString(lpszName);
  1065. }
  1066. if (lpszTempName)
  1067. {
  1068. FreeMemPaged(lpszTempName);
  1069. }
  1070. if (lpszTempName1)
  1071. {
  1072. FreeMemPaged(lpszTempName1);
  1073. }
  1074. return (fRet);
  1075. }
  1076. LPVOID
  1077. GetRecordPointerFromRBA(
  1078. LPRBA lpRBA,
  1079. unsigned ulRec
  1080. )
  1081. /*++
  1082. Routine Description:
  1083. Parameters:
  1084. Return Value:
  1085. Notes:
  1086. --*/
  1087. {
  1088. DWORD indxRec, indxRBE;
  1089. if (lpRBA->sGH.ulRecords < ulRec)
  1090. {
  1091. RecchkKdPrint(BADERRORS, ("GetRecordPointerFromRBA: invalid rec passed in lpRBA->ulidShadow=%xh lpRBA->sGH.ulRecords=%xh ulRec=%xh\r\n",
  1092. lpRBA->ulidShadow, lpRBA->sGH.ulRecords, ulRec));
  1093. return NULL;
  1094. }
  1095. indxRBE = (ulRec-1)/lpRBA->cntRecsPerRBE;
  1096. indxRec = (ulRec-1)%lpRBA->cntRecsPerRBE;
  1097. Assert(lpRBA->rgRBE[indxRBE]);
  1098. return ((lpRBA->rgRBE[indxRBE])+indxRec*lpRBA->sGH.uRecSize);
  1099. }
  1100. BOOL
  1101. ReadRecordFromRBA(
  1102. LPRBA lpRBA,
  1103. unsigned ulRec,
  1104. LPGENERICREC lpGR
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. Parameters:
  1109. Return Value:
  1110. Notes:
  1111. --*/
  1112. {
  1113. DWORD indxRec, indxRBE, cntOvf, i;
  1114. char uchOvfType;
  1115. LPGENERICREC lpGRT;
  1116. if(lpRBA->sGH.ulRecords < ulRec)
  1117. {
  1118. // this must have been fixed when we read the file in
  1119. // only in case of priority Q, where the records point
  1120. // to each other is it possible that this could happen
  1121. Assert(lpRBA->ulidShadow == ULID_PQ);
  1122. }
  1123. indxRBE = (ulRec-1)/lpRBA->cntRecsPerRBE;
  1124. indxRec = (ulRec-1)%lpRBA->cntRecsPerRBE;
  1125. Assert(lpRBA->rgRBE[indxRBE]);
  1126. lpGRT = (LPGENERICREC)((lpRBA->rgRBE[indxRBE])+indxRec*lpRBA->sGH.uRecSize);
  1127. memcpy(lpGR, (lpRBA->rgRBE[indxRBE])+indxRec*lpRBA->sGH.uRecSize, lpRBA->sGH.uRecSize);
  1128. if ((lpGR->uchType == REC_DATA)||(lpGR->uchType == REC_EMPTY))
  1129. {
  1130. cntOvf = (DWORD)OvfCount(lpGR);
  1131. uchOvfType = (lpGR->uchType == REC_DATA)?REC_OVERFLOW:REC_EMPTY;
  1132. if (cntOvf > MAX_OVERFLOW_RECORDS)
  1133. {
  1134. lpRBA->ulErrorFlags |= RBA_ERROR_INVALID_OVF;
  1135. SetOvfCount(lpGR, MAX_OVERFLOW_RECORDS);
  1136. }
  1137. if (cntOvf)
  1138. {
  1139. for (i=1; i<=cntOvf; ++i)
  1140. {
  1141. indxRBE = (ulRec+i-1)/lpRBA->cntRecsPerRBE;
  1142. indxRec = (ulRec+i-1)%lpRBA->cntRecsPerRBE;
  1143. memcpy(((LPBYTE)lpGR)+i*lpRBA->sGH.uRecSize, (lpRBA->rgRBE[indxRBE])+indxRec*lpRBA->sGH.uRecSize, lpRBA->sGH.uRecSize);
  1144. if (((LPGENERICREC)(((LPBYTE)lpGR)+i*lpRBA->sGH.uRecSize))->uchType != uchOvfType)
  1145. {
  1146. lpRBA->ulErrorFlags |= RBA_ERROR_INVALID_OVF;
  1147. SetOvfCount(lpGR, (i-1));
  1148. }
  1149. }
  1150. }
  1151. }
  1152. else
  1153. {
  1154. lpGR->uchType = REC_EMPTY;
  1155. SetOvfCount(lpGR, 0);
  1156. lpGRT->uchType = REC_EMPTY;
  1157. SetOvfCount(lpGRT, 0);
  1158. lpRBA->ulErrorFlags |= RBA_ERROR_MISALIGNED_RECORD;
  1159. RecchkKdPrint(BADERRORS, ("ReadRecordFromRBA: misaligned record found \r\n"));
  1160. }
  1161. return (TRUE);
  1162. }
  1163. BOOL
  1164. WriteRecordToRBA(
  1165. LPRBA lpRBA,
  1166. unsigned ulRec,
  1167. LPGENERICREC lpGR,
  1168. BOOL fOverwrite,
  1169. LPDWORD lpdwError
  1170. )
  1171. /*++
  1172. Routine Description:
  1173. Parameters:
  1174. Return Value:
  1175. Notes:
  1176. --*/
  1177. {
  1178. DWORD indxRec, indxRBE, cntOvf, i, ulRecords;
  1179. LPGENERICREC lpGRT;
  1180. indxRBE = (ulRec-1)/lpRBA->cntRecsPerRBE;
  1181. indxRec = (ulRec-1)%lpRBA->cntRecsPerRBE;
  1182. if (indxRBE >= MAX_RBES_EXPECTED)
  1183. {
  1184. lpRBA->ulErrorFlags |= RBA_ERROR_LIMIT_EXCEEDED;
  1185. RecchkKdPrint(BADERRORS, ("WriteRecordToRBA: Limit of reached, for Inode %x, skipping\r\n", lpRBA->ulidShadow));
  1186. if (lpdwError)
  1187. {
  1188. *lpdwError = ERROR_BUFFER_OVERFLOW;
  1189. }
  1190. return FALSE;
  1191. }
  1192. if (!lpRBA->rgRBE[indxRBE])
  1193. {
  1194. if (!FillupRBAUptoThisRBE(lpRBA, indxRBE))
  1195. {
  1196. RecchkKdPrint(BADERRORS, ("WriteRecordToRBA: failed to fillup RBA\r\n"));
  1197. if (lpdwError)
  1198. {
  1199. *lpdwError = ERROR_NOT_ENOUGH_MEMORY;
  1200. }
  1201. return FALSE;
  1202. }
  1203. }
  1204. Assert(lpRBA->rgRBE[indxRBE]);
  1205. lpGRT = (LPGENERICREC)((lpRBA->rgRBE[indxRBE])+indxRec*lpRBA->sGH.uRecSize);
  1206. if (!fOverwrite && ((lpGRT->uchType == REC_DATA)||(lpGRT->uchType == REC_OVERFLOW)))
  1207. {
  1208. RecchkKdPrint(RBA, ("Not overwriting at ulrec=%d in RBA for Inode 0x%x", ulRec, lpRBA->ulidShadow));
  1209. if (lpdwError)
  1210. {
  1211. *lpdwError = ERROR_INVALID_PARAMETER;
  1212. }
  1213. return FALSE;
  1214. }
  1215. memcpy((lpRBA->rgRBE[indxRBE])+indxRec*lpRBA->sGH.uRecSize, lpGR, lpRBA->sGH.uRecSize);
  1216. cntOvf = (DWORD)OvfCount(lpGR);
  1217. if (cntOvf)
  1218. {
  1219. for (i=1; i<=cntOvf; ++i)
  1220. {
  1221. indxRBE = (ulRec+i-1)/lpRBA->cntRecsPerRBE;
  1222. indxRec = (ulRec+i-1)%lpRBA->cntRecsPerRBE;
  1223. if (!lpRBA->rgRBE[indxRBE])
  1224. {
  1225. RecchkKdPrint(RBA, ("Extending RBEs upto indx=%d \r\n", indxRBE));
  1226. if (!FillupRBAUptoThisRBE(lpRBA, indxRBE))
  1227. {
  1228. RecchkKdPrint(BADERRORS, ("WriteRecordToRBA: failed to fillup RBA\r\n"));
  1229. return FALSE;
  1230. }
  1231. }
  1232. memcpy( (lpRBA->rgRBE[indxRBE])+indxRec*lpRBA->sGH.uRecSize,
  1233. ((LPBYTE)lpGR)+i*lpRBA->sGH.uRecSize,
  1234. lpRBA->sGH.uRecSize);
  1235. }
  1236. }
  1237. // reflect any addition in the count of records
  1238. // add up total records in all RBEs except the last one
  1239. // which might be partially filled, then add the index of the
  1240. // one we just filled in , then add one because the index is
  1241. // 0 based
  1242. ulRecords = lpRBA->cntRecsPerRBE * indxRBE
  1243. + indxRec
  1244. + 1;
  1245. if (ulRecords > lpRBA->sGH.ulRecords)
  1246. {
  1247. RecchkKdPrint(RBA, ("# of records got increased from %d to %d\r\n", lpRBA->sGH.ulRecords, ulRecords));
  1248. lpRBA->sGH.ulRecords = ulRecords;
  1249. }
  1250. return (TRUE);
  1251. }
  1252. BOOL
  1253. FillupRBAUptoThisRBE(
  1254. LPRBA lpRBA,
  1255. DWORD indxRBE
  1256. )
  1257. /*++
  1258. Routine Description:
  1259. Parameters:
  1260. Return Value:
  1261. Notes:
  1262. --*/
  1263. {
  1264. DWORD i;
  1265. for (i=0; i<= indxRBE; ++i)
  1266. {
  1267. if (!lpRBA->rgRBE[i])
  1268. {
  1269. lpRBA->rgRBE[i] = (LPBYTE)AllocMemPaged(lpRBA->cbRBE);
  1270. if (!lpRBA->rgRBE[i])
  1271. {
  1272. RecchkKdPrint(BADERRORS, ("FillupRBAUptoThisPoint:Failed memory allocation \r\n"));
  1273. return FALSE;
  1274. }
  1275. InitializeRBE(lpRBA, i);
  1276. }
  1277. }
  1278. return (TRUE);
  1279. }
  1280. VOID
  1281. InitializeRBE(
  1282. LPRBA lpRBA,
  1283. DWORD indxRBE
  1284. )
  1285. /*++
  1286. Routine Description:
  1287. Parameters:
  1288. Return Value:
  1289. Notes:
  1290. --*/
  1291. {
  1292. DWORD i;
  1293. LPBYTE lpT = lpRBA->rgRBE[indxRBE];
  1294. for (i=0; i< lpRBA->cntRecsPerRBE; ++i)
  1295. {
  1296. Assert(((LPGENERICREC)lpT)->uchType != REC_DATA);
  1297. ((LPGENERICREC)lpT)->uchType = REC_EMPTY;
  1298. lpT += lpRBA->sGH.uRecSize;
  1299. }
  1300. }
  1301. BOOL
  1302. InsertRBAPQEntryFile(
  1303. LPRBA lpRBAPQ,
  1304. LPQREC lpPQDst,
  1305. unsigned ulrecDst
  1306. )
  1307. /*++
  1308. Routine Description:
  1309. Parameters:
  1310. Return Value:
  1311. Notes:
  1312. --*/
  1313. {
  1314. LPQREC lpPQCur, lpPQPred=NULL;
  1315. LPQHEADER lpQH = NULL;
  1316. unsigned ulrecCur, ulrecPred;
  1317. lpQH = (LPQHEADER)&(lpRBAPQ->sGH);
  1318. if (!lpQH->ulrecHead)
  1319. {
  1320. Assert(!lpQH->ulrecTail);
  1321. lpQH->ulrecHead = lpQH->ulrecTail = ulrecDst;
  1322. lpPQDst->ulrecNext = lpPQDst->ulrecPrev = 0;
  1323. }
  1324. else
  1325. {
  1326. for(ulrecCur = lpQH->ulrecHead, lpPQPred=NULL, ulrecPred=0;;)
  1327. {
  1328. if (!(lpPQCur = GetRecordPointerFromRBA(lpRBAPQ, ulrecCur)))
  1329. {
  1330. RecchkKdPrint(BADERRORS, ("InsertRBAPQEntry: failed getting q entry at %d\r\n", ulrecCur));
  1331. return FALSE;
  1332. }
  1333. // are we greater than or equal to the current one?
  1334. if (IComparePri(lpPQDst, lpPQCur) >= 0)
  1335. {
  1336. // yes, insert here
  1337. if (!lpPQPred)
  1338. {
  1339. // no predecessor, must be the head of the list
  1340. Assert(!lpPQCur->ulrecPrev);
  1341. // when we become the head, we got no prev
  1342. lpPQDst->ulrecPrev = 0;
  1343. // and the current head is our next
  1344. lpPQDst->ulrecNext = lpQH->ulrecHead;
  1345. // fix up the current heads prev to point to us
  1346. lpPQCur->ulrecPrev = ulrecDst;
  1347. // and fix the current head to point to us
  1348. lpQH->ulrecHead = ulrecDst;
  1349. }
  1350. else
  1351. {
  1352. // normal case, we go between lpPQPred and lpPQCur
  1353. Assert(ulrecPred);
  1354. // fix up the passed in guy first
  1355. lpPQDst->ulrecPrev = ulrecPred;
  1356. lpPQDst->ulrecNext = ulrecCur;
  1357. // now fix the predecessor's next and current guys prev to point to us
  1358. lpPQPred->ulrecNext = lpPQCur->ulrecPrev = ulrecDst;
  1359. }
  1360. break;
  1361. }
  1362. ulrecPred = ulrecCur;
  1363. ulrecCur = lpPQCur->ulrecNext;
  1364. if (!ulrecCur)
  1365. {
  1366. // Insert at the tail
  1367. lpPQDst->ulrecNext = 0;
  1368. lpPQDst->ulrecPrev = lpQH->ulrecTail;
  1369. lpPQCur->ulrecNext = ulrecDst;
  1370. lpQH->ulrecTail = ulrecDst;
  1371. break;
  1372. }
  1373. lpPQPred = lpPQCur;
  1374. }
  1375. }
  1376. return (TRUE);
  1377. }
  1378. BOOL
  1379. InsertRBAPQEntryDir(
  1380. LPRBA lpRBAPQ,
  1381. LPQREC lpPQDst,
  1382. unsigned ulrecDst
  1383. )
  1384. /*++
  1385. Routine Description:
  1386. Parameters:
  1387. Return Value:
  1388. Notes:
  1389. --*/
  1390. {
  1391. LPQREC lpPQCur, lpPQSucc=NULL;
  1392. LPQHEADER lpQH = NULL;
  1393. unsigned ulrecCur, ulrecSucc;
  1394. lpQH = (LPQHEADER)&(lpRBAPQ->sGH);
  1395. if (!lpQH->ulrecHead)
  1396. {
  1397. Assert(!lpQH->ulrecTail);
  1398. lpQH->ulrecHead = lpQH->ulrecTail = ulrecDst;
  1399. lpPQDst->ulrecNext = lpPQDst->ulrecPrev = 0;
  1400. }
  1401. else
  1402. {
  1403. for(ulrecCur = lpQH->ulrecTail, lpPQSucc=NULL, ulrecSucc=0;;)
  1404. {
  1405. if (!(lpPQCur = GetRecordPointerFromRBA(lpRBAPQ, ulrecCur)))
  1406. {
  1407. RecchkKdPrint(BADERRORS, ("InsertRBAPQEntry: failed getting q entry at %d\r\n", ulrecCur));
  1408. return FALSE;
  1409. }
  1410. // are we less than or equal to the current one?
  1411. if (IComparePri(lpPQDst, lpPQCur) <= 0)
  1412. {
  1413. // yes, insert here
  1414. if (!lpPQSucc)
  1415. {
  1416. // no Succecessor, must be the tail of the list
  1417. Assert(!lpPQCur->ulrecNext);
  1418. // when we become the tail, we got no next
  1419. lpPQDst->ulrecNext = 0;
  1420. // and the current tail is our prev
  1421. lpPQDst->ulrecPrev = lpQH->ulrecTail;
  1422. Assert(lpQH->ulrecTail == ulrecCur);
  1423. Assert(!lpPQCur->ulrecNext);
  1424. // fix up the current tails next to point to us
  1425. lpPQCur->ulrecNext = ulrecDst;
  1426. // and fix the current tail to point to us
  1427. lpQH->ulrecTail = ulrecDst;
  1428. }
  1429. else
  1430. {
  1431. // normal case, we go between lpPQCur and lpPQSucc
  1432. Assert(ulrecSucc);
  1433. // fix up the passed in guy first
  1434. lpPQDst->ulrecNext = ulrecSucc;
  1435. lpPQDst->ulrecPrev = ulrecCur;
  1436. // now fix the Succecessor's prev and current guys next to point to us
  1437. lpPQSucc->ulrecPrev = lpPQCur->ulrecNext = ulrecDst;
  1438. }
  1439. break;
  1440. }
  1441. ulrecSucc = ulrecCur;
  1442. ulrecCur = lpPQCur->ulrecPrev;
  1443. if (!ulrecCur)
  1444. {
  1445. // Insert at the head
  1446. lpPQDst->ulrecPrev = 0;
  1447. lpPQDst->ulrecNext = lpQH->ulrecHead;
  1448. lpPQCur->ulrecPrev = ulrecDst;
  1449. lpQH->ulrecHead = ulrecDst;
  1450. break;
  1451. }
  1452. lpPQSucc = lpPQCur;
  1453. }
  1454. }
  1455. return (TRUE);
  1456. }
  1457. BOOL
  1458. ValidateQrecFromFilerec(
  1459. unsigned ulidShare,
  1460. unsigned ulidDir,
  1461. LPFILERECEXT lpFR,
  1462. LPQREC lpQR,
  1463. unsigned ulrecDirEntry
  1464. )
  1465. /*++
  1466. Routine Description:
  1467. Parameters:
  1468. Return Value:
  1469. Notes:
  1470. --*/
  1471. {
  1472. if (lpQR->uchType != REC_DATA)
  1473. {
  1474. RecchkKdPrint(BADERRORS, ("Invalid Qrec type %c \r\n", lpQR->uchType));
  1475. return FALSE;
  1476. }
  1477. if ((lpQR->ulidShare != ulidShare)||
  1478. (lpQR->ulidDir != ulidDir)||
  1479. (lpQR->ulidShadow != lpFR->sFR.ulidShadow))
  1480. {
  1481. RecchkKdPrint(BADERRORS, ("Mismatched server, dir or inode \r\n"));
  1482. return FALSE;
  1483. }
  1484. if ((lpQR->usStatus != lpFR->sFR.usStatus)||
  1485. (lpQR->uchRefPri != lpFR->sFR.uchRefPri)||
  1486. (lpQR->uchIHPri != lpFR->sFR.uchIHPri)||
  1487. (lpQR->uchHintFlags != lpFR->sFR.uchHintFlags)||
  1488. (lpQR->uchHintPri != lpFR->sFR.uchHintPri))
  1489. {
  1490. RecchkKdPrint(BADERRORS, ("Mismatched status or pincount\r\n"));
  1491. return FALSE;
  1492. }
  1493. if (ulidDir && (lpQR->ulrecDirEntry != ulrecDirEntry))
  1494. {
  1495. RecchkKdPrint(BADERRORS, ("Mismatched ulrecDirEntry\r\n"));
  1496. return FALSE;
  1497. }
  1498. return TRUE;
  1499. }
  1500. #if 0
  1501. #ifdef DEBUG
  1502. VOID
  1503. PrintShareHeader(
  1504. LPSHAREHEADER lpSH,
  1505. LPFNPRINTPROC lpfnPrintProc
  1506. )
  1507. /*++
  1508. Routine Description:
  1509. Parameters:
  1510. Return Value:
  1511. Notes:
  1512. --*/
  1513. {
  1514. int iRet=0;
  1515. if (lpfnPrintProc)
  1516. {
  1517. iRet += wsprintfA(vchPrintBuff,"****ShareHeader****\r\n" );
  1518. iRet+=wsprintfA(vchPrintBuff+iRet,"Header: Flags=%xh Version=%lxh Records=%ld Size=%d \r\n",
  1519. lpSH->uchFlags, lpSH->ulVersion, lpSH->ulRecords, lpSH->uRecSize);
  1520. iRet+=wsprintfA(vchPrintBuff+iRet,"Store: Max=%ld Current=%ld \r\n", lpSH->sMax.ulSize, lpSH->sCur.ulSize);
  1521. iRet+=wsprintfA(vchPrintBuff+iRet,"\r\n");
  1522. (lpfnPrintProc)(vchPrintBuff);
  1523. }
  1524. }
  1525. VOID
  1526. PrintPQHeader(
  1527. LPQHEADER lpQH,
  1528. PRINTPROC lpfnPrintProc
  1529. )
  1530. {
  1531. int iRet=0;
  1532. if (lpfnPrintProc)
  1533. {
  1534. iRet += wsprintfA(vchPrintBuff+iRet,"****PQHeader****\r\n" );
  1535. iRet += wsprintfA(vchPrintBuff+iRet,"Flags=%xh Version=%lxh Records=%ld Size=%d head=%ld tail=%ld\r\n",
  1536. lpQH->uchFlags, lpQH->ulVersion, lpQH->ulRecords, lpQH->uRecSize, lpQH->ulrecHead, lpQH->ulrecTail);
  1537. iRet += wsprintfA(vchPrintBuff+iRet,"\r\n");
  1538. (lpfnPrintProc)(vchPrintBuff);
  1539. }
  1540. }
  1541. VOID
  1542. PrintFileHeader(
  1543. LPFILEHEADER lpFH,
  1544. unsigned ulSpaces,
  1545. PRINTPROC lpfnPrintProc
  1546. )
  1547. /*++
  1548. Routine Description:
  1549. Parameters:
  1550. Return Value:
  1551. Notes:
  1552. --*/
  1553. {
  1554. int iRet=0;
  1555. if (lpfnPrintProc)
  1556. {
  1557. iRet += PrintSpaces(vchPrintBuff+iRet, ulSpaces);
  1558. iRet += wsprintfA(vchPrintBuff+iRet,"****FileHeader****\r\n" );
  1559. iRet += PrintSpaces(vchPrintBuff+iRet, ulSpaces);
  1560. iRet += wsprintfA(vchPrintBuff+iRet,"Flags=%xh Version=%lxh Records=%ld Size=%d\r\n",
  1561. lpFH->uchFlags, lpFH->ulVersion, lpFH->ulRecords, lpFH->uRecSize);
  1562. iRet += PrintSpaces(vchPrintBuff+iRet, ulSpaces);
  1563. iRet += wsprintfA(vchPrintBuff+iRet,"bytes=%ld entries=%d Share=%xh Dir=%xh\r\n",
  1564. lpFH->ulsizeShadow, lpFH->ucShadows, lpFH->ulidShare, lpFH->ulidDir);
  1565. iRet += wsprintfA(vchPrintBuff+iRet,"\r\n");
  1566. (lpfnPrintProc)(vchPrintBuff);
  1567. }
  1568. }
  1569. VOID
  1570. PrintPQrec(
  1571. unsigned ulRec,
  1572. LPQREC lpQrec,
  1573. PRINTPROC lpfnPrintProc
  1574. )
  1575. /*++
  1576. Routine Description:
  1577. Parameters:
  1578. Return Value:
  1579. Notes:
  1580. --*/
  1581. {
  1582. int iRet=0;
  1583. if (lpfnPrintProc)
  1584. {
  1585. iRet += wsprintfA(vchPrintBuff+iRet,"rec=%xh: Srvr=%xh dir=%xh shd=%xh prev=%xh next=%xh Stts=%xh, RfPr=%d PnCnt=%x PnFlgs=%xh DrEntr=%d\r\n"
  1586. ,ulRec
  1587. , lpQrec->ulidShare
  1588. , lpQrec->ulidDir
  1589. , lpQrec->ulidShadow
  1590. , lpQrec->ulrecPrev
  1591. , lpQrec->ulrecNext
  1592. , (unsigned long)(lpQrec->usStatus)
  1593. , (unsigned long)(lpQrec->uchRefPri)
  1594. , (unsigned long)(lpQrec->uchHintPri)
  1595. , (unsigned long)(lpQrec->uchHintFlags)
  1596. , lpQrec->ulrecDirEntry
  1597. );
  1598. (lpfnPrintProc)(vchPrintBuff);
  1599. }
  1600. }
  1601. VOID PrintShareRec(
  1602. unsigned ulRec,
  1603. LPSHAREREC lpSR,
  1604. PRINTPROC lpfnPrintProc
  1605. )
  1606. /*++
  1607. Routine Description:
  1608. Parameters:
  1609. Return Value:
  1610. Notes:
  1611. --*/
  1612. {
  1613. int iRet=0;
  1614. if (lpfnPrintProc)
  1615. {
  1616. iRet += wsprintfA(vchPrintBuff+iRet,"Type=%c Flags=%xh hShare=%lxh Root=%0lxh status=%xh Share=%s \r\n"
  1617. , lpSR->uchType, (unsigned)lpSR->uchFlags, ulRec, lpSR->ulidShadow
  1618. , lpSR->uStatus, lpSR->rgPath);
  1619. iRet += wsprintfA(vchPrintBuff+iRet,"Hint: HintFlags=%xh, HintPri=%d, IHPri=%d\r\n",
  1620. (unsigned)(lpSR->uchHintFlags)
  1621. , (int)(lpSR->uchHintPri)
  1622. , (int)(lpSR->uchIHPri));
  1623. iRet += wsprintfA(vchPrintBuff+iRet,"\r\n");
  1624. (lpfnPrintProc)(vchPrintBuff+iRet);
  1625. }
  1626. }
  1627. VOID PrintFilerec(
  1628. unsigned ulRec,
  1629. LPFILERECEXT lpFR,
  1630. unsigned ulSpaces,
  1631. PRINTPROC lpfnPrintProc
  1632. )
  1633. /*++
  1634. Routine Description:
  1635. Parameters:
  1636. Return Value:
  1637. Notes:
  1638. --*/
  1639. {
  1640. int i;
  1641. int iRet=0;
  1642. if (lpfnPrintProc)
  1643. {
  1644. iRet += PrintSpaces(vchPrintBuff+iRet, ulSpaces);
  1645. iRet += wsprintfA(vchPrintBuff+iRet,"Type=%c Flags=%xh Inode=%0lxh status=%xh 83Name=%ls size=%ld attrib=%lxh \r\n",
  1646. lpFR->sFR.uchType, (unsigned)lpFR->sFR.uchFlags, lpFR->sFR.ulidShadow,
  1647. lpFR->sFR.uStatus, lpFR->sFR.rgw83Name, lpFR->sFR.ulFileSize, lpFR->sFR.dwFileAttrib);
  1648. iRet += PrintSpaces(vchPrintBuff+iRet, ulSpaces);
  1649. iRet += wsprintfA(vchPrintBuff+iRet,"time: hi=%lxh lo=%lxh orgtime: hi=%lxh lo=%lxh\r\n"
  1650. , lpFR->sFR.ftLastWriteTime.dwHighDateTime,lpFR->sFR.ftLastWriteTime.dwLowDateTime
  1651. , lpFR->sFR.ftOrgTime.dwHighDateTime,lpFR->sFR.ftOrgTime.dwLowDateTime);
  1652. iRet += PrintSpaces(vchPrintBuff+iRet, ulSpaces);
  1653. iRet += wsprintfA(vchPrintBuff+iRet,"Hint: HintFlags=%xh, RefPri=%d, HintPri=%d AliasInode=%0lxh \r\n",
  1654. (unsigned)(lpFR->sFR.uchHintFlags)
  1655. , (int)(lpFR->sFR.uchRefPri)
  1656. , (int)(lpFR->sFR.uchHintPri)
  1657. , lpFR->sFR.ulidShadowFrom);
  1658. iRet += PrintSpaces(vchPrintBuff+iRet, ulSpaces);
  1659. iRet += wsprintfA(vchPrintBuff+iRet,"LFN=%-14ls", lpFR->sFR.rgwName);
  1660. for(i = 0; i < OvfCount(lpFR); ++i)
  1661. {
  1662. iRet += wsprintfA(vchPrintBuff+iRet,"%-74s", &(lpFR->sFR.ulidShadow));
  1663. }
  1664. iRet += wsprintfA(vchPrintBuff+iRet,"\r\n");
  1665. (lpfnPrintProc)(vchPrintBuff);
  1666. }
  1667. }
  1668. int
  1669. PrintSpaces(
  1670. LPSTR lpBuff,
  1671. unsigned ulSpaces
  1672. )
  1673. /*++
  1674. Routine Description:
  1675. Parameters:
  1676. Return Value:
  1677. Notes:
  1678. --*/
  1679. {
  1680. unsigned i;
  1681. int iRet=0;
  1682. for (i=0; i< ulSpaces; ++i)
  1683. {
  1684. iRet += wsprintfA(lpBuff+iRet," ");
  1685. }
  1686. return iRet;
  1687. }
  1688. #endif
  1689. #endif