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.

5379 lines
171 KiB

  1. /************************************************************************
  2. Copyright (c) Microsoft Corporation 1997
  3. All rights reserved
  4. ***************************************************************************/
  5. #include "pch.h"
  6. #include <aclapip.h>
  7. #include <winldap.h>
  8. #include "check.h"
  9. #include "dialogs.h"
  10. #include "setup.h"
  11. #include "check.h"
  12. #include <sddl.h>
  13. DEFINE_MODULE( "Setup" );
  14. #ifdef SMALL_BUFFER_SIZE
  15. #undef SMALL_BUFFER_SIZE
  16. #endif
  17. #define SMALL_BUFFER_SIZE 512
  18. #define MAX_FILES_SIZE 1920000
  19. #define BIG_BUFFER 4096
  20. #define MACHINENAME_SIZE 32
  21. static const WCHAR chSlash = TEXT('\\');
  22. static const WCHAR SISCommonStoreDir[] = L"SIS Common Store";
  23. typedef LONGLONG INDEX;
  24. SCPDATA scpdata[] = {
  25. { L"netbootAllowNewClients", L"TRUE" },
  26. { L"netbootLimitClients", L"FALSE" },
  27. { L"netbootCurrentClientCount", L"0" },
  28. { L"netbootMaxClients", L"100" },
  29. { L"netbootAnswerRequests", L"TRUE" },
  30. { L"netbootAnswerOnlyValidClients", L"FALSE" },
  31. { L"netbootNewMachineNamingPolicy", L"%61Username%#" },
  32. { L"netbootNewMachineOU", NULL },
  33. { L"netbootServer", NULL }
  34. };
  35. //
  36. // Use this structure to drive changes (lines) that
  37. // need to be added/removed from login.osc when we run
  38. // risetup. We'll use this mechanism to patch legacy
  39. // instances of login.osc that may be hanging around
  40. // on the machine.
  41. //
  42. // Note: Don't re-order these entries unless you fix up the index
  43. // entries. For example, you'll see that entry 3 has a dependency
  44. // on entry 2 (but the reverse is not true). That means that when
  45. // we're about to look at processing entry 3, we'll go check entry
  46. // 2's OperationCompletedSuccessfully value to see if we should indeed
  47. // process entry 3.
  48. //
  49. LOGIN_PATCHES LoginOSCPatches[] = {
  50. // Add (TRUE) or remove (FALSE) the specified string from the file.
  51. // | Did the operation complete successfully?
  52. // | | Index to any entries we're dependent on.
  53. // | | | Tag which specifies the start of the section where our string will be found.
  54. // | | | | Tag which specifies the end of the section where our string will be found.
  55. // | | | | | String to be added or removed from the specified section.
  56. // | | | | | |
  57. { TRUE, FALSE, (-1), "<FORM", "</FORM>", "<INPUT NAME=\"NTLMV2Enabled\" VALUE=%NTLMV2Enabled% MAXLENGTH=255 type=VARIABLE>" },
  58. { TRUE, FALSE, (-1), "<FORM", "</FORM>", "<INPUT NAME=\"ServerUTCFileTime\" VALUE=%ServerUTCFileTime% MAXLENGTH=255 type=VARIABLE>" },
  59. { FALSE, FALSE, (-1), "<FORM", "</FORM>", "Domain Name: <INPUT NAME=\"USERDOMAIN\" MAXLENGTH=255>" },
  60. { TRUE, FALSE, 2, "<FORM", "</FORM>", "Domain Name: <INPUT NAME=\"USERDOMAIN\" VALUE=%SERVERDOMAIN% MAXLENGTH=255>" }
  61. };
  62. //
  63. // This set of strings defines the ACLs we'll place on the d:\reminst
  64. // directory.
  65. //
  66. WCHAR *REMINSTszSecurityDescriptor = L"D:" // DACL
  67. L"(A;OICI;GA;;;SY)" // Allow SYSTEM Generic All (full control)
  68. L"(A;OICI;GA;;;BA)" // Allow Builtin Administrators Generic All (full control)
  69. L"(A;OICI;GRGX;;;AU)"; // Allow Authenticated generic read/execute
  70. #define MACHINEOU_INDEX 7
  71. #define NETBOOTSERVER_INDEX 8
  72. #define BINL_PARAMETERS_KEY L"System\\CurrentControlSet\\Services\\Binlsvc\\Parameters"
  73. PCWSTR
  74. SetupExtensionFromProcessorTag(
  75. PCWSTR ProcessorTag
  76. )
  77. {
  78. if (wcscmp(ProcessorTag,L"i386")==0) {
  79. return(L"x86");
  80. } else {
  81. return(ProcessorTag);
  82. }
  83. }
  84. //
  85. // KeepUIAlive( )
  86. //
  87. BOOL
  88. KeepUIAlive(
  89. HWND hDlg )
  90. {
  91. MSG Msg;
  92. //
  93. // process messages to keep UI alive
  94. //
  95. while ( PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE ) )
  96. {
  97. TranslateMessage( &Msg );
  98. DispatchMessage( &Msg );
  99. if ( hDlg != NULL && Msg.message == WM_KEYUP && Msg.wParam == VK_ESCAPE ) {
  100. VerifyCancel( hDlg );
  101. }
  102. }
  103. return( g_Options.fError || g_Options.fAbort );
  104. }
  105. //
  106. // CreateSCP( )
  107. //
  108. HRESULT
  109. CreateSCP(
  110. HWND hDlg
  111. )
  112. /*++
  113. Routine Description:
  114. Creates SCP information so that BINL can create the SCP when it starts up.
  115. Arguments:
  116. hDlg - dialog window handle for putting up error messages.
  117. Return Value:
  118. HRESULT indicating outcome.
  119. --*/
  120. {
  121. TraceFunc( "CreateSCP( )\n" );
  122. HRESULT hr;
  123. ULONG ulSize;
  124. LPWSTR pszMachinePath = NULL;
  125. DWORD i,Err;
  126. HKEY hKey = 0;
  127. DWORD DontCare;
  128. Err = RegCreateKeyEx(
  129. HKEY_LOCAL_MACHINE,
  130. BINL_PARAMETERS_KEY,
  131. 0,
  132. NULL,
  133. REG_OPTION_NON_VOLATILE,
  134. KEY_SET_VALUE,
  135. NULL,
  136. &hKey,
  137. &DontCare);
  138. if (Err != ERROR_SUCCESS) {
  139. hr = HRESULT_FROM_WIN32( Err );
  140. goto e0;
  141. }
  142. if ( !GetComputerObjectName( NameFullyQualifiedDN, NULL, &ulSize )) {
  143. hr = HRESULT_FROM_WIN32( GetLastError() );
  144. goto e1;
  145. }
  146. pszMachinePath = (LPWSTR) TraceAlloc( LPTR, ulSize * sizeof(WCHAR) );
  147. if ( !pszMachinePath ) {
  148. hr = THR( E_OUTOFMEMORY );
  149. goto e1;
  150. }
  151. if ( !GetComputerObjectName( NameFullyQualifiedDN, pszMachinePath, &ulSize )) {
  152. hr = HRESULT_FROM_WIN32( GetLastError() );
  153. goto e2;
  154. }
  155. scpdata[MACHINEOU_INDEX].pszValue = pszMachinePath;
  156. scpdata[NETBOOTSERVER_INDEX].pszValue = pszMachinePath;
  157. //
  158. // Add default attribute values
  159. //
  160. for( i = 0; i < ARRAYSIZE(scpdata); i++ )
  161. {
  162. Err = RegSetValueEx(
  163. hKey,
  164. scpdata[i].pszAttribute,
  165. NULL,
  166. REG_SZ,
  167. (LPBYTE)scpdata[i].pszValue,
  168. ((DWORD)wcslen(scpdata[i].pszValue)+1)*sizeof(WCHAR) );
  169. if (Err != ERROR_SUCCESS) {
  170. hr = HRESULT_FROM_WIN32( Err );
  171. goto e3;
  172. }
  173. }
  174. hr = S_OK;
  175. Err = 0;
  176. RegSetValueEx(
  177. hKey,
  178. L"ScpCreated",
  179. NULL,
  180. REG_DWORD,
  181. (LPBYTE)&Err,
  182. sizeof(DWORD) );
  183. e3:
  184. if (FAILED(hr)) {
  185. for( i = 0; i < ARRAYSIZE(scpdata); i++ ) {
  186. RegDeleteValue(
  187. hKey,
  188. scpdata[i].pszAttribute );
  189. }
  190. }
  191. e2:
  192. TraceFree( pszMachinePath );
  193. e1:
  194. RegCloseKey(hKey);
  195. e0:
  196. if ( FAILED(hr)) {
  197. MessageBoxFromStrings( hDlg, IDS_SCPCREATIONFAIL_CAPTION, IDS_SCPCREATIONFAIL_TEXT, MB_OK );
  198. ErrorMsg( "Error 0x%08x occurred.\n", hr );
  199. }
  200. HRETURN(hr);
  201. }
  202. PWSTR
  203. GenerateCompressedName(
  204. IN PCWSTR Filename
  205. )
  206. /*++
  207. Routine Description:
  208. Given a filename, generate the compressed form of the name.
  209. The compressed form is generated as follows:
  210. Look backwards for a dot. If there is no dot, append "._" to the name.
  211. If there is a dot followed by 0, 1, or 2 charcaters, append "_".
  212. Otherwise there is a 3-character or greater extension and we replace
  213. the last character with "_".
  214. Arguments:
  215. Filename - supplies filename whose compressed form is desired.
  216. Return Value:
  217. Pointer to buffer containing nul-terminated compressed-form filename.
  218. The caller must free this buffer via TraceFree().
  219. --*/
  220. {
  221. PWSTR CompressedName,p,q;
  222. UINT u;
  223. //
  224. // The maximum length of the compressed filename is the length of the
  225. // original name plus 2 (for ._).
  226. //
  227. CompressedName = (PWSTR)TraceAlloc(LPTR, ((DWORD)wcslen(Filename)+3)*sizeof(WCHAR));
  228. if(CompressedName) {
  229. wcscpy(CompressedName,Filename);
  230. p = wcsrchr(CompressedName,L'.');
  231. q = wcsrchr(CompressedName,L'\\');
  232. if(q < p) {
  233. //
  234. // If there are 0, 1, or 2 characters after the dot, just append
  235. // the underscore. p points to the dot so include that in the length.
  236. //
  237. u = (DWORD)wcslen(p);
  238. if(u < 4) {
  239. wcscat(CompressedName,L"_");
  240. } else {
  241. //
  242. // There are at least 3 characters in the extension.
  243. // Replace the final one with an underscore.
  244. //
  245. p[u-1] = L'_';
  246. }
  247. } else {
  248. //
  249. // No dot, just add ._.
  250. //
  251. wcscat(CompressedName,L"._");
  252. }
  253. }
  254. return(CompressedName);
  255. }
  256. BOOL
  257. IsFileOrCompressedVersionPresent(
  258. LPCWSTR FilePath,
  259. PWSTR *pCompressedName OPTIONAL
  260. )
  261. /*++
  262. Routine Description:
  263. Check if a file or a compressed version of it is present at the
  264. specified location.
  265. Arguments:
  266. FilePath - fully qualified path to the file to check for.
  267. pCompressedName - if the file is compressed, this can receive the compressed
  268. name
  269. Return Value:
  270. TRUE indicats the file or a compressed copy of it is present.
  271. --*/
  272. {
  273. BOOL FileIsPresent = FALSE, IsCompressed = FALSE;
  274. WCHAR ActualName[MAX_PATH];
  275. PWSTR p;
  276. lstrcpyn( ActualName, FilePath, ARRAYSIZE(ActualName)) ;
  277. if (0xFFFFFFFF != GetFileAttributes( ActualName )) {
  278. FileIsPresent = TRUE;
  279. } else {
  280. //
  281. // the file isn't present, so try generating the compressed name
  282. //
  283. p = GenerateCompressedName( ActualName );
  284. if (p) {
  285. lstrcpyn( ActualName, p, ARRAYSIZE(ActualName) );
  286. TraceFree( p );
  287. p = NULL;
  288. if (0xFFFFFFFF != GetFileAttributes( ActualName )) {
  289. IsCompressed = TRUE;
  290. FileIsPresent = TRUE;
  291. }
  292. }
  293. }
  294. if (FileIsPresent && IsCompressed && pCompressedName) {
  295. *pCompressedName = (PWSTR)TraceAlloc( LPTR, ((DWORD)wcslen(ActualName)+1) * sizeof(WCHAR));
  296. if (*pCompressedName) {
  297. wcscpy( *pCompressedName, ActualName) ;
  298. }
  299. }
  300. return( FileIsPresent == TRUE);
  301. }
  302. //
  303. // Builds the pathes used for installation
  304. //
  305. HRESULT
  306. BuildDirectories( void )
  307. {
  308. TraceFunc( "BuildDirectories( void )\n" );
  309. //
  310. // Create
  311. // "D:\IntelliMirror\Setup\English\Images\nt50.wks"
  312. //
  313. lstrcpyn( g_Options.szInstallationPath, g_Options.szIntelliMirrorPath, ARRAYSIZE(g_Options.szInstallationPath));
  314. ConcatenatePaths( g_Options.szInstallationPath, L"\\Setup", ARRAYSIZE(g_Options.szInstallationPath));
  315. ConcatenatePaths( g_Options.szInstallationPath, g_Options.szLanguage, ARRAYSIZE(g_Options.szInstallationPath));
  316. ConcatenatePaths( g_Options.szInstallationPath, REMOTE_INSTALL_IMAGE_DIR_W, ARRAYSIZE(g_Options.szInstallationPath));
  317. ConcatenatePaths( g_Options.szInstallationPath, g_Options.szInstallationName, ARRAYSIZE(g_Options.szInstallationPath));
  318. //ConcatenatePaths( g_Options.szInstallationPath, g_Options.ProcessorArchitectureString, ARRAYSIZE(g_Options.szInstallationPath));
  319. Assert( wcslen(g_Options.szInstallationPath) < ARRAYSIZE(g_Options.szInstallationPath) );
  320. HRETURN(S_OK);
  321. }
  322. //
  323. // Creates the IntelliMirror directory tree.
  324. //
  325. HRESULT
  326. CreateDirectoryPath(
  327. HWND hDlg,
  328. LPWSTR DirectoryPath,
  329. PSECURITY_ATTRIBUTES SecurityAttributes,
  330. BOOL fAllowExisting
  331. )
  332. {
  333. PWCHAR p, pBackslash;
  334. BOOL f;
  335. DWORD attributes;
  336. //
  337. // Find the \ that indicates the root directory. There should be at least
  338. // one \, but if there isn't, we just fall through.
  339. //
  340. p = wcschr( DirectoryPath, L'\\' );
  341. if ( p != NULL ) {
  342. //
  343. // Find the \ that indicates the end of the first level directory. It's
  344. // probable that there won't be another \, in which case we just fall
  345. // through to creating the entire path.
  346. //
  347. p = wcschr( p + 1, L'\\' );
  348. while ( p != NULL ) {
  349. //
  350. // Skip multiple \ that appear together.
  351. //
  352. pBackslash = p;
  353. ++p;
  354. while (*p == L'\\') {
  355. ++p;
  356. }
  357. if (*p == 0) {
  358. //
  359. // These \ are all at the end of the string, so we can
  360. // proceed to the creation of the leaf directory.
  361. //
  362. break;
  363. }
  364. //
  365. // Terminate the directory path at the current level.
  366. //
  367. *pBackslash = 0;
  368. //
  369. // Create a directory at the current level.
  370. //
  371. attributes = GetFileAttributes( DirectoryPath );
  372. if ( 0xFFFFffff == attributes ) {
  373. f = CreateDirectory( DirectoryPath, NULL );
  374. if ( !f ) {
  375. if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
  376. ErrorBox( hDlg, DirectoryPath );
  377. HRETURN(E_FAIL);
  378. }
  379. }
  380. } else if ( (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 ) {
  381. MessageBoxFromError( hDlg, DirectoryPath, ERROR_DIRECTORY );
  382. HRETURN(E_FAIL);
  383. }
  384. //
  385. // Restore the \ and find the next one.
  386. //
  387. *pBackslash = L'\\';
  388. p = wcschr( p, L'\\' );
  389. }
  390. }
  391. //
  392. // Create the target directory.
  393. //
  394. f = CreateDirectory( DirectoryPath, SecurityAttributes );
  395. if ( !f && (!fAllowExisting || (GetLastError() != ERROR_ALREADY_EXISTS)) ) {
  396. ErrorBox( hDlg, DirectoryPath );
  397. HRETURN(E_FAIL);
  398. }
  399. HRETURN(NO_ERROR);
  400. }
  401. DWORD
  402. ApplyDaclToFileDirectory(
  403. PWSTR FileDirectoryName,
  404. SECURITY_DESCRIPTOR_RELATIVE *IncomingSecDescriptorRelative
  405. )
  406. /*++
  407. Routine Description:
  408. This function will apply the specified security descriptor
  409. to the given file or directory name.
  410. Arguments:
  411. FileDirectoryName - Full path specifying location of file
  412. or directory we're operating on.
  413. IncomingSecDescriptorRelative - Security descriptor we'll attempt
  414. to apply to the file/directory.
  415. Return Value:
  416. win32 status code indicating whether we succeeded or failed (and why).
  417. --*/
  418. {
  419. SECURITY_DESCRIPTOR_RELATIVE *pRel = (SECURITY_DESCRIPTOR_RELATIVE *)(IncomingSecDescriptorRelative);
  420. DWORD dw = ERROR_SUCCESS;
  421. DWORD dwLen = 0;
  422. DWORD dwLenDACL = 0;
  423. DWORD dwLenSACL = 0;
  424. DWORD dwLenOWNER = 0;
  425. DWORD dwLenGRP = 0;
  426. PACL pDacl = NULL;
  427. SECURITY_INFORMATION SecurityInfo = DACL_SECURITY_INFORMATION |
  428. PROTECTED_DACL_SECURITY_INFORMATION;
  429. //
  430. // We were given a relative security descriptor. Convert it to an
  431. // absolute descriptor.
  432. //
  433. MakeAbsoluteSD( IncomingSecDescriptorRelative,
  434. NULL,&dwLen,
  435. NULL,&dwLenDACL,
  436. NULL,&dwLenSACL,
  437. NULL,&dwLenOWNER,
  438. NULL,&dwLenGRP );
  439. pDacl = (PACL)LocalAlloc( 0, dwLenDACL );
  440. if( pDacl == NULL ) {
  441. dw = GetLastError();
  442. return dw;
  443. }
  444. memcpy( pDacl, (BYTE *)pRel + pRel->Dacl, dwLenDACL );
  445. //
  446. // Try to set the security descriptor on the file/directory.
  447. //
  448. dw = SetNamedSecurityInfo( FileDirectoryName, // Name of object
  449. SE_FILE_OBJECT, // It's a file/directory
  450. SecurityInfo, // bit vector flags.
  451. NULL, // *SidOwner
  452. NULL, // *SidGroup
  453. pDacl, // Our new DACL
  454. NULL ); // Our new SACL
  455. //
  456. // Clean up and exit.
  457. //
  458. LocalFree( pDacl );
  459. return( dw );
  460. }
  461. //
  462. // Creates the IntelliMirror directory tree.
  463. //
  464. HRESULT
  465. CreateDirectories( HWND hDlg )
  466. {
  467. HRESULT hr = S_OK;
  468. WCHAR szPath[ MAX_PATH ];
  469. WCHAR szCreating[ SMALL_BUFFER_SIZE ];
  470. HWND hProg = GetDlgItem( hDlg, IDC_P_METER );
  471. DWORD dwLen;
  472. DWORD dw;
  473. BOOL f;
  474. LPARAM lRange;
  475. DWORD attributes;
  476. SECURITY_ATTRIBUTES sa;
  477. TraceFunc( "CreateDirectories( hDlg )\n" );
  478. lRange = MAKELPARAM( 0 , 0
  479. + ( g_Options.fIMirrorShareFound ? 0 : 1 )
  480. + ( g_Options.fDirectoryTreeExists ? 0 : 7 )
  481. + ( g_Options.fOSChooserInstalled ? 0 : 1 )
  482. + ( g_Options.fNewOSDirectoryExists ? 0 : 1 )
  483. + ( g_Options.fOSChooserScreensDirectory ? 0 : (g_Options.fLanguageSet ? 1 : 0 ) ) );
  484. SendMessage( hProg, PBM_SETRANGE, 0, lRange );
  485. SendMessage( hProg, PBM_SETSTEP, 1, 0 );
  486. dw = LoadString( g_hinstance, IDS_CREATINGDIRECTORIES, szCreating, ARRAYSIZE(szCreating));
  487. Assert( dw );
  488. SetWindowText( GetDlgItem( hDlg, IDC_S_OPERATION ), szCreating );
  489. //
  490. // Create a security descriptor based on the ACLs
  491. // defined in REMINSTszSecurityDescriptor.
  492. //
  493. // If our directories exist, we'll apply this security
  494. // descriptor on them. If our directories don't exist, then
  495. // we'll use this security descriptor when we create them.
  496. //
  497. RtlZeroMemory( &sa, sizeof(SECURITY_ATTRIBUTES) );
  498. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  499. sa.bInheritHandle = TRUE;
  500. f = ConvertStringSecurityDescriptorToSecurityDescriptor( REMINSTszSecurityDescriptor,
  501. SDDL_REVISION_1,
  502. &(sa.lpSecurityDescriptor),
  503. NULL );
  504. if( !f ) {
  505. dw = GetLastError();
  506. MessageBoxFromError( hDlg, NULL, dw );
  507. hr = THR(HRESULT_FROM_WIN32(dw));
  508. goto Error;
  509. }
  510. attributes = GetFileAttributes( g_Options.szIntelliMirrorPath );
  511. if ( (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 ) {
  512. //
  513. // There's a file there.
  514. //
  515. #if 0
  516. // whack the file and move on.
  517. DeleteFile( g_Options.szIntelliMirrorPath );
  518. #else
  519. MessageBoxFromError( hDlg, g_Options.szIntelliMirrorPath, ERROR_DIRECTORY );
  520. hr = E_FAIL;
  521. goto Error;
  522. #endif
  523. }
  524. if( attributes == 0xFFFFFFFF ) {
  525. //
  526. // Probably doesn't exist. Go create it (with our specified
  527. // access rights).
  528. //
  529. hr = CreateDirectoryPath( hDlg, g_Options.szIntelliMirrorPath, &sa, FALSE );
  530. if ( hr != NO_ERROR ) {
  531. goto Error;
  532. }
  533. } else {
  534. //
  535. // The directory is already there. Go fixup security on it.
  536. //
  537. dw = ApplyDaclToFileDirectory( g_Options.szIntelliMirrorPath,
  538. (SECURITY_DESCRIPTOR_RELATIVE *)(sa.lpSecurityDescriptor) );
  539. if( dw != ERROR_SUCCESS ) {
  540. MessageBoxFromError( hDlg, NULL, dw );
  541. hr = HRESULT_FROM_WIN32(dw);
  542. goto Error;
  543. }
  544. }
  545. //
  546. // Our base directory should be created by now.
  547. // Prevent the index server from indexing the IntelliMirror directory.
  548. //
  549. attributes = GetFileAttributes( g_Options.szIntelliMirrorPath );
  550. attributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
  551. f = SetFileAttributes( g_Options.szIntelliMirrorPath, attributes );
  552. if ( !f ) {
  553. ErrorBox( hDlg, g_Options.szIntelliMirrorPath );
  554. hr = THR(S_FALSE);
  555. }
  556. SendMessage( hProg, PBM_DELTAPOS, 1, 0 );
  557. //
  558. // Create
  559. // "D:\<reminst>\Setup"
  560. //
  561. lstrcpyn( szPath, g_Options.szIntelliMirrorPath, ARRAYSIZE(szPath) );
  562. ConcatenatePaths( szPath, L"\\Setup", ARRAYSIZE(szPath) );
  563. Assert( wcslen(szPath) < ARRAYSIZE(szPath) );
  564. if ( 0xFFFFffff == GetFileAttributes( szPath ) ) {
  565. f = CreateDirectory( szPath, NULL );
  566. if ( !f ) {
  567. ErrorBox( hDlg, szPath );
  568. hr = THR(S_FALSE);
  569. }
  570. }
  571. SendMessage( hProg, PBM_DELTAPOS, 1, 0 );
  572. //
  573. // Create
  574. // "D:\<reminst>\Setup\English"
  575. //
  576. lstrcpyn( szPath, g_Options.szIntelliMirrorPath, ARRAYSIZE(szPath) );
  577. ConcatenatePaths( szPath, L"\\Setup", ARRAYSIZE(szPath));
  578. ConcatenatePaths( szPath, g_Options.szLanguage, ARRAYSIZE(szPath));
  579. Assert( wcslen(szPath) < ARRAYSIZE(szPath) );
  580. if ( 0xFFFFffff == GetFileAttributes( szPath ) ) {
  581. f = CreateDirectory( szPath, NULL );
  582. if ( !f ) {
  583. ErrorBox( hDlg, szPath );
  584. hr = THR(S_FALSE);
  585. }
  586. }
  587. SendMessage( hProg, PBM_DELTAPOS, 1, 0 );
  588. //
  589. // Create
  590. // "D:\<reminst>\Setup\English\Images"
  591. //
  592. lstrcpyn( szPath, g_Options.szIntelliMirrorPath, ARRAYSIZE(szPath) );
  593. ConcatenatePaths( szPath, L"\\Setup", ARRAYSIZE(szPath));
  594. ConcatenatePaths( szPath, g_Options.szLanguage, ARRAYSIZE(szPath));
  595. ConcatenatePaths( szPath, REMOTE_INSTALL_IMAGE_DIR_W, ARRAYSIZE(szPath));
  596. Assert( wcslen(szPath) < ARRAYSIZE(szPath) );
  597. if ( 0xFFFFffff == GetFileAttributes( szPath ) ) {
  598. f = CreateDirectory( szPath, NULL );
  599. if ( !f ) {
  600. ErrorBox( hDlg, szPath );
  601. hr = THR(S_FALSE);
  602. }
  603. }
  604. SendMessage( hProg, PBM_DELTAPOS, 1, 0 );
  605. if ( !g_Options.fNewOSDirectoryExists
  606. && g_Options.fNewOS ) {
  607. //
  608. // Create
  609. // "D:\<reminst>\Setup\English\Images\nt50.wks\i386"
  610. //
  611. if ( 0xFFFFffff == GetFileAttributes( g_Options.szInstallationPath ) ) {
  612. f = CreateDirectory( g_Options.szInstallationPath, NULL );
  613. if ( !f ) {
  614. ErrorBox( hDlg, g_Options.szInstallationPath );
  615. hr = THR(S_FALSE);
  616. }
  617. }
  618. SendMessage( hProg, PBM_DELTAPOS, 1, 0 );
  619. }
  620. if ( !g_Options.fOSChooserDirectory ) {
  621. //
  622. // Create the OS Chooser tree
  623. // "D:\<reminst>\OSChooser"
  624. //
  625. lstrcpyn( g_Options.szOSChooserPath, g_Options.szIntelliMirrorPath, ARRAYSIZE(g_Options.szOSChooserPath) );
  626. ConcatenatePaths( g_Options.szOSChooserPath, L"\\OSChooser", ARRAYSIZE(g_Options.szOSChooserPath));
  627. Assert( wcslen(g_Options.szOSChooserPath) < ARRAYSIZE(g_Options.szOSChooserPath) );
  628. if ( 0xFFFFffff == GetFileAttributes( g_Options.szOSChooserPath ) ) {
  629. f = CreateDirectory( g_Options.szOSChooserPath, NULL );
  630. if ( !f ) {
  631. ErrorBox( hDlg, g_Options.szOSChooserPath );
  632. hr = THR(E_FAIL);
  633. goto Error;
  634. }
  635. }
  636. SendMessage( hProg, PBM_DELTAPOS, 1, 0 );
  637. }
  638. if ( g_Options.hinf != INVALID_HANDLE_VALUE
  639. && !g_Options.fOSChooserDirectoryTreeExists ) {
  640. WCHAR szFile[ MAX_PATH ];
  641. BOOL fFound;
  642. INFCONTEXT context;
  643. fFound = SetupFindFirstLine( g_Options.hinf, L"OSChooser", NULL, &context );
  644. AssertMsg( fFound, "Could not find 'OSChooser' section in REMINST.INF.\n" );
  645. while ( fFound
  646. && SetupGetStringField( &context, 1, szFile, ARRAYSIZE(szFile), NULL ) )
  647. {
  648. dwLen = lstrlen( szFile );
  649. LPWSTR psz = StrRChr( szFile, &szFile[ dwLen ], L'\\' );
  650. if ( psz ) {
  651. *psz = L'\0'; // terminate
  652. _snwprintf( szPath,
  653. ARRAYSIZE(szPath),
  654. L"%s\\%s",
  655. g_Options.szOSChooserPath,
  656. szFile );
  657. TERMINATE_BUFFER(szPath);
  658. if ( 0xFFFFffff == GetFileAttributes( szPath ) ) {
  659. HRESULT hr2;
  660. hr2 = CreateDirectoryPath( hDlg, szPath, NULL, TRUE );
  661. if ( FAILED ( hr2 )) {
  662. hr = hr2;
  663. }
  664. }
  665. }
  666. fFound = SetupFindNextLine( &context, &context );
  667. }
  668. }
  669. if ( FAILED( hr )) goto Error;
  670. if ( !g_Options.fOSChooserScreensDirectory
  671. && g_Options.fLanguageSet ) {
  672. //
  673. // Create
  674. // "D:\<reminst>\OSChooser\English"
  675. //
  676. lstrcpyn( szPath, g_Options.szIntelliMirrorPath, ARRAYSIZE(szPath) );
  677. ConcatenatePaths( szPath, L"\\OSChooser", ARRAYSIZE(szPath));
  678. ConcatenatePaths( szPath, g_Options.szLanguage, ARRAYSIZE(szPath));
  679. Assert( wcslen(szPath) < ARRAYSIZE(szPath) );
  680. if ( 0xFFFFffff == GetFileAttributes( szPath ) ) {
  681. f = CreateDirectory( szPath, NULL );
  682. if ( !f ) {
  683. ErrorBox( hDlg, szPath );
  684. hr = THR(E_FAIL); // major error
  685. goto Error;
  686. }
  687. }
  688. SendMessage( hProg, PBM_DELTAPOS, 1, 0 );
  689. }
  690. // do this last
  691. if ( !g_Options.fIMirrorShareFound ) {
  692. //
  693. // Add the share
  694. //
  695. hr = CreateRemoteBootShare( hDlg );
  696. SendMessage( hProg, PBM_SETPOS, 1 , 0 );
  697. }
  698. Error:
  699. if( sa.lpSecurityDescriptor ) {
  700. LocalFree(sa.lpSecurityDescriptor);
  701. }
  702. HRETURN(hr);
  703. }
  704. //
  705. // Find the filename part from a complete path.
  706. //
  707. LPWSTR FilenameOnly( LPWSTR pszPath )
  708. {
  709. LPWSTR psz = pszPath;
  710. // find the end
  711. while ( *psz )
  712. psz++;
  713. // find the slash
  714. while ( psz > pszPath && *psz != chSlash )
  715. psz--;
  716. // move in front of the slash
  717. if ( psz != pszPath )
  718. psz++;
  719. return psz;
  720. }
  721. //
  722. // Private structure containing information that the CopyFilesCallback()
  723. // needs.
  724. //
  725. typedef struct {
  726. PVOID pContext; // "Context" for DefaultQueueCallback
  727. HWND hProg; // hwnd to the progress meter
  728. HWND hOperation; // hwnd to the "current operation"
  729. DWORD nCopied; // number of files copied
  730. DWORD nToBeCopied; // number of file to be copied
  731. DWORD dwCopyingLength; // length of the IDS_COPYING
  732. WCHAR szCopyingString[ SMALL_BUFFER_SIZE ]; // buffer to create "Copying file.ext..."
  733. BOOL fQuiet; // do things quietly
  734. HWND hDlg; // hwnd to the Tasks Dialog
  735. } MYCONTEXT, *LPMYCONTEXT;
  736. //
  737. // Callback that the SETUP APIs calls. It handles updating the
  738. // progress meters as well as UI updating. Any messages not
  739. // handled are passed to the default SETUP callback.
  740. //
  741. UINT CALLBACK
  742. CopyFilesCallback(
  743. IN PVOID Context,
  744. IN UINT Notification,
  745. IN UINT_PTR Param1,
  746. IN UINT_PTR Param2
  747. )
  748. {
  749. LPMYCONTEXT pMyContext = (LPMYCONTEXT) Context;
  750. KeepUIAlive( pMyContext->hDlg );
  751. if ( g_Options.fAbort )
  752. {
  753. if ( !g_Options.fError )
  754. {
  755. WCHAR szAbort[ SMALL_BUFFER_SIZE ];
  756. // change filename text to aborting...
  757. DWORD dw;
  758. dw = LoadString( g_hinstance, IDS_ABORTING, szAbort, ARRAYSIZE(szAbort) );
  759. Assert( dw );
  760. SetWindowText( pMyContext->hOperation, szAbort );
  761. g_Options.fError = TRUE;
  762. }
  763. if ( g_Options.fError ) {
  764. SetLastError(ERROR_CANCELLED);
  765. return FILEOP_ABORT;
  766. }
  767. }
  768. switch ( Notification )
  769. {
  770. case SPFILENOTIFY_ENDCOPY:
  771. if ( !(pMyContext->fQuiet) ) {
  772. pMyContext->nCopied++;
  773. SendMessage( pMyContext->hProg, PBM_SETPOS,
  774. (5000 * pMyContext->nCopied) / pMyContext->nToBeCopied, 0 );
  775. }
  776. break;
  777. case SPFILENOTIFY_STARTCOPY:
  778. if ( !(pMyContext->fQuiet) ) {
  779. DWORD dwLen;
  780. LPWSTR * ppszCopyingFile = (LPWSTR *) Param1;
  781. lstrcpy( &pMyContext->szCopyingString[ pMyContext->dwCopyingLength ],
  782. FilenameOnly( *ppszCopyingFile ) );
  783. dwLen = lstrlen( pMyContext->szCopyingString );
  784. lstrcpy( &pMyContext->szCopyingString[ dwLen ], L"..." );
  785. SetWindowText( pMyContext->hOperation, pMyContext->szCopyingString );
  786. }
  787. break;
  788. case SPFILENOTIFY_LANGMISMATCH:
  789. case SPFILENOTIFY_TARGETEXISTS:
  790. case SPFILENOTIFY_TARGETNEWER:
  791. if ( !pMyContext->fQuiet )
  792. {
  793. UINT u = SetupDefaultQueueCallback( pMyContext->pContext, Notification, Param1, Param2 );
  794. return u;
  795. }
  796. break;
  797. case SPFILENOTIFY_RENAMEERROR:
  798. case SPFILENOTIFY_DELETEERROR:
  799. case SPFILENOTIFY_COPYERROR:
  800. {
  801. FILEPATHS *fp = (FILEPATHS *) Param1;
  802. Assert( fp->Win32Error != ERROR_FILE_NOT_FOUND ); // Malformed DRIVERS.CAB file
  803. if ( fp->Win32Error == ERROR_FILE_NOT_FOUND )
  804. return FILEOP_SKIP;
  805. }
  806. case SPFILENOTIFY_NEEDMEDIA:
  807. UINT u = SetupDefaultQueueCallback( pMyContext->pContext, Notification, Param1, Param2 );
  808. if ( u == FILEOP_ABORT )
  809. {
  810. g_Options.fAbort = g_Options.fError = TRUE;
  811. }
  812. return u;
  813. }
  814. return FILEOP_DOIT;
  815. }
  816. //
  817. // CopyInfSection( )
  818. //
  819. HRESULT
  820. CopyInfSection(
  821. HSPFILEQ Queue,
  822. HINF hinf,
  823. LPCWSTR pszSection,
  824. LPCWSTR pszSourcePath,
  825. LPCWSTR pszSubPath, OPTIONAL
  826. LPCWSTR pszDescName,
  827. LPCWSTR pszTagFile,
  828. LPCWSTR pszDestinationRoot,
  829. LPDWORD pdwCount )
  830. /*++
  831. Routine Description:
  832. queues up files from the specified section to be installed into the
  833. remote install directory.
  834. Arguments:
  835. Queue - queue handle to queue the copy operations to.
  836. hinf - handle to inf which specifies the list of files to be copied
  837. pszSection - section listing files to be copied
  838. pszSourcePath - specifies the base source path,where the files may
  839. be found on the *source* media
  840. pszSubPath - specifies the subdirectory, if any, where the files may
  841. be found on the *source* media
  842. pszDescName- user printable description of the media where this file is
  843. located. this may be used when the queue is committed.
  844. pszTagFile - specifies the tag file that is to uniquely describe the media
  845. where these files are located
  846. pszDestinationRoot - specifies the root location where files are to be
  847. copied to
  848. pdwCount - specifies the number of files that were queued from this
  849. section on return. if the function fails, this value is
  850. undefined.
  851. Return Value:
  852. An HRESULT indicating the outcome.
  853. --*/
  854. {
  855. HRESULT hr = S_OK;
  856. INFCONTEXT context;
  857. BOOL b;
  858. TraceFunc( "CopyInfSection( ... )\n" );
  859. //
  860. // make sure the section we're looking for exists.
  861. // We'll use this context to enumerate the files in the section
  862. //
  863. b = SetupFindFirstLine( hinf, pszSection, NULL, &context );
  864. AssertMsg( b, "Missing section?" );
  865. if ( !b ) {
  866. hr = S_FALSE;
  867. }
  868. while ( b )
  869. {
  870. LPWSTR pszDestRename = NULL;
  871. WCHAR szDestPath[ MAX_PATH ],szRename[100];;
  872. WCHAR szSrcName[ 64 ];
  873. DWORD dw;
  874. KeepUIAlive( NULL );
  875. lstrcpyn(szDestPath, pszSubPath, ARRAYSIZE(szDestPath) );
  876. dw = SetupGetFieldCount( &context );
  877. if ( dw > 1 ) {
  878. //
  879. // first field is the destination name.
  880. // we overload this field to also contain a subdirectory where
  881. // the files should be placed as well
  882. //
  883. b = SetupGetStringField(
  884. &context,
  885. 1,
  886. szRename,
  887. ARRAYSIZE( szRename ),
  888. NULL );
  889. AssertMsg( b, "Missing field?" );
  890. if ( b ) {
  891. //
  892. // 2nd field is the actual source filename
  893. //
  894. b = SetupGetStringField(
  895. &context,
  896. 2,
  897. szSrcName,
  898. ARRAYSIZE(szSrcName),
  899. NULL );
  900. AssertMsg( b, "Missing field?" );
  901. pszDestRename = szRename;
  902. }
  903. } else {
  904. //
  905. // if there's only one field, this is the actual source name. the
  906. // destination name will be the same as the source name.
  907. //
  908. b = SetupGetStringField(
  909. &context,
  910. 1,
  911. szSrcName,
  912. ARRAYSIZE(szSrcName),
  913. NULL );
  914. AssertMsg( b, "Missing field?" );
  915. }
  916. if ( !b ) {
  917. hr = S_FALSE;
  918. goto SkipIt;
  919. }
  920. ConcatenatePaths(
  921. szDestPath,
  922. pszDestRename
  923. ? pszDestRename
  924. : szSrcName,
  925. ARRAYSIZE(szDestPath) );
  926. //
  927. // all files are installed into the
  928. //
  929. b = SetupQueueCopy( Queue,
  930. pszSourcePath,
  931. pszSubPath,
  932. szSrcName,
  933. pszDescName,
  934. pszTagFile,
  935. pszDestinationRoot,
  936. szDestPath,
  937. SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER
  938. | SP_COPY_WARNIFSKIP | SP_COPY_SOURCE_ABSOLUTE );
  939. if ( !b ) {
  940. ErrorBox( NULL, szSrcName );
  941. hr = THR(S_FALSE);
  942. goto SkipIt;
  943. }
  944. // increment file count
  945. (*pdwCount)++;
  946. SkipIt:
  947. b = SetupFindNextLine( &context, &context );
  948. }
  949. HRETURN(hr);
  950. }
  951. typedef struct _EXPANDCABLISTPARAMS {
  952. HWND hDlg;
  953. HINF hinf;
  954. LPCWSTR pszSection;
  955. LPCWSTR pszSourcePath;
  956. LPCWSTR pszDestPath;
  957. LPCWSTR pszSubDir;
  958. } EXPANDCABLISTPARAMS, *PEXPANDCABLISTPARAMS;
  959. //
  960. // ExpandCabList( )
  961. //
  962. DWORD WINAPI
  963. ExpandCabList( LPVOID lpVoid )
  964. {
  965. PEXPANDCABLISTPARAMS pParams = (PEXPANDCABLISTPARAMS) lpVoid;
  966. HRESULT hr = S_OK;
  967. INFCONTEXT context;
  968. WCHAR TempDstPath[MAX_PATH];
  969. WCHAR TempSrcPath[MAX_PATH];
  970. BOOL b;
  971. TraceFunc( "ExpandCabList( ... )\n" );
  972. // First make sure the DestPath exists, since we may call this
  973. // before we commit the setup copy queue.
  974. Assert( pParams->pszSection );
  975. Assert( pParams->pszSourcePath );
  976. Assert( pParams->pszDestPath );
  977. Assert( pParams->pszSubDir );
  978. DebugMsg( "Expand section %s from %s to %s\n",
  979. pParams->pszSection,
  980. pParams->pszSourcePath,
  981. pParams->pszDestPath );
  982. lstrcpyn( TempDstPath, pParams->pszDestPath, ARRAYSIZE(TempDstPath));
  983. ConcatenatePaths( TempDstPath, pParams->pszSubDir, ARRAYSIZE(TempDstPath) );
  984. hr = CreateDirectoryPath( pParams->hDlg, TempDstPath, NULL, TRUE );
  985. if ( ! SUCCEEDED(hr) ) {
  986. HRETURN(hr);
  987. }
  988. lstrcpyn( TempSrcPath, pParams->pszSourcePath, ARRAYSIZE(TempSrcPath));
  989. ConcatenatePaths( TempSrcPath, pParams->pszSubDir, ARRAYSIZE(TempSrcPath) );
  990. b = SetupFindFirstLine( pParams->hinf, pParams->pszSection, NULL, &context );
  991. AssertMsg( b, "Missing section?" );
  992. if ( !b ) {
  993. hr = S_FALSE;
  994. }
  995. while ( b && !g_Options.fError && !g_Options.fAbort )
  996. {
  997. WCHAR wszCabName[ MAX_PATH ];
  998. CHAR szCabPath[ MAX_PATH ];
  999. CHAR szDestPath[ MAX_PATH ];
  1000. DWORD dwSourcePathLen;
  1001. b = SetupGetStringField( &context, 1, wszCabName, ARRAYSIZE(wszCabName), NULL );
  1002. AssertMsg( b, "Missing field?" );
  1003. if ( !b ) {
  1004. hr = S_FALSE;
  1005. goto SkipIt;
  1006. }
  1007. // szCabPath is pszSourcePath\wszCabName, in ANSI
  1008. dwSourcePathLen = (DWORD)wcslen(TempSrcPath);
  1009. wcstombs( szCabPath, TempSrcPath, dwSourcePathLen );
  1010. if (szCabPath[dwSourcePathLen-1] != '\\') {
  1011. szCabPath[dwSourcePathLen] = '\\';
  1012. ++dwSourcePathLen;
  1013. }
  1014. wcstombs( &szCabPath[dwSourcePathLen], wszCabName, wcslen(wszCabName)+1 );
  1015. wcstombs( szDestPath, TempDstPath, wcslen(TempDstPath)+1 );
  1016. hr = ExtractFiles( szCabPath, szDestPath, 0, NULL, NULL, 0 );
  1017. if ( !SUCCEEDED(hr) ) {
  1018. ErrorBox( pParams->hDlg, wszCabName );
  1019. goto SkipIt;
  1020. }
  1021. SkipIt:
  1022. b = SetupFindNextLine( &context, &context );
  1023. }
  1024. HRETURN(hr);
  1025. }
  1026. //
  1027. // RecursiveCopySubDirectory
  1028. //
  1029. HRESULT
  1030. RecursiveCopySubDirectory(
  1031. HSPFILEQ Queue, // Setup queue
  1032. LPWSTR pszSrcDir, // points to a buffer MAX_PATH big and contains the source dir to recurse
  1033. LPWSTR pszDestDir, // points to a buffer MAX_PATH big and contains the destination dir to recurse
  1034. LPWSTR pszDiscName, // CD name, if any
  1035. LPWSTR pszTagFile, // tagfile to look for, if any
  1036. LPDWORD pdwCount ) // copy file counter
  1037. {
  1038. HRESULT hr = S_OK;
  1039. BOOL b;
  1040. TraceFunc( "RecursiveCopySubDirectory( ... )\n" );
  1041. WIN32_FIND_DATA fda;
  1042. HANDLE hfda = INVALID_HANDLE_VALUE;
  1043. LONG uOrginalSrcLength = (DWORD)wcslen( pszSrcDir );
  1044. LONG uOrginalDstLength = (DWORD)wcslen( pszDestDir );
  1045. ConcatenatePaths( pszSrcDir, L"*", MAX_PATH ); // trust the caller
  1046. hfda = FindFirstFile( pszSrcDir, &fda );
  1047. if ( hfda == INVALID_HANDLE_VALUE )
  1048. {
  1049. ErrorBox( NULL, pszSrcDir );
  1050. hr = E_FAIL;
  1051. goto Cleanup;
  1052. }
  1053. pszSrcDir[ uOrginalSrcLength ] = L'\0';
  1054. do
  1055. {
  1056. KeepUIAlive( NULL );
  1057. if (( fda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  1058. && ( wcscmp( fda.cFileName, L"." ) )
  1059. && ( wcscmp( fda.cFileName, L".." ) )) // no dot dirs
  1060. {
  1061. if ( wcslen( fda.cFileName ) + uOrginalDstLength >= MAX_PATH
  1062. || wcslen( fda.cFileName ) + uOrginalSrcLength >= MAX_PATH )
  1063. {
  1064. SetLastError( ERROR_BUFFER_OVERFLOW );
  1065. ErrorBox( NULL, fda.cFileName );
  1066. hr = E_FAIL;
  1067. goto Cleanup;
  1068. }
  1069. ConcatenatePaths( pszSrcDir, fda.cFileName, MAX_PATH ); // trust the caller
  1070. ConcatenatePaths( pszDestDir, fda.cFileName, MAX_PATH ); // trust the caller
  1071. RecursiveCopySubDirectory( Queue,
  1072. pszSrcDir,
  1073. pszDestDir,
  1074. pszDiscName,
  1075. pszTagFile,
  1076. pdwCount );
  1077. pszSrcDir[ uOrginalSrcLength ] = L'\0';
  1078. pszDestDir[ uOrginalDstLength ] = L'\0';
  1079. goto SkipFile;
  1080. }
  1081. else if (fda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  1082. goto SkipFile;
  1083. b = SetupQueueCopy( Queue,
  1084. pszSrcDir,
  1085. NULL,
  1086. fda.cFileName,
  1087. pszDiscName,
  1088. pszTagFile,
  1089. pszDestDir,
  1090. NULL,
  1091. SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER
  1092. | SP_COPY_WARNIFSKIP | SP_COPY_SOURCE_ABSOLUTE );
  1093. if ( !b ) {
  1094. ErrorBox( NULL, fda.cFileName );
  1095. hr = THR(S_FALSE);
  1096. goto SkipFile;
  1097. }
  1098. // increment file counter
  1099. (*pdwCount)++;
  1100. SkipFile:
  1101. ; // nop
  1102. } while ( FindNextFile( hfda, &fda ) );
  1103. Cleanup:
  1104. if ( hfda != INVALID_HANDLE_VALUE ) {
  1105. FindClose( hfda );
  1106. hfda = INVALID_HANDLE_VALUE;
  1107. }
  1108. HRETURN(hr);
  1109. }
  1110. #define COPY_OPTIONAL_DIRS_OPTIONAL (0x00000001)
  1111. //
  1112. // CopyOptionalDirs
  1113. //
  1114. HRESULT
  1115. CopyOptionalDirs(
  1116. HSPFILEQ Queue,
  1117. HINF hinf,
  1118. LPWSTR pszSection,
  1119. LPWSTR pszDiscName,
  1120. LPWSTR pszTagFile,
  1121. LPDWORD pdwCount )
  1122. {
  1123. HRESULT hr = S_OK;
  1124. INFCONTEXT context;
  1125. BOOL b;
  1126. TraceFunc( "CopyOptionalDirs( ... )\n" );
  1127. b = SetupFindFirstLine( hinf, pszSection, NULL, &context );
  1128. #if 0
  1129. // this will hit installing a 2195 build because [AdditionalClientDirs]
  1130. // is missing, so take it out for now
  1131. AssertMsg( b, "Missing section?" );
  1132. #endif
  1133. if ( !b ) {
  1134. hr = S_FALSE;
  1135. }
  1136. while ( b && hr == S_OK )
  1137. {
  1138. WCHAR szSrcPath[ 40 ]; // should be 8.3 directory name
  1139. WCHAR szSrcDir[ MAX_PATH ];
  1140. WCHAR szDestDir[ MAX_PATH ];
  1141. INT iOptions = 0;
  1142. DWORD dwAttribs;
  1143. DWORD Fields;
  1144. Fields = SetupGetFieldCount(&context);
  1145. //
  1146. // Contains optionality flag?
  1147. //
  1148. if (Fields > 1) {
  1149. b = SetupGetStringField( &context, 1, szSrcPath, ARRAYSIZE(szSrcPath), NULL );
  1150. AssertMsg( b, "Missing field?" );
  1151. if ( !b ) {
  1152. hr = S_FALSE;
  1153. goto Cleanup;
  1154. }
  1155. b = SetupGetIntField(&context, 2, &iOptions);
  1156. AssertMsg(b, "Missing optionality field?");
  1157. if (!b) {
  1158. hr = S_FALSE;
  1159. goto Cleanup;
  1160. }
  1161. }
  1162. //
  1163. // Otherwise, just use the base string in the inf file
  1164. //
  1165. else {
  1166. b = SetupGetStringField( &context, 0, szSrcPath, ARRAYSIZE(szSrcPath), NULL );
  1167. AssertMsg( b, "Missing field?" );
  1168. if ( !b ) {
  1169. hr = S_FALSE;
  1170. goto Cleanup;
  1171. }
  1172. }
  1173. lstrcpyn( szSrcDir, g_Options.szSourcePath, ARRAYSIZE(szSrcDir) );
  1174. //
  1175. // If we're on an x86 platform, we have to deal with backwards
  1176. // compatibility. The problem is that w2k didn't have the subdirectory
  1177. // listed in the optional source dirs, so we have to append it here.
  1178. // on ia64, we have multiple optional source dirs, and it's easiest
  1179. // if we just get the subdir from the source directory.
  1180. //
  1181. if (g_Options.ProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64) {
  1182. ConcatenatePaths( szSrcDir, g_Options.ProcessorArchitectureString, ARRAYSIZE(szSrcDir) );
  1183. }
  1184. ConcatenatePaths( szSrcDir, szSrcPath, ARRAYSIZE(szSrcDir));
  1185. Assert( wcslen( szSrcDir ) < ARRAYSIZE(szSrcDir) );
  1186. lstrcpyn( szDestDir, g_Options.szInstallationPath, ARRAYSIZE(szDestDir) );
  1187. if (g_Options.ProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64) {
  1188. ConcatenatePaths( szDestDir, g_Options.ProcessorArchitectureString, ARRAYSIZE(szDestDir));
  1189. }
  1190. ConcatenatePaths( szDestDir, szSrcPath, ARRAYSIZE(szDestDir) );
  1191. Assert( wcslen( szDestDir ) < ARRAYSIZE(szDestDir) );
  1192. //
  1193. // If the file is missing, and the 'optional' bit is set on the file, then
  1194. // we can skip it.
  1195. //
  1196. dwAttribs = GetFileAttributes(szSrcDir);
  1197. if ((dwAttribs == INVALID_FILE_ATTRIBUTES) &&
  1198. ((GetLastError() == ERROR_FILE_NOT_FOUND) || (GetLastError() == ERROR_PATH_NOT_FOUND)))
  1199. {
  1200. //
  1201. // If the directory isn't there, but it's really marked as optional, then we can skip
  1202. // it without saying anything.
  1203. //
  1204. if (iOptions & COPY_OPTIONAL_DIRS_OPTIONAL)
  1205. {
  1206. b = SetupFindNextLine( &context, &context );
  1207. continue;
  1208. }
  1209. }
  1210. hr = RecursiveCopySubDirectory( Queue,
  1211. szSrcDir,
  1212. szDestDir,
  1213. pszDiscName,
  1214. pszTagFile,
  1215. pdwCount );
  1216. if (! SUCCEEDED(hr)) {
  1217. goto Cleanup;
  1218. }
  1219. b = SetupFindNextLine( &context, &context );
  1220. }
  1221. Cleanup:
  1222. HRETURN(hr);
  1223. }
  1224. //
  1225. // IsEntryInCab( )
  1226. BOOL
  1227. IsEntryInCab(
  1228. HINF hinf,
  1229. PCWSTR pszFileName
  1230. )
  1231. {
  1232. TraceFunc( "IsEntryInCab( ... )\n" );
  1233. INFCONTEXT Context;
  1234. INFCONTEXT SectionContext;
  1235. WCHAR szCabinetName[ MAX_PATH ];
  1236. UINT uField;
  1237. UINT uFieldCount;
  1238. DWORD dwLen = ARRAYSIZE( szCabinetName );
  1239. Assert( hinf != INVALID_HANDLE_VALUE );
  1240. Assert( pszFileName );
  1241. // Find the cab files listing section
  1242. if ( !SetupFindFirstLineW( hinf, L"Version", L"CabFiles", &SectionContext ) )
  1243. {
  1244. RETURN( FALSE );
  1245. }
  1246. do
  1247. {
  1248. uFieldCount = SetupGetFieldCount( &SectionContext );
  1249. for( uField = 1; uField <= uFieldCount; uField++ )
  1250. {
  1251. SetupGetStringField( &SectionContext, uField, szCabinetName, dwLen, NULL );
  1252. if( SetupFindFirstLineW( hinf, szCabinetName, pszFileName, &Context ) )
  1253. {
  1254. RETURN( TRUE ); // it's in a CAB
  1255. }
  1256. }
  1257. } while ( SetupFindNextMatchLine( &SectionContext, L"CabFiles", &SectionContext ) );
  1258. RETURN( FALSE );
  1259. }
  1260. typedef struct _LL_FILES_TO_EXTRACT LL_FILES_TO_EXTRACT;
  1261. typedef struct _LL_FILES_TO_EXTRACT {
  1262. LL_FILES_TO_EXTRACT * Next;
  1263. DWORD dwLen;
  1264. WCHAR szFilename[ MAX_PATH ];
  1265. WCHAR szSubDir[ MAX_PATH ];
  1266. } LL_FILES_TO_EXTRACT, * PLL_FILES_TO_EXTRACT;
  1267. PLL_FILES_TO_EXTRACT pExtractionList;
  1268. //
  1269. // AddEntryToExtractionQueue( )
  1270. //
  1271. HRESULT
  1272. AddEntryToExtractionQueue(
  1273. LPWSTR pszFileName )
  1274. {
  1275. TraceFunc( "AddEntryToExtractionQueue( ... )\n" );
  1276. HRESULT hr = S_OK;
  1277. PLL_FILES_TO_EXTRACT pNode = pExtractionList;
  1278. DWORD dwLen;
  1279. dwLen = (DWORD)wcslen( pszFileName );
  1280. while ( pNode )
  1281. {
  1282. if ( dwLen == pNode->dwLen
  1283. && _wcsicmp( pszFileName, pNode->szFilename ) == 0 )
  1284. {
  1285. hr = S_FALSE;
  1286. goto exit; // duplicate
  1287. }
  1288. pNode = pNode->Next;
  1289. }
  1290. pNode = (PLL_FILES_TO_EXTRACT) LocalAlloc( LMEM_FIXED, sizeof(LL_FILES_TO_EXTRACT) );
  1291. if ( pNode )
  1292. {
  1293. pNode->dwLen = dwLen;
  1294. pNode->Next = pExtractionList;
  1295. wcscpy( pNode->szFilename, pszFileName );
  1296. pExtractionList = pNode;
  1297. DebugMsg( "QUEUEING : %s to be extracted.\n", pszFileName );
  1298. }
  1299. else
  1300. {
  1301. hr = THR( E_OUTOFMEMORY );
  1302. }
  1303. exit:
  1304. HRETURN(hr);
  1305. }
  1306. BOOL
  1307. MySetupGetSourceInfo(
  1308. IN HINF hInf,
  1309. IN UINT SrcId,
  1310. IN UINT InfoDesired,
  1311. IN PCWSTR ProcessorArchitectureOverride, OPTIONAL
  1312. OUT PWSTR Buffer,
  1313. IN DWORD BufferSizeInBytes,
  1314. OUT LPDWORD RequiredSize OPTIONAL
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. Wrapper for SetupGetSourceInfo because it doesn't handle platform path
  1319. override correctly.
  1320. --*/
  1321. {
  1322. WCHAR TempSectionName[MAX_PATH];
  1323. WCHAR SourceId[20];
  1324. INFCONTEXT Context;
  1325. BOOL RetVal = FALSE;
  1326. if (!ProcessorArchitectureOverride) {
  1327. return SetupGetSourceInfo(
  1328. hInf,
  1329. SrcId,
  1330. InfoDesired,
  1331. Buffer,
  1332. BufferSizeInBytes,
  1333. RequiredSize );
  1334. }
  1335. Assert( InfoDesired == SRCINFO_PATH );
  1336. wsprintf( TempSectionName, L"SourceDisksNames.%s", ProcessorArchitectureOverride );
  1337. wsprintf( SourceId, L"%d", SrcId );
  1338. if (!SetupFindFirstLine( hInf, TempSectionName,SourceId, &Context )) {
  1339. lstrcpyn( TempSectionName, L"SourceDisksNames", ARRAYSIZE(TempSectionName) );
  1340. if (!SetupFindFirstLine( hInf, TempSectionName,SourceId, &Context )) {
  1341. goto exit;
  1342. }
  1343. }
  1344. RetVal = SetupGetStringField( &Context, 4, Buffer, BufferSizeInBytes/sizeof(TCHAR), NULL );
  1345. exit:
  1346. return(RetVal);
  1347. }
  1348. //
  1349. // CopyLayoutInfSection( )
  1350. //
  1351. HRESULT
  1352. CopyLayoutInfSection(
  1353. HSPFILEQ Queue,
  1354. HINF hinf,
  1355. HINF hinfDrivers,
  1356. LPCWSTR pszSection,
  1357. LPCWSTR pszDescName,
  1358. LPCWSTR pszTagFile,
  1359. LPCWSTR pszDestination,
  1360. LPDWORD pdwCount )
  1361. /*++
  1362. Routine Description:
  1363. Queues up files from the specified section in layout.inf to be installed
  1364. into the remote install image directory. This code is similar to what
  1365. textmode setup does, and it reads several of the extended layout flags
  1366. that textmode setup reads and setupapi doesn't have intrinsic knowledge
  1367. about.
  1368. Arguments:
  1369. Queue - queue handle to queue the copy operations to.
  1370. hinf - handle to layout.inf
  1371. hinfDrivers - handle to drvindex.inf, to be used to see if files are
  1372. located in the driver cabinet or not
  1373. pszSection - section listing files to be copied
  1374. pszDescName- user printable description of the media where this file is
  1375. located. this may be used when the queue is committed.
  1376. pszTagFile - specifies the tag file that is to uniquely describe the media
  1377. where these files are located
  1378. pszDestination - specifies the location where files are to be
  1379. copied to
  1380. pdwCount - specifies the number of files that were queued from this
  1381. section on return. if the function fails, this value is
  1382. undefined.
  1383. Return Value:
  1384. An HRESULT indicating the outcome.
  1385. --*/
  1386. {
  1387. HRESULT hr = S_OK;
  1388. INFCONTEXT context;
  1389. BOOL b;
  1390. TraceFunc( "CopyLayoutInfSection( ... )\n" );
  1391. b = SetupFindFirstLine( hinf, pszSection, NULL, &context );
  1392. AssertMsg( b, "Missing section?" );
  1393. if ( !b ) {
  1394. hr = S_FALSE;
  1395. }
  1396. while ( b )
  1397. {
  1398. BOOL fDecompress = FALSE;
  1399. WCHAR szTemp[ 5 ]; // "_x" is the biggest string right now
  1400. DWORD SrcId;
  1401. WCHAR szSrcName[ MAX_PATH ];
  1402. WCHAR szSubDir[20];
  1403. WCHAR szSubDirPlusFileName[MAX_PATH];
  1404. LPWSTR pszPeriod;
  1405. KeepUIAlive( NULL );
  1406. b = SetupGetStringField( &context, 0, szSrcName, ARRAYSIZE(szSrcName), NULL );
  1407. AssertMsg( b, "Missing field?" );
  1408. if ( !b ) {
  1409. hr = S_FALSE;
  1410. goto SkipIt;
  1411. }
  1412. //
  1413. // get the subdirectory that this file is located in, based on the
  1414. // sourcedisksnames data in field 1
  1415. //
  1416. b = SetupGetStringField( &context, 1, szTemp, ARRAYSIZE(szTemp), NULL );
  1417. AssertMsg( b, "Missing field?" );
  1418. if ( !b ) {
  1419. hr = S_FALSE;
  1420. goto SkipIt;
  1421. }
  1422. SrcId = _wtoi(szTemp);
  1423. b = MySetupGetSourceInfo(
  1424. hinf,
  1425. SrcId,
  1426. SRCINFO_PATH,
  1427. SetupExtensionFromProcessorTag(g_Options.ProcessorArchitectureString),
  1428. szSubDir,
  1429. ARRAYSIZE(szSubDir),
  1430. NULL );
  1431. if (!b) {
  1432. hr = S_FALSE;
  1433. goto SkipIt;
  1434. }
  1435. // If there is an "_" in the 2nd character of "source" column of the
  1436. // layout.inf file, then this file should be decompressed because
  1437. // it is a file needed for booting.
  1438. szTemp[1] = 0;
  1439. b = SetupGetStringField( &context, 7, szTemp, ARRAYSIZE(szTemp), NULL );
  1440. AssertMsg( b, "Missing field?" );
  1441. if ( szTemp[1] == L'_' ) {
  1442. fDecompress = TRUE;
  1443. DebugMsg( "DECOMPRESS: %s is a boot driver.\n", szSrcName );
  1444. goto CopyIt;
  1445. }
  1446. // If the 7th field isn't NULL, then the file exists outside the
  1447. // CABs so just copy it.
  1448. if ( wcslen( szTemp ) > 0 ) {
  1449. DebugMsg( "BOOTFLOPPY: %s is external from CAB.\n", szSrcName );
  1450. goto CopyIt;
  1451. }
  1452. // If it is in the CAB and didn't meet any of the conditions above,
  1453. // don't copy the file. It'll be in the CAB when/if setup needs it.
  1454. if ( IsEntryInCab( hinfDrivers, szSrcName ) ) {
  1455. #if DBG
  1456. pszPeriod = wcschr(szSrcName, L'.');
  1457. if ((pszPeriod != NULL) && (_wcsicmp(pszPeriod, L".inf") == 0)) {
  1458. DebugMsg(
  1459. "WARNING: %s is an INF in a cab. This file will not be available for network inf processing .\n",
  1460. szSrcName );
  1461. }
  1462. #endif
  1463. DebugMsg( "SKIPPING : %s in a CAB.\n", szSrcName );
  1464. goto SkipIt;
  1465. }
  1466. // If the extension is ".inf", then decompress so binlsvc
  1467. // can do its network .inf processing.
  1468. pszPeriod = wcschr(szSrcName, L'.');
  1469. if ((pszPeriod != NULL) && (_wcsicmp(pszPeriod, L".inf") == 0)) {
  1470. fDecompress = TRUE;
  1471. DebugMsg( "DECOMPRESS: %s is an INF.\n", szSrcName );
  1472. }
  1473. CopyIt:
  1474. //
  1475. // we do this so that files end up in the proper subdirectory
  1476. //
  1477. lstrcpyn(szSubDirPlusFileName, szSubDir, ARRAYSIZE(szSubDirPlusFileName) );
  1478. ConcatenatePaths( szSubDirPlusFileName, szSrcName, ARRAYSIZE(szSubDirPlusFileName) );
  1479. b = SetupQueueCopy( Queue,
  1480. g_Options.szSourcePath,
  1481. szSubDir,
  1482. szSrcName,
  1483. pszDescName,
  1484. pszTagFile,
  1485. pszDestination,
  1486. szSubDirPlusFileName,
  1487. SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER | SP_COPY_WARNIFSKIP
  1488. | SP_COPY_SOURCE_ABSOLUTE | ( fDecompress ? 0 : SP_COPY_NODECOMP ) );
  1489. if ( !b ) {
  1490. ErrorBox( NULL, szSrcName );
  1491. hr = THR(S_FALSE);
  1492. goto SkipIt;
  1493. }
  1494. // increment file counter
  1495. (*pdwCount)++;
  1496. SkipIt:
  1497. b = SetupFindNextLine( &context, &context );
  1498. }
  1499. HRETURN(hr);
  1500. }
  1501. //
  1502. // EnumNetworkDriversCallback( )
  1503. //
  1504. ULONG
  1505. EnumNetworkDriversCallback(
  1506. LPVOID pContext,
  1507. LPWSTR pszInfName,
  1508. LPWSTR pszFileName )
  1509. {
  1510. UNREFERENCED_PARAMETER(pszInfName);
  1511. TraceFunc( "EnumNetworkDriversCallback( ... )\n" );
  1512. MYCONTEXT * pMyContext = (MYCONTEXT *) pContext;
  1513. HRESULT hr;
  1514. Assert( pszFileName );
  1515. Assert( pszInfName );
  1516. //DebugMsg( "In %s: %s\n", pszInfName, pszFileName );
  1517. if ( KeepUIAlive( pMyContext->hDlg ) )
  1518. {
  1519. RETURN(ERROR_CANCELLED);
  1520. }
  1521. hr = AddEntryToExtractionQueue( pszFileName );
  1522. if ( hr == S_OK )
  1523. {
  1524. pMyContext->nToBeCopied++;
  1525. }
  1526. else if ( hr == S_FALSE )
  1527. { // duplicate found in queue... keep going
  1528. hr = S_OK;
  1529. }
  1530. HRETURN(hr);
  1531. }
  1532. //
  1533. // EnumCabinetCallback( )
  1534. //
  1535. UINT CALLBACK
  1536. EnumCabinetCallback(
  1537. IN PVOID Context,
  1538. IN UINT Notification,
  1539. IN UINT_PTR Param1,
  1540. IN UINT_PTR Param2
  1541. )
  1542. {
  1543. UNREFERENCED_PARAMETER(Param2);
  1544. TraceFunc( "EnumCabinetCallback( ... )\n" );
  1545. UINT uResult = 0;
  1546. PLL_FILES_TO_EXTRACT pNode = pExtractionList;
  1547. PLL_FILES_TO_EXTRACT pLast = NULL;
  1548. DWORD dwLen;
  1549. PFILE_IN_CABINET_INFO pfici;
  1550. MYCONTEXT *pMyContext = (MYCONTEXT *) Context;
  1551. Assert( pMyContext );
  1552. KeepUIAlive( pMyContext->hDlg );
  1553. if ( g_Options.fAbort )
  1554. {
  1555. if ( !g_Options.fError )
  1556. {
  1557. WCHAR szAbort[ SMALL_BUFFER_SIZE ];
  1558. // change filename text to aborting...
  1559. DWORD dw;
  1560. dw = LoadString( g_hinstance, IDS_ABORTING, szAbort, ARRAYSIZE(szAbort) );
  1561. Assert( dw );
  1562. SetWindowText( pMyContext->hOperation, szAbort );
  1563. g_Options.fError = TRUE;
  1564. }
  1565. if ( g_Options.fError ) {
  1566. SetLastError(ERROR_CANCELLED);
  1567. uResult = FILEOP_ABORT;
  1568. goto exit;
  1569. }
  1570. }
  1571. if ( Notification == SPFILENOTIFY_FILEINCABINET )
  1572. {
  1573. pfici = (PFILE_IN_CABINET_INFO) Param1;
  1574. Assert( pfici );
  1575. Assert( pfici->NameInCabinet );
  1576. dwLen = (DWORD)wcslen( pfici->NameInCabinet );
  1577. while ( pNode )
  1578. {
  1579. if ( dwLen == pNode->dwLen
  1580. && _wcsicmp( pfici->NameInCabinet, pNode->szFilename ) == 0 )
  1581. { // match! remove it from the list and extract it.
  1582. if ( pNode == pExtractionList )
  1583. {
  1584. pExtractionList = pNode->Next;
  1585. }
  1586. else
  1587. {
  1588. if( pLast ) {
  1589. pLast->Next = pNode->Next;
  1590. }
  1591. }
  1592. LocalFree( pNode );
  1593. // create target path
  1594. lstrcpyn( pfici->FullTargetName, g_Options.szInstallationPath, MAX_PATH );
  1595. ConcatenatePaths( pfici->FullTargetName, g_Options.ProcessorArchitectureString, MAX_PATH );
  1596. ConcatenatePaths( pfici->FullTargetName, pfici->NameInCabinet, MAX_PATH );
  1597. if ( !(pMyContext->fQuiet) ) {
  1598. wcscpy( &pMyContext->szCopyingString[ pMyContext->dwCopyingLength ],
  1599. pfici->NameInCabinet );
  1600. dwLen = (DWORD)wcslen( pMyContext->szCopyingString );
  1601. wcscpy( &pMyContext->szCopyingString[ dwLen ], L"..." );
  1602. SetWindowText( pMyContext->hOperation, pMyContext->szCopyingString );
  1603. }
  1604. DebugMsg( "EXTRACTING: %s from CAB.\n", pfici->NameInCabinet );
  1605. uResult = FILEOP_DOIT;
  1606. goto exit;
  1607. }
  1608. pLast = pNode;
  1609. pNode = pNode->Next;
  1610. }
  1611. uResult = FILEOP_SKIP;
  1612. }
  1613. else if ( Notification == SPFILENOTIFY_FILEEXTRACTED )
  1614. {
  1615. PFILEPATHS pfp = (PFILEPATHS) Param1;
  1616. Assert( pfp );
  1617. pMyContext->nCopied++;
  1618. SendMessage( pMyContext->hProg, PBM_SETPOS, (5000 * pMyContext->nCopied) / pMyContext->nToBeCopied, 0 );
  1619. uResult = pfp->Win32Error;
  1620. }
  1621. exit:
  1622. RETURN(uResult);
  1623. }
  1624. //
  1625. // AddInfSectionToExtractQueue( )
  1626. //
  1627. HRESULT
  1628. AddInfSectionToExtractQueue(
  1629. HINF hinf,
  1630. LPWSTR pszSection,
  1631. LPMYCONTEXT Context )
  1632. {
  1633. TraceFunc( "AddInfSectionToExtractQueue( ... )\n" );
  1634. HRESULT hr = S_OK;
  1635. BOOL b;
  1636. INFCONTEXT context;
  1637. b = SetupFindFirstLine( hinf, pszSection, NULL, &context );
  1638. if ( !b ) goto Cleanup; // nothing to do - don't complain!
  1639. while ( b )
  1640. {
  1641. WCHAR szFilename[ MAX_PATH ];
  1642. DWORD dwLen = ARRAYSIZE( szFilename );
  1643. b = SetupGetStringField( &context, 1, szFilename, dwLen, NULL );
  1644. if ( !b ) goto Error;
  1645. hr = AddEntryToExtractionQueue( szFilename );
  1646. if (FAILED( hr )) goto Cleanup;
  1647. if (hr == S_OK) {
  1648. Context->nToBeCopied += 1;
  1649. }
  1650. b = SetupFindNextLine( &context, &context );
  1651. }
  1652. Cleanup:
  1653. HRETURN(hr);
  1654. Error:
  1655. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1656. goto Cleanup;
  1657. }
  1658. //
  1659. // Copies the files into the setup directory.
  1660. //
  1661. HRESULT
  1662. CopyClientFiles( HWND hDlg )
  1663. {
  1664. HRESULT hr = S_OK;
  1665. DWORD dwLen;
  1666. BOOL b;
  1667. HWND hProg = GetDlgItem( hDlg, IDC_P_METER );
  1668. DWORD dwCount = 0;
  1669. DWORD dw;
  1670. WCHAR szText[ SMALL_BUFFER_SIZE ];
  1671. WCHAR szFilepath[ MAX_PATH ];
  1672. WCHAR szTempPath[ MAX_PATH ];
  1673. WCHAR szInsertMedia[ MAX_PATH ];
  1674. HINF hinfLayout = INVALID_HANDLE_VALUE;
  1675. HINF hinfReminst = INVALID_HANDLE_VALUE;
  1676. HINF hinfDrivers = INVALID_HANDLE_VALUE;
  1677. HINF hinfDosnet = INVALID_HANDLE_VALUE;
  1678. UINT uLineNum;
  1679. DWORD dwFlags = IDF_CHECKFIRST | IDF_NOSKIP;
  1680. WCHAR *p;
  1681. PWSTR FullDllPath = NULL;
  1682. PLL_FILES_TO_EXTRACT pNode;
  1683. HMODULE hBinlsvc = NULL;
  1684. PNETINFENUMFILES pfnNetInfEnumFiles = NULL;
  1685. HANDLE hThread = NULL;
  1686. EXPANDCABLISTPARAMS ExpandParams;
  1687. INFCONTEXT context;
  1688. HSPFILEQ Queue = INVALID_HANDLE_VALUE;
  1689. MYCONTEXT MyContext;
  1690. TraceFunc( "CopyClientFiles( hDlg )\n" );
  1691. //
  1692. // Setup and display next section of dialog
  1693. //
  1694. SendMessage( hProg, PBM_SETRANGE, 0, MAKELPARAM(0, 5000 ));
  1695. SendMessage( hProg, PBM_SETPOS, 0, 0 );
  1696. dw = LoadString( g_hinstance, IDS_BUILDINGFILELIST, szText, ARRAYSIZE(szText));
  1697. Assert( dw );
  1698. SetDlgItemText( hDlg, IDC_S_OPERATION, szText );
  1699. // Initialize
  1700. ZeroMemory( &MyContext, sizeof(MyContext) );
  1701. pExtractionList = NULL;
  1702. ZeroMemory( &ExpandParams, sizeof(ExpandParams) );
  1703. FullDllPath = (PWSTR)TraceAlloc(LPTR, MAX_PATH*sizeof(WCHAR));
  1704. if( !FullDllPath ) {
  1705. hr = THR( HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ) );
  1706. ErrorBox( hDlg, L"BINLSVC.DLL" );
  1707. goto Cleanup;
  1708. }
  1709. if (!ExpandEnvironmentStrings(L"%systemroot%\\system32\\binlsvc.dll", FullDllPath, MAX_PATH) ) {
  1710. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1711. ErrorBox( hDlg, L"BINLSVC.DLL" );
  1712. goto Cleanup;
  1713. }
  1714. hBinlsvc = LoadLibrary( FullDllPath );
  1715. if (!hBinlsvc) {
  1716. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1717. ErrorBox( hDlg, L"BINLSVC.DLL" );
  1718. goto Cleanup;
  1719. }
  1720. pfnNetInfEnumFiles = (PNETINFENUMFILES) GetProcAddress( hBinlsvc, NETINFENUMFILESENTRYPOINT );
  1721. if ( pfnNetInfEnumFiles == NULL )
  1722. {
  1723. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1724. ErrorBox( hDlg, L"BINLSVC.DLL" );
  1725. goto Cleanup;
  1726. }
  1727. // Make sure the workstation CD is the CD-ROM drive
  1728. dw = LoadString( g_hinstance, IDS_INSERT_MEDIA, szInsertMedia, ARRAYSIZE(szInsertMedia) );
  1729. Assert( dw );
  1730. AskForDisk:
  1731. lstrcpyn(szTempPath, g_Options.szSourcePath, ARRAYSIZE(szTempPath));
  1732. ConcatenatePaths( szTempPath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szTempPath));
  1733. if ( DPROMPT_SUCCESS !=
  1734. SetupPromptForDisk( hDlg,
  1735. szInsertMedia,
  1736. g_Options.szWorkstationDiscName,
  1737. szTempPath,
  1738. L"layout.inf",
  1739. g_Options.szWorkstationTagFile,
  1740. dwFlags,
  1741. g_Options.szSourcePath,
  1742. MAX_PATH,
  1743. NULL ) )
  1744. {
  1745. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1746. goto Cleanup;
  1747. }
  1748. //
  1749. // if they gave us a trailing architecture tag, then remove it
  1750. //
  1751. if (g_Options.szSourcePath[wcslen(g_Options.szSourcePath)-1] == L'\\') {
  1752. //
  1753. // lose the trailing backslash if present
  1754. //
  1755. g_Options.szSourcePath[wcslen(g_Options.szSourcePath)-1] = L'\0';
  1756. }
  1757. p = wcsrchr( g_Options.szSourcePath, L'\\');
  1758. if (p) {
  1759. p = StrStrI(p,g_Options.ProcessorArchitectureString);
  1760. if (p) {
  1761. *(p-1) = L'\0';
  1762. }
  1763. }
  1764. dw = CheckImageSource( hDlg );
  1765. if ( dw != ERROR_SUCCESS )
  1766. {
  1767. dwFlags = IDF_NOSKIP;
  1768. goto AskForDisk;
  1769. }
  1770. if ( g_Options.fAbort || g_Options.fError )
  1771. goto Cleanup;
  1772. lstrcpyn(szFilepath, g_Options.szSourcePath, ARRAYSIZE(szFilepath));
  1773. ConcatenatePaths( szFilepath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szFilepath));
  1774. ConcatenatePaths( szFilepath, L"layout.inf", ARRAYSIZE(szFilepath));
  1775. Assert( wcslen( szFilepath ) < ARRAYSIZE(szFilepath) );
  1776. hinfLayout = SetupOpenInfFile( szFilepath, NULL, INF_STYLE_WIN4, &uLineNum);
  1777. if ( hinfLayout == INVALID_HANDLE_VALUE ) {
  1778. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1779. ErrorBox( hDlg, szFilepath );
  1780. goto Cleanup;
  1781. }
  1782. // Openning layout can take a long time. Update the UI and check to see
  1783. // if the user wants to abort.
  1784. if ( KeepUIAlive( hDlg ) )
  1785. {
  1786. hr = HRESULT_FROM_WIN32( ERROR_CANCELLED );
  1787. goto Cleanup;
  1788. }
  1789. lstrcpyn(szFilepath, g_Options.szSourcePath, ARRAYSIZE(szFilepath));
  1790. ConcatenatePaths( szFilepath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szFilepath));
  1791. ConcatenatePaths( szFilepath, L"drvindex.inf", ARRAYSIZE(szFilepath));
  1792. Assert( wcslen( szFilepath ) < ARRAYSIZE(szFilepath) );
  1793. hinfDrivers = SetupOpenInfFile( szFilepath, NULL, INF_STYLE_WIN4, &uLineNum);
  1794. if ( hinfDrivers == INVALID_HANDLE_VALUE ) {
  1795. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1796. ErrorBox( hDlg, szFilepath );
  1797. goto Cleanup;
  1798. }
  1799. //
  1800. // Create the Queue
  1801. //
  1802. Queue = SetupOpenFileQueue( );
  1803. //
  1804. // Copy to REMINST.inf quietly
  1805. //
  1806. dw = GetEnvironmentVariable( L"TMP",
  1807. g_Options.szWorkstationRemBootInfPath,
  1808. ARRAYSIZE(g_Options.szWorkstationRemBootInfPath) );
  1809. Assert( dw );
  1810. ConcatenatePaths( g_Options.szWorkstationRemBootInfPath, L"\\REMINST.inf", ARRAYSIZE(g_Options.szWorkstationRemBootInfPath));
  1811. Assert( wcslen(g_Options.szWorkstationRemBootInfPath) < ARRAYSIZE(g_Options.szWorkstationRemBootInfPath) );
  1812. lstrcpyn(szTempPath, g_Options.szSourcePath, ARRAYSIZE(szTempPath));
  1813. ConcatenatePaths( szTempPath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szTempPath));
  1814. b = SetupInstallFile( hinfLayout,
  1815. NULL,
  1816. L"REMINST.inf",
  1817. szTempPath,
  1818. g_Options.szWorkstationRemBootInfPath,
  1819. SP_COPY_FORCE_NEWER,
  1820. NULL,
  1821. NULL );
  1822. if ( !b ) {
  1823. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1824. WCHAR szCaption[SMALL_BUFFER_SIZE];
  1825. DWORD LoadStringResult;
  1826. szCaption[0] = L'\0';
  1827. LoadStringResult = LoadString( g_hinstance, IDS_COPYING_REMINST_TITLE, szCaption, SMALL_BUFFER_SIZE );
  1828. Assert( LoadStringResult );
  1829. ErrorBox( hDlg, szCaption );
  1830. AssertMsg( b, "Failed to copy REMINST.INF to TEMP" );
  1831. goto Cleanup;
  1832. }
  1833. // The above call will initialize a lot of the SETUPAPI. This might take
  1834. // a long time as well. Refresh the UI and check for user abort.
  1835. if ( KeepUIAlive( hDlg ) )
  1836. {
  1837. hr = HRESULT_FROM_WIN32( ERROR_CANCELLED );
  1838. goto Cleanup;
  1839. }
  1840. // Now check the version of the workstation to make sure it's compatible
  1841. hr = CheckServerVersion( );
  1842. if ( FAILED(hr) )
  1843. goto Cleanup;
  1844. //
  1845. // Copy architecture-indepenedent files.
  1846. //
  1847. hr = CopyLayoutInfSection( Queue,
  1848. hinfLayout,
  1849. hinfDrivers,
  1850. L"SourceDisksFiles",
  1851. g_Options.szWorkstationDiscName,
  1852. g_Options.szWorkstationTagFile,
  1853. g_Options.szInstallationPath,
  1854. &dwCount );
  1855. if ( FAILED(hr) ) {
  1856. goto Cleanup;
  1857. }
  1858. //
  1859. // Copy architecture-depenedent files.
  1860. //
  1861. wsprintf(
  1862. szTempPath,
  1863. L"SourceDisksFiles.%s",
  1864. SetupExtensionFromProcessorTag(g_Options.ProcessorArchitectureString) );
  1865. hr = CopyLayoutInfSection( Queue,
  1866. hinfLayout,
  1867. hinfDrivers,
  1868. szTempPath,
  1869. g_Options.szWorkstationDiscName,
  1870. g_Options.szWorkstationTagFile,
  1871. g_Options.szInstallationPath,
  1872. &dwCount );
  1873. if ( FAILED(hr) ) {
  1874. goto Cleanup;
  1875. }
  1876. //
  1877. // build the path to dosnet.inf
  1878. //
  1879. lstrcpyn( szFilepath, g_Options.szSourcePath, ARRAYSIZE(szFilepath) );
  1880. ConcatenatePaths( szFilepath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szFilepath) );
  1881. ConcatenatePaths( szFilepath, L"dosnet.inf", ARRAYSIZE(szTempPath));
  1882. Assert( wcslen( szFilepath ) < ARRAYSIZE(szFilepath));
  1883. hinfDosnet = SetupOpenInfFile( szFilepath, NULL, INF_STYLE_WIN4, &uLineNum);
  1884. if ( hinfDosnet == INVALID_HANDLE_VALUE ) {
  1885. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1886. ErrorBox( NULL, szFilepath );
  1887. goto Cleanup;
  1888. }
  1889. //
  1890. // we only do this so that we can install w2k x86 images. It's not
  1891. // necessary and causes an error on ia64. The proper place to add
  1892. // directories is in the AdditionalClientDirs section of reminst.inf
  1893. //
  1894. if (g_Options.ProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64) {
  1895. hr = CopyOptionalDirs( Queue,
  1896. hinfDosnet,
  1897. L"OptionalSrcDirs",
  1898. g_Options.szWorkstationDiscName,
  1899. g_Options.szWorkstationTagFile,
  1900. &dwCount );
  1901. }
  1902. if ( FAILED(hr) )
  1903. goto Cleanup;
  1904. SetupCloseInfFile( hinfLayout );
  1905. hinfLayout = INVALID_HANDLE_VALUE;
  1906. SetupCloseInfFile( hinfDosnet );
  1907. hinfDosnet = INVALID_HANDLE_VALUE;
  1908. //
  1909. // Add additional files not specified in the LAYOUT.INF
  1910. //
  1911. hinfReminst = SetupOpenInfFile( g_Options.szWorkstationRemBootInfPath, NULL, INF_STYLE_WIN4, &uLineNum);
  1912. if ( hinfReminst == INVALID_HANDLE_VALUE ) {
  1913. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1914. ErrorBox( hDlg, g_Options.szWorkstationRemBootInfPath );
  1915. goto Cleanup;
  1916. }
  1917. hr = CopyInfSection( Queue,
  1918. hinfReminst,
  1919. L"AdditionalClientFiles",
  1920. g_Options.szSourcePath,
  1921. g_Options.szWorkstationSubDir,
  1922. g_Options.szWorkstationDiscName,
  1923. g_Options.szWorkstationTagFile,
  1924. g_Options.szInstallationPath,
  1925. &dwCount );
  1926. if( FAILED(hr) )
  1927. goto Cleanup;
  1928. //
  1929. // Add additional directories not specified in LAYOUT.INF
  1930. //
  1931. hr = CopyOptionalDirs( Queue,
  1932. hinfReminst,
  1933. L"AdditionalClientDirs",
  1934. g_Options.szWorkstationDiscName,
  1935. g_Options.szWorkstationTagFile,
  1936. &dwCount );
  1937. if ( FAILED(hr) )
  1938. goto Cleanup;
  1939. //
  1940. // This information will be passed to CopyFileCallback() as
  1941. // the Context.
  1942. //
  1943. MyContext.nToBeCopied = dwCount;
  1944. MyContext.nCopied = 0;
  1945. MyContext.pContext = SetupInitDefaultQueueCallbackEx(NULL,(HWND)INVALID_HANDLE_VALUE,0,0,NULL);
  1946. MyContext.hProg = hProg;
  1947. MyContext.hOperation = GetDlgItem( hDlg, IDC_S_OPERATION );
  1948. MyContext.hDlg = hDlg;
  1949. MyContext.fQuiet = FALSE;
  1950. MyContext.dwCopyingLength =
  1951. LoadString( g_hinstance, IDS_COPYING, MyContext.szCopyingString, ARRAYSIZE(MyContext.szCopyingString));
  1952. Assert(MyContext.dwCopyingLength);
  1953. //
  1954. // Start copying
  1955. //
  1956. Assert( dwCount );
  1957. if ( dwCount != 0 )
  1958. {
  1959. b = SetupCommitFileQueue( NULL,
  1960. Queue,
  1961. (PSP_FILE_CALLBACK) CopyFilesCallback,
  1962. (PVOID) &MyContext );
  1963. if ( !b ) {
  1964. DWORD dwErr = GetLastError( );
  1965. switch ( dwErr )
  1966. {
  1967. case ERROR_CANCELLED:
  1968. hr = THR( HRESULT_FROM_WIN32( ERROR_CANCELLED ) );
  1969. goto Cleanup;
  1970. default:
  1971. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  1972. MessageBoxFromError( hDlg, NULL, dwErr );
  1973. goto Cleanup;
  1974. }
  1975. }
  1976. }
  1977. SetupCloseFileQueue( Queue );
  1978. Queue = INVALID_HANDLE_VALUE;
  1979. //
  1980. // Ask BINL to go through the INFs to find the drivers
  1981. // that we need to extract from the CABs.
  1982. //
  1983. dw = LoadString( g_hinstance, IDS_BUILDINGFILELIST, szText, ARRAYSIZE(szText));
  1984. Assert( dw );
  1985. SetDlgItemText( hDlg, IDC_S_OPERATION, szText );
  1986. SendMessage( hProg, PBM_SETPOS, 0, 0 );
  1987. // Re-init these values
  1988. MyContext.nCopied = 0;
  1989. MyContext.nToBeCopied = 0;
  1990. // Pre-fill the link list of things to extract from the cab with
  1991. // things in the workstations REMINST.INF if needed. The section
  1992. // can be missing if there is nothing to pre-fill.
  1993. hr = AddInfSectionToExtractQueue( hinfReminst, L"ExtractFromCabs", &MyContext );
  1994. if (FAILED( hr ))
  1995. goto Cleanup;
  1996. // compile the list of files
  1997. lstrcpyn( szTempPath, g_Options.szInstallationPath, ARRAYSIZE(szTempPath) );
  1998. ConcatenatePaths( szTempPath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szTempPath));
  1999. dw = pfnNetInfEnumFiles( szTempPath,
  2000. g_Options.ProcessorArchitecture,
  2001. &MyContext,
  2002. EnumNetworkDriversCallback );
  2003. if ( dw != ERROR_SUCCESS )
  2004. {
  2005. hr = THR( HRESULT_FROM_WIN32( dw ) );
  2006. MessageBoxFromError( hDlg, NULL, dw );
  2007. goto Cleanup;
  2008. }
  2009. DebugMsg( "%d files need to be extracted from CABs.\n", MyContext.nToBeCopied );
  2010. // Go through the CABs extracting only the ones in the link list
  2011. if ( !SetupFindFirstLineW( hinfDrivers, L"Version", L"CabFiles", &context) )
  2012. {
  2013. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2014. ErrorBox( hDlg, NULL );
  2015. goto Cleanup;
  2016. }
  2017. do
  2018. {
  2019. UINT uFieldCount = SetupGetFieldCount( &context );
  2020. DebugMsg( "uFieldCount = %u\n", uFieldCount );
  2021. for( UINT uField = 1; uField <= uFieldCount; uField++ )
  2022. {
  2023. WCHAR CabinetNameKey[64];
  2024. INFCONTEXT DrvContext;
  2025. WCHAR szCabinetName[ MAX_PATH ];
  2026. dwLen = ARRAYSIZE( szCabinetName );
  2027. if (!SetupGetStringField( &context, uField, CabinetNameKey, ARRAYSIZE( CabinetNameKey ), NULL ) ||
  2028. !SetupFindFirstLine( hinfDrivers, L"Cabs", CabinetNameKey, &DrvContext) ||
  2029. !SetupGetStringField( &DrvContext, 1, szCabinetName, dwLen, NULL )) {
  2030. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2031. ErrorBox( hDlg, NULL );
  2032. goto Cleanup;
  2033. }
  2034. lstrcpyn( szFilepath, g_Options.szInstallationPath, ARRAYSIZE(szFilepath));
  2035. ConcatenatePaths( szFilepath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szFilepath));
  2036. ConcatenatePaths( szFilepath, szCabinetName, ARRAYSIZE(szFilepath));
  2037. DebugMsg( "Iterating: %s\n", szFilepath );
  2038. if ( szCabinetName[0] == L'\0' )
  2039. continue; // skip blanks
  2040. b = SetupIterateCabinet( szFilepath,
  2041. 0,
  2042. EnumCabinetCallback,
  2043. &MyContext );
  2044. if ( !b )
  2045. {
  2046. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2047. ErrorBox( hDlg, szFilepath );
  2048. goto Cleanup;
  2049. }
  2050. }
  2051. } while ( SetupFindNextMatchLine( &context, L"CabFiles", &context ) );
  2052. //
  2053. // comment out this assert because it always fires -- some files we are
  2054. // queuing up (the ones in the ExtractFromCabs section) are not part of
  2055. // any cab, so they are handled in the following section.
  2056. //
  2057. #if 0
  2058. // This should be empty - if not tell someone on the CHKed version.
  2059. AssertMsg( pExtractionList == NULL, "Some network drivers are not in the CABs.\n\nIgnore this if you do not care." );
  2060. #endif
  2061. if ( pExtractionList != NULL )
  2062. {
  2063. WCHAR szDstPath[ MAX_PATH ];
  2064. // Ok. Someone decided that these files shouldn't be in the CAB. So
  2065. // let's try to get them from outside the CAB.
  2066. pNode = pExtractionList;
  2067. while ( pNode )
  2068. {
  2069. DWORD dwConditionalFlags = 0;
  2070. PWSTR CompressedName = NULL;
  2071. //
  2072. // see if we copied the file to the installation image already
  2073. //
  2074. // if the file is already at the destination, we can skip copying
  2075. // this file or just decompress it (and delete the compressed
  2076. // source). In the case where the file is compressed, we may need
  2077. // to tweak the file attributes so that the source file can be
  2078. // successfully retreived.
  2079. //
  2080. lstrcpyn( szFilepath, g_Options.szInstallationPath, ARRAYSIZE(szFilepath));
  2081. ConcatenatePaths( szFilepath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szFilepath));
  2082. ConcatenatePaths( szFilepath, pNode->szFilename, ARRAYSIZE(szFilepath));
  2083. if ( !IsFileOrCompressedVersionPresent( szFilepath, &CompressedName )) {
  2084. //
  2085. // It's not already there, so check the source.
  2086. //
  2087. // Note that we don't care if the file is compressed or not, we
  2088. // just want the file to be there, because setupapi can do the
  2089. // rest without any help from us.
  2090. //
  2091. lstrcpyn( szFilepath, g_Options.szSourcePath, ARRAYSIZE(szFilepath));
  2092. ConcatenatePaths( szFilepath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szFilepath));
  2093. ConcatenatePaths( szFilepath, pNode->szFilename, ARRAYSIZE(szFilepath));
  2094. if ( !IsFileOrCompressedVersionPresent( szFilepath, &CompressedName )) {
  2095. //
  2096. // it's not there on the source - we must give up
  2097. //
  2098. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  2099. MessageBoxFromError( hDlg, pNode->szFilename, ERROR_FILE_NOT_FOUND );
  2100. goto Cleanup;
  2101. }
  2102. } else {
  2103. if (CompressedName) {
  2104. //
  2105. // Make sure we can delete the compressed source file at
  2106. // the destination path since we're going to decompress
  2107. // this file
  2108. //
  2109. DWORD dwAttribs = GetFileAttributes( CompressedName );
  2110. DebugMsg( "!!compressed name!!: %s\n", CompressedName );
  2111. if ( dwAttribs & FILE_ATTRIBUTE_READONLY )
  2112. {
  2113. dwAttribs &= ~FILE_ATTRIBUTE_READONLY;
  2114. SetFileAttributes( CompressedName, dwAttribs );
  2115. }
  2116. dwConditionalFlags = SP_COPY_DELETESOURCE;
  2117. TraceFree( CompressedName );
  2118. } else {
  2119. //
  2120. // the file is already expanded in the destination - NOP.
  2121. //
  2122. goto DeleteIt;
  2123. }
  2124. }
  2125. // Update UI
  2126. wcscpy( &MyContext.szCopyingString[ MyContext.dwCopyingLength ], pNode->szFilename );
  2127. wcscpy( &MyContext.szCopyingString[ wcslen( MyContext.szCopyingString ) ], L"..." );
  2128. SetWindowText( MyContext.hOperation, MyContext.szCopyingString );
  2129. DebugMsg( "!!COPYING!!: %s\n", szFilepath );
  2130. lstrcpyn( szDstPath, g_Options.szInstallationPath, ARRAYSIZE(szDstPath));
  2131. ConcatenatePaths( szDstPath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szDstPath));
  2132. ConcatenatePaths( szDstPath, pNode->szFilename, ARRAYSIZE(szDstPath));
  2133. b= SetupInstallFile( NULL,
  2134. NULL,
  2135. szFilepath,
  2136. NULL,
  2137. szDstPath,
  2138. SP_COPY_SOURCE_ABSOLUTE | SP_COPY_NEWER_ONLY
  2139. | SP_COPY_FORCE_NEWER | dwConditionalFlags,
  2140. NULL,
  2141. NULL );
  2142. if ( !b )
  2143. {
  2144. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2145. ErrorBox( hDlg, szFilepath );
  2146. goto Cleanup;
  2147. }
  2148. if ( KeepUIAlive( hDlg ) )
  2149. {
  2150. hr = HRESULT_FROM_WIN32( ERROR_CANCELLED );
  2151. goto Cleanup;
  2152. }
  2153. DeleteIt:
  2154. // Update meter
  2155. MyContext.nCopied++;
  2156. SendMessage( MyContext.hProg, PBM_SETPOS, (5000 * MyContext.nCopied) / MyContext.nToBeCopied, 0 );
  2157. pExtractionList = pNode->Next;
  2158. LocalFree( pNode );
  2159. pNode = pExtractionList;
  2160. }
  2161. }
  2162. //
  2163. // Finally, blow out all the files in these cabs
  2164. //
  2165. dw = LoadString( g_hinstance, IDS_EXPANDING_CABS, szText, ARRAYSIZE(szText));
  2166. Assert( dw );
  2167. SetDlgItemText( hDlg, IDC_S_OPERATION, szText );
  2168. ExpandParams.hDlg = hDlg;
  2169. ExpandParams.hinf = hinfReminst;
  2170. ExpandParams.pszSection = L"CabsToExpand";
  2171. ExpandParams.pszSourcePath = g_Options.szSourcePath;
  2172. ExpandParams.pszDestPath = g_Options.szInstallationPath;
  2173. ExpandParams.pszSubDir = g_Options.ProcessorArchitectureString;
  2174. // Expand CABs in background to keep UI alive
  2175. hThread = CreateThread( NULL, NULL, (LPTHREAD_START_ROUTINE) ExpandCabList, (LPVOID) &ExpandParams, NULL, NULL );
  2176. while ( WAIT_TIMEOUT == WaitForSingleObject( hThread, 10 ) )
  2177. {
  2178. KeepUIAlive( hDlg );
  2179. }
  2180. GetExitCodeThread( hThread, (ULONG*)&hr );
  2181. DebugMsg( "Thread Exit Code was 0x%08x\n", hr );
  2182. if ( FAILED( hr ) ) {
  2183. goto Cleanup;
  2184. }
  2185. //
  2186. // Make sure there's an oschoice loader in the \oschoice directory. It
  2187. // may not have been put there because it's difficult to get all
  2188. // the oschoice loaders on the CDROM that was used to install the
  2189. // server we're running on and the \oschoice directory is essentially
  2190. // populated from the %windir%\system32\reminst directory.
  2191. //
  2192. // For that reason, if there's no oschoice loader present in our
  2193. // \oschoice directory, then let's get it off the CDROM we're using
  2194. // to create this client image.
  2195. //
  2196. //
  2197. // Build a path to our oschoice loader.
  2198. //
  2199. lstrcpyn( szFilepath, g_Options.szOSChooserPath, ARRAYSIZE(szFilepath) );
  2200. ConcatenatePaths( szFilepath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szFilepath));
  2201. //
  2202. // d:\reminst\oschooser should have been built by now, but maybe not
  2203. // d:\reminst\oschooser\<architecture>
  2204. //
  2205. CreateDirectoryPath( hDlg, szFilepath, NULL, TRUE );
  2206. //
  2207. // Build a path to our source file.
  2208. //
  2209. lstrcpyn(szTempPath, g_Options.szSourcePath, ARRAYSIZE(szTempPath));
  2210. ConcatenatePaths( szTempPath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szTempPath));
  2211. // That loader file name will be different depending on our
  2212. // architecture.
  2213. switch( g_Options.ProcessorArchitecture ) {
  2214. case PROCESSOR_ARCHITECTURE_IA64:
  2215. ConcatenatePaths( szFilepath, L"oschoice.efi", ARRAYSIZE(szFilepath) );
  2216. ConcatenatePaths( szTempPath, L"oschoice.efi", ARRAYSIZE(szTempPath) );
  2217. break;
  2218. default:
  2219. // assume the x86 case.
  2220. ConcatenatePaths( szFilepath, L"ntldr", ARRAYSIZE(szFilepath) );
  2221. ConcatenatePaths( szTempPath, L"oschoice.exe", ARRAYSIZE(szTempPath) );
  2222. break;
  2223. }
  2224. //
  2225. // Now see if our oschoice loader is present.
  2226. //
  2227. dw = GetFileAttributes( szFilepath );
  2228. if( dw == 0xFFFFFFFF ) {
  2229. SetupInstallFile( NULL, // InfHandle
  2230. NULL, // pInfContext
  2231. szTempPath, // Src
  2232. NULL, // Src path
  2233. szFilepath, // Dst
  2234. SP_COPY_SOURCE_ABSOLUTE | SP_COPY_NOOVERWRITE, // copy flags
  2235. NULL, // copy callback
  2236. NULL ); // Context for callback.
  2237. } else {
  2238. DWORD OSChoiceBuildNumber;
  2239. //
  2240. // The file's there, but for ia64 (and maybe x86), we need
  2241. // to see if we should update the oschoice file.
  2242. // to do that, we'll go check the version of the kernel on
  2243. // our install media and compare it against the version of the
  2244. // oschoice file. If it's newer, we'll replace it.
  2245. // We don't check against the oschoice on the CDROM because
  2246. // it's compressed.
  2247. //
  2248. OSChoiceBuildNumber = MyGetFileVersionInfo( szFilepath );
  2249. if( (OSChoiceBuildNumber != 0) &&
  2250. (g_Options.dwBuildNumber > OSChoiceBuildNumber) ) {
  2251. //
  2252. // Copy it.
  2253. //
  2254. SetupInstallFile( NULL, // InfHandle
  2255. NULL, // pInfContext
  2256. szTempPath, // Src
  2257. NULL, // Src path
  2258. szFilepath, // Dst
  2259. SP_COPY_SOURCE_ABSOLUTE, // copy flags
  2260. NULL, // copy callback
  2261. NULL ); // Context for callback.
  2262. }
  2263. }
  2264. Cleanup:
  2265. if ( hThread != NULL ) {
  2266. CloseHandle( hThread );
  2267. }
  2268. if ( MyContext.pContext ) {
  2269. SetupTermDefaultQueueCallback( MyContext.pContext );
  2270. }
  2271. if ( Queue != INVALID_HANDLE_VALUE ) {
  2272. SetupCloseFileQueue( Queue );
  2273. }
  2274. if ( hinfLayout != INVALID_HANDLE_VALUE ) {
  2275. SetupCloseInfFile( hinfLayout );
  2276. }
  2277. if ( hinfReminst != INVALID_HANDLE_VALUE ) {
  2278. SetupCloseInfFile( hinfReminst );
  2279. }
  2280. if ( hinfDrivers != INVALID_HANDLE_VALUE ) {
  2281. SetupCloseInfFile( hinfDrivers );
  2282. }
  2283. if ( hinfDosnet != INVALID_HANDLE_VALUE ) {
  2284. SetupCloseInfFile( hinfDosnet );
  2285. }
  2286. if (FullDllPath) {
  2287. TraceFree(FullDllPath);
  2288. }
  2289. if ( hBinlsvc != NULL ) {
  2290. FreeLibrary( hBinlsvc );
  2291. }
  2292. AssertMsg( pExtractionList == NULL, "The list still isn't empty.\n\nThe image will be missing some drivers.\n" );
  2293. while ( pExtractionList )
  2294. {
  2295. PLL_FILES_TO_EXTRACT pExtractNode = pExtractionList;
  2296. pExtractionList = pExtractionList->Next;
  2297. LocalFree( pExtractNode );
  2298. }
  2299. b = DeleteFile( g_Options.szWorkstationRemBootInfPath );
  2300. AssertMsg( b, "Failed to delete temp\\REMINST.INF\nThis was just a warning and can be ignored." );
  2301. g_Options.szWorkstationRemBootInfPath[0] = L'\0';
  2302. SendMessage( hProg, PBM_SETPOS, 5000, 0 );
  2303. SetDlgItemText( hDlg, IDC_S_OPERATION, L"" );
  2304. HRETURN(hr);
  2305. }
  2306. //
  2307. // Modifies registry from the registry section of the REMINST.INF
  2308. //
  2309. HRESULT
  2310. ModifyRegistry( HWND hDlg )
  2311. {
  2312. HRESULT hr = S_OK;
  2313. HWND hProg = GetDlgItem( hDlg, IDC_P_METER );
  2314. WCHAR szText[ SMALL_BUFFER_SIZE ];
  2315. WCHAR szSection[ SMALL_BUFFER_SIZE ];
  2316. WCHAR szPath[ MAX_PATH ];
  2317. BOOL b;
  2318. DWORD dw;
  2319. UINT spinstFlags = 0;
  2320. TraceFunc( "ModifyRegistry( hDlg )\n" );
  2321. Assert( g_Options.hinf != INVALID_HANDLE_VALUE );
  2322. if ( g_Options.hinf == INVALID_HANDLE_VALUE )
  2323. HRETURN( HRESULT_FROM_WIN32( ERROR_INVALID_HANDLE ) ); // need this handle!
  2324. //
  2325. // Update UI
  2326. //
  2327. SendMessage( hProg, PBM_SETRANGE, 0, MAKELPARAM( 0, 1 ) );
  2328. dw = LoadString( g_hinstance, IDS_UPDATING_REGISTRY, szText, ARRAYSIZE(szText));
  2329. Assert( dw );
  2330. SetDlgItemText( hDlg, IDC_S_OPERATION, szText );
  2331. dw = LoadString( g_hinstance, IDS_INF_SECTION, szSection, ARRAYSIZE(szSection));
  2332. Assert( dw );
  2333. //
  2334. // Process the INF's registry section
  2335. //
  2336. if ( !g_Options.fRegistryIntact ) {
  2337. spinstFlags |= SPINST_REGISTRY;
  2338. }
  2339. if ( !g_Options.fRegSrvDllsRegistered ) {
  2340. spinstFlags |= SPINST_REGSVR;
  2341. }
  2342. b = SetupInstallFromInfSection( hDlg, // hwndOwner
  2343. g_Options.hinf, // inf handle
  2344. szSection, // name of component
  2345. spinstFlags,
  2346. NULL, // relative key root
  2347. NULL, // source root path
  2348. 0, // copy flags
  2349. NULL, // callback routine
  2350. NULL, // callback routine context
  2351. NULL, // device info set
  2352. NULL); // device info struct
  2353. if ( !b ) {
  2354. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2355. ErrorBox( hDlg, szSection );
  2356. goto Error;
  2357. }
  2358. //
  2359. // Add the Reg Key for TFTPD
  2360. //
  2361. if ( !g_Options.fTFTPDDirectoryFound ) {
  2362. HKEY hkey;
  2363. dw = LoadString( g_hinstance, IDS_TFTPD_SERVICE_PARAMETERS, szPath, ARRAYSIZE(szPath));
  2364. Assert( dw );
  2365. if ( ERROR_SUCCESS == RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  2366. szPath,
  2367. 0, // options
  2368. NULL, // class
  2369. 0, // options
  2370. KEY_WRITE,
  2371. NULL, // security
  2372. &hkey,
  2373. &dw ) ) { // disposition
  2374. ULONG lLen;
  2375. LONG lErr;
  2376. // paranoid
  2377. Assert( wcslen(g_Options.szIntelliMirrorPath) < ARRAYSIZE(g_Options.szIntelliMirrorPath));
  2378. lLen = lstrlen( g_Options.szIntelliMirrorPath ) * sizeof(WCHAR);
  2379. lErr = RegSetValueEx( hkey,
  2380. L"Directory",
  2381. 0, // reserved
  2382. REG_SZ,
  2383. (LPBYTE) g_Options.szIntelliMirrorPath,
  2384. lLen );
  2385. RegCloseKey( hkey );
  2386. if ( lErr == ERROR_SUCCESS ) {
  2387. DebugMsg( "TFTPD's Directory RegKey set.\n" );
  2388. } else {
  2389. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2390. ErrorBox( hDlg, szPath );
  2391. DebugMsg( "HKLM\\%s could be not created.\n", szPath );
  2392. goto Error;
  2393. }
  2394. } else {
  2395. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2396. ErrorBox( hDlg, szPath );
  2397. DebugMsg( "HKLM\\%s could be not created.\n", szPath );
  2398. goto Error;
  2399. }
  2400. }
  2401. Error:
  2402. SendMessage( hProg, PBM_SETPOS, 1 , 0 );
  2403. SetDlgItemText( hDlg, IDC_S_OPERATION, L"" );
  2404. HRETURN(hr);
  2405. }
  2406. //
  2407. // Stop a specific service
  2408. //
  2409. HRESULT
  2410. StopRBService(
  2411. HWND hDlg,
  2412. SC_HANDLE schSystem,
  2413. LPWSTR pszService
  2414. )
  2415. {
  2416. HRESULT hr = S_OK;
  2417. SC_HANDLE schService = NULL;
  2418. SERVICE_STATUS ssStatus;
  2419. BOOL b;
  2420. DWORD dwErr;
  2421. UNREFERENCED_PARAMETER(hDlg);
  2422. TraceFunc( "StopRBService( ... )\n" );
  2423. Assert( schSystem );
  2424. Assert( pszService );
  2425. schService = OpenService( schSystem,
  2426. pszService,
  2427. SERVICE_STOP | SERVICE_QUERY_STATUS );
  2428. if ( !schService ) {
  2429. goto Cleanup;
  2430. }
  2431. b = ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus );
  2432. #define SLEEP_TIME 2000
  2433. #define LOOP_COUNT 30
  2434. if ( !b && GetLastError() != ERROR_SERVICE_NOT_ACTIVE ) {
  2435. dwErr = GetLastError( );
  2436. } else {
  2437. DWORD loopCount = 0;
  2438. do {
  2439. b = QueryServiceStatus( schService, &ssStatus);
  2440. if ( !b ) {
  2441. goto Cleanup;
  2442. }
  2443. if (ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
  2444. if ( loopCount++ == LOOP_COUNT ) {
  2445. dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
  2446. break;
  2447. }
  2448. Sleep( SLEEP_TIME );
  2449. } else {
  2450. if ( ssStatus.dwCurrentState != SERVICE_STOPPED ) {
  2451. dwErr = ssStatus.dwWin32ExitCode;
  2452. if ( dwErr == ERROR_SERVICE_SPECIFIC_ERROR ) {
  2453. dwErr = ssStatus.dwServiceSpecificExitCode;
  2454. }
  2455. } else {
  2456. dwErr = NO_ERROR;
  2457. }
  2458. break;
  2459. }
  2460. } while ( TRUE );
  2461. }
  2462. Cleanup:
  2463. if ( schService )
  2464. CloseServiceHandle( schService );
  2465. HRETURN(hr);
  2466. }
  2467. //
  2468. // Start a specific service
  2469. //
  2470. HRESULT
  2471. StartRBService(
  2472. HWND hDlg,
  2473. SC_HANDLE schSystem,
  2474. LPWSTR pszService,
  2475. LPWSTR pszServiceName,
  2476. LPWSTR pszServiceDescription )
  2477. {
  2478. HRESULT hr = S_OK;
  2479. SC_HANDLE schService = NULL;
  2480. SERVICE_STATUS ssStatus;
  2481. BOOL b;
  2482. DWORD dwErr;
  2483. TraceFunc( "StartRBService( ... )\n" );
  2484. Assert( schSystem );
  2485. Assert( pszService );
  2486. Assert( pszServiceName );
  2487. schService = OpenService( schSystem,
  2488. pszService,
  2489. SERVICE_ALL_ACCESS );
  2490. if ( !schService ) {
  2491. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2492. ErrorBox( hDlg, pszServiceName );
  2493. goto Cleanup;
  2494. }
  2495. b = ChangeServiceConfig( schService,
  2496. SERVICE_NO_CHANGE,
  2497. SERVICE_AUTO_START,
  2498. SERVICE_NO_CHANGE,
  2499. NULL,
  2500. NULL,
  2501. NULL,
  2502. NULL,
  2503. NULL,
  2504. NULL,
  2505. NULL );
  2506. if ( !b ) {
  2507. ErrorBox( hDlg, pszServiceName );
  2508. hr = THR(S_FALSE);
  2509. }
  2510. // If the service is paused, continue it; else try to start it.
  2511. b = QueryServiceStatus( schService, &ssStatus);
  2512. if ( !b ) {
  2513. ErrorBox( hDlg, pszServiceName );
  2514. hr = THR(S_FALSE);
  2515. goto Cleanup;
  2516. }
  2517. if ( ssStatus.dwCurrentState == SERVICE_PAUSED ) {
  2518. b = ControlService( schService, SERVICE_CONTROL_CONTINUE, &ssStatus );
  2519. } else {
  2520. b = StartService( schService, 0, NULL );
  2521. }
  2522. #define SLEEP_TIME 2000
  2523. #define LOOP_COUNT 30
  2524. if ( !b ) {
  2525. dwErr = GetLastError( );
  2526. } else {
  2527. DWORD loopCount = 0;
  2528. do {
  2529. b = QueryServiceStatus( schService, &ssStatus);
  2530. if ( !b ) {
  2531. ErrorBox( hDlg, pszServiceName );
  2532. hr = THR(S_FALSE);
  2533. goto Cleanup;
  2534. }
  2535. if ( ssStatus.dwCurrentState != SERVICE_RUNNING ) {
  2536. if ( loopCount++ == LOOP_COUNT ) {
  2537. if ( (ssStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) ||
  2538. (ssStatus.dwCurrentState == SERVICE_START_PENDING) ) {
  2539. dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
  2540. } else {
  2541. dwErr = ssStatus.dwWin32ExitCode;
  2542. if ( dwErr == ERROR_SERVICE_SPECIFIC_ERROR ) {
  2543. dwErr = ssStatus.dwServiceSpecificExitCode;
  2544. }
  2545. }
  2546. break;
  2547. }
  2548. Sleep( SLEEP_TIME );
  2549. } else {
  2550. dwErr = NO_ERROR;
  2551. break;
  2552. }
  2553. } while ( TRUE );
  2554. }
  2555. if ( dwErr != NO_ERROR ) {
  2556. switch ( dwErr )
  2557. {
  2558. default:
  2559. hr = THR( HRESULT_FROM_WIN32( dwErr ) );
  2560. MessageBoxFromError( hDlg, pszServiceName, dwErr );
  2561. break;
  2562. case ERROR_SERVICE_ALREADY_RUNNING:
  2563. {
  2564. // Attempt to HUP the service
  2565. SERVICE_STATUS ss;
  2566. ControlService( schService, SERVICE_CONTROL_INTERROGATE, &ss );
  2567. }
  2568. break;
  2569. }
  2570. }
  2571. else {
  2572. // There is a pathological case where the service is deleted and then risetup restarts it. When it does so, it doesn't set the description string.
  2573. // We check here if there is a description for the service and if not we give it one.
  2574. // We can't do this in CreateRemoteBootServices beacuse the services must be started.
  2575. SERVICE_DESCRIPTION description;
  2576. DWORD bytes_needed;
  2577. if( QueryServiceConfig2( schService, SERVICE_CONFIG_DESCRIPTION, ( LPBYTE )&description, sizeof( description ), &bytes_needed )) {
  2578. // Now, if there were a description the previous call would have failed with a ERROR_INSUFFICIENT_BUFFER error.
  2579. // We do a quick check to make sure that everything is valid.
  2580. Assert( description.lpDescription == NULL );
  2581. // Now we can change it.
  2582. description.lpDescription = pszServiceDescription;
  2583. ChangeServiceConfig2( schService, SERVICE_CONFIG_DESCRIPTION, &description );
  2584. // If that caused an error, we'll ignore it since the description is not essential to the operation of RIS.
  2585. }
  2586. // Whatever error the query threw we don't care as the description isn't sufficiently vital to RIS.
  2587. }
  2588. Cleanup:
  2589. if ( schService )
  2590. CloseServiceHandle( schService );
  2591. HRETURN(hr);
  2592. }
  2593. //
  2594. // Start the services needed for remote boot.
  2595. //
  2596. HRESULT
  2597. StartRemoteBootServices( HWND hDlg )
  2598. {
  2599. WCHAR szServiceName[ SMALL_BUFFER_SIZE ];
  2600. WCHAR szServiceDescription[ 1024 ]; // Size is the maximum allowed by ChangeServiceConfig2
  2601. WCHAR szText[ SMALL_BUFFER_SIZE ];
  2602. SC_HANDLE schSystem;
  2603. HWND hProg = GetDlgItem( hDlg, IDC_P_METER );
  2604. DWORD dw;
  2605. HRESULT hr;
  2606. HRESULT hrFatalError = S_OK;
  2607. HRESULT hrStartFailure = S_OK;
  2608. HWND hOper = GetDlgItem( hDlg, IDC_S_OPERATION );
  2609. TraceFunc( "StartRemoteBootServices( hDlg )\n" );
  2610. SendMessage( hProg, PBM_SETRANGE, 0, MAKELPARAM( 0, 2 ) );
  2611. SendMessage( hProg, PBM_SETPOS, 0, 0 );
  2612. szText[0]= L'\0';
  2613. dw = LoadString( g_hinstance, IDS_STARTING_SERVICES, szText, ARRAYSIZE(szText));
  2614. Assert( dw );
  2615. SetDlgItemText( hDlg, IDC_S_OPERATION, szText );
  2616. schSystem = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  2617. Assert( schSystem );
  2618. if ( !schSystem ) {
  2619. hrFatalError = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2620. WCHAR szCaption[SMALL_BUFFER_SIZE];
  2621. szCaption[0] = L'\0';
  2622. dw = LoadString( g_hinstance, IDS_OPENING_SERVICE_MANAGER_TITLE, szCaption, SMALL_BUFFER_SIZE );
  2623. Assert( dw );
  2624. ErrorBox( hDlg, szCaption );
  2625. goto Cleanup;
  2626. }
  2627. //
  2628. // start TFTPD services
  2629. //
  2630. szServiceName[0]= L'\0';
  2631. dw = LoadString( g_hinstance, IDS_TFTPD_SERVICENAME, szServiceName, ARRAYSIZE(szServiceName));
  2632. Assert( dw );
  2633. szServiceDescription[0]= L'\0';
  2634. dw = LoadString( g_hinstance, IDS_TFTPD_DESCRIPTION, szServiceDescription, ARRAYSIZE(szServiceDescription));
  2635. Assert( dw );
  2636. SetWindowText( hOper, szServiceName );
  2637. hr = StartRBService( hDlg, schSystem, L"TFTPD", szServiceName, szServiceDescription );
  2638. if ( FAILED(hr) ) {
  2639. hrFatalError = hr;
  2640. goto Cleanup;
  2641. } else if ( hr != S_OK ) {
  2642. hrStartFailure = hr;
  2643. }
  2644. //
  2645. // start BINLSVC services
  2646. //
  2647. szServiceName[0]= L'\0';
  2648. dw = LoadString( g_hinstance, IDS_BINL_SERVICENAME, szServiceName, ARRAYSIZE(szServiceName));
  2649. Assert( dw );
  2650. szServiceDescription[0]= L'\0';
  2651. dw = LoadString( g_hinstance, IDS_BINL_DESCRIPTION, szServiceDescription, ARRAYSIZE(szServiceDescription));
  2652. Assert( dw );
  2653. SetWindowText( hOper, szServiceName );
  2654. if (!g_Options.fBINLSCPFound) {
  2655. StopRBService( hDlg, schSystem, L"BINLSVC" );
  2656. }
  2657. hr = StartRBService( hDlg, schSystem, L"BINLSVC", szServiceName, szServiceDescription );
  2658. if ( FAILED(hr) ) {
  2659. hrFatalError = hr;
  2660. goto Cleanup;
  2661. } else if ( hr != S_OK ) {
  2662. hrStartFailure = hr;
  2663. }
  2664. //
  2665. // start GROVELER services
  2666. //
  2667. szServiceName[0]= L'\0';
  2668. dw = LoadString( g_hinstance, IDS_SISGROVELER_SERVICENAME, szServiceName, ARRAYSIZE(szServiceName));
  2669. Assert( dw );
  2670. szServiceDescription[0]= L'\0';
  2671. dw = LoadString( g_hinstance, IDS_SISGROVELER_DESCRIPTION, szServiceDescription, ARRAYSIZE(szServiceDescription));
  2672. Assert( dw );
  2673. SetWindowText( hOper, szServiceName );
  2674. hr = StartRBService( hDlg, schSystem, L"GROVELER", szServiceName, szServiceDescription );
  2675. if ( FAILED(hr) ) {
  2676. hrFatalError = hr;
  2677. goto Cleanup;
  2678. } else if ( hr != S_OK ) {
  2679. hrStartFailure = hr;
  2680. }
  2681. Cleanup:
  2682. SetDlgItemText( hDlg, IDC_S_OPERATION, L"" );
  2683. if ( schSystem )
  2684. CloseServiceHandle( schSystem );
  2685. if ( hrFatalError != S_OK ) {
  2686. hr = hrFatalError;
  2687. } else if ( hrStartFailure != S_OK ) {
  2688. hr = hrStartFailure;
  2689. } else {
  2690. hr = S_OK;
  2691. }
  2692. RETURN(hr);
  2693. }
  2694. //
  2695. // create IntelliMirror share
  2696. //
  2697. HRESULT
  2698. CreateRemoteBootShare( HWND hDlg )
  2699. {
  2700. SHARE_INFO_502 si502;
  2701. WCHAR szRemark[ SMALL_BUFFER_SIZE ];
  2702. WCHAR szRemoteBoot[ SMALL_BUFFER_SIZE ];
  2703. WCHAR szText[ SMALL_BUFFER_SIZE ];
  2704. WCHAR szPath[ 129 ];
  2705. DWORD dwErr;
  2706. DWORD dw;
  2707. HRESULT hr;
  2708. TraceFunc( "CreateRemoteBootShare( hDlg )\n" );
  2709. dw = LoadString( g_hinstance, IDS_CREATINGSHARES, szText, ARRAYSIZE(szText));
  2710. Assert( dw );
  2711. SetDlgItemText( hDlg, IDC_S_OPERATION, szText );
  2712. dw = LoadString( g_hinstance, IDS_REMOTEBOOTSHAREREMARK, szRemark, ARRAYSIZE(szRemark));
  2713. Assert( dw );
  2714. dw = LoadString( g_hinstance, IDS_REMOTEBOOTSHARENAME, szRemoteBoot, ARRAYSIZE(szRemoteBoot));
  2715. Assert( dw );
  2716. lstrcpyn( szPath, g_Options.szIntelliMirrorPath, ARRAYSIZE(szPath) );
  2717. if ( wcslen( szPath ) == 2 ) {
  2718. wcscat( szPath, L"\\" );
  2719. }
  2720. si502.shi502_netname = szRemoteBoot;
  2721. si502.shi502_type = STYPE_DISKTREE;
  2722. si502.shi502_remark = szRemark;
  2723. si502.shi502_permissions = ACCESS_ALL;
  2724. si502.shi502_max_uses = (DWORD)(-1); // unlimited
  2725. si502.shi502_current_uses = 0;
  2726. si502.shi502_path = szPath;
  2727. si502.shi502_passwd = NULL; // ignored
  2728. si502.shi502_reserved = 0; // must be zero
  2729. si502.shi502_security_descriptor = NULL;
  2730. Assert( wcslen(g_Options.szIntelliMirrorPath) < ARRAYSIZE(g_Options.szIntelliMirrorPath) ); // paranoid
  2731. dwErr = NetShareAdd( NULL, 502, (LPBYTE) &si502, NULL );
  2732. switch ( dwErr )
  2733. {
  2734. // ignore these
  2735. case NERR_Success:
  2736. case NERR_DuplicateShare:
  2737. dwErr = ERROR_SUCCESS;
  2738. break;
  2739. default:
  2740. MessageBoxFromError( hDlg, g_Options.szIntelliMirrorPath, dwErr );
  2741. goto Error;
  2742. }
  2743. #ifdef REMOTE_BOOT
  2744. #error("Remote boot is dead!! Turn off the REMOTE_BOOT flag.")
  2745. si1005.shi1005_flags = CSC_CACHE_AUTO_REINT;
  2746. NetShareSetInfo( NULL, szRemoteBoot, 1005, (LPBYTE)&si1005, &dwErr );
  2747. switch ( dwErr )
  2748. {
  2749. // ignore these
  2750. case NERR_Success:
  2751. dwErr = ERROR_SUCCESS;
  2752. break;
  2753. default:
  2754. MessageBoxFromError( hDlg, g_Options.szIntelliMirrorPath, dwErr );
  2755. }
  2756. #endif // REMOTE_BOOT
  2757. Error:
  2758. hr = THR( HRESULT_FROM_WIN32(dwErr) );
  2759. HRETURN(hr);
  2760. }
  2761. typedef int (WINAPI * REGISTERDLL)( void );
  2762. //
  2763. // Register Dlls
  2764. //
  2765. // If hDlg is NULL, this will fail silently.
  2766. //
  2767. HRESULT
  2768. RegisterDll( HWND hDlg, LPWSTR pszDLLPath )
  2769. {
  2770. REGISTERDLL pfnRegisterDll = NULL;
  2771. HINSTANCE hLib;
  2772. HRESULT hr = S_OK;
  2773. TraceFunc( "RegisterDll( ... )\n" );
  2774. //
  2775. // We'll try to register it locally, but if fails MMC should
  2776. // grab it from the DS and register it on the machine.
  2777. //
  2778. hLib = LoadLibrary( pszDLLPath );
  2779. AssertMsg( hLib, "RegisterDll: Missing DLL?" );
  2780. if ( !hLib ) {
  2781. hr = S_FALSE;
  2782. goto Cleanup;
  2783. }
  2784. pfnRegisterDll = (REGISTERDLL) GetProcAddress( hLib, "DllRegisterServer" );
  2785. AssertMsg( pfnRegisterDll, "RegisterDll: Missing entry point?" );
  2786. if ( pfnRegisterDll != NULL )
  2787. {
  2788. hr = THR( pfnRegisterDll() );
  2789. if ( FAILED(hr) && hDlg ) {
  2790. MessageBoxFromStrings( hDlg,
  2791. IDS_REGISTER_IMADMIU_FAILED_CAPTION,
  2792. IDS_REGISTER_IMADMIU_FAILED_TEXT,
  2793. MB_OK );
  2794. }
  2795. }
  2796. FreeLibrary( hLib );
  2797. Cleanup:
  2798. HRETURN(hr);
  2799. }
  2800. //
  2801. // Creates the services needed for remote boot.
  2802. //
  2803. HRESULT
  2804. CreateRemoteBootServices( HWND hDlg )
  2805. {
  2806. HRESULT hr = S_OK;
  2807. WCHAR szServiceName[ SMALL_BUFFER_SIZE ]; // TFTPD service name
  2808. WCHAR szText[ SMALL_BUFFER_SIZE ]; // general use
  2809. WCHAR szGroup[ SMALL_BUFFER_SIZE ];
  2810. SC_HANDLE schSystem; // Handle to System Services
  2811. SC_HANDLE schService; // Temp handle to new service
  2812. DWORD dw; // general use
  2813. LPARAM lRange;
  2814. HWND hProg = GetDlgItem( hDlg, IDC_P_METER );
  2815. HWND hOper = GetDlgItem( hDlg, IDC_S_OPERATION );
  2816. TraceFunc( "CreateRemoteBootServices( hDlg )\n" );
  2817. lRange = 0;
  2818. if ( !g_Options.fBINLServiceInstalled ) {
  2819. lRange++;
  2820. }
  2821. if ( !g_Options.fBINLSCPFound ) {
  2822. lRange++;
  2823. }
  2824. if ( !g_Options.fTFTPDServiceInstalled ) {
  2825. lRange++;
  2826. }
  2827. if ( !g_Options.fSISServiceInstalled ) {
  2828. lRange++;
  2829. }
  2830. lRange = MAKELPARAM( 0, lRange );
  2831. SendMessage( hProg, PBM_SETRANGE, 0, lRange );
  2832. SendMessage( hProg, PBM_SETPOS, 0, 0 );
  2833. //
  2834. // Display what we are doing in operations area
  2835. //
  2836. dw = LoadString( g_hinstance, IDS_STARTING_SERVICES, szText, ARRAYSIZE(szText));
  2837. Assert( dw );
  2838. SetWindowText( hOper, szText );
  2839. //
  2840. // Open System Services Manager
  2841. //
  2842. schSystem = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  2843. Assert( schSystem );
  2844. if ( !schSystem ) {
  2845. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2846. WCHAR szCaption[SMALL_BUFFER_SIZE];
  2847. dw = LoadString( g_hinstance, IDS_OPENING_SERVICE_MANAGER_TITLE, szCaption, SMALL_BUFFER_SIZE );
  2848. Assert( dw );
  2849. ErrorBox( hDlg, szCaption );
  2850. goto Cleanup;
  2851. }
  2852. //
  2853. // Create TFTPD service
  2854. //
  2855. if ( !g_Options.fTFTPDServiceInstalled ) {
  2856. dw = LoadString( g_hinstance, IDS_TFTPD_SERVICENAME, szServiceName, ARRAYSIZE(szServiceName));
  2857. Assert( dw );
  2858. dw = LoadString( g_hinstance, IDS_TFTPD, szText, ARRAYSIZE(szText));
  2859. Assert( dw );
  2860. SetWindowText( hOper, szServiceName );
  2861. dw = LoadString( g_hinstance, IDS_TFTPD_PATH, szText, ARRAYSIZE(szText));
  2862. Assert( dw );
  2863. schService = CreateService(
  2864. schSystem,
  2865. L"TFTPD",
  2866. szServiceName,
  2867. STANDARD_RIGHTS_REQUIRED | SERVICE_START,
  2868. SERVICE_WIN32_OWN_PROCESS,
  2869. SERVICE_AUTO_START,
  2870. SERVICE_ERROR_NORMAL,
  2871. szText,
  2872. NULL,
  2873. NULL,
  2874. L"Tcpip\0",
  2875. NULL,
  2876. NULL );
  2877. if ( !schService ) {
  2878. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2879. ErrorBox( hDlg, szServiceName );
  2880. } else {
  2881. CloseServiceHandle( schService );
  2882. }
  2883. SendMessage( hProg, PBM_DELTAPOS, 1 , 0 );
  2884. }
  2885. //
  2886. // Create BINLSVC
  2887. //
  2888. if ( !g_Options.fBINLServiceInstalled ) {
  2889. dw = LoadString( g_hinstance, IDS_BINL_SERVICENAME, szServiceName, ARRAYSIZE(szServiceName));
  2890. Assert( dw );
  2891. SetWindowText( hOper, szServiceName );
  2892. dw = LoadString( g_hinstance, IDS_BINL_PATH, szText, ARRAYSIZE(szText));
  2893. Assert( dw );
  2894. schService = CreateService(
  2895. schSystem,
  2896. L"BINLSVC",
  2897. szServiceName,
  2898. STANDARD_RIGHTS_REQUIRED | SERVICE_START,
  2899. SERVICE_WIN32_SHARE_PROCESS,
  2900. SERVICE_AUTO_START,
  2901. SERVICE_ERROR_NORMAL,
  2902. szText,
  2903. NULL,
  2904. NULL,
  2905. L"Tcpip\0LanmanServer\0",
  2906. NULL,
  2907. NULL );
  2908. if ( !schService ) {
  2909. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2910. ErrorBox( hDlg, szServiceName );
  2911. } else {
  2912. CloseServiceHandle( schService );
  2913. }
  2914. SendMessage( hProg, PBM_DELTAPOS, 1 , 0 );
  2915. }
  2916. //
  2917. // Create SIS
  2918. //
  2919. if ( !g_Options.fSISServiceInstalled ) {
  2920. dw = LoadString( g_hinstance, IDS_SIS_SERVICENAME, szServiceName, ARRAYSIZE(szServiceName));
  2921. Assert( dw );
  2922. SetWindowText( hOper, szServiceName );
  2923. dw = LoadString( g_hinstance, IDS_SIS_PATH, szText, ARRAYSIZE(szText));
  2924. Assert( dw );
  2925. dw = LoadString( g_hinstance, IDS_SIS_GROUP, szGroup, ARRAYSIZE(szGroup));
  2926. Assert( dw );
  2927. schService = CreateService(
  2928. schSystem,
  2929. L"SIS",
  2930. szServiceName,
  2931. STANDARD_RIGHTS_REQUIRED | SERVICE_START,
  2932. SERVICE_FILE_SYSTEM_DRIVER,
  2933. SERVICE_BOOT_START,
  2934. SERVICE_ERROR_NORMAL,
  2935. szText,
  2936. szGroup,
  2937. NULL,
  2938. NULL,
  2939. NULL,
  2940. NULL );
  2941. if ( !schService ) {
  2942. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2943. ErrorBox( hDlg, szServiceName );
  2944. } else {
  2945. CloseServiceHandle( schService );
  2946. }
  2947. SendMessage( hProg, PBM_DELTAPOS, 1 , 0 );
  2948. }
  2949. //
  2950. // Create SIS Groveler
  2951. //
  2952. if ( !g_Options.fSISGrovelerServiceInstalled ) {
  2953. dw = LoadString( g_hinstance, IDS_SISGROVELER_SERVICENAME, szServiceName, ARRAYSIZE(szServiceName));
  2954. Assert( dw );
  2955. SetWindowText( hOper, szServiceName );
  2956. dw = LoadString( g_hinstance, IDS_SISGROVELER_PATH, szText, ARRAYSIZE(szText));
  2957. Assert( dw );
  2958. dw = LoadString( g_hinstance, IDS_SISGROVELER_GROUP, szGroup, ARRAYSIZE(szGroup));
  2959. Assert( dw );
  2960. schService = CreateService(
  2961. schSystem,
  2962. L"Groveler",
  2963. szServiceName,
  2964. STANDARD_RIGHTS_REQUIRED | SERVICE_START,
  2965. SERVICE_WIN32_OWN_PROCESS,
  2966. SERVICE_AUTO_START,
  2967. SERVICE_ERROR_NORMAL,
  2968. szText,
  2969. NULL,
  2970. NULL,
  2971. L"SIS\0",
  2972. NULL,
  2973. NULL );
  2974. if ( !schService ) {
  2975. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  2976. ErrorBox( hDlg, szServiceName );
  2977. } else {
  2978. CloseServiceHandle( schService );
  2979. }
  2980. SendMessage( hProg, PBM_DELTAPOS, 1 , 0 );
  2981. }
  2982. //
  2983. // Create the BINL SCP
  2984. //
  2985. if ( !g_Options.fBINLSCPFound ) {
  2986. dw = LoadString( g_hinstance, IDS_BINL_SERVICECONTROLPOINT, szText, ARRAYSIZE(szText) );
  2987. Assert( dw );
  2988. SetWindowText( hOper, szText );
  2989. hr = CreateSCP( hDlg );
  2990. SendMessage( hProg, PBM_DELTAPOS, 1 , 0 );
  2991. }
  2992. Cleanup:
  2993. SetDlgItemText( hDlg, IDC_S_OPERATION, L"" );
  2994. HRETURN(hr);
  2995. }
  2996. //
  2997. // Reads the server's layout.inf file for disc name, tag file and
  2998. // optional sub-dir. All parameters are assumed to be MAX_PATH in
  2999. // size except the tag files which can only be 10.3 format.
  3000. //
  3001. HRESULT
  3002. RetrieveServerDiscInfo(
  3003. HWND hDlg,
  3004. LPWSTR pszDiscName,
  3005. LPWSTR pszTagFile,
  3006. LPWSTR pszSubDir )
  3007. {
  3008. TraceFunc("RetrieveServerDiscInfo()\n");
  3009. HRESULT hr = S_OK;
  3010. HINF hinf = INVALID_HANDLE_VALUE;
  3011. UINT uLineNum;
  3012. INFCONTEXT context;
  3013. WCHAR szSourcePath[ MAX_PATH ];
  3014. BOOL b;
  3015. if ( !GetEnvironmentVariable(L"windir", szSourcePath, ARRAYSIZE(szSourcePath)) )
  3016. {
  3017. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3018. ErrorBox( hDlg, szSourcePath );
  3019. goto Cleanup;
  3020. }
  3021. wcscat( szSourcePath, L"\\inf\\layout.inf" );
  3022. hinf = SetupOpenInfFile( szSourcePath, NULL, INF_STYLE_WIN4, &uLineNum);
  3023. if ( hinf == INVALID_HANDLE_VALUE ) {
  3024. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3025. ErrorBox( hDlg, szSourcePath );
  3026. goto Cleanup;
  3027. }
  3028. b = FALSE;
  3029. if ( g_Options.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ) {
  3030. b = SetupFindFirstLine( hinf, L"SourceDisksNames.x86", L"1", &context );
  3031. } else if ( g_Options.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ) {
  3032. b = SetupFindFirstLine( hinf, L"SourceDisksNames.ia64", L"1", &context );
  3033. }
  3034. if ( !b )
  3035. {
  3036. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3037. ErrorBox( hDlg, szSourcePath );
  3038. goto Cleanup;
  3039. }
  3040. if ( pszDiscName ) {
  3041. b = SetupGetStringField( &context, 1, pszDiscName, MAX_PATH, NULL );
  3042. if ( !b )
  3043. {
  3044. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3045. ErrorBox( hDlg, szSourcePath );
  3046. goto Cleanup;
  3047. }
  3048. }
  3049. if ( pszTagFile )
  3050. {
  3051. b = SetupGetStringField( &context, 2, pszTagFile, 14 /* 10.3 + NULL */, NULL );
  3052. if ( !b )
  3053. {
  3054. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3055. ErrorBox( hDlg, szSourcePath );
  3056. goto Cleanup;
  3057. }
  3058. }
  3059. if ( pszSubDir )
  3060. {
  3061. b = SetupGetStringField( &context, 4, pszSubDir, MAX_PATH, NULL );
  3062. if ( !b )
  3063. {
  3064. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3065. ErrorBox( hDlg, szSourcePath );
  3066. goto Cleanup;
  3067. }
  3068. }
  3069. Cleanup:
  3070. if ( hinf != INVALID_HANDLE_VALUE )
  3071. SetupCloseInfFile( hinf );
  3072. HRETURN(hr);
  3073. }
  3074. //
  3075. // Copies the files needed by the server from where the server
  3076. // was orginally installed from.
  3077. //
  3078. HRESULT
  3079. CopyServerFiles( HWND hDlg )
  3080. {
  3081. HRESULT hr = S_OK;
  3082. HSPFILEQ Queue = INVALID_HANDLE_VALUE;
  3083. WCHAR szSection[ SMALL_BUFFER_SIZE ];
  3084. HWND hProg = GetDlgItem( hDlg, IDC_P_METER );
  3085. DWORD dwCount = 0;
  3086. DWORD dw;
  3087. BOOL b;
  3088. UINT iResult;
  3089. WCHAR szServerDiscName[ MAX_PATH ] = { L'\0' };
  3090. MYCONTEXT MyContext;
  3091. INFCONTEXT context;
  3092. ZeroMemory( &MyContext, sizeof(MyContext) );
  3093. TraceFunc( "CopyServerFiles( hDlg )\n" );
  3094. Assert( g_Options.hinf != INVALID_HANDLE_VALUE );
  3095. if ( g_Options.hinf == INVALID_HANDLE_VALUE ) {
  3096. hr = E_FAIL; // need this handle!
  3097. goto Cleanup;
  3098. }
  3099. //
  3100. // Setup and display next section of dialog
  3101. //
  3102. SendMessage( hProg, PBM_SETRANGE, 0, MAKELPARAM(0, 5000 ));
  3103. SendMessage( hProg, PBM_SETPOS, 0, 0 );
  3104. //
  3105. // Ask for CD if any of the Services files are missing.
  3106. // Or if the System32\RemBoot directory is missing and we
  3107. // need the OS Chooser files (not screens).
  3108. //
  3109. if ( !g_Options.fBINLFilesFound
  3110. || !g_Options.fTFTPDFilesFound
  3111. || !g_Options.fSISFilesFound
  3112. || !g_Options.fSISGrovelerFilesFound
  3113. || !g_Options.fRegSrvDllsFilesFound
  3114. || ( !g_Options.fRemBootDirectory && !g_Options.fOSChooserInstalled ) ) {
  3115. WCHAR szSourcePath[ MAX_PATH ];
  3116. WCHAR szServerTagFile[ 14 ] = { L'\0' };
  3117. WCHAR szInsertMedia[ 64 ];
  3118. WCHAR szServerSubDir[ MAX_PATH ] = { L'\0' };
  3119. DebugMsg( "Queue and copy reminst files\n" );
  3120. //
  3121. // Ask user to check the CDROM to make sure the right CD is in the drive.
  3122. // We skip this if it was installed from a share.
  3123. //
  3124. szInsertMedia[63] = L'\0';
  3125. dw = LoadString( g_hinstance, IDS_INSERT_MEDIA, szInsertMedia, ARRAYSIZE(szInsertMedia) );
  3126. Assert( dw );
  3127. hr = RetrieveServerDiscInfo( hDlg, szServerDiscName, szServerTagFile, szServerSubDir );
  3128. // if it fails, try to proceed anyway to see if the user is smart enough
  3129. // to fix the problem.
  3130. iResult = SetupPromptForDisk( hDlg, // parent window of the dialog box
  3131. szInsertMedia, // optional, title of the dialog box
  3132. szServerDiscName, // optional, name of disk to insert
  3133. NULL, // optional, expected source path
  3134. szServerTagFile, // name of file needed
  3135. szServerTagFile, // optional, source media tag file
  3136. IDF_CHECKFIRST | IDF_NODETAILS | IDF_NOSKIP, // specifies dialog box behavior
  3137. szSourcePath, // receives the source location
  3138. MAX_PATH, // size of the supplied buffer
  3139. NULL ); // optional, buffer size needed
  3140. if ( iResult != DPROMPT_SUCCESS )
  3141. {
  3142. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3143. goto Cleanup;
  3144. }
  3145. szSection[SMALL_BUFFER_SIZE-1] = L'\0';
  3146. dw = LoadString( g_hinstance, IDS_INF_SECTION, szSection, ARRAYSIZE(szSection) );
  3147. Assert( dw );
  3148. //
  3149. // Create the Queue
  3150. //
  3151. Queue = SetupOpenFileQueue( );
  3152. //
  3153. // Add the files
  3154. //
  3155. b = SetupInstallFilesFromInfSection( g_Options.hinf,
  3156. NULL,
  3157. Queue,
  3158. szSection,
  3159. szSourcePath,
  3160. SP_COPY_WARNIFSKIP | SP_COPY_FORCE_NEWER
  3161. | SP_COPY_NEWER_ONLY ); // copy flags
  3162. Assert( b );
  3163. if ( !b ) {
  3164. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3165. ErrorBox( hDlg, szSection );
  3166. goto Cleanup;
  3167. }
  3168. //
  3169. // Add a section that is done during textmode setup
  3170. //
  3171. b = SetupQueueCopySection( Queue,
  3172. szSourcePath,
  3173. g_Options.hinf,
  3174. NULL,
  3175. L"REMINST.OtherSystemFiles",
  3176. SP_COPY_WARNIFSKIP | SP_COPY_FORCE_NEWER
  3177. | SP_COPY_NEWER_ONLY ); // copy flags
  3178. Assert( b );
  3179. if ( !b ) {
  3180. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3181. ErrorBox( hDlg, L"REMINST.OtherSystemFiles" );
  3182. goto Cleanup;
  3183. }
  3184. //
  3185. // This information will be passed to CopyFileCallback() as
  3186. // the Context.
  3187. //
  3188. MyContext.nToBeCopied = 12; // todo: generate this dynamically
  3189. MyContext.nCopied = 0;
  3190. MyContext.pContext = SetupInitDefaultQueueCallbackEx(NULL,(HWND)INVALID_HANDLE_VALUE,0,0,NULL);
  3191. MyContext.hProg = hProg;
  3192. MyContext.hOperation = GetDlgItem( hDlg, IDC_S_OPERATION );
  3193. MyContext.hDlg = hDlg;
  3194. MyContext.dwCopyingLength =
  3195. LoadString( g_hinstance, IDS_COPYING, MyContext.szCopyingString, ARRAYSIZE(MyContext.szCopyingString));
  3196. b = SetupCommitFileQueue( NULL, Queue, (PSP_FILE_CALLBACK) CopyFilesCallback, (PVOID) &MyContext );
  3197. if ( !b ) {
  3198. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3199. ErrorBox( hDlg, NULL );
  3200. }
  3201. SetupTermDefaultQueueCallback( MyContext.pContext );
  3202. ZeroMemory( &MyContext, sizeof(MyContext) );
  3203. SetupCloseFileQueue( Queue );
  3204. Queue = INVALID_HANDLE_VALUE;
  3205. // recheck
  3206. HRESULT hr2 = CheckInstallation( );
  3207. if ( FAILED(hr2) ) {
  3208. hr = THR( hr2 );
  3209. goto Cleanup;
  3210. }
  3211. // because of the recheck, this flag should be set
  3212. Assert( g_Options.fRemBootDirectory );
  3213. g_Options.fRemBootDirectory = TRUE;
  3214. }
  3215. //
  3216. // Move OS Chooser files to the IntelliMirror\OSChooser tree.
  3217. //
  3218. if ( !g_Options.fOSChooserInstalled
  3219. && g_Options.fRemBootDirectory ) {
  3220. DebugMsg( "Queue and copy os chooser files\n" );
  3221. Assert( g_Options.fIMirrorDirectory );
  3222. Assert( g_Options.fOSChooserDirectory );
  3223. b = SetupFindFirstLine( g_Options.hinf, L"OSChooser", NULL, &context );
  3224. AssertMsg( b, "Missing section?" );
  3225. if ( !b ) {
  3226. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3227. }
  3228. if ( szServerDiscName[0] == L'\0' )
  3229. {
  3230. hr = RetrieveServerDiscInfo( hDlg, szServerDiscName, NULL, NULL );
  3231. // if it fails, try to proceed anyway to see if the user is smart enough
  3232. // to fix the problem.
  3233. }
  3234. dwCount = 0;
  3235. //
  3236. // Create the Queue
  3237. //
  3238. Queue = SetupOpenFileQueue( );
  3239. while ( b )
  3240. {
  3241. WCHAR szSrcFile[ MAX_PATH ];
  3242. WCHAR szDestFile[ MAX_PATH ];
  3243. LPWSTR pszDest = NULL;
  3244. dw = SetupGetFieldCount( &context );
  3245. if ( dw > 1 ) {
  3246. b = SetupGetStringField( &context, 1, szDestFile, ARRAYSIZE(szDestFile) , NULL );
  3247. AssertMsg( b, "Missing field?" );
  3248. if ( b ) {
  3249. b = SetupGetStringField( &context, 2, szSrcFile, ARRAYSIZE(szSrcFile), NULL );
  3250. AssertMsg( b, "Missing field?" );
  3251. pszDest = szDestFile;
  3252. }
  3253. } else {
  3254. b = SetupGetStringField( &context, 1, szSrcFile, ARRAYSIZE(szSrcFile), NULL );
  3255. AssertMsg( b, "Missing field?" );
  3256. }
  3257. if ( !b ) {
  3258. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3259. goto SkipIt;
  3260. }
  3261. b = SetupQueueCopy( Queue,
  3262. g_Options.szRemBootDirectory,
  3263. NULL,
  3264. szSrcFile,
  3265. szServerDiscName,
  3266. NULL,
  3267. g_Options.szOSChooserPath,
  3268. pszDest,
  3269. SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER
  3270. | SP_COPY_WARNIFSKIP | SP_COPY_SOURCEPATH_ABSOLUTE );
  3271. if ( !b ) {
  3272. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3273. ErrorBox( NULL, szSrcFile );
  3274. goto SkipIt;
  3275. }
  3276. // increment file count
  3277. dwCount++;
  3278. SkipIt:
  3279. b = SetupFindNextLine( &context, &context );
  3280. }
  3281. b = SetupFindFirstLine( g_Options.hinf, L"OSChooser.NoOverwrite", NULL, &context );
  3282. AssertMsg( b, "Missing section?" );
  3283. if ( !b ) {
  3284. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3285. }
  3286. while ( b )
  3287. {
  3288. WCHAR szSrcFile[ MAX_PATH ];
  3289. WCHAR szDestFile[ MAX_PATH ];
  3290. LPWSTR pszDest = NULL;
  3291. dw = SetupGetFieldCount( &context );
  3292. if ( dw > 1 ) {
  3293. b = SetupGetStringField( &context, 1, szDestFile, ARRAYSIZE(szDestFile) , NULL );
  3294. AssertMsg( b, "Missing field?" );
  3295. if ( b ) {
  3296. b = SetupGetStringField( &context, 2, szSrcFile, ARRAYSIZE(szSrcFile) , NULL );
  3297. AssertMsg( b, "Missing field?" );
  3298. pszDest = szDestFile;
  3299. }
  3300. } else {
  3301. b = SetupGetStringField( &context, 1, szSrcFile, ARRAYSIZE(szSrcFile) , NULL );
  3302. AssertMsg( b, "Missing field?" );
  3303. }
  3304. if ( !b ) {
  3305. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3306. goto SkipNonCritical;
  3307. }
  3308. b = SetupQueueCopy( Queue,
  3309. g_Options.szRemBootDirectory,
  3310. NULL,
  3311. szSrcFile,
  3312. szServerDiscName,
  3313. NULL,
  3314. g_Options.szOSChooserPath,
  3315. pszDest,
  3316. SP_COPY_NOOVERWRITE
  3317. | SP_COPY_WARNIFSKIP
  3318. | SP_COPY_SOURCEPATH_ABSOLUTE );
  3319. if ( !b ) {
  3320. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3321. ErrorBox( NULL, szSrcFile );
  3322. goto SkipNonCritical;
  3323. }
  3324. // increment file count
  3325. dwCount++;
  3326. SkipNonCritical:
  3327. b = SetupFindNextLine( &context, &context );
  3328. }
  3329. //
  3330. // This information will be passed to CopyFileCallback() as
  3331. // the Context.
  3332. //
  3333. MyContext.nToBeCopied = dwCount;
  3334. MyContext.nCopied = 0;
  3335. MyContext.pContext = SetupInitDefaultQueueCallbackEx(NULL,(HWND)INVALID_HANDLE_VALUE,0,0,NULL);
  3336. MyContext.hProg = hProg;
  3337. MyContext.hDlg = hDlg;
  3338. MyContext.hOperation = GetDlgItem( hDlg, IDC_S_OPERATION );
  3339. MyContext.dwCopyingLength =
  3340. LoadString( g_hinstance, IDS_COPYING, MyContext.szCopyingString, ARRAYSIZE(MyContext.szCopyingString));
  3341. b = SetupCommitFileQueue( NULL, Queue, (PSP_FILE_CALLBACK) CopyFilesCallback, (PVOID) &MyContext );
  3342. if ( !b ) {
  3343. DWORD dwErr = GetLastError( );
  3344. hr = THR( HRESULT_FROM_WIN32( dwErr ) );
  3345. switch ( dwErr )
  3346. {
  3347. case ERROR_CANCELLED:
  3348. goto Cleanup;
  3349. break; // expected
  3350. default:
  3351. MessageBoxFromError( hDlg, NULL, dwErr );
  3352. goto Cleanup;
  3353. break;
  3354. }
  3355. }
  3356. }
  3357. Cleanup:
  3358. if ( MyContext.pContext )
  3359. SetupTermDefaultQueueCallback( MyContext.pContext );
  3360. if ( Queue != INVALID_HANDLE_VALUE )
  3361. SetupCloseFileQueue( Queue );
  3362. HRETURN(hr);
  3363. }
  3364. //
  3365. // CopyTemplateFiles( )
  3366. //
  3367. HRESULT
  3368. CopyTemplateFiles( HWND hDlg )
  3369. {
  3370. HRESULT hr = S_OK;
  3371. WCHAR sz[ SMALL_BUFFER_SIZE ];
  3372. WCHAR szSourcePath[ MAX_PATH ];
  3373. WCHAR szTemplatePath[ MAX_PATH ];
  3374. WCHAR szFileName[ MAX_PATH ];
  3375. BOOL fNotOverwrite;
  3376. BOOL b;
  3377. DWORD dw;
  3378. TraceFunc( "CopyTemplateFiles( ... )\n" );
  3379. dw = LoadString( g_hinstance, IDS_UPDATING_SIF_FILE, sz, ARRAYSIZE(sz) );
  3380. Assert( dw );
  3381. SetDlgItemText( hDlg, IDC_S_OPERATION, sz );
  3382. dw = LoadString( g_hinstance, IDS_DEFAULT_SIF, szFileName, ARRAYSIZE(szFileName) );
  3383. Assert( dw );
  3384. //
  3385. // Create the path "IntelliMirror\Setup\English\nt50.wks\i386\default.sif"
  3386. //
  3387. lstrcpyn( szSourcePath, g_Options.szInstallationPath, ARRAYSIZE(szSourcePath));
  3388. ConcatenatePaths( szSourcePath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szSourcePath));
  3389. ConcatenatePaths( szSourcePath, szFileName, ARRAYSIZE(szSourcePath));
  3390. Assert( wcslen( szSourcePath ) < ARRAYSIZE(szSourcePath) );
  3391. //
  3392. // Create the path "IntelliMirror\Setup\English\nt50.wks\i386\Templates"
  3393. //
  3394. lstrcpyn( szTemplatePath, g_Options.szInstallationPath, ARRAYSIZE(szTemplatePath));
  3395. ConcatenatePaths( szTemplatePath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szTemplatePath));
  3396. ConcatenatePaths( szTemplatePath, L"Templates", ARRAYSIZE(szTemplatePath));
  3397. Assert( wcslen( szTemplatePath ) < ARRAYSIZE(szTemplatePath) );
  3398. if ( 0xFFFFffff == GetFileAttributes( szTemplatePath ) ) {
  3399. b = CreateDirectory( szTemplatePath, NULL );
  3400. if ( !b ) {
  3401. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3402. ErrorBox( hDlg, szTemplatePath );
  3403. goto Error;
  3404. }
  3405. }
  3406. //
  3407. // Create the path "IntelliMirror\Setup\English\nt50.wks\i386\Templates\default.sif"
  3408. //
  3409. ConcatenatePaths( szTemplatePath, szFileName, ARRAYSIZE(szTemplatePath));
  3410. Assert( wcslen( szTemplatePath ) < ARRAYSIZE(szTemplatePath) );
  3411. DebugMsg( "Copying %s to %s...\n", szSourcePath, szTemplatePath );
  3412. fNotOverwrite = TRUE;
  3413. while ( hr == S_OK && !CopyFile( szSourcePath, szTemplatePath, fNotOverwrite) )
  3414. {
  3415. DWORD dwErr = GetLastError( );
  3416. switch (dwErr)
  3417. {
  3418. case ERROR_FILE_EXISTS:
  3419. {
  3420. dw = LoadString( g_hinstance, IDS_OVERWRITE_TEXT, sz, ARRAYSIZE(sz) );
  3421. Assert( dw );
  3422. if ( IDYES == MessageBox( hDlg, sz, szFileName, MB_YESNO ) )
  3423. {
  3424. fNotOverwrite = FALSE;
  3425. }
  3426. else
  3427. {
  3428. OPENFILENAME ofn;
  3429. dw = LoadString( g_hinstance, IDS_SAVE_SIF_TITLE, sz, ARRAYSIZE(sz) );
  3430. Assert( dw );
  3431. GetFileNameAgain:
  3432. memset( &ofn, 0, sizeof( ofn ) );
  3433. ofn.lStructSize = sizeof( ofn );
  3434. ofn.hwndOwner = hDlg;
  3435. ofn.hInstance = g_hinstance;
  3436. ofn.lpstrFilter = L"Unattended Setup Answer Files\0*.SIF\0\0";
  3437. ofn.lpstrFile = szTemplatePath;
  3438. ofn.nMaxFile = MAX_PATH;
  3439. ofn.lpstrInitialDir = szTemplatePath;
  3440. ofn.lpstrTitle = sz;
  3441. ofn.Flags = OFN_CREATEPROMPT |
  3442. OFN_NOCHANGEDIR |
  3443. OFN_NONETWORKBUTTON |
  3444. OFN_NOREADONLYRETURN |
  3445. OFN_OVERWRITEPROMPT |
  3446. OFN_PATHMUSTEXIST;
  3447. ofn.nFileOffset = (WORD)(lstrlen( szTemplatePath ) - lstrlen( szFileName ));
  3448. ofn.nFileExtension = (WORD)lstrlen( szTemplatePath ) - 3;
  3449. ofn.lpstrDefExt = L"SIF";
  3450. b = GetSaveFileName( &ofn );
  3451. if ( !b ) {
  3452. hr = S_FALSE;
  3453. }
  3454. // paranoid
  3455. Assert( wcslen(szTemplatePath) < ARRAYSIZE(szTemplatePath) );
  3456. Assert( wcslen(g_Options.szIntelliMirrorPath) < ARRAYSIZE(g_Options.szIntelliMirrorPath) );
  3457. if ( wcslen(szTemplatePath) - wcslen(g_Options.szIntelliMirrorPath) + 53 >= 128 )
  3458. {
  3459. MessageBoxFromStrings( hDlg, IDS_BOOTP_FILENAME_LENGTH_RESTRICTION_TITLE, IDS_BOOTP_FILENAME_LENGTH_RESTRICTION_TEXT, MB_OK );
  3460. goto GetFileNameAgain;
  3461. }
  3462. }
  3463. }
  3464. break;
  3465. default:
  3466. MessageBoxFromError( hDlg, szFileName, dwErr );
  3467. hr = S_FALSE;
  3468. }
  3469. }
  3470. if ( hr == S_OK )
  3471. {
  3472. //
  3473. // Need to add "Quotes" around the text
  3474. //
  3475. WCHAR szDescription[ REMOTE_INSTALL_MAX_DESCRIPTION_CHAR_COUNT + 2 ];
  3476. WCHAR szHelpText[ REMOTE_INSTALL_MAX_HELPTEXT_CHAR_COUNT + 2 ];
  3477. WCHAR szOSVersion[ 32 ];
  3478. wsprintf( szDescription, L"\"%s\"", g_Options.szDescription );
  3479. Assert( wcslen(szDescription) < ARRAYSIZE(szDescription) );
  3480. wsprintf( szHelpText, L"\"%s\"", g_Options.szHelpText );
  3481. Assert( wcslen(szHelpText) < ARRAYSIZE(szHelpText) );
  3482. wsprintf( szOSVersion, L"\"%s.%s (%d)\"", g_Options.szMajorVersion, g_Options.szMinorVersion, g_Options.dwBuildNumber );
  3483. Assert( wcslen(szOSVersion) < ARRAYSIZE(szOSVersion) );
  3484. WritePrivateProfileString( L"OSChooser",
  3485. L"Description",
  3486. szDescription,
  3487. szTemplatePath );
  3488. WritePrivateProfileString( L"OSChooser",
  3489. L"Help",
  3490. szHelpText,
  3491. szTemplatePath );
  3492. WritePrivateProfileString( L"OSChooser",
  3493. L"ImageType",
  3494. L"Flat",
  3495. szTemplatePath );
  3496. WritePrivateProfileString( L"OSChooser",
  3497. L"Version",
  3498. szOSVersion,
  3499. szTemplatePath );
  3500. }
  3501. Error:
  3502. HRETURN(hr);
  3503. }
  3504. HRESULT
  3505. GetSisVolumePath(
  3506. PWCHAR buffer,
  3507. DWORD sizeInChars //buffer size in characters
  3508. )
  3509. {
  3510. HRESULT hr = S_OK;
  3511. size_t ln;
  3512. Assert(g_Options.szIntelliMirrorPath[0] != NULL);
  3513. if (!GetVolumePathName( g_Options.szIntelliMirrorPath, buffer, sizeInChars )) {
  3514. hr = HRESULT_FROM_WIN32(GetLastError());
  3515. } else {
  3516. ln = wcslen(buffer);
  3517. if ((ln <= 0) || (buffer[ln-1] != L'\\')) {
  3518. hr = StringCchCat(buffer,sizeInChars,L"\\");
  3519. }
  3520. if (SUCCEEDED(hr)) {
  3521. hr = StringCchCat( buffer, sizeInChars, SISCommonStoreDir );
  3522. }
  3523. }
  3524. HRETURN(hr);
  3525. }
  3526. //
  3527. // Create Common Store Volume
  3528. //
  3529. HRESULT
  3530. CreateSISVolume( HWND hDlg )
  3531. {
  3532. HRESULT hr = E_FAIL;
  3533. WCHAR sz[ SMALL_BUFFER_SIZE ];
  3534. DWORD dw;
  3535. BOOL b;
  3536. WCHAR szSISPath[ MAX_PATH ];
  3537. HANDLE hMaxIndex;
  3538. WCHAR szIndexFilePath[ MAX_PATH ];
  3539. TraceFunc( "CreateSISVolume( hDlg )\n" );
  3540. //
  3541. // Get volume name
  3542. //
  3543. hr = GetSisVolumePath( szSISPath, sizeof(szSISPath)/sizeof(WCHAR));
  3544. if (FAILED(hr)) {
  3545. goto Error;
  3546. }
  3547. TraceMsg( TF_ALWAYS, "Creating %s...\n", szSISPath );
  3548. //
  3549. // We may have not known the IntelliMirror Drive/Directory
  3550. // until now and it was previously an SIS volume.
  3551. //
  3552. // If the directory already exists, force set the ACLs
  3553. //
  3554. if ( g_Options.fSISVolumeCreated ) {
  3555. //
  3556. // Identify what we are doing
  3557. //
  3558. dw = LoadString( g_hinstance, IDS_CORRECTING_SIS_ACLS, sz, ARRAYSIZE(sz) );
  3559. if (!dw) {
  3560. hr = THR(HRESULT_FROM_WIN32(GetLastError()));
  3561. goto Error;
  3562. }
  3563. SetDlgItemText( hDlg, IDC_S_OPERATION, sz );
  3564. //
  3565. // Set the correct ACLs
  3566. //
  3567. hr = SetSISCommonStoreSecurity( szSISPath );
  3568. hr = S_OK; //ignore if it fails
  3569. goto Error;
  3570. }
  3571. //
  3572. // Identify what we are doing
  3573. //
  3574. dw = LoadString( g_hinstance, IDS_CREATING_SIS_VOLUME, sz, ARRAYSIZE(sz) );
  3575. if (dw == 0) {
  3576. hr = THR(HRESULT_FROM_WIN32(GetLastError()));
  3577. goto Error;
  3578. }
  3579. SetDlgItemText( hDlg, IDC_S_OPERATION, sz );
  3580. //
  3581. // Create and zero SIS store
  3582. //
  3583. b = CreateDirectory( szSISPath, NULL );
  3584. if ( !b ) {
  3585. dw = GetLastError();
  3586. if (ERROR_ALREADY_EXISTS != dw) {
  3587. hr = THR( HRESULT_FROM_WIN32( dw ) );
  3588. ErrorBox( hDlg, szSISPath );
  3589. DebugMsg( "Cannot create Common Store directory." );
  3590. goto Error;
  3591. }
  3592. }
  3593. b = SetFileAttributes( szSISPath, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM );
  3594. if ( !b ) {
  3595. ErrorBox( hDlg, szSISPath );
  3596. DebugMsg( "Could not mark SIS Common Store directory as hidden and system. Error: %u\n", GetLastError() );
  3597. }
  3598. //
  3599. // Create the MaxIndex file.
  3600. //
  3601. _snwprintf( szIndexFilePath, ARRAYSIZE(szIndexFilePath), L"%s\\MaxIndex", szSISPath );
  3602. TERMINATE_BUFFER(szIndexFilePath);
  3603. hMaxIndex = CreateFile( szIndexFilePath,
  3604. GENERIC_READ | GENERIC_WRITE,
  3605. 0,
  3606. NULL,
  3607. CREATE_NEW,
  3608. FILE_ATTRIBUTE_NORMAL,
  3609. NULL);
  3610. if ( hMaxIndex == INVALID_HANDLE_VALUE ) {
  3611. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3612. ErrorBox( hDlg, szIndexFilePath );
  3613. DebugMsg( "Can't create %s.\n", szIndexFilePath );
  3614. goto Error;
  3615. } else {
  3616. DWORD bytesWritten;
  3617. INDEX maxIndex = 1;
  3618. if ( !WriteFile( hMaxIndex, &maxIndex, sizeof maxIndex, &bytesWritten, NULL )
  3619. || ( bytesWritten < sizeof maxIndex ) ) {
  3620. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3621. ErrorBox( hDlg, szIndexFilePath );
  3622. DebugMsg( "Can't write MaxIndex. Error: %u\n", GetLastError() );
  3623. CloseHandle( hMaxIndex );
  3624. goto Error;
  3625. } else {
  3626. CloseHandle( hMaxIndex );
  3627. TraceMsg( TF_ALWAYS, "MaxIndex of %lu written\n", maxIndex );
  3628. hr = S_OK;
  3629. }
  3630. }
  3631. //
  3632. // Set security information on the common store directory
  3633. //
  3634. hr = SetSISCommonStoreSecurity( szSISPath );
  3635. if (FAILED(hr)) {
  3636. MessageBoxFromError( hDlg, NULL, hr );
  3637. goto Error;
  3638. }
  3639. Error:
  3640. HRETURN(hr);
  3641. }
  3642. //
  3643. // This routine will setup the correct security on the given SIS common
  3644. // store directory
  3645. //
  3646. HRESULT
  3647. SetSISCommonStoreSecurity( PWCHAR szSISPath )
  3648. {
  3649. HRESULT hr = S_OK;
  3650. DWORD dw;
  3651. PACL newAcl = NULL;
  3652. PSID systemSid = NULL;
  3653. SID_IDENTIFIER_AUTHORITY ntSidAuthority = SECURITY_NT_AUTHORITY;
  3654. EXPLICIT_ACCESS explicitEntries;
  3655. SECURITY_DESCRIPTOR secDescriptor;
  3656. //
  3657. // setup SYSTEM sid
  3658. //
  3659. if (!AllocateAndInitializeSid( &ntSidAuthority,
  3660. 1,
  3661. SECURITY_LOCAL_SYSTEM_RID,
  3662. 0, 0, 0, 0, 0, 0, 0,
  3663. &systemSid ))
  3664. {
  3665. hr = THR(HRESULT_FROM_WIN32(GetLastError()));
  3666. goto Cleanup;
  3667. }
  3668. //
  3669. // Build a new ACL with SYSTEM access in it
  3670. //
  3671. // Set the access control information
  3672. //
  3673. explicitEntries.grfAccessPermissions = FILE_ALL_ACCESS;
  3674. explicitEntries.grfAccessMode = SET_ACCESS;
  3675. explicitEntries.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  3676. BuildTrusteeWithSid( &explicitEntries.Trustee, systemSid );
  3677. //
  3678. // Set the Acl with the ExplicitEntry rights
  3679. //
  3680. dw = SetEntriesInAcl( 1,
  3681. &explicitEntries,
  3682. NULL,
  3683. &newAcl );
  3684. if ( dw != ERROR_SUCCESS ) {
  3685. hr = THR(HRESULT_FROM_WIN32(dw));
  3686. goto Cleanup;
  3687. }
  3688. //
  3689. // Create the Security Descriptor
  3690. //
  3691. InitializeSecurityDescriptor( &secDescriptor, SECURITY_DESCRIPTOR_REVISION );
  3692. if (!SetSecurityDescriptorDacl( &secDescriptor, TRUE, newAcl, FALSE )) {
  3693. hr = THR(HRESULT_FROM_WIN32(GetLastError()));
  3694. goto Cleanup;
  3695. }
  3696. //
  3697. // SET security on the Directory
  3698. //
  3699. if (!SetFileSecurity(szSISPath,
  3700. DACL_SECURITY_INFORMATION,
  3701. &secDescriptor))
  3702. {
  3703. hr = THR(HRESULT_FROM_WIN32(GetLastError()));
  3704. goto Cleanup;
  3705. }
  3706. //
  3707. // Cleanup our variables
  3708. //
  3709. Cleanup:
  3710. if (systemSid) {
  3711. FreeSid( systemSid );
  3712. }
  3713. if (newAcl) {
  3714. LocalFree( newAcl );
  3715. }
  3716. return hr;
  3717. }
  3718. //
  3719. // This routine will check to see if the security of the common store
  3720. // directory is correct. If it is TRUE will be returned, else FALSE
  3721. // is returned.
  3722. //
  3723. BOOL
  3724. CheckSISCommonStoreSecurity( PWCHAR szSISPath )
  3725. {
  3726. DWORD dw;
  3727. BOOL retval = FALSE;
  3728. PSECURITY_DESCRIPTOR secDes = NULL;
  3729. PACL dacl;
  3730. PSID systemSid = NULL;
  3731. PACCESS_ALLOWED_ACE ace;
  3732. PACCESS_ALLOWED_ACE systemAce;
  3733. SID_IDENTIFIER_AUTHORITY ntSidAuthority = SECURITY_NT_AUTHORITY;
  3734. ULONG i;
  3735. //
  3736. // Get the current security settings of the "SIS Common Store" directory
  3737. //
  3738. dw = GetNamedSecurityInfo( szSISPath,
  3739. SE_FILE_OBJECT,
  3740. (DACL_SECURITY_INFORMATION |
  3741. OWNER_SECURITY_INFORMATION),
  3742. NULL,
  3743. NULL,
  3744. &dacl,
  3745. NULL,
  3746. &secDes );
  3747. if (dw != ERROR_SUCCESS) {
  3748. secDes = NULL;
  3749. goto Cleanup;
  3750. }
  3751. //
  3752. // setup SYSTEM sid
  3753. //
  3754. if (!AllocateAndInitializeSid( &ntSidAuthority,
  3755. 1,
  3756. SECURITY_LOCAL_SYSTEM_RID,
  3757. 0, 0, 0, 0, 0, 0, 0,
  3758. &systemSid ))
  3759. {
  3760. systemSid = NULL;
  3761. goto Cleanup;
  3762. }
  3763. //
  3764. // Make sure we have a valid ACL
  3765. //
  3766. if (!dacl ||
  3767. !IsValidAcl( dacl ))
  3768. {
  3769. goto Cleanup;
  3770. }
  3771. //
  3772. // Examine the ACE's inside the ACL, make sure there is ONLY a
  3773. // SYSTEM ACE. If there is any other ACE, reset things.
  3774. //
  3775. systemAce = NULL;
  3776. for (i=0; ; i++) {
  3777. if (!GetAce( dacl, i, (LPVOID *)&ace )) {
  3778. break;
  3779. }
  3780. if (ace->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
  3781. continue;
  3782. }
  3783. //
  3784. // If we find the SYSTEM sid, save it, if we find any other
  3785. // SID, flag we want to RESET things
  3786. //
  3787. if (EqualSid(((PSID)&ace->SidStart),systemSid)) {
  3788. systemAce = ace;
  3789. } else {
  3790. goto Cleanup;
  3791. }
  3792. }
  3793. //
  3794. // If no SYSTEM ACE was found, return FALSE.
  3795. //
  3796. if (!systemAce) {
  3797. goto Cleanup;
  3798. }
  3799. //
  3800. // We found the SYSTEM ace, verify it has proper inheritence.
  3801. // If not, return FALSE
  3802. //
  3803. if (!(systemAce->Header.AceFlags & OBJECT_INHERIT_ACE) ||
  3804. !(systemAce->Header.AceFlags & CONTAINER_INHERIT_ACE) ||
  3805. ((systemAce->Mask & STANDARD_RIGHTS_ALL) != STANDARD_RIGHTS_ALL))
  3806. {
  3807. goto Cleanup;
  3808. }
  3809. //
  3810. // Everything is fine, return "security valid" value
  3811. //
  3812. retval = TRUE;
  3813. Cleanup:
  3814. if (secDes) {
  3815. LocalFree( secDes );
  3816. }
  3817. if (systemSid) {
  3818. FreeSid( systemSid );
  3819. }
  3820. return retval;
  3821. }
  3822. //
  3823. // CopyScreenFiles( )
  3824. //
  3825. HRESULT
  3826. CopyScreenFiles( HWND hDlg )
  3827. {
  3828. HRESULT hr = S_OK;
  3829. WCHAR szText[ SMALL_BUFFER_SIZE ];
  3830. WCHAR szRembootPath[ MAX_PATH ];
  3831. WCHAR szScreenDirectory[ MAX_PATH ];
  3832. WCHAR szRemboot[ 14 ];
  3833. UINT uLineNum;
  3834. HINF hinf = INVALID_HANDLE_VALUE;
  3835. DWORD dwCount = 0;
  3836. DWORD dw;
  3837. BOOL b;
  3838. INFCONTEXT context;
  3839. HSPFILEQ Queue = INVALID_HANDLE_VALUE;
  3840. HWND hProg = GetDlgItem( hDlg, IDC_P_METER );
  3841. MYCONTEXT MyContext;
  3842. ZeroMemory( &MyContext, sizeof(MyContext) );
  3843. TraceFunc( "CopyScreenFiles( ... )\n" );
  3844. AssertMsg( !g_Options.fScreenLeaveAlone, "Should not have made it here with this flag set." );
  3845. SendMessage( hProg, PBM_SETRANGE, 0, MAKELPARAM(0, 5000 ));
  3846. SendMessage( hProg, PBM_SETPOS, 0, 0 );
  3847. szText[SMALL_BUFFER_SIZE-1] = L'\0';
  3848. dw = LoadString( g_hinstance, IDS_BUILDINGLIST, szText, ARRAYSIZE(szText));
  3849. Assert( dw );
  3850. SetDlgItemText( hDlg, IDC_S_OPERATION, szText );
  3851. szRemboot[13] = L'\0';
  3852. dw = LoadString( g_hinstance, IDS_REMBOOTINF, szRemboot, ARRAYSIZE(szRemboot) );
  3853. Assert( dw );
  3854. Assert( g_Options.fLanguageSet );
  3855. lstrcpyn( szRembootPath, g_Options.szInstallationPath, ARRAYSIZE(szRembootPath));
  3856. ConcatenatePaths( szRembootPath, g_Options.ProcessorArchitectureString, ARRAYSIZE(szRembootPath));
  3857. ConcatenatePaths( szRembootPath, szRemboot, ARRAYSIZE(szRembootPath));
  3858. Assert( wcslen( szRembootPath ) < ARRAYSIZE(szRembootPath) );
  3859. DebugMsg( "REMINST.INF: %s\n", szRembootPath );
  3860. lstrcpyn( szScreenDirectory, g_Options.szOSChooserPath, ARRAYSIZE(szScreenDirectory));
  3861. ConcatenatePaths( szScreenDirectory, g_Options.szLanguage, ARRAYSIZE(szScreenDirectory));
  3862. Assert( wcslen(szScreenDirectory) < ARRAYSIZE(szScreenDirectory) );
  3863. DebugMsg( "Destination: %s\n", szScreenDirectory );
  3864. hinf = SetupOpenInfFile( szRembootPath, NULL, INF_STYLE_WIN4, &uLineNum);
  3865. if ( hinf == INVALID_HANDLE_VALUE ) {
  3866. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3867. ErrorBox( hDlg, szRembootPath );
  3868. goto Cleanup;
  3869. }
  3870. Queue = SetupOpenFileQueue( );
  3871. b = SetupFindFirstLine( hinf, L"OSChooser Screens", NULL, &context );
  3872. if ( !b ) {
  3873. ErrorBox( hDlg, szRembootPath );
  3874. hr = THR(S_FALSE);
  3875. }
  3876. while ( b )
  3877. {
  3878. LPWSTR pszDest = NULL;
  3879. WCHAR szSrcPath[ MAX_PATH ];
  3880. WCHAR szDestPath[ MAX_PATH ];
  3881. dw = SetupGetFieldCount( &context );
  3882. if ( dw > 1 ) {
  3883. b = SetupGetStringField( &context, 1, szDestPath, ARRAYSIZE( szDestPath ), NULL );
  3884. AssertMsg( b, "REMINST: Missing field?" );
  3885. if ( b ) {
  3886. b = SetupGetStringField( &context, 2, szSrcPath, ARRAYSIZE(szSrcPath), NULL );
  3887. AssertMsg( b, "REMINST: Missing field?" );
  3888. pszDest = szDestPath;
  3889. }
  3890. } else {
  3891. b = SetupGetStringField( &context, 1, szSrcPath, ARRAYSIZE(szSrcPath), NULL );
  3892. AssertMsg( b, "REMINST: Missing field?" );
  3893. }
  3894. if ( !b ) {
  3895. hr = S_FALSE;
  3896. goto SkipIt;
  3897. }
  3898. if ( g_Options.fScreenSaveOld ) {
  3899. WCHAR szPath[ MAX_PATH ];
  3900. WCHAR szMovePath[ MAX_PATH ];
  3901. DWORD dwLen;
  3902. if ( pszDest ) {
  3903. lstrcpyn( szPath, szScreenDirectory, ARRAYSIZE( szPath ) );
  3904. ConcatenatePaths( szPath, pszDest, ARRAYSIZE( szPath ) );
  3905. } else {
  3906. lstrcpyn( szPath, szScreenDirectory, ARRAYSIZE( szPath ) );
  3907. ConcatenatePaths( szPath, szSrcPath, ARRAYSIZE( szPath ) );
  3908. }
  3909. // Rename to *.BAK
  3910. lstrcpyn( szMovePath, szPath, ARRAYSIZE(szMovePath) );
  3911. dwLen = lstrlen( szMovePath );
  3912. Assert( _wcsicmp( &szMovePath[ dwLen - 3 ], L"OSC" ) == 0 );
  3913. lstrcpyn( &szMovePath[ dwLen - 3 ], L"BAK", ARRAYSIZE(szMovePath) - dwLen - 3);
  3914. DebugMsg( "Renaming %s to %s...\n", szPath, szMovePath );
  3915. b = DeleteFile( szMovePath );
  3916. b = MoveFile( szPath, szMovePath );
  3917. if ( !b ) {
  3918. DWORD dwErr = GetLastError( );
  3919. switch ( dwErr )
  3920. {
  3921. #if 0 // blast over files
  3922. case ERROR_FILE_EXISTS:
  3923. if ( !fWarning ) {
  3924. MessageBoxFromStrings( hDlg,
  3925. IDS_BACKUPSCREENFILEEXISTS_CAPTION,
  3926. IDS_BACKUPSCREENFILEEXISTS_TEXT,
  3927. MB_OK );
  3928. fWarning = TRUE;
  3929. }
  3930. #endif
  3931. case ERROR_FILE_NOT_FOUND:
  3932. break; // ignore this error
  3933. // It is possible that the user deleted the source files (old OSCs).
  3934. default:
  3935. MessageBoxFromError( hDlg, NULL, dwErr );
  3936. break;
  3937. }
  3938. }
  3939. }
  3940. b = SetupQueueCopy( Queue,
  3941. g_Options.szInstallationPath,
  3942. g_Options.ProcessorArchitectureString,
  3943. szSrcPath,
  3944. NULL,
  3945. NULL,
  3946. szScreenDirectory,
  3947. pszDest,
  3948. g_Options.fScreenOverwrite ?
  3949. SP_COPY_FORCE_NEWER | SP_COPY_WARNIFSKIP :
  3950. SP_COPY_NOOVERWRITE | SP_COPY_WARNIFSKIP );
  3951. if ( !b ) {
  3952. ErrorBox( hDlg, szSrcPath );
  3953. hr = THR(S_FALSE);
  3954. goto SkipIt;
  3955. }
  3956. dwCount++;
  3957. SkipIt:
  3958. b = SetupFindNextLine( &context, &context );
  3959. }
  3960. //
  3961. // This information will be passed to CopyFileCallback() as
  3962. // the Context.
  3963. //
  3964. MyContext.nToBeCopied = dwCount;
  3965. MyContext.nCopied = 0;
  3966. MyContext.pContext = SetupInitDefaultQueueCallbackEx(NULL,(HWND)INVALID_HANDLE_VALUE,0,0,NULL);
  3967. MyContext.hProg = hProg;
  3968. MyContext.hOperation = GetDlgItem( hDlg, IDC_S_OPERATION );
  3969. MyContext.hDlg = hDlg;
  3970. MyContext.fQuiet = FALSE;
  3971. MyContext.dwCopyingLength =
  3972. LoadString( g_hinstance, IDS_COPYING, MyContext.szCopyingString, ARRAYSIZE(MyContext.szCopyingString));
  3973. Assert(MyContext.dwCopyingLength);
  3974. //
  3975. // Start copying
  3976. //
  3977. if ( dwCount != 0 )
  3978. {
  3979. b = SetupCommitFileQueue( NULL,
  3980. Queue,
  3981. (PSP_FILE_CALLBACK) CopyFilesCallback,
  3982. (PVOID) &MyContext );
  3983. if ( !b ) {
  3984. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  3985. ErrorBox( hDlg, NULL );
  3986. goto Cleanup;
  3987. }
  3988. }
  3989. Cleanup:
  3990. SendMessage( hProg, PBM_SETPOS, 5000, 0 );
  3991. SetDlgItemText( hDlg, IDC_S_OPERATION, L"" );
  3992. if ( MyContext.pContext )
  3993. SetupTermDefaultQueueCallback( MyContext.pContext );
  3994. if ( Queue != INVALID_HANDLE_VALUE )
  3995. SetupCloseFileQueue( Queue );
  3996. if ( hinf != INVALID_HANDLE_VALUE )
  3997. SetupCloseInfFile( hinf );
  3998. HRETURN( hr );
  3999. }
  4000. BOOLEAN
  4001. CALLBACK
  4002. FixLoginOSC(
  4003. PWSTR FileName
  4004. )
  4005. /*++
  4006. Routine Description:
  4007. This function will open the specified login.osc file and add
  4008. in the ntlmv2 flags.
  4009. Arguments:
  4010. FileName - Full path specifying location of login.osc file.
  4011. Return Value:
  4012. BOOLEAN specifiying success.
  4013. --*/
  4014. {
  4015. PCHAR Buffer = NULL;
  4016. PCHAR Buffer2 = NULL;
  4017. PCHAR p = NULL;
  4018. ULONG CurrentFileSize = 0;
  4019. ULONG BytesRead = 0;
  4020. ULONG i = 0;
  4021. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  4022. BOOLEAN RetValue = TRUE;
  4023. //
  4024. // Open the file and read it in.
  4025. //
  4026. if( !FileName ) {
  4027. RetValue = FALSE;
  4028. goto FixLoginOSCExit;
  4029. }
  4030. FileHandle = CreateFile( FileName,
  4031. GENERIC_READ | GENERIC_WRITE,
  4032. FILE_SHARE_READ,
  4033. NULL,
  4034. OPEN_EXISTING,
  4035. 0,
  4036. NULL );
  4037. if( FileHandle == INVALID_HANDLE_VALUE ) {
  4038. RetValue = FALSE;
  4039. goto FixLoginOSCExit;
  4040. }
  4041. CurrentFileSize = GetFileSize( FileHandle, NULL );
  4042. if( CurrentFileSize == (DWORD)(-1) ) {
  4043. RetValue = FALSE;
  4044. goto FixLoginOSCExit;
  4045. }
  4046. Buffer = (PCHAR)TraceAlloc(LPTR, CurrentFileSize + 3 );
  4047. if( Buffer == NULL ) {
  4048. RetValue = FALSE;
  4049. goto FixLoginOSCExit;
  4050. }
  4051. RetValue = (BOOLEAN)ReadFile(FileHandle,Buffer,CurrentFileSize,&BytesRead,NULL);
  4052. if( !RetValue ) {
  4053. goto FixLoginOSCExit;
  4054. }
  4055. //
  4056. // We now have the file up in memory. Go walk through our
  4057. // data structure and operate on the buffer.
  4058. //
  4059. //
  4060. // Walk through our data structure and take
  4061. // care of deleting any of the lines we're asked to.
  4062. //
  4063. for( i = 0; i < (sizeof(LoginOSCPatches)/sizeof(LoginOSCPatches[0])); i++ ) {
  4064. if( LoginOSCPatches[i].AddString == FALSE ) {
  4065. //
  4066. // This is a delete operation.
  4067. //
  4068. //
  4069. // Find the tag that specifies the start of our
  4070. // specified section.
  4071. //
  4072. p = Buffer;
  4073. CurrentFileSize = (ULONG)strlen(Buffer);
  4074. while( (p < (Buffer + CurrentFileSize - strlen(LoginOSCPatches[i].SectionStartTag))) &&
  4075. (_strnicmp(p, LoginOSCPatches[i].SectionStartTag, strlen(LoginOSCPatches[i].SectionStartTag))) ) {
  4076. p++;
  4077. }
  4078. // make sure we found the tag.
  4079. if( _strnicmp(p, LoginOSCPatches[i].SectionStartTag, strlen(LoginOSCPatches[i].SectionStartTag)) ) {
  4080. // nope.
  4081. continue;
  4082. }
  4083. //
  4084. // Look for the specified string.
  4085. //
  4086. while(
  4087. // make sure we don't walk off the end of our buffer.
  4088. (p < (Buffer + CurrentFileSize - strlen(LoginOSCPatches[i].TargetString))) &&
  4089. // make sure we don't walk off the end of our section.
  4090. _strnicmp(p, LoginOSCPatches[i].SectionEndTag, strlen(LoginOSCPatches[i].SectionEndTag)) &&
  4091. // see if we actually found our target string.
  4092. _strnicmp(p, LoginOSCPatches[i].TargetString, strlen(LoginOSCPatches[i].TargetString)) ) {
  4093. p++;
  4094. }
  4095. //
  4096. // Three cases to consider here:
  4097. // 1. p points to our string. Here we must remove our string.
  4098. // from the buffer.
  4099. // 2. p points to the closing tag, meaning we didn't find our string.
  4100. // We do nothing here.
  4101. // 3. p points to the end of the buffer, meaning we never found
  4102. // our close block, which is invalid, but it means we do nothing.
  4103. //
  4104. // So all we really care about is case 1...
  4105. //
  4106. if( !_strnicmp(p, LoginOSCPatches[i].TargetString, strlen(LoginOSCPatches[i].TargetString)) ) {
  4107. //
  4108. // Here, we just copy the buffer as it exists after our string, right ontop of our
  4109. // string.
  4110. //
  4111. //
  4112. // Make sure that if we're dependent on any other entry having been
  4113. // completed successfully, we actually go check that that entry
  4114. // did indeed complete successfully.
  4115. //
  4116. if( (LoginOSCPatches[i].DependingEntry == (-1)) ||
  4117. ( (LoginOSCPatches[i].DependingEntry < ARRAYSIZE(LoginOSCPatches)) &&
  4118. (LoginOSCPatches[LoginOSCPatches[i].DependingEntry].OperationCompletedSuccessfully) ) ) {
  4119. strcpy( p, p+strlen(LoginOSCPatches[i].TargetString) );
  4120. //
  4121. // Remember that we did this one.
  4122. //
  4123. LoginOSCPatches[i].OperationCompletedSuccessfully = TRUE;
  4124. }
  4125. }
  4126. }
  4127. }
  4128. //
  4129. // Walk through our data structure and take
  4130. // care of adding any of the lines we're asked to.
  4131. //
  4132. for( i = 0; i < (sizeof(LoginOSCPatches)/sizeof(LoginOSCPatches[0])); i++ ) {
  4133. if( LoginOSCPatches[i].AddString == TRUE ) {
  4134. //
  4135. // This is an add operation.
  4136. //
  4137. //
  4138. // Find the tag that specifies the start of our
  4139. // specified section.
  4140. //
  4141. p = Buffer;
  4142. CurrentFileSize = (ULONG)strlen(Buffer);
  4143. while( (p < (Buffer + CurrentFileSize - strlen(LoginOSCPatches[i].SectionStartTag))) &&
  4144. (_strnicmp(p, LoginOSCPatches[i].SectionStartTag, strlen(LoginOSCPatches[i].SectionStartTag))) ) {
  4145. p++;
  4146. }
  4147. // make sure we found the tag.
  4148. if( _strnicmp(p, LoginOSCPatches[i].SectionStartTag, strlen(LoginOSCPatches[i].SectionStartTag)) ) {
  4149. // nope.
  4150. continue;
  4151. }
  4152. //
  4153. // Look for the specified string.
  4154. //
  4155. while(
  4156. // make sure we don't walk off the end of our buffer.
  4157. (p < (Buffer + CurrentFileSize - strlen(LoginOSCPatches[i].TargetString))) &&
  4158. // make sure we don't walk off the end of our section.
  4159. _strnicmp(p, LoginOSCPatches[i].SectionEndTag, strlen(LoginOSCPatches[i].SectionEndTag)) &&
  4160. // see if we actually found our target string.
  4161. _strnicmp(p, LoginOSCPatches[i].TargetString, strlen(LoginOSCPatches[i].TargetString)) ) {
  4162. p++;
  4163. }
  4164. //
  4165. // Three cases to consider here:
  4166. // 1. p points to our string. This means our string already
  4167. // exists, so we do nothing.
  4168. // 2. p points to the closing tag, meaning we didn't find our string.
  4169. // This means we must add our string right here.
  4170. // 3. p points to the end of the buffer, meaning we never found
  4171. // our close block, which is invalid, but it means we do nothing.
  4172. //
  4173. // So all we really care about is case 2...
  4174. //
  4175. if( !_strnicmp(p, LoginOSCPatches[i].SectionEndTag, strlen(LoginOSCPatches[i].SectionEndTag)) ) {
  4176. //
  4177. // Make sure that if we're dependent on any other entry having been
  4178. // completed successfully, we actually go check that that entry
  4179. // did indeed complete successfully.
  4180. //
  4181. if( (LoginOSCPatches[i].DependingEntry == (-1)) ||
  4182. ( (LoginOSCPatches[i].DependingEntry < ARRAYSIZE(LoginOSCPatches)) &&
  4183. (LoginOSCPatches[LoginOSCPatches[i].DependingEntry].OperationCompletedSuccessfully) ) ) {
  4184. // Alloc a buffer big enough for our additional string.
  4185. Buffer2 = (PCHAR)TraceAlloc( LPTR,
  4186. CurrentFileSize + 3 +
  4187. (DWORD)strlen(LoginOSCPatches[i].TargetString) + 3); // 2 for \r\n, 1 for null
  4188. if( !Buffer2 ) {
  4189. RetValue = FALSE;
  4190. goto FixLoginOSCExit;
  4191. }
  4192. // insert our new string.
  4193. *p = '\0';
  4194. strcpy( Buffer2, Buffer );
  4195. strcat( Buffer2, LoginOSCPatches[i].TargetString );
  4196. strcat( Buffer2, "\r\n" );
  4197. *p = LoginOSCPatches[i].SectionEndTag[0];
  4198. strcat( Buffer2, p );
  4199. //
  4200. // Buffer2 now contains our fixed up file with
  4201. // the new entry. Realloc Buffer and copy in
  4202. // the contents of Buffer2, then free Buffer2.
  4203. //
  4204. TraceFree( Buffer );
  4205. Buffer = (PCHAR)TraceAlloc(LPTR, (DWORD)strlen(Buffer2)+2);
  4206. if( !Buffer ) {
  4207. RetValue = FALSE;
  4208. goto FixLoginOSCExit;
  4209. }
  4210. strcpy( Buffer, Buffer2 );
  4211. TraceFree( Buffer2 );
  4212. Buffer2 = NULL;
  4213. //
  4214. // Remember that we did this one.
  4215. //
  4216. LoginOSCPatches[i].OperationCompletedSuccessfully = TRUE;
  4217. }
  4218. }
  4219. }
  4220. }
  4221. //
  4222. // re-write our file with the new Buffer.
  4223. //
  4224. SetFilePointer(FileHandle, 0, NULL, FILE_BEGIN);
  4225. WriteFile( FileHandle,
  4226. Buffer,
  4227. (DWORD)strlen(Buffer),
  4228. &BytesRead,
  4229. NULL );
  4230. SetEndOfFile( FileHandle );
  4231. FixLoginOSCExit:
  4232. if( FileHandle != INVALID_HANDLE_VALUE ) {
  4233. CloseHandle( FileHandle );
  4234. }
  4235. if( Buffer != NULL ) {
  4236. TraceFree( Buffer );
  4237. }
  4238. if( Buffer2 != NULL ) {
  4239. TraceFree( Buffer2 );
  4240. }
  4241. return RetValue;
  4242. }
  4243. HRESULT
  4244. EnumAndOperate(
  4245. PWSTR pszDirName,
  4246. PWSTR pszTargetFile,
  4247. POPERATECALLBACK FileOperateCallback
  4248. )
  4249. /*++
  4250. Routine Description:
  4251. Recursively searches a directory for any instances of the specified
  4252. file. If 'file' is found, the specified callback is called.
  4253. Arguments:
  4254. pszDirName - Root directory to start searching.
  4255. pszTargetFile - File to be searched for.
  4256. FileOperateCallback - Function to be called if pszTargetFile is found.
  4257. Return Value:
  4258. HRESULT indicating outcome.
  4259. --*/
  4260. {
  4261. WIN32_FIND_DATA FindData;
  4262. HANDLE hFindData = INVALID_HANDLE_VALUE;
  4263. PWCHAR pOrigDirName = pszDirName + wcslen(pszDirName);
  4264. ConcatenatePaths( pszDirName, L"*", MAX_PATH );
  4265. hFindData = FindFirstFile( pszDirName, &FindData );
  4266. if( hFindData != INVALID_HANDLE_VALUE ) {
  4267. do {
  4268. if( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  4269. if( wcscmp(FindData.cFileName, L".") &&
  4270. wcscmp(FindData.cFileName, L"..") ) {
  4271. // get rid of the \* on the end of the path and
  4272. // append our new directory name.
  4273. *pOrigDirName = L'\0';
  4274. ConcatenatePaths( pszDirName, FindData.cFileName, MAX_PATH );
  4275. EnumAndOperate( pszDirName,
  4276. pszTargetFile,
  4277. FileOperateCallback );
  4278. *pOrigDirName = L'\0';
  4279. }
  4280. } else {
  4281. if( !_wcsicmp(pszTargetFile,FindData.cFileName) ) {
  4282. *pOrigDirName = L'\0';
  4283. ConcatenatePaths( pszDirName, FindData.cFileName, MAX_PATH );
  4284. FileOperateCallback( pszDirName );
  4285. *pOrigDirName = L'\0';
  4286. }
  4287. }
  4288. } while ( FindNextFile( hFindData, &FindData ) );
  4289. }
  4290. return( S_OK );
  4291. }
  4292. //
  4293. // UpdateRemoteInstallTree( )
  4294. //
  4295. HRESULT
  4296. UpdateRemoteInstallTree( )
  4297. {
  4298. TraceFunc( "UpdateRemoteInstallTree( )\n" );
  4299. HRESULT hr = S_OK;
  4300. HKEY hkey;
  4301. DWORD dw;
  4302. BOOL b;
  4303. HINF hinf = INVALID_HANDLE_VALUE;
  4304. WCHAR szServerRemBootInfPath[ MAX_PATH ];
  4305. WCHAR szRemInstSetupPath[ MAX_PATH ];
  4306. WCHAR szRemoteInstallPath[ MAX_PATH ];
  4307. WCHAR szPath[ MAX_PATH ];
  4308. UINT uLineNum;
  4309. INFCONTEXT context;
  4310. SECURITY_ATTRIBUTES sa;
  4311. PWSTR EndOfOriginalszRemoteInstallPath = NULL;
  4312. //
  4313. // Try finding TFTPD's regkey to find the IntelliMirror Directory
  4314. //
  4315. szPath[MAX_PATH-1] = L'\0';
  4316. dw = LoadString( g_hinstance, IDS_TFTPD_SERVICE_PARAMETERS, szPath, ARRAYSIZE( szPath ));
  4317. Assert( dw );
  4318. if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  4319. szPath,
  4320. 0, // options
  4321. KEY_QUERY_VALUE,
  4322. &hkey ) ) {
  4323. ULONG l;
  4324. DWORD dwType;
  4325. LONG lErr;
  4326. l = sizeof(szRemoteInstallPath);
  4327. lErr = RegQueryValueEx( hkey,
  4328. L"Directory",
  4329. 0, // reserved
  4330. &dwType,
  4331. (LPBYTE) szRemoteInstallPath,
  4332. &l );
  4333. if ( lErr == ERROR_SUCCESS ) {
  4334. DebugMsg( "Found TFTPD's Directory regkey: %s\n", szRemoteInstallPath );
  4335. // Remember where our original remote install path ends so we can
  4336. // write a NULL there and get back our original path later on.
  4337. EndOfOriginalszRemoteInstallPath = szRemoteInstallPath + wcslen(szRemoteInstallPath);
  4338. // now append "OSChooser"
  4339. wcscat( szRemoteInstallPath, L"\\OSChooser" );
  4340. if ( 0xFFFFffff == GetFileAttributes( szRemoteInstallPath ) ) {
  4341. DebugMsg( "%s - directory doesn't exist.\n", szRemoteInstallPath );
  4342. hr = S_FALSE;
  4343. }
  4344. } else {
  4345. hr = S_FALSE;
  4346. }
  4347. RegCloseKey( hkey );
  4348. }
  4349. else
  4350. {
  4351. hr = S_FALSE;
  4352. }
  4353. if ( hr == S_OK )
  4354. {
  4355. // make x:\winnt
  4356. dw = ExpandEnvironmentStrings( TEXT("%SystemRoot%"), szServerRemBootInfPath, ARRAYSIZE( szServerRemBootInfPath ));
  4357. Assert( dw );
  4358. // make x:\winnt\system32
  4359. ConcatenatePaths( szServerRemBootInfPath, L"\\System32\\", ARRAYSIZE(szServerRemBootInfPath) );
  4360. lstrcpyn( szRemInstSetupPath, szServerRemBootInfPath, ARRAYSIZE(szRemInstSetupPath) );
  4361. // make x:\winnt\system32\reminst.inf
  4362. dw = lstrlen( szServerRemBootInfPath );
  4363. dw = LoadString( g_hinstance, IDS_REMBOOTINF, &szServerRemBootInfPath[dw], ARRAYSIZE( szServerRemBootInfPath ) - dw );
  4364. Assert( dw );
  4365. // make x:\winnt\system32\reminst
  4366. ConcatenatePaths( szRemInstSetupPath, L"reminst", ARRAYSIZE(szRemInstSetupPath) );
  4367. DebugMsg( "RemBoot.INF Path: %s\n", szServerRemBootInfPath );
  4368. DebugMsg( "RemInst Setup Path: %s\n", szRemInstSetupPath );
  4369. hinf = SetupOpenInfFile( szServerRemBootInfPath, NULL, INF_STYLE_WIN4, &uLineNum);
  4370. if ( hinf != INVALID_HANDLE_VALUE ) {
  4371. b = SetupFindFirstLine( hinf, L"OSChooser", NULL, &context );
  4372. AssertMsg( b, "Missing section?" );
  4373. if ( !b ) {
  4374. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  4375. }
  4376. } else {
  4377. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  4378. }
  4379. }
  4380. if ( hr == S_OK )
  4381. {
  4382. HSPFILEQ Queue;
  4383. //
  4384. // Create the Queue
  4385. //
  4386. Queue = SetupOpenFileQueue( );
  4387. b = TRUE;
  4388. while ( b )
  4389. {
  4390. WCHAR szSrcFile[ MAX_PATH ];
  4391. WCHAR szDestFile[ MAX_PATH ];
  4392. LPWSTR pszDest = NULL;
  4393. dw = SetupGetFieldCount( &context );
  4394. if ( dw > 1 ) {
  4395. b = SetupGetStringField( &context, 1, szDestFile, ARRAYSIZE(szDestFile), NULL );
  4396. AssertMsg( b, "Missing field?" );
  4397. if ( b ) {
  4398. b = SetupGetStringField( &context, 2, szSrcFile, ARRAYSIZE(szSrcFile), NULL );
  4399. AssertMsg( b, "Missing field?" );
  4400. pszDest = szDestFile;
  4401. }
  4402. } else {
  4403. b = SetupGetStringField( &context, 1, szSrcFile, ARRAYSIZE(szSrcFile), NULL );
  4404. AssertMsg( b, "Missing field?" );
  4405. }
  4406. if ( !b ) {
  4407. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  4408. goto SkipIt;
  4409. }
  4410. b = SetupQueueCopy( Queue,
  4411. szRemInstSetupPath,
  4412. NULL,
  4413. szSrcFile,
  4414. NULL,
  4415. NULL,
  4416. szRemoteInstallPath,
  4417. pszDest,
  4418. SP_COPY_NEWER | SP_COPY_FORCE_NEWER
  4419. | SP_COPY_WARNIFSKIP | SP_COPY_SOURCEPATH_ABSOLUTE );
  4420. if ( !b ) {
  4421. THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  4422. }
  4423. SkipIt:
  4424. b = SetupFindNextLine( &context, &context );
  4425. }
  4426. b = SetupCommitFileQueue( NULL,
  4427. Queue,
  4428. SetupDefaultQueueCallback,
  4429. SetupInitDefaultQueueCallbackEx(NULL,(HWND)INVALID_HANDLE_VALUE,0,0,NULL) );
  4430. if ( !b ) {
  4431. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  4432. }
  4433. SetupCloseFileQueue( Queue );
  4434. }
  4435. if ( hinf != INVALID_HANDLE_VALUE ) {
  4436. SetupCloseInfFile( hinf );
  4437. }
  4438. //
  4439. //
  4440. // Fix ACLs on the reminst sharepoint.
  4441. //
  4442. //
  4443. //
  4444. // Create a security descriptor based on the ACLs
  4445. // defined in REMINSTszSecurityDescriptor.
  4446. //
  4447. RtlZeroMemory( &sa, sizeof(SECURITY_ATTRIBUTES) );
  4448. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  4449. sa.bInheritHandle = TRUE;
  4450. b = ConvertStringSecurityDescriptorToSecurityDescriptor( REMINSTszSecurityDescriptor,
  4451. SDDL_REVISION_1,
  4452. &(sa.lpSecurityDescriptor),
  4453. NULL );
  4454. //
  4455. // Fix up szRemoteInstallPath. He's got L"\\OSChooser"
  4456. // concatenated, so we need to get rid of that part
  4457. // of the path.
  4458. //
  4459. if( EndOfOriginalszRemoteInstallPath != NULL ) {
  4460. *EndOfOriginalszRemoteInstallPath = L'\0';
  4461. }
  4462. if( !b ) {
  4463. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  4464. } else {
  4465. //
  4466. // Go apply our security descriptor to the d:\reminst sharepoint.
  4467. //
  4468. dw = ApplyDaclToFileDirectory( szRemoteInstallPath,
  4469. (SECURITY_DESCRIPTOR_RELATIVE *)(sa.lpSecurityDescriptor) );
  4470. LocalFree(sa.lpSecurityDescriptor);
  4471. if( dw != ERROR_SUCCESS ) {
  4472. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  4473. }
  4474. }
  4475. HRETURN( hr );
  4476. }