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.

724 lines
16 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. regmigrt.c
  5. Abstract:
  6. Registry migration routines
  7. Author:
  8. Ted Miller (tedm) 12-Apr-1996
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. typedef enum {
  14. AddQuotesNone,
  15. AddQuotesNormal,
  16. AddQuotesOpenNoClose,
  17. AddQuotesNoOpenOrClose,
  18. } AddQuotesOp;
  19. BOOL
  20. RetrieveMessageIntoBufferV(
  21. IN UINT MessageId,
  22. OUT PTSTR Buffer,
  23. IN UINT BufferSizeChars,
  24. IN va_list *arglist
  25. )
  26. {
  27. DWORD d;
  28. d = FormatMessage(
  29. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM,
  30. hInst,
  31. MessageId,
  32. 0,
  33. Buffer,
  34. BufferSizeChars,
  35. arglist
  36. );
  37. if(!d) {
  38. d = FormatMessage(
  39. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  40. hInst,
  41. MSG_NOT_FOUND,
  42. 0,
  43. Buffer,
  44. BufferSizeChars,
  45. (va_list *)&MessageId
  46. );
  47. if(!d) {
  48. return FALSE;
  49. }
  50. }
  51. return TRUE;
  52. }
  53. DWORD
  54. WriteText(
  55. IN HANDLE FileHandle,
  56. IN UINT MessageId,
  57. ...
  58. )
  59. {
  60. TCHAR Message[2048];
  61. CHAR message[4096];
  62. va_list arglist;
  63. DWORD Written;
  64. BOOL b;
  65. va_start(arglist,MessageId);
  66. b = RetrieveMessageIntoBufferV(
  67. MessageId,
  68. Message,
  69. sizeof(Message)/sizeof(Message[0]),
  70. &arglist
  71. );
  72. va_end(arglist);
  73. if(!b)
  74. return ERROR_INVALID_PARAMETER;
  75. #ifdef UNICODE
  76. Written = (DWORD)WideCharToMultiByte(
  77. CP_ACP,
  78. 0,
  79. Message,
  80. lstrlen(Message),
  81. message,
  82. sizeof(message),
  83. NULL,
  84. NULL
  85. );
  86. #else
  87. StringCchCopyA(message,sizeof(message),Message);
  88. Written = lstrlen(message);
  89. #endif
  90. b = WriteFile(FileHandle,message,Written,&Written,NULL);
  91. return(b ? NO_ERROR : GetLastError());
  92. }
  93. DWORD
  94. FlushGenInfLineBuf(
  95. IN OUT PINFFILEGEN Context,
  96. IN HANDLE File
  97. )
  98. {
  99. CHAR TransBuf[INFLINEBUFLEN*2];
  100. DWORD rc;
  101. PVOID Buffer;
  102. DWORD Size;
  103. BOOL b;
  104. Buffer = TransBuf;
  105. #ifdef UNICODE
  106. Size = WideCharToMultiByte(
  107. CP_ACP,
  108. 0,
  109. Context->LineBuf,
  110. Context->LineBufUsed,
  111. TransBuf,
  112. sizeof(TransBuf),
  113. NULL,
  114. NULL
  115. );
  116. #else
  117. StringCchCopyA(TransBuf,sizeof(TransBuf),Context->LineBuf);
  118. Size = Context->LineBufUsed;
  119. #endif
  120. if(WriteFile(File,Buffer,Size,&rc,NULL)) {
  121. rc = NO_ERROR;
  122. Context->LineBufUsed = 0;
  123. } else {
  124. rc = GetLastError();
  125. }
  126. return(rc);
  127. }
  128. DWORD
  129. __inline
  130. GenInfWriteChar(
  131. IN OUT PINFFILEGEN Context,
  132. IN HANDLE File,
  133. IN TCHAR Char
  134. )
  135. {
  136. DWORD rc;
  137. PVOID Buffer;
  138. Context->LineBuf[Context->LineBufUsed++] = Char;
  139. rc = (Context->LineBufUsed == INFLINEBUFLEN)
  140. ? FlushGenInfLineBuf(Context,File)
  141. : NO_ERROR;
  142. return(rc);
  143. }
  144. DWORD
  145. GenInfWriteString(
  146. IN OUT PINFFILEGEN Context,
  147. IN HANDLE File,
  148. IN LPCTSTR String,
  149. IN AddQuotesOp AddQuotes
  150. )
  151. {
  152. DWORD rc;
  153. TCHAR CONST *p;
  154. if((AddQuotes == AddQuotesNormal) || (AddQuotes == AddQuotesOpenNoClose)) {
  155. rc = GenInfWriteChar(Context,File,TEXT('\"'));
  156. if(rc != NO_ERROR) {
  157. return(rc);
  158. }
  159. }
  160. for(p=String; *p; p++) {
  161. rc = GenInfWriteChar(Context,File,*p);
  162. if(rc != NO_ERROR) {
  163. return(rc);
  164. }
  165. if((*p == TEXT('\"')) && (AddQuotes != AddQuotesNone)) {
  166. rc = GenInfWriteChar(Context,File,TEXT('\"'));
  167. if(rc != NO_ERROR) {
  168. return(rc);
  169. }
  170. }
  171. }
  172. if(AddQuotes == AddQuotesNormal) {
  173. rc = GenInfWriteChar(Context,File,TEXT('\"'));
  174. if(rc != NO_ERROR) {
  175. return(rc);
  176. }
  177. }
  178. return(NO_ERROR);
  179. }
  180. DWORD
  181. CreateAndOpenTempFile(
  182. IN LPCTSTR Path,
  183. IN LPCTSTR HeaderLine, OPTIONAL
  184. OUT HANDLE *Handle,
  185. OUT PTSTR Filename
  186. )
  187. {
  188. HANDLE h;
  189. DWORD rc;
  190. //
  191. // Note that this creates the file.
  192. //
  193. if(!GetTempFileName(Path,TEXT("$IF"),0,Filename)) {
  194. rc = GetLastError();
  195. goto c0;
  196. }
  197. h = CreateFile(
  198. Filename,
  199. GENERIC_WRITE,
  200. FILE_SHARE_READ,
  201. NULL,
  202. CREATE_ALWAYS,
  203. FILE_ATTRIBUTE_NORMAL,
  204. NULL
  205. );
  206. if(h == INVALID_HANDLE_VALUE) {
  207. rc = GetLastError();
  208. goto c1;
  209. }
  210. if(HeaderLine) {
  211. rc = WriteText(h,MSG_INF_SINGLELINE,HeaderLine);
  212. if(rc != NO_ERROR) {
  213. goto c2;
  214. }
  215. }
  216. *Handle = h;
  217. return(NO_ERROR);
  218. c2:
  219. CloseHandle(h);
  220. c1:
  221. DeleteFile(Filename);
  222. c0:
  223. return(rc);
  224. }
  225. DWORD
  226. InfCreateSection(
  227. IN LPCTSTR SectionName,
  228. IN OUT PINFFILEGEN *Context
  229. )
  230. {
  231. PTSTR Buffer;
  232. DWORD rc;
  233. Buffer = MALLOC( (lstrlen(SectionName) + 3)*sizeof(TCHAR) );
  234. if( !Buffer ) {
  235. return ERROR_NOT_ENOUGH_MEMORY;
  236. }
  237. lstrcpy( Buffer, TEXT("[") );
  238. lstrcat( Buffer, SectionName );
  239. lstrcat( Buffer, TEXT("]") );
  240. rc = WriteText((*Context)->FileHandle,MSG_INF_SINGLELINE,Buffer);
  241. FREE( Buffer );
  242. return(rc);
  243. }
  244. DWORD
  245. InfStart(
  246. IN LPCTSTR InfName,
  247. IN LPCTSTR Directory,
  248. OUT PINFFILEGEN *Context
  249. )
  250. {
  251. TCHAR InfFileName[MAX_PATH];
  252. DWORD d;
  253. DWORD rc;
  254. PINFFILEGEN context;
  255. UCHAR UnicodeMark[2];
  256. PTSTR p;
  257. DWORD BytesWritten = 0;
  258. //
  259. // Allocate some context.
  260. //
  261. context = MALLOC(sizeof(INFFILEGEN));
  262. if(!context) {
  263. rc = ERROR_NOT_ENOUGH_MEMORY;
  264. goto c0;
  265. }
  266. ZeroMemory(context,sizeof(INFFILEGEN));
  267. //
  268. // We'll create a unique inf name in the given directory
  269. // to use as the output inf. The directory itself will
  270. // become the oem file root.
  271. //
  272. if(!GetFullPathName(Directory,MAX_PATH,context->FileName,&p)) {
  273. rc = GetLastError();
  274. goto c1;
  275. }
  276. if (!ConcatenatePaths(context->FileName,InfName,MAX_PATH)) {
  277. rc = ERROR_BUFFER_OVERFLOW;
  278. goto c1;
  279. }
  280. SetFileAttributes(context->FileName, FILE_ATTRIBUTE_NORMAL);
  281. DeleteFile(context->FileName);
  282. //
  283. // Create the output file.
  284. //
  285. context->FileHandle = CreateFile(
  286. context->FileName,
  287. GENERIC_WRITE,
  288. FILE_SHARE_READ,
  289. NULL,
  290. CREATE_ALWAYS,
  291. FILE_ATTRIBUTE_NORMAL,
  292. NULL
  293. );
  294. if(context->FileHandle == INVALID_HANDLE_VALUE) {
  295. rc = GetLastError();
  296. goto c1;
  297. }
  298. //
  299. // Write out header for inf file.
  300. //
  301. WriteFile(context->FileHandle,
  302. INF_FILE_HEADER,
  303. strlen(INF_FILE_HEADER),
  304. &BytesWritten,
  305. NULL);
  306. rc = GetLastError();
  307. if(rc != NO_ERROR) {
  308. goto c5;
  309. }
  310. *Context = context;
  311. return(NO_ERROR);
  312. c5:
  313. CloseHandle(context->FileHandle);
  314. DeleteFile(context->FileName);
  315. c1:
  316. FREE(context);
  317. c0:
  318. return(rc);
  319. }
  320. DWORD
  321. InfEnd(
  322. IN OUT PINFFILEGEN *Context
  323. )
  324. {
  325. PINFFILEGEN context;
  326. DWORD rc;
  327. HANDLE h;
  328. DWORD Size;
  329. context = *Context;
  330. *Context = NULL;
  331. h = context->FileHandle;
  332. rc = NO_ERROR;
  333. CloseHandle(h);
  334. if(rc != NO_ERROR) {
  335. DeleteFile(context->FileName);
  336. }
  337. FREE(context);
  338. return(rc);
  339. }
  340. DWORD
  341. pInfRegLineCommon(
  342. IN OUT PINFFILEGEN Context,
  343. IN HANDLE OutputFile,
  344. IN HKEY Key,
  345. IN LPCTSTR Subkey,
  346. IN LPCTSTR Value OPTIONAL
  347. )
  348. {
  349. LPCTSTR RootSpec;
  350. LPCTSTR SubkeySpec;
  351. DWORD rc;
  352. if(Subkey[0] == TEXT('\\')) {
  353. Subkey++;
  354. }
  355. //
  356. // Figure out the root key spec.
  357. //
  358. switch((ULONG_PTR)Key) {
  359. case (ULONG_PTR)HKEY_LOCAL_MACHINE:
  360. //
  361. // Check for HKEY_CLASSES_ROOT
  362. //
  363. if(_tcsnicmp(Subkey,TEXT("SOFTWARE\\Classes"),16)) {
  364. RootSpec = TEXT("HKLM");
  365. SubkeySpec = Subkey;
  366. } else {
  367. RootSpec = TEXT("HKCR");
  368. SubkeySpec = Subkey+16;
  369. if(*SubkeySpec == TEXT('\\')) {
  370. SubkeySpec++;
  371. }
  372. }
  373. break;
  374. case (ULONG_PTR)HKEY_CURRENT_USER:
  375. RootSpec = TEXT("HKCU");
  376. SubkeySpec = Subkey;
  377. break;
  378. case (ULONG_PTR)HKEY_CLASSES_ROOT:
  379. RootSpec = TEXT("HKCR");
  380. SubkeySpec = Subkey;
  381. break;
  382. default:
  383. //
  384. // Value we can't express via inf.
  385. // Use HKEY_ROOT but also write out a comment incidating
  386. // that there's a problem
  387. //
  388. RootSpec = TEXT("HKR");
  389. SubkeySpec = Subkey;
  390. Context->SawBogusOp = TRUE;
  391. rc = FlushGenInfLineBuf(Context,OutputFile);
  392. if(rc != NO_ERROR) {
  393. return(rc);
  394. }
  395. rc = WriteText(OutputFile,MSG_INF_BAD_REGSPEC_1);
  396. if(rc != NO_ERROR) {
  397. return(rc);
  398. }
  399. break;
  400. }
  401. rc = GenInfWriteString(Context,OutputFile,RootSpec,AddQuotesNone);
  402. if(rc == NO_ERROR) {
  403. rc = GenInfWriteChar(Context,OutputFile,TEXT(','));
  404. if(rc == NO_ERROR) {
  405. rc = GenInfWriteString(Context,OutputFile,SubkeySpec,AddQuotesNormal);
  406. if((rc == NO_ERROR) && Value) {
  407. rc = GenInfWriteChar(Context,OutputFile,TEXT(','));
  408. if(rc == NO_ERROR) {
  409. rc = GenInfWriteString(Context,OutputFile,Value,AddQuotesNormal);
  410. }
  411. }
  412. }
  413. }
  414. return(rc);
  415. }
  416. DWORD
  417. InfRecordAddReg(
  418. IN OUT PINFFILEGEN Context,
  419. IN HKEY Key,
  420. IN LPCTSTR Subkey,
  421. IN LPCTSTR Value, OPTIONAL
  422. IN DWORD DataType,
  423. IN PVOID Data,
  424. IN DWORD DataLength,
  425. IN BOOL SetNoClobberFlag
  426. )
  427. {
  428. DWORD rc;
  429. DWORD Flags;
  430. PTSTR p;
  431. DWORD d;
  432. int LineLen;
  433. TCHAR NumStr[24];
  434. //
  435. // Figure out flags based on data type.
  436. // The flags dword is built as two halves depending on whether
  437. // data is string or binary in nature.
  438. //
  439. // We do this before we write out the actual line
  440. // since that routine might also write a warning if a bogus root key
  441. // is specified.
  442. //
  443. switch(DataType) {
  444. case REG_SZ:
  445. Flags = FLG_ADDREG_TYPE_SZ;
  446. break;
  447. case REG_EXPAND_SZ:
  448. Flags = FLG_ADDREG_TYPE_EXPAND_SZ;
  449. break;
  450. case REG_MULTI_SZ:
  451. Flags = FLG_ADDREG_TYPE_MULTI_SZ;
  452. break;
  453. case REG_DWORD:
  454. Flags = FLG_ADDREG_TYPE_DWORD;
  455. break;
  456. //case REG_NONE:
  457. // Flags = FLG_ADDREG_TYPE_NONE;
  458. // break;
  459. case REG_NONE:
  460. Flags = FLG_ADDREG_KEYONLY;
  461. break;
  462. default:
  463. //
  464. // Arbitrary binary data. Better hope the data type doesn't overflow
  465. // 16 bits.
  466. //
  467. if(DataType > 0xffff) {
  468. Context->SawBogusOp = TRUE;
  469. rc = FlushGenInfLineBuf(Context,Context->FileHandle);
  470. if(rc != NO_ERROR) {
  471. return(rc);
  472. }
  473. rc = WriteText(Context->FileHandle,MSG_INF_BAD_REGSPEC_2);
  474. if(rc != NO_ERROR) {
  475. return(rc);
  476. }
  477. DataType = REG_BINARY;
  478. }
  479. Flags = FLG_ADDREG_BINVALUETYPE | (DataType << 16);
  480. break;
  481. }
  482. rc = pInfRegLineCommon(Context,Context->FileHandle,Key,Subkey,Value);
  483. if(rc != NO_ERROR) {
  484. return(rc);
  485. }
  486. if(Flags == FLG_ADDREG_KEYONLY) {
  487. rc = GenInfWriteChar(Context,Context->FileHandle,TEXT(','));
  488. if(rc != NO_ERROR) {
  489. return(rc);
  490. }
  491. }
  492. //
  493. // _stprintf(NumStr,TEXT(",%0#10lx"),Flags | 0x00000002); // Force NO_CLOBBER
  494. //
  495. // _stprintf(NumStr,TEXT(",%0#10lx"),Flags);
  496. wsprintf(NumStr,
  497. TEXT(",%#08lx"),
  498. SetNoClobberFlag? (Flags | 0x00000002) : Flags);
  499. rc = GenInfWriteString(Context,Context->FileHandle,NumStr,AddQuotesNone);
  500. if(rc != NO_ERROR) {
  501. return(rc);
  502. }
  503. //
  504. // Now we need to write out the data itself.
  505. // How we do this is dependent on the data type.
  506. //
  507. switch(DataType) {
  508. case REG_SZ:
  509. case REG_EXPAND_SZ:
  510. //
  511. // Single string. Ignore data length.
  512. //
  513. rc = GenInfWriteChar(Context,Context->FileHandle,TEXT(','));
  514. if(rc == NO_ERROR) {
  515. rc = GenInfWriteString(Context,Context->FileHandle,Data,AddQuotesNormal);
  516. }
  517. break;
  518. case REG_DWORD:
  519. //
  520. // Write out as a dword.
  521. //
  522. wsprintf(NumStr,TEXT(",%u"),*(DWORD UNALIGNED *)Data);
  523. rc = GenInfWriteString(Context,Context->FileHandle,NumStr,AddQuotesNone);
  524. break;
  525. case REG_MULTI_SZ:
  526. //
  527. // Write out each string.
  528. //
  529. for(p=Data; (rc==NO_ERROR) && *p; p+=lstrlen(p)+1) {
  530. rc = GenInfWriteChar(Context,Context->FileHandle,TEXT(','));
  531. if(rc == NO_ERROR) {
  532. rc = GenInfWriteString(Context,Context->FileHandle,p,AddQuotesNormal);
  533. }
  534. }
  535. break;
  536. case REG_NONE:
  537. //
  538. // Don't create a value entry
  539. //
  540. break;
  541. default:
  542. //
  543. // Treat as binary. If we have any data at all start a new line.
  544. //
  545. if(DataLength) {
  546. rc = GenInfWriteString(Context,Context->FileHandle,TEXT(",\\\r\n "),AddQuotesNone);
  547. }
  548. LineLen = 0;
  549. for(d=0; (rc==NO_ERROR) && (d<DataLength); d++) {
  550. if(LineLen == 25) {
  551. rc = GenInfWriteString(Context,Context->FileHandle,TEXT(",\\\r\n "),AddQuotesNone);
  552. LineLen = 0;
  553. }
  554. if(rc == NO_ERROR) {
  555. if(LineLen) {
  556. rc = GenInfWriteChar(Context,Context->FileHandle,TEXT(','));
  557. }
  558. if(rc == NO_ERROR) {
  559. wsprintf(NumStr,TEXT("%02x"),((PBYTE)Data)[d]);
  560. rc = GenInfWriteString(Context,Context->FileHandle,NumStr,AddQuotesNone);
  561. LineLen++;
  562. }
  563. }
  564. }
  565. break;
  566. }
  567. if(rc == NO_ERROR) {
  568. rc = GenInfWriteString(Context,Context->FileHandle,TEXT("\r\n"),AddQuotesNone);
  569. if(rc == NO_ERROR) {
  570. rc = FlushGenInfLineBuf(Context,Context->FileHandle);
  571. }
  572. }
  573. return(rc);
  574. }
  575. #if 0
  576. DWORD
  577. InfRecordDelReg(
  578. IN OUT PINFFILEGEN Context,
  579. IN HKEY Key,
  580. IN LPCTSTR Subkey,
  581. IN LPCTSTR Value OPTIONAL
  582. )
  583. {
  584. DWORD rc;
  585. rc = pInfRegLineCommon(Context,Context->DelRegFile,Key,Subkey,Value);
  586. if(rc == NO_ERROR) {
  587. rc = GenInfWriteString(Context,Context->DelRegFile,TEXT("\r\n"),AddQuotesNone);
  588. if(rc == NO_ERROR) {
  589. rc = FlushGenInfLineBuf(Context,Context->DelRegFile);
  590. }
  591. }
  592. return(rc);
  593. }
  594. #endif