Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4468 lines
110 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. utils.c
  5. Abstract:
  6. Utilitaries for winnt32.
  7. Author:
  8. Revision History:
  9. Ovidiu Temereanca (ovidiut) 24-Jul-2000
  10. --*/
  11. #include "precomp.h"
  12. #include <mbstring.h>
  13. #pragma hdrstop
  14. VOID
  15. MyWinHelp(
  16. IN HWND Window,
  17. IN UINT Command,
  18. IN ULONG_PTR Data
  19. )
  20. {
  21. TCHAR Buffer[2*MAX_PATH];
  22. LPTSTR p;
  23. HANDLE FindHandle;
  24. BOOL b;
  25. WIN32_FIND_DATA FindData;
  26. LPCTSTR HelpFileName = TEXT("winnt32.hlp");
  27. //
  28. // The likely scenario is that a user invokes winnt32 from
  29. // a network share. We'll expect the help file to be there too.
  30. //
  31. b = FALSE;
  32. if(GetModuleFileName(NULL,Buffer,sizeof(Buffer)/sizeof(TCHAR))
  33. && (p = _tcsrchr(Buffer,TEXT('\\'))))
  34. {
  35. lstrcpy(p+1,HelpFileName);
  36. //
  37. // See whether the help file is there. If so, use it.
  38. //
  39. FindHandle = FindFirstFile(Buffer,&FindData);
  40. if(FindHandle != INVALID_HANDLE_VALUE) {
  41. FindClose(FindHandle);
  42. b = WinHelp(Window,Buffer,Command,Data);
  43. }
  44. }
  45. if(!b) {
  46. //
  47. // Try just the base help file name.
  48. //
  49. b = WinHelp(Window,HelpFileName,Command,Data);
  50. }
  51. if(!b) {
  52. //
  53. // Tell user.
  54. //
  55. MessageBoxFromMessage(
  56. Window,
  57. MSG_CANT_OPEN_HELP_FILE,
  58. FALSE,
  59. AppTitleStringId,
  60. MB_OK | MB_ICONINFORMATION,
  61. HelpFileName
  62. );
  63. }
  64. }
  65. VOID
  66. ConcatenatePaths(
  67. IN OUT PTSTR Path1,
  68. IN LPCTSTR Path2,
  69. IN DWORD BufferSizeChars
  70. )
  71. /*++
  72. Routine Description:
  73. Concatenate two path strings together, supplying a path separator
  74. character (\) if necessary between the 2 parts.
  75. Arguments:
  76. Path1 - supplies prefix part of path. Path2 is concatenated to Path1.
  77. Path2 - supplies the suffix part of path. If Path1 does not end with a
  78. path separator and Path2 does not start with one, then a path sep
  79. is appended to Path1 before appending Path2.
  80. BufferSizeChars - supplies the size in chars (Unicode version) or
  81. bytes (Ansi version) of the buffer pointed to by Path1. The string
  82. will be truncated as necessary to not overflow that size.
  83. Return Value:
  84. None.
  85. --*/
  86. {
  87. BOOL NeedBackslash = TRUE;
  88. DWORD l;
  89. if(!Path1)
  90. return;
  91. l = lstrlen(Path1);
  92. if(BufferSizeChars >= sizeof(TCHAR)) {
  93. //
  94. // Leave room for terminating nul.
  95. //
  96. BufferSizeChars -= sizeof(TCHAR);
  97. }
  98. //
  99. // Determine whether we need to stick a backslash
  100. // between the components.
  101. //
  102. if(l && (Path1[l-1] == TEXT('\\'))) {
  103. NeedBackslash = FALSE;
  104. }
  105. if(Path2 && *Path2 == TEXT('\\')) {
  106. if(NeedBackslash) {
  107. NeedBackslash = FALSE;
  108. } else {
  109. //
  110. // Not only do we not need a backslash, but we
  111. // need to eliminate one before concatenating.
  112. //
  113. Path2++;
  114. }
  115. }
  116. //
  117. // Append backslash if necessary and if it fits.
  118. //
  119. if(NeedBackslash && (l < BufferSizeChars)) {
  120. lstrcat(Path1,TEXT("\\"));
  121. }
  122. //
  123. // Append second part of string to first part if it fits.
  124. //
  125. if(Path2 && ((l+lstrlen(Path2)) < BufferSizeChars)) {
  126. lstrcat(Path1,Path2);
  127. }
  128. }
  129. LPTSTR
  130. DupString(
  131. IN LPCTSTR String
  132. )
  133. /*++
  134. Routine Description:
  135. Make a duplicate of a nul-terminated string.
  136. Arguments:
  137. String - supplies pointer to nul-terminated string to copy.
  138. Return Value:
  139. Copy of string or NULL if OOM. Caller can free with FREE().
  140. --*/
  141. {
  142. LPTSTR p;
  143. if(p = MALLOC((lstrlen(String)+1)*sizeof(TCHAR))) {
  144. lstrcpy(p,String);
  145. }
  146. return(p);
  147. }
  148. PTSTR
  149. DupMultiSz (
  150. IN PCTSTR MultiSz
  151. )
  152. /*++
  153. Routine Description:
  154. Make a duplicate of a MultiSz.
  155. Arguments:
  156. MultiSz - supplies pointer to the multi-string to duplicate.
  157. Return Value:
  158. Copy of string or NULL if OOM. Caller can free with FREE().
  159. --*/
  160. {
  161. PCTSTR p;
  162. PTSTR q;
  163. DWORD size = sizeof (TCHAR);
  164. for (p = MultiSz; *p; p = _tcschr (p, 0) + 1) {
  165. size += (lstrlen (p) + 1) * sizeof(TCHAR);
  166. }
  167. if (q = MALLOC (size)) {
  168. CopyMemory (q, MultiSz, size);
  169. }
  170. return q;
  171. }
  172. PTSTR
  173. CreatePrintableString (
  174. IN PCTSTR MultiSz
  175. )
  176. /*++
  177. Routine Description:
  178. Creates a string of the form (str1, str2, ..., strN) from a MultiSz
  179. Arguments:
  180. MultiSz - supplies pointer to the MultiSz string to represent.
  181. Return Value:
  182. Pointer to the new string string or NULL if OOM. Caller can free with FREE().
  183. --*/
  184. {
  185. PCTSTR p;
  186. PTSTR q, r;
  187. DWORD size = 3 * sizeof (TCHAR);
  188. for (p = MultiSz; *p; p = _tcschr (p, 0) + 1) {
  189. size += (lstrlen (p) + 1) * sizeof(TCHAR);
  190. }
  191. if (r = MALLOC (size)) {
  192. q = r;
  193. *q++ = TEXT('(');
  194. for (p = MultiSz; *p; p = _tcschr (p, 0) + 1) {
  195. if (q - r > 1) {
  196. *q++ = TEXT(',');
  197. }
  198. q += wsprintf (q, TEXT("%s"), p);
  199. }
  200. *q++ = TEXT(')');
  201. *q = 0;
  202. }
  203. return r;
  204. }
  205. PSTR
  206. UnicodeToAnsi (
  207. IN PCWSTR Unicode
  208. )
  209. /*++
  210. Routine Description:
  211. Makes an ANSI duplicate of a UNICODE string.
  212. Arguments:
  213. Unicode - supplies pointer to the UNICODE string to duplicate.
  214. Return Value:
  215. Copy of string or NULL if OOM. Caller can free with FREE().
  216. --*/
  217. {
  218. PSTR p;
  219. DWORD size;
  220. if (!Unicode) {
  221. return NULL;
  222. }
  223. size = (lstrlenW (Unicode) + 1) * sizeof(WCHAR);
  224. if (p = MALLOC (size)) {
  225. if (!WideCharToMultiByte (
  226. CP_ACP,
  227. 0,
  228. Unicode,
  229. -1,
  230. p,
  231. size,
  232. NULL,
  233. NULL
  234. )) {
  235. FREE (p);
  236. p = NULL;
  237. }
  238. }
  239. return p;
  240. }
  241. PWSTR
  242. MultiSzAnsiToUnicode (
  243. IN PCSTR MultiSzAnsi
  244. )
  245. /*++
  246. Routine Description:
  247. Makes a UNICODE duplicate of a multi-sz ANSI string.
  248. Arguments:
  249. MultiSzAnsi - supplies pointer to the multisz ANSI string to duplicate.
  250. Return Value:
  251. Copy of string or NULL if OOM. Caller can free with FREE().
  252. --*/
  253. {
  254. PCSTR p;
  255. PWSTR q;
  256. DWORD size = 1;
  257. if (!MultiSzAnsi) {
  258. return NULL;
  259. }
  260. for (p = MultiSzAnsi; *p; p = _mbschr (p, 0) + 1) {
  261. size += lstrlenA (p) + 1;
  262. }
  263. if (q = MALLOC (size * sizeof(WCHAR))) {
  264. if (!MultiByteToWideChar (
  265. CP_ACP,
  266. 0,
  267. MultiSzAnsi,
  268. size,
  269. q,
  270. size
  271. )) {
  272. FREE (q);
  273. q = NULL;
  274. }
  275. }
  276. return q;
  277. }
  278. UINT
  279. MyGetDriveType(
  280. IN TCHAR Drive
  281. )
  282. /*++
  283. Routine Description:
  284. Same as GetDriveType() Win32 API except on NT returns
  285. DRIVE_FIXED for removeable hard drives.
  286. Arguments:
  287. Drive - supplies drive letter whose type is desired.
  288. Return Value:
  289. Same as GetDriveType().
  290. --*/
  291. {
  292. TCHAR DriveNameNt[] = TEXT("\\\\.\\?:");
  293. TCHAR DriveName[] = TEXT("?:\\");
  294. HANDLE hDisk;
  295. BOOL b;
  296. UINT rc;
  297. DWORD DataSize;
  298. DISK_GEOMETRY MediaInfo;
  299. //
  300. // First, get the win32 drive type. If it tells us DRIVE_REMOVABLE,
  301. // then we need to see whether it's a floppy or hard disk. Otherwise
  302. // just believe the api.
  303. //
  304. //
  305. MYASSERT (Drive);
  306. DriveName[0] = Drive;
  307. rc = GetDriveType(DriveName);
  308. #ifdef _X86_ //NEC98
  309. //
  310. // NT5 for NEC98 can not access AT formated HD during setup.
  311. // We need except these type.
  312. if (IsNEC98() && ISNT() && (rc == DRIVE_FIXED) && BuildNumber <= NT40) {
  313. TCHAR aho[100];
  314. //
  315. // Check ATA Card?
  316. //
  317. {
  318. HANDLE hDisk;
  319. TCHAR HardDiskName[] = TEXT("\\\\.\\?:");
  320. HardDiskName[4] = Drive;
  321. hDisk = CreateFile( HardDiskName,
  322. GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  323. NULL,
  324. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  325. if(hDisk == INVALID_HANDLE_VALUE) {
  326. return(DRIVE_UNKNOWN);
  327. }
  328. if (CheckATACardonNT4(hDisk)){
  329. CloseHandle(hDisk);
  330. return(DRIVE_REMOVABLE);
  331. }
  332. CloseHandle(hDisk);
  333. }
  334. if (!IsValidDrive(Drive)){
  335. // HD format is not NEC98 format.
  336. return(DRIVE_UNKNOWN);
  337. }
  338. }
  339. if((rc != DRIVE_REMOVABLE) || !ISNT() || (!IsNEC98() && (Drive < L'C'))) {
  340. return(rc);
  341. }
  342. #else //NEC98
  343. if((rc != DRIVE_REMOVABLE) || !ISNT() || (Drive < L'C')) {
  344. return(rc);
  345. }
  346. #endif
  347. //
  348. // DRIVE_REMOVABLE on NT.
  349. //
  350. //
  351. // Disallow use of removable media (e.g. Jazz, Zip, ...).
  352. //
  353. DriveNameNt[4] = Drive;
  354. hDisk = CreateFile(
  355. DriveNameNt,
  356. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  357. FILE_SHARE_READ | FILE_SHARE_WRITE,
  358. NULL,
  359. OPEN_EXISTING,
  360. 0,
  361. NULL
  362. );
  363. if(hDisk != INVALID_HANDLE_VALUE) {
  364. b = DeviceIoControl(
  365. hDisk,
  366. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  367. NULL,
  368. 0,
  369. &MediaInfo,
  370. sizeof(MediaInfo),
  371. &DataSize,
  372. NULL
  373. );
  374. //
  375. // It's really a hard disk if the media type is removable.
  376. //
  377. if(b && (MediaInfo.MediaType == RemovableMedia)) {
  378. rc = DRIVE_FIXED;
  379. }
  380. CloseHandle(hDisk);
  381. }
  382. return(rc);
  383. }
  384. #ifdef UNICODE
  385. UINT
  386. MyGetDriveType2 (
  387. IN PCWSTR NtVolumeName
  388. )
  389. /*++
  390. Routine Description:
  391. Same as GetDriveType() Win32 API except on NT returns
  392. DRIVE_FIXED for removeable hard drives.
  393. Arguments:
  394. NtVolumeName - supplies device name whose type is desired.
  395. Return Value:
  396. Same as GetDriveType().
  397. --*/
  398. {
  399. NTSTATUS Status;
  400. OBJECT_ATTRIBUTES Obja;
  401. UNICODE_STRING DeviceName;
  402. HANDLE hDisk;
  403. IO_STATUS_BLOCK IoStatusBlock;
  404. BOOL b;
  405. UINT rc;
  406. DWORD DataSize;
  407. DISK_GEOMETRY MediaInfo;
  408. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  409. //
  410. // First, get the win32 drive type. If it tells us DRIVE_REMOVABLE,
  411. // then we need to see whether it's a floppy or hard disk. Otherwise
  412. // just believe the api.
  413. //
  414. INIT_OBJA (&Obja, &DeviceName, NtVolumeName);
  415. Status = NtOpenFile (
  416. &hDisk,
  417. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  418. &Obja,
  419. &IoStatusBlock,
  420. FILE_SHARE_READ | FILE_SHARE_WRITE,
  421. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
  422. );
  423. if (!NT_SUCCESS( Status )) {
  424. return DRIVE_NO_ROOT_DIR;
  425. }
  426. //
  427. // Determine if this is a network or disk file system. If it
  428. // is a disk file system determine if this is removable or not
  429. //
  430. Status = NtQueryVolumeInformationFile(
  431. hDisk,
  432. &IoStatusBlock,
  433. &DeviceInfo,
  434. sizeof(DeviceInfo),
  435. FileFsDeviceInformation
  436. );
  437. if (!NT_SUCCESS (Status)) {
  438. rc = DRIVE_UNKNOWN;
  439. } else if (DeviceInfo.Characteristics & FILE_REMOTE_DEVICE) {
  440. rc = DRIVE_REMOTE;
  441. } else {
  442. switch (DeviceInfo.DeviceType) {
  443. case FILE_DEVICE_NETWORK:
  444. case FILE_DEVICE_NETWORK_FILE_SYSTEM:
  445. rc = DRIVE_REMOTE;
  446. break;
  447. case FILE_DEVICE_CD_ROM:
  448. case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
  449. rc = DRIVE_CDROM;
  450. break;
  451. case FILE_DEVICE_VIRTUAL_DISK:
  452. rc = DRIVE_RAMDISK;
  453. break;
  454. case FILE_DEVICE_DISK:
  455. case FILE_DEVICE_DISK_FILE_SYSTEM:
  456. if ( DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA ) {
  457. rc = DRIVE_REMOVABLE;
  458. } else {
  459. rc = DRIVE_FIXED;
  460. }
  461. break;
  462. default:
  463. rc = DRIVE_UNKNOWN;
  464. break;
  465. }
  466. }
  467. if(rc == DRIVE_REMOVABLE) {
  468. //
  469. // DRIVE_REMOVABLE on NT.
  470. // Disallow use of removable media (e.g. Jazz, Zip, ...).
  471. //
  472. Status = NtDeviceIoControlFile(
  473. hDisk,
  474. 0,
  475. NULL,
  476. NULL,
  477. &IoStatusBlock,
  478. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  479. NULL,
  480. 0,
  481. &MediaInfo,
  482. sizeof(DISK_GEOMETRY)
  483. );
  484. //
  485. // It's really a hard disk if the media type is removable.
  486. //
  487. if(NT_SUCCESS (Status) && (MediaInfo.MediaType == RemovableMedia)) {
  488. rc = DRIVE_FIXED;
  489. }
  490. }
  491. NtClose (hDisk);
  492. return(rc);
  493. }
  494. #endif
  495. BOOL
  496. GetPartitionInfo(
  497. IN TCHAR Drive,
  498. OUT PPARTITION_INFORMATION PartitionInfo
  499. )
  500. /*++
  501. Routine Description:
  502. Fill in a PARTITION_INFORMATION structure with information about
  503. a particular drive.
  504. This routine is meaningful only when run on NT -- it always fails
  505. on Win95.
  506. Arguments:
  507. Drive - supplies drive letter whose partition info is desired.
  508. PartitionInfo - upon success, receives partition info for Drive.
  509. Return Value:
  510. Boolean value indicating whether PartitionInfo has been filled in.
  511. --*/
  512. {
  513. TCHAR DriveName[] = TEXT("\\\\.\\?:");
  514. HANDLE hDisk;
  515. BOOL b;
  516. DWORD DataSize;
  517. if(!ISNT()) {
  518. return(FALSE);
  519. }
  520. DriveName[4] = Drive;
  521. hDisk = CreateFile(
  522. DriveName,
  523. GENERIC_READ,
  524. FILE_SHARE_READ | FILE_SHARE_WRITE,
  525. NULL,
  526. OPEN_EXISTING,
  527. 0,
  528. NULL
  529. );
  530. if(hDisk == INVALID_HANDLE_VALUE) {
  531. return(FALSE);
  532. }
  533. b = DeviceIoControl(
  534. hDisk,
  535. IOCTL_DISK_GET_PARTITION_INFO,
  536. NULL,
  537. 0,
  538. PartitionInfo,
  539. sizeof(PARTITION_INFORMATION),
  540. &DataSize,
  541. NULL
  542. );
  543. CloseHandle(hDisk);
  544. return(b);
  545. }
  546. #ifdef UNICODE
  547. BOOL
  548. GetPartitionInfo2 (
  549. IN PCWSTR NtVolumeName,
  550. OUT PPARTITION_INFORMATION PartitionInfo
  551. )
  552. /*++
  553. Routine Description:
  554. Fill in a PARTITION_INFORMATION structure with information about
  555. a particular drive.
  556. This routine is meaningful only when run on NT -- it always fails
  557. on Win95.
  558. Arguments:
  559. NtVolumeName - supplies NT volume name whose partition info is desired.
  560. PartitionInfo - upon success, receives partition info for Drive.
  561. Return Value:
  562. Boolean value indicating whether PartitionInfo has been filled in.
  563. --*/
  564. {
  565. NTSTATUS Status;
  566. OBJECT_ATTRIBUTES Obja;
  567. UNICODE_STRING DeviceName;
  568. HANDLE hDisk;
  569. IO_STATUS_BLOCK IoStatusBlock;
  570. BOOL b = FALSE;
  571. DWORD DataSize;
  572. //
  573. // Open the file
  574. //
  575. INIT_OBJA (&Obja, &DeviceName, NtVolumeName);
  576. Status = NtOpenFile (
  577. &hDisk,
  578. (ACCESS_MASK)FILE_READ_DATA | SYNCHRONIZE,
  579. &Obja,
  580. &IoStatusBlock,
  581. FILE_SHARE_READ | FILE_SHARE_WRITE,
  582. FILE_SYNCHRONOUS_IO_NONALERT
  583. );
  584. if (NT_SUCCESS (Status)) {
  585. Status = NtDeviceIoControlFile (
  586. hDisk,
  587. 0,
  588. NULL,
  589. NULL,
  590. &IoStatusBlock,
  591. IOCTL_DISK_GET_PARTITION_INFO,
  592. NULL,
  593. 0,
  594. PartitionInfo,
  595. sizeof(PARTITION_INFORMATION)
  596. );
  597. NtClose (hDisk);
  598. b = NT_SUCCESS (Status);
  599. }
  600. return(b);
  601. }
  602. #endif
  603. BOOL
  604. IsDriveNTFT(
  605. IN TCHAR Drive,
  606. IN PCTSTR NtVolumeName
  607. )
  608. /*++
  609. Routine Description:
  610. Determine whether a drive is any kind of NTFT set.
  611. This routine is meaningful only when run on NT -- it always fails
  612. on Win95.
  613. Arguments:
  614. Drive - supplies drive letter to check; optional
  615. NtVolumeName - supplies volume name to check; required if Drive not specified
  616. Return Value:
  617. Boolean value indicating whether the drive is NTFT.
  618. --*/
  619. {
  620. PARTITION_INFORMATION PartitionInfo;
  621. if(!ISNT()) {
  622. return(FALSE);
  623. }
  624. //
  625. // If we can't open the drive, assume not NTFT.
  626. //
  627. if (Drive) {
  628. if(!GetPartitionInfo(Drive,&PartitionInfo)) {
  629. return(FALSE);
  630. }
  631. } else {
  632. #ifdef UNICODE
  633. if(!GetPartitionInfo2 (NtVolumeName, &PartitionInfo)) {
  634. return(FALSE);
  635. }
  636. #else
  637. MYASSERT (FALSE);
  638. return(FALSE);
  639. #endif
  640. }
  641. //
  642. // It's FT if the partition type is marked NTFT (ie, high bit set).
  643. //
  644. if((IsRecognizedPartition(PartitionInfo.PartitionType)) &&
  645. ((PartitionInfo.PartitionType & PARTITION_NTFT) != 0)) {
  646. #if defined(_IA64_)
  647. //
  648. // This check is dependant on the EFI system partition type not being
  649. // a recognized type. It's unlikely that we'd start recognizing it
  650. // before we start requiring GPT partitions on the system disk, but
  651. // just in case we'll assert before returning true for an ESP.
  652. //
  653. ASSERT(PartitionInfo.PartitionType != 0xef);
  654. #endif
  655. return TRUE;
  656. } else {
  657. return FALSE;
  658. }
  659. }
  660. BOOL
  661. IsDriveVeritas(
  662. IN TCHAR Drive,
  663. IN PCTSTR NtVolumeName
  664. )
  665. {
  666. TCHAR name[3];
  667. TCHAR Target[MAX_PATH];
  668. if(ISNT()) {
  669. //
  670. // Check for Veritas volume, which links to \Device\HarddiskDmVolumes...
  671. //
  672. if (Drive) {
  673. name[0] = Drive;
  674. name[1] = TEXT(':');
  675. name[2] = 0;
  676. if(!QueryDosDevice(name,Target,MAX_PATH)) {
  677. return FALSE;
  678. }
  679. } else {
  680. lstrcpy (Target, NtVolumeName);
  681. }
  682. if(!_tcsnicmp(Target,TEXT("\\Device\\HarddiskDm"),18)) {
  683. return(TRUE);
  684. }
  685. }
  686. return(FALSE);
  687. }
  688. //
  689. // Get Harddisk BPS
  690. // I970721
  691. //
  692. ULONG
  693. GetHDBps(
  694. HANDLE hDisk
  695. )
  696. {
  697. BOOL b;
  698. UINT rc;
  699. DWORD DataSize;
  700. DISK_GEOMETRY MediaInfo;
  701. b = DeviceIoControl(
  702. hDisk,
  703. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  704. NULL,
  705. 0,
  706. &MediaInfo,
  707. sizeof(MediaInfo),
  708. &DataSize,
  709. NULL
  710. );
  711. if(!b) {
  712. return(0);
  713. } else {
  714. return(MediaInfo.BytesPerSector);
  715. }
  716. }
  717. #ifdef UNICODE
  718. #ifdef _WIN64
  719. //
  720. // define IOCTL_VOLUME_IS_PARTITION since we don't include ntddvol.h
  721. //
  722. #define IOCTL_VOLUME_IS_PARTITION CTL_CODE(IOCTL_VOLUME_BASE, 10, METHOD_BUFFERED, FILE_ANY_ACCESS)
  723. BOOL
  724. IsSoftPartition(
  725. IN TCHAR Drive,
  726. IN PCTSTR NtVolumeName
  727. )
  728. /*++
  729. Routine Description:
  730. Finds out whether the given volume is soft partition
  731. or not (i.e. does it have an underlying partition).
  732. NOTE : We just use the IOCTL_VOLUME_IS_PARTITION.
  733. Arguments:
  734. Drive - supplies drive letter for the volume
  735. NtVolumeName - supplies NT volume name
  736. Return Value:
  737. TRUE if the volume is soft partition otherwise FALSE.
  738. --*/
  739. {
  740. BOOL SoftPartition;
  741. HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
  742. ULONG DataSize;
  743. //
  744. // Assume that the partition is a soft one.
  745. // If we cannot determine whether or not the partition is a soft partition, then assume it is a soft
  746. // partition. This will prevent us from placing $win_nt$.~ls in such a drive.
  747. //
  748. SoftPartition = TRUE;
  749. if (Drive) {
  750. TCHAR Name[MAX_PATH];
  751. BOOL Result;
  752. wsprintf(Name, TEXT("\\\\.\\%c:"), Drive);
  753. VolumeHandle = CreateFile(Name,
  754. GENERIC_READ,
  755. FILE_SHARE_READ | FILE_SHARE_WRITE,
  756. NULL,
  757. OPEN_EXISTING,
  758. FILE_ATTRIBUTE_NORMAL,
  759. INVALID_HANDLE_VALUE);
  760. if (VolumeHandle != INVALID_HANDLE_VALUE) {
  761. Result = DeviceIoControl(VolumeHandle,
  762. IOCTL_VOLUME_IS_PARTITION,
  763. NULL,
  764. 0,
  765. NULL,
  766. 0,
  767. &DataSize,
  768. NULL);
  769. SoftPartition = !Result;
  770. CloseHandle(VolumeHandle);
  771. }
  772. } else {
  773. NTSTATUS Status;
  774. OBJECT_ATTRIBUTES Obja;
  775. UNICODE_STRING DeviceName;
  776. IO_STATUS_BLOCK IoStatusBlock;
  777. //
  778. // Open the file
  779. //
  780. INIT_OBJA (&Obja, &DeviceName, NtVolumeName);
  781. Status = NtOpenFile (&VolumeHandle,
  782. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  783. &Obja,
  784. &IoStatusBlock,
  785. FILE_SHARE_READ | FILE_SHARE_WRITE,
  786. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
  787. if (NT_SUCCESS (Status)) {
  788. Status = NtDeviceIoControlFile(VolumeHandle,
  789. 0,
  790. NULL,
  791. NULL,
  792. &IoStatusBlock,
  793. IOCTL_VOLUME_IS_PARTITION,
  794. NULL,
  795. 0,
  796. NULL,
  797. 0);
  798. if (NT_SUCCESS(Status)) {
  799. SoftPartition = FALSE;
  800. }
  801. NtClose(VolumeHandle);
  802. }
  803. }
  804. return SoftPartition;
  805. }
  806. #else
  807. BOOL
  808. IsSoftPartition(
  809. IN TCHAR Drive,
  810. IN PCTSTR NtVolumeName
  811. )
  812. {
  813. TCHAR name[80];
  814. PARTITION_INFORMATION partInfo;
  815. DWORD bytes;
  816. BOOL SoftPartition = TRUE;
  817. BOOL b;
  818. HANDLE h = INVALID_HANDLE_VALUE;
  819. IO_STATUS_BLOCK IoStatusBlock;
  820. LARGE_INTEGER SoftPartitionStartingOffset;
  821. ULONG bps;
  822. NTSTATUS Status;
  823. OBJECT_ATTRIBUTES Obja;
  824. UNICODE_STRING DeviceName;
  825. DWORD DataSize;
  826. DISK_GEOMETRY MediaInfo;
  827. if( !IsDriveVeritas( Drive, NtVolumeName ) ) {
  828. return( FALSE );
  829. }
  830. //
  831. // Assume that the partition is a soft one.
  832. // If we cannot determine whether or not the partition is a soft partition, then assume it is a soft
  833. // partition. This will prevent us from placing $win_nt$.~ls in such a drive.
  834. //
  835. SoftPartition = TRUE;
  836. if (Drive) {
  837. wsprintf(name, TEXT("\\\\.\\%c:"), Drive);
  838. h = CreateFile(name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  839. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  840. INVALID_HANDLE_VALUE);
  841. if (h == INVALID_HANDLE_VALUE) {
  842. #if DBG
  843. GetLastError();
  844. #endif
  845. goto Exit;
  846. }
  847. b = DeviceIoControl(
  848. h,
  849. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  850. NULL,
  851. 0,
  852. &MediaInfo,
  853. sizeof(MediaInfo),
  854. &DataSize,
  855. NULL
  856. );
  857. if(!b) {
  858. #if DBG
  859. GetLastError();
  860. #endif
  861. goto CleanUp;
  862. }
  863. b = DeviceIoControl(h, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0,
  864. &partInfo, sizeof(partInfo), &bytes, NULL);
  865. if (!b) {
  866. #if DBG
  867. GetLastError();
  868. #endif
  869. goto CleanUp;
  870. }
  871. } else {
  872. //
  873. // Open the file
  874. //
  875. INIT_OBJA (&Obja, &DeviceName, NtVolumeName);
  876. Status = NtOpenFile (
  877. &h,
  878. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  879. &Obja,
  880. &IoStatusBlock,
  881. FILE_SHARE_READ | FILE_SHARE_WRITE,
  882. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
  883. );
  884. if (!NT_SUCCESS (Status)) {
  885. goto Exit;
  886. }
  887. Status = NtDeviceIoControlFile(
  888. h,
  889. 0,
  890. NULL,
  891. NULL,
  892. &IoStatusBlock,
  893. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  894. NULL,
  895. 0,
  896. &MediaInfo,
  897. sizeof(DISK_GEOMETRY)
  898. );
  899. if (!NT_SUCCESS (Status)) {
  900. goto CleanUp;
  901. }
  902. Status = NtDeviceIoControlFile(
  903. h,
  904. 0,
  905. NULL,
  906. NULL,
  907. &IoStatusBlock,
  908. IOCTL_DISK_GET_PARTITION_INFO,
  909. NULL,
  910. 0,
  911. &partInfo,
  912. sizeof(PARTITION_INFORMATION)
  913. );
  914. if (!NT_SUCCESS (Status)) {
  915. goto CleanUp;
  916. }
  917. }
  918. bps = MediaInfo.BytesPerSector;
  919. //
  920. // Find out the number of bytes per sector of the drive
  921. //
  922. //
  923. // A soft partition always starts at sector 29 (0x1d)
  924. //
  925. SoftPartitionStartingOffset.QuadPart = 29*bps;
  926. SoftPartition = ( partInfo.StartingOffset.QuadPart == SoftPartitionStartingOffset.QuadPart );
  927. CleanUp:
  928. if (Drive) {
  929. CloseHandle(h);
  930. } else {
  931. NtClose (h);
  932. }
  933. Exit:
  934. return( SoftPartition );
  935. }
  936. #endif // WIN64
  937. BOOL
  938. MyGetDiskFreeSpace (
  939. IN PCWSTR NtVolumeName,
  940. IN PDWORD SectorsPerCluster,
  941. IN PDWORD BytesPerSector,
  942. IN PDWORD NumberOfFreeClusters,
  943. IN PDWORD TotalNumberOfClusters
  944. )
  945. {
  946. NTSTATUS Status;
  947. OBJECT_ATTRIBUTES Obja;
  948. HANDLE Handle;
  949. UNICODE_STRING VolumeName;
  950. IO_STATUS_BLOCK IoStatusBlock;
  951. BOOLEAN TranslationStatus;
  952. PVOID FreeBuffer;
  953. FILE_FS_SIZE_INFORMATION SizeInfo;
  954. WCHAR DefaultPath[2];
  955. DWORD dwTemp;
  956. BOOL bAppHack;
  957. INIT_OBJA (&Obja, &VolumeName, NtVolumeName);
  958. //
  959. // Open the file
  960. //
  961. Status = NtOpenFile(
  962. &Handle,
  963. (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  964. &Obja,
  965. &IoStatusBlock,
  966. FILE_SHARE_READ | FILE_SHARE_WRITE,
  967. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY
  968. );
  969. if (!NT_SUCCESS (Status)) {
  970. return FALSE;
  971. }
  972. //
  973. // Determine the size parameters of the volume.
  974. //
  975. Status = NtQueryVolumeInformationFile(
  976. Handle,
  977. &IoStatusBlock,
  978. &SizeInfo,
  979. sizeof(SizeInfo),
  980. FileFsSizeInformation
  981. );
  982. NtClose(Handle);
  983. if (!NT_SUCCESS(Status)) {
  984. return FALSE;
  985. }
  986. if (SizeInfo.TotalAllocationUnits.HighPart) {
  987. SizeInfo.TotalAllocationUnits.LowPart = (ULONG)-1;
  988. }
  989. if (SizeInfo.AvailableAllocationUnits.HighPart) {
  990. SizeInfo.AvailableAllocationUnits.LowPart = (ULONG)-1;
  991. }
  992. *SectorsPerCluster = SizeInfo.SectorsPerAllocationUnit;
  993. *BytesPerSector = SizeInfo.BytesPerSector;
  994. *NumberOfFreeClusters = SizeInfo.AvailableAllocationUnits.LowPart;
  995. *TotalNumberOfClusters = SizeInfo.TotalAllocationUnits.LowPart;
  996. return TRUE;
  997. }
  998. #endif
  999. BOOL
  1000. IsDriveNTFS(
  1001. IN TCHAR Drive
  1002. )
  1003. /*++
  1004. Routine Description:
  1005. Determine whether a drive is any kind of NTFT set.
  1006. This routine is meaningful only when run on NT -- it always fails
  1007. on Win95.
  1008. Arguments:
  1009. Drive - supplies drive letter to check.
  1010. Return Value:
  1011. Boolean value indicating whether the drive is NTFT.
  1012. --*/
  1013. {
  1014. TCHAR DriveName[4];
  1015. TCHAR Filesystem[256];
  1016. TCHAR VolumeName[MAX_PATH];
  1017. DWORD SerialNumber;
  1018. DWORD MaxComponent;
  1019. DWORD Flags;
  1020. BOOL b;
  1021. if(!ISNT()) {
  1022. return(FALSE);
  1023. }
  1024. MYASSERT (Drive);
  1025. DriveName[0] = Drive;
  1026. DriveName[1] = TEXT(':');
  1027. DriveName[2] = TEXT('\\');
  1028. DriveName[3] = 0;
  1029. b = GetVolumeInformation(
  1030. DriveName,
  1031. VolumeName,MAX_PATH,
  1032. &SerialNumber,
  1033. &MaxComponent,
  1034. &Flags,
  1035. Filesystem,
  1036. sizeof(Filesystem)/sizeof(TCHAR)
  1037. );
  1038. if(!b || !lstrcmpi(Filesystem,TEXT("NTFS"))) {
  1039. return( TRUE );
  1040. }
  1041. return( FALSE );
  1042. }
  1043. DWORD
  1044. MapFileForRead(
  1045. IN LPCTSTR FileName,
  1046. OUT PDWORD FileSize,
  1047. OUT PHANDLE FileHandle,
  1048. OUT PHANDLE MappingHandle,
  1049. OUT PVOID *BaseAddress
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. Open and map an entire file for read access. The file must
  1054. not be 0-length or the routine fails.
  1055. Arguments:
  1056. FileName - supplies pathname to file to be mapped.
  1057. FileSize - receives the size in bytes of the file.
  1058. FileHandle - receives the win32 file handle for the open file.
  1059. The file will be opened for generic read access.
  1060. MappingHandle - receives the win32 handle for the file mapping
  1061. object. This object will be for read access. This value is
  1062. undefined if the file being opened is 0 length.
  1063. BaseAddress - receives the address where the file is mapped. This
  1064. value is undefined if the file being opened is 0 length.
  1065. Return Value:
  1066. NO_ERROR if the file was opened and mapped successfully.
  1067. The caller must unmap the file with UnmapFile when
  1068. access to the file is no longer desired.
  1069. Win32 error code if the file was not successfully mapped.
  1070. --*/
  1071. {
  1072. DWORD rc;
  1073. //
  1074. // Open the file -- fail if it does not exist.
  1075. //
  1076. *FileHandle = CreateFile(
  1077. FileName,
  1078. GENERIC_READ,
  1079. FILE_SHARE_READ,
  1080. NULL,
  1081. OPEN_EXISTING,
  1082. 0,
  1083. NULL
  1084. );
  1085. if(*FileHandle == INVALID_HANDLE_VALUE) {
  1086. rc = GetLastError();
  1087. } else {
  1088. //
  1089. // Get the size of the file.
  1090. //
  1091. *FileSize = GetFileSize(*FileHandle,NULL);
  1092. if(*FileSize == (DWORD)(-1)) {
  1093. rc = GetLastError();
  1094. } else {
  1095. //
  1096. // Create file mapping for the whole file.
  1097. //
  1098. *MappingHandle = CreateFileMapping(
  1099. *FileHandle,
  1100. NULL,
  1101. PAGE_READONLY,
  1102. 0,
  1103. *FileSize,
  1104. NULL
  1105. );
  1106. if(*MappingHandle) {
  1107. //
  1108. // Map the whole file.
  1109. //
  1110. *BaseAddress = MapViewOfFile(
  1111. *MappingHandle,
  1112. FILE_MAP_READ,
  1113. 0,
  1114. 0,
  1115. *FileSize
  1116. );
  1117. if(*BaseAddress) {
  1118. return(NO_ERROR);
  1119. }
  1120. rc = GetLastError();
  1121. CloseHandle(*MappingHandle);
  1122. } else {
  1123. rc = GetLastError();
  1124. }
  1125. }
  1126. CloseHandle(*FileHandle);
  1127. }
  1128. return(rc);
  1129. }
  1130. DWORD
  1131. UnmapFile(
  1132. IN HANDLE MappingHandle,
  1133. IN PVOID BaseAddress
  1134. )
  1135. /*++
  1136. Routine Description:
  1137. Unmap and close a file.
  1138. Arguments:
  1139. MappingHandle - supplies the win32 handle for the open file mapping
  1140. object.
  1141. BaseAddress - supplies the address where the file is mapped.
  1142. Return Value:
  1143. NO_ERROR if the file was unmapped successfully.
  1144. Win32 error code if the file was not successfully unmapped.
  1145. --*/
  1146. {
  1147. DWORD rc;
  1148. rc = UnmapViewOfFile(BaseAddress) ? NO_ERROR : GetLastError();
  1149. if(!CloseHandle(MappingHandle)) {
  1150. if(rc == NO_ERROR) {
  1151. rc = GetLastError();
  1152. }
  1153. }
  1154. return(rc);
  1155. }
  1156. VOID
  1157. GenerateCompressedName(
  1158. IN LPCTSTR Filename,
  1159. OUT LPTSTR CompressedName
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. Given a filename, generate the compressed form of the name.
  1164. The compressed form is generated as follows:
  1165. Look backwards for a dot. If there is no dot, append "._" to the name.
  1166. If there is a dot followed by 0, 1, or 2 charcaters, append "_".
  1167. Otherwise assume there is a 3-character extension and replace the
  1168. third character after the dot with "_".
  1169. Arguments:
  1170. Filename - supplies filename whose compressed form is desired.
  1171. CompressedName - receives compressed form. This routine assumes
  1172. that this buffer is MAX_PATH TCHARs in size.
  1173. Return Value:
  1174. None.
  1175. --*/
  1176. {
  1177. LPTSTR p,q;
  1178. //
  1179. // Leave room for the worst case, namely where there's no extension
  1180. // (and we thus have to append ._).
  1181. //
  1182. lstrcpyn(CompressedName,Filename,MAX_PATH-2);
  1183. p = _tcsrchr(CompressedName,TEXT('.'));
  1184. q = _tcsrchr(CompressedName,TEXT('\\'));
  1185. if(q < p) {
  1186. //
  1187. // If there are 0, 1, or 2 characters after the dot, just append
  1188. // the underscore. p points to the dot so include that in the length.
  1189. //
  1190. if(lstrlen(p) < 4) {
  1191. lstrcat(CompressedName,TEXT("_"));
  1192. } else {
  1193. //
  1194. // Assume there are 3 characters in the extension and replace
  1195. // the final one with an underscore.
  1196. //
  1197. p[3] = TEXT('_');
  1198. }
  1199. } else {
  1200. //
  1201. // No dot, just add ._.
  1202. //
  1203. lstrcat(CompressedName,TEXT("._"));
  1204. }
  1205. }
  1206. DWORD
  1207. CreateMultiLevelDirectory(
  1208. IN LPCTSTR Directory
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. This routine ensures that a multi-level path exists by creating individual
  1213. levels one at a time. It can handle either paths of form x:... or \\?\Volume{...
  1214. Arguments:
  1215. Directory - supplies fully-qualified Win32 pathspec of directory to create
  1216. Return Value:
  1217. Win32 error code indicating outcome.
  1218. --*/
  1219. {
  1220. TCHAR Buffer[MAX_PATH];
  1221. PTCHAR p,q;
  1222. TCHAR c;
  1223. BOOL Done;
  1224. DWORD d = ERROR_SUCCESS;
  1225. INT Skip=0;
  1226. lstrcpyn(Buffer,Directory,MAX_PATH);
  1227. //
  1228. // If it already exists do nothing. (We do this before syntax checking
  1229. // to allow for remote paths that already exist. This is needed for
  1230. // remote boot machines.)
  1231. //
  1232. d = GetFileAttributes(Buffer);
  1233. if(d != (DWORD)(-1)) {
  1234. return((d & FILE_ATTRIBUTE_DIRECTORY) ? NO_ERROR : ERROR_DIRECTORY);
  1235. }
  1236. //
  1237. // Check path format
  1238. //
  1239. c = (TCHAR)CharUpper((LPTSTR)Buffer[0]);
  1240. if(((c < TEXT('A')) || (c > TEXT('Z')) || (Buffer[1] != TEXT(':'))) && c != TEXT('\\')) {
  1241. return(ERROR_INVALID_PARAMETER);
  1242. }
  1243. if (c != TEXT('\\')) {
  1244. //
  1245. // Ignore drive roots, which we allow to be either x:\ or x:.
  1246. //
  1247. if(Buffer[2] != TEXT('\\')) {
  1248. return(Buffer[2] ? ERROR_INVALID_PARAMETER : ERROR_SUCCESS);
  1249. }
  1250. q = Buffer + 3;
  1251. if(*q == 0) {
  1252. return(ERROR_SUCCESS);
  1253. }
  1254. } else {
  1255. //
  1256. // support \\server\share[\xxx] format
  1257. //
  1258. q = NULL;
  1259. if (Buffer[1] != TEXT('\\') || Buffer[1] != 0 && Buffer[2] == TEXT('\\')) {
  1260. return(ERROR_INVALID_PARAMETER);
  1261. }
  1262. q = _tcschr (&Buffer[2], TEXT('\\'));
  1263. if (!q) {
  1264. return(ERROR_INVALID_PARAMETER);
  1265. }
  1266. if (q[1] == TEXT('\\')) {
  1267. return(ERROR_INVALID_PARAMETER);
  1268. }
  1269. q = _tcschr (&q[1], TEXT('\\'));
  1270. if (!q) {
  1271. return(ERROR_SUCCESS);
  1272. }
  1273. q++;
  1274. #ifdef UNICODE
  1275. //
  1276. // Hack to make sure the system partition case works on IA64 (arc)
  1277. // We beieve this should be the only case where we use a
  1278. // GlobalRoot style name as the other cases deal with OEM partitions etc.
  1279. // which we should never touch. WE skip over by the length of
  1280. // SystemPartitionVolumeGuid. We take care of the \ present at the end.
  1281. //
  1282. if (SystemPartitionVolumeGuid != NULL && _wcsnicmp (Buffer, SystemPartitionVolumeGuid, (wcslen(SystemPartitionVolumeGuid)-1)) == 0 ){
  1283. Skip = wcslen(SystemPartitionVolumeGuid)-1;
  1284. } else if (_wcsnicmp (Buffer, L"\\\\?\\Volume{", 11) == 0 &&
  1285. Buffer[47] == L'}') {
  1286. //
  1287. // skip over the VolumeGUID part
  1288. //
  1289. Skip = 48;
  1290. }
  1291. if (Skip > 0) {
  1292. if (Buffer[Skip] == 0) {
  1293. return ERROR_SUCCESS;
  1294. }
  1295. q = Buffer + Skip + 1;
  1296. }
  1297. #endif
  1298. }
  1299. Done = FALSE;
  1300. do {
  1301. //
  1302. // Locate the next path sep char. If there is none then
  1303. // this is the deepest level of the path.
  1304. //
  1305. if(p = _tcschr(q,TEXT('\\'))) {
  1306. *p = 0;
  1307. } else {
  1308. Done = TRUE;
  1309. }
  1310. //
  1311. // Create this portion of the path.
  1312. //
  1313. if(CreateDirectory(Buffer,NULL)) {
  1314. d = ERROR_SUCCESS;
  1315. } else {
  1316. d = GetLastError();
  1317. if(d == ERROR_ALREADY_EXISTS) {
  1318. d = ERROR_SUCCESS;
  1319. }
  1320. }
  1321. if(d == ERROR_SUCCESS) {
  1322. //
  1323. // Put back the path sep and move to the next component.
  1324. //
  1325. if(!Done) {
  1326. *p = TEXT('\\');
  1327. q = p+1;
  1328. }
  1329. } else {
  1330. Done = TRUE;
  1331. }
  1332. } while(!Done);
  1333. return(d);
  1334. }
  1335. BOOL
  1336. ForceFileNoCompress(
  1337. IN LPCTSTR Filename
  1338. )
  1339. /*++
  1340. Routine Description:
  1341. This routine makes sure that a file on a volume that supports per-file
  1342. compression is not compressed. The caller need not ensure that the volume
  1343. actually supports this, since this routine will query the attributes of
  1344. the file before deciding whether any operation is actually necessary,
  1345. and the compressed attribute will not be set on volumes that don't support
  1346. per-file compression.
  1347. It assumed that the file exists. If the file does not exist, this routine
  1348. will fail.
  1349. Arguments:
  1350. Filename - supplies the filename of the file to mke uncompressed.
  1351. Return Value:
  1352. Boolean value indicating outcome. If FALSE, last error is set.
  1353. --*/
  1354. {
  1355. ULONG d;
  1356. HANDLE h;
  1357. BOOL b;
  1358. USHORT u;
  1359. DWORD Attributes;
  1360. Attributes = GetFileAttributes(Filename);
  1361. if(Attributes == (DWORD)(-1)) {
  1362. return(FALSE);
  1363. }
  1364. if(!(Attributes & FILE_ATTRIBUTE_COMPRESSED)) {
  1365. return(TRUE);
  1366. }
  1367. //
  1368. // Temporarily nullify attributes that might prevent opening
  1369. // the file for read-write access.
  1370. //
  1371. // We preserve the 'standard' attributes that the file might have,
  1372. // to be restored later.
  1373. //
  1374. Attributes &= (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE);
  1375. SetFileAttributes(Filename,FILE_ATTRIBUTE_NORMAL);
  1376. h = CreateFile(
  1377. Filename,
  1378. FILE_READ_DATA | FILE_WRITE_DATA,
  1379. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1380. NULL,
  1381. OPEN_EXISTING,
  1382. FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN,
  1383. NULL
  1384. );
  1385. if(h == INVALID_HANDLE_VALUE) {
  1386. SetFileAttributes(Filename,Attributes);
  1387. return(FALSE);
  1388. }
  1389. u = 0;
  1390. b = DeviceIoControl( h,
  1391. FSCTL_SET_COMPRESSION,
  1392. &u,
  1393. sizeof(USHORT),
  1394. NULL,
  1395. 0,
  1396. &d,
  1397. FALSE);
  1398. d = GetLastError();
  1399. CloseHandle(h);
  1400. SetFileAttributes(Filename,Attributes);
  1401. SetLastError(d);
  1402. return(b);
  1403. }
  1404. BOOL
  1405. IsCurrentOsServer(
  1406. void
  1407. )
  1408. {
  1409. LONG l;
  1410. HKEY hKey;
  1411. DWORD d;
  1412. DWORD Size;
  1413. TCHAR Value[100];
  1414. DWORD Type;
  1415. l = RegCreateKeyEx(
  1416. HKEY_LOCAL_MACHINE,
  1417. TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
  1418. 0,
  1419. NULL,
  1420. 0,
  1421. KEY_QUERY_VALUE,
  1422. NULL,
  1423. &hKey,
  1424. &d
  1425. );
  1426. if (l != NO_ERROR) {
  1427. return FALSE;
  1428. }
  1429. Size = sizeof(Value);
  1430. l = RegQueryValueEx(hKey,TEXT("ProductType"),NULL,&Type,(LPBYTE)Value,&Size);
  1431. RegCloseKey(hKey);
  1432. if (l != NO_ERROR) {
  1433. return FALSE;
  1434. }
  1435. if (lstrcmpi(Value,TEXT("winnt")) == 0) {
  1436. return FALSE;
  1437. }
  1438. return TRUE;
  1439. }
  1440. BOOL
  1441. IsCurrentAdvancedServer(
  1442. void
  1443. )
  1444. {
  1445. LONG l;
  1446. HKEY hKey;
  1447. DWORD d;
  1448. DWORD Size;
  1449. TCHAR Value[100];
  1450. DWORD Type;
  1451. l = RegCreateKeyEx(
  1452. HKEY_LOCAL_MACHINE,
  1453. TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
  1454. 0,
  1455. NULL,
  1456. 0,
  1457. KEY_QUERY_VALUE,
  1458. NULL,
  1459. &hKey,
  1460. &d
  1461. );
  1462. if (l != NO_ERROR) {
  1463. return FALSE;
  1464. }
  1465. Size = sizeof(Value);
  1466. l = RegQueryValueEx(hKey,TEXT("ProductType"),NULL,&Type,(LPBYTE)Value,&Size);
  1467. RegCloseKey(hKey);
  1468. if (l != NO_ERROR) {
  1469. return FALSE;
  1470. }
  1471. if (lstrcmpi(Value,TEXT("lanmannt")) == 0) {
  1472. return TRUE;
  1473. }
  1474. return FALSE;
  1475. }
  1476. BOOL
  1477. ConcatenateFile(
  1478. IN HANDLE hOpenFile,
  1479. IN LPTSTR FileName
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. This routine will go load the named file, and concatenate its
  1484. contents into the open file.
  1485. Arguments:
  1486. FileName The name of the file we're going to concatenate.
  1487. Return Value:
  1488. TRUE Everything went okay.
  1489. FALSE We failed.
  1490. --*/
  1491. {
  1492. HANDLE hFile, hFileMapping;
  1493. DWORD FileSize, BytesWritten;
  1494. BYTE *pbFile;
  1495. BOOL ReturnValue = TRUE;
  1496. //
  1497. // Open the file...
  1498. //
  1499. hFile = CreateFile( FileName,
  1500. GENERIC_READ,
  1501. 0,
  1502. NULL,
  1503. OPEN_EXISTING,
  1504. FILE_ATTRIBUTE_NORMAL,
  1505. NULL );
  1506. if( hFile != INVALID_HANDLE_VALUE ) {
  1507. //
  1508. // Map the file...
  1509. //
  1510. hFileMapping = CreateFileMapping( hFile,
  1511. NULL,
  1512. PAGE_READONLY,
  1513. 0,
  1514. 0,
  1515. NULL );
  1516. if( hFileMapping ) {
  1517. pbFile = MapViewOfFile( hFileMapping,
  1518. FILE_MAP_READ,
  1519. 0,
  1520. 0,
  1521. 0 );
  1522. if( pbFile ) {
  1523. //
  1524. // Write the file...
  1525. //
  1526. FileSize = GetFileSize( hFile, NULL );
  1527. if( FileSize != 0xFFFFFFFF ) {
  1528. if( hOpenFile ) {
  1529. WriteFile( hOpenFile, pbFile, FileSize, &BytesWritten, NULL );
  1530. } else {
  1531. ReturnValue = FALSE;
  1532. }
  1533. } else {
  1534. ReturnValue = FALSE;
  1535. }
  1536. UnmapViewOfFile( pbFile );
  1537. } else {
  1538. ReturnValue = FALSE;
  1539. }
  1540. CloseHandle( hFileMapping );
  1541. } else {
  1542. ReturnValue = FALSE;
  1543. }
  1544. CloseHandle( hFile );
  1545. } else {
  1546. ReturnValue = FALSE;
  1547. }
  1548. return( ReturnValue );
  1549. }
  1550. BOOL
  1551. FileExists(
  1552. IN PCTSTR FileName,
  1553. OUT PWIN32_FIND_DATA FindData OPTIONAL
  1554. )
  1555. /*++
  1556. Routine Description:
  1557. Determine if a file exists and is accessible.
  1558. Errormode is set (and then restored) so the user will not see
  1559. any pop-ups.
  1560. Arguments:
  1561. FileName - supplies full path of file to check for existance.
  1562. FindData - if specified, receives find data for the file.
  1563. Return Value:
  1564. TRUE if the file exists and is accessible.
  1565. FALSE if not. GetLastError() returns extended error info.
  1566. --*/
  1567. {
  1568. WIN32_FIND_DATA findData;
  1569. HANDLE FindHandle;
  1570. UINT OldMode;
  1571. DWORD Error;
  1572. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1573. FindHandle = FindFirstFile(FileName,&findData);
  1574. if(FindHandle == INVALID_HANDLE_VALUE) {
  1575. Error = GetLastError();
  1576. } else {
  1577. FindClose(FindHandle);
  1578. if(FindData) {
  1579. *FindData = findData;
  1580. }
  1581. Error = NO_ERROR;
  1582. }
  1583. SetErrorMode(OldMode);
  1584. SetLastError(Error);
  1585. return (Error == NO_ERROR);
  1586. }
  1587. BOOL
  1588. DoesDirectoryExist (
  1589. IN PCTSTR DirSpec
  1590. )
  1591. /*++
  1592. Routine Description:
  1593. Determine if a directory exists and is accessible.
  1594. This routine works even with the root of drives or with the root of
  1595. network shares (like \\server\share).
  1596. Arguments:
  1597. DirSpec - supplies full path of dir to check for existance;
  1598. Return Value:
  1599. TRUE if the dir exists and is accessible.
  1600. --*/
  1601. {
  1602. TCHAR pattern[MAX_PATH];
  1603. BOOL b = FALSE;
  1604. if (DirSpec) {
  1605. if (BuildPath2 (pattern, MAX_PATH, DirSpec, TEXT("*"))) {
  1606. WIN32_FIND_DATA fd;
  1607. HANDLE h = FindFirstFile (pattern, &fd);
  1608. if (h != INVALID_HANDLE_VALUE) {
  1609. FindClose (h);
  1610. b = TRUE;
  1611. }
  1612. }
  1613. }
  1614. return b;
  1615. }
  1616. #ifdef _X86_
  1617. BOOLEAN
  1618. IsValidDrive(
  1619. TCHAR Drive
  1620. )
  1621. {
  1622. /*++
  1623. Routine Description:
  1624. This routine check formatted disk type
  1625. NEC98 of NT4 has supported NEC98 format and PC-AT format.
  1626. But BIOS is handling only NEC98 format.
  1627. So We need setup Boot stuff to ONLY NEC98 formated HD.
  1628. Arguments:
  1629. Drive Drive letter.
  1630. Return Value:
  1631. TRUE Dive is NEC98 format.
  1632. FALSE Drive is not NEC98 format.
  1633. --*/
  1634. HANDLE hDisk;
  1635. TCHAR HardDiskName[] = TEXT("\\\\.\\?:");
  1636. PUCHAR pBuffer,pUBuffer;
  1637. WCHAR Buffer[128];
  1638. WCHAR DevicePath[128];
  1639. WCHAR DriveName[3];
  1640. WCHAR DiskNo;
  1641. STORAGE_DEVICE_NUMBER number;
  1642. PWCHAR p;
  1643. ULONG bps;
  1644. NTSTATUS Sts;
  1645. DWORD DataSize,ExtentSize;
  1646. BOOL b;
  1647. PVOLUME_DISK_EXTENTS Extent;
  1648. if (!ISNT())
  1649. return TRUE;
  1650. HardDiskName[4] = Drive;
  1651. DriveName[0] = Drive;
  1652. DriveName[1] = ':';
  1653. DriveName[2] = 0;
  1654. if(QueryDosDeviceW(DriveName, Buffer, sizeof(Buffer)/sizeof(TCHAR))) {
  1655. if (BuildNumber <= NT40){ //check NT Version
  1656. //
  1657. // QueryDosDevice in NT3.51 is buggy.
  1658. // This API return "\\Harddisk\...." or
  1659. // "\\harddisk\...."
  1660. // We need work around.
  1661. //
  1662. p = wcsstr(Buffer, L"arddisk");
  1663. if (!p) {
  1664. return FALSE;
  1665. }
  1666. DiskNo = (*(p + 7) - 0x30);
  1667. } else {
  1668. hDisk = CreateFile(
  1669. HardDiskName,
  1670. 0,
  1671. FILE_SHARE_WRITE, NULL,
  1672. OPEN_EXISTING, 0, NULL
  1673. );
  1674. if(hDisk == INVALID_HANDLE_VALUE) {
  1675. return FALSE;
  1676. }
  1677. b = DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
  1678. &number, sizeof(number), &DataSize, NULL);
  1679. if (b) {
  1680. DiskNo = (TCHAR) number.DeviceNumber;
  1681. } else {
  1682. Extent = malloc(1024);
  1683. ExtentSize = 1024;
  1684. if(!Extent) {
  1685. CloseHandle( hDisk );
  1686. return FALSE;
  1687. }
  1688. b = DeviceIoControl(hDisk, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
  1689. NULL, 0,
  1690. (PVOID)Extent, ExtentSize, &DataSize, NULL);
  1691. if (!b) {
  1692. free(Extent);
  1693. CloseHandle( hDisk );
  1694. return FALSE;
  1695. }
  1696. if (Extent->NumberOfDiskExtents != 1){
  1697. free(Extent);
  1698. CloseHandle( hDisk );
  1699. return FALSE;
  1700. }
  1701. DiskNo = (TCHAR)Extent->Extents->DiskNumber;
  1702. free(Extent);
  1703. }
  1704. CloseHandle(hDisk);
  1705. }
  1706. swprintf(DevicePath, L"\\\\.\\PHYSICALDRIVE%u", DiskNo);
  1707. hDisk = CreateFileW( DevicePath,
  1708. GENERIC_READ|GENERIC_WRITE,
  1709. FILE_SHARE_READ, NULL,
  1710. OPEN_EXISTING, 0, NULL);
  1711. if(hDisk == INVALID_HANDLE_VALUE) {
  1712. return FALSE;
  1713. }
  1714. if ((bps = GetHDBps(hDisk)) == 0){
  1715. CloseHandle(hDisk);
  1716. return FALSE;
  1717. }
  1718. pUBuffer = MALLOC(bps * 2);
  1719. pBuffer = ALIGN(pUBuffer, bps);
  1720. RtlZeroMemory(pBuffer, bps);
  1721. Sts = SpReadWriteDiskSectors(hDisk,0,1,bps,pBuffer, NEC_READSEC);
  1722. if(!NT_SUCCESS(Sts)) {
  1723. FREE(pUBuffer);
  1724. CloseHandle(hDisk);
  1725. return FALSE;
  1726. }
  1727. if (!(pBuffer[4] == 'I'
  1728. && pBuffer[5] == 'P'
  1729. && pBuffer[6] == 'L'
  1730. && pBuffer[7] == '1')){
  1731. FREE(pUBuffer);
  1732. CloseHandle(hDisk);
  1733. return FALSE;
  1734. }
  1735. FREE(pUBuffer);
  1736. CloseHandle(hDisk);
  1737. return TRUE;
  1738. }
  1739. return FALSE;
  1740. }
  1741. BOOLEAN
  1742. CheckATACardonNT4(
  1743. HANDLE hDisk
  1744. )
  1745. {
  1746. //
  1747. // NT4, NT3.51 for NEC98.
  1748. // NEC98 does not handle to boot from PCMCIA ATA card disk.
  1749. // So we need to check ATA Disk.
  1750. //
  1751. // Return
  1752. // TRUE is ATA Card
  1753. // FALSE is Other
  1754. //
  1755. #define IOCTL_DISK_GET_FORMAT_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
  1756. #define FORMAT_MEDIA_98 0 // TYPE NEC98
  1757. #define FORMAT_MEDIA_AT 1 // TYPE PC-AT
  1758. #define FORMAT_MEDIA_OTHER 2 // Unknown
  1759. struct _OutBuffer {
  1760. ULONG CurrentFormatMedia;
  1761. ULONG InitializeFormatMedia;
  1762. } OutBuffer;
  1763. DWORD ReturnedByteCount;
  1764. if (!(DeviceIoControl(hDisk, IOCTL_DISK_GET_FORMAT_MEDIA, NULL,
  1765. 0,
  1766. &OutBuffer,
  1767. sizeof(struct _OutBuffer),
  1768. &ReturnedByteCount,
  1769. NULL
  1770. ) )){
  1771. return FALSE;
  1772. }
  1773. if (OutBuffer.InitializeFormatMedia == FORMAT_MEDIA_AT){
  1774. return TRUE;
  1775. }
  1776. return FALSE;
  1777. }
  1778. #endif
  1779. BOOL
  1780. IsMachineSupported(
  1781. OUT PCOMPATIBILITY_ENTRY CompEntry
  1782. )
  1783. /*++
  1784. Routine Description:
  1785. This function determines whether or not the machine is supported by the version
  1786. of NT to be installed.
  1787. Arguments:
  1788. CompEntry - If the machine is not supported, the Compatability Entry
  1789. is updated to describe why the machine is not supported.
  1790. Return Value:
  1791. Boolean value indicating whether the machine is supported.
  1792. --*/
  1793. {
  1794. TCHAR SetupLogPath[MAX_PATH];
  1795. TCHAR KeyName[MAX_PATH];
  1796. TCHAR HalName[MAX_PATH];
  1797. LPTSTR p;
  1798. LPTSTR szHalDll = TEXT("hal.dll");
  1799. LPTSTR SectionName;
  1800. LPTSTR UnsupportedName;
  1801. BOOL b;
  1802. //
  1803. // Assume that the machine is supported
  1804. //
  1805. b = TRUE;
  1806. #ifdef _X86_
  1807. try {
  1808. ULONG Name0, Name1, Name2, Family, Flags;
  1809. _asm {
  1810. push ebx ;; save ebx
  1811. mov eax, 0 ;; get processor vendor
  1812. _emit 00fh ;; CPUID(0)
  1813. _emit 0a2h ;;
  1814. mov Name0, ebx ;; Name[0-3]
  1815. mov Name1, edx ;; Name[4-7]
  1816. mov Name2, ecx ;; Name[8-11]
  1817. mov eax, 1 ;; get family/model/stepping and features
  1818. _emit 00fh ;; CPUID(1)
  1819. _emit 0a2h
  1820. mov Family, eax ;; save family/model/stepping
  1821. mov Flags, edx ;; save flags returned by CPUID
  1822. pop ebx ;; restore ebx
  1823. }
  1824. //
  1825. // Check the cmpxchg8b flag in the flags returned by CPUID.
  1826. //
  1827. if ((Flags & 0x100) == 0) {
  1828. //
  1829. // This processor doesn't support the CMPXCHG instruction
  1830. // which is required for Whistler.
  1831. //
  1832. // Some processors actually do support it but claim they
  1833. // don't because of a bug in NT 4. See if this processor
  1834. // is one of these.
  1835. //
  1836. if (!(((Name0 == 'uneG') &&
  1837. (Name1 == 'Teni') &&
  1838. (Name2 == '68xM') &&
  1839. (Family >= 0x542)) ||
  1840. (Name0 == 'tneC') &&
  1841. (Name1 == 'Hrua') &&
  1842. (Name2 == 'slua') &&
  1843. (Family >= 0x500))) {
  1844. b = FALSE;
  1845. }
  1846. }
  1847. } except(EXCEPTION_EXECUTE_HANDLER) {
  1848. //
  1849. // If this processor doesn't support CPUID, we don't
  1850. // run on it.
  1851. //
  1852. b = FALSE;
  1853. }
  1854. if (!b) {
  1855. CompEntry->HtmlName = TEXT("cpufeat.htm");
  1856. CompEntry->TextName = TEXT("cpufeat.txt");
  1857. SectionName = TEXT("UnsupportedArchitectures");
  1858. UnsupportedName = TEXT("missprocfeat");
  1859. }
  1860. #endif // _X86_
  1861. if( b && ISNT() ) {
  1862. //
  1863. // Build the path to setup.log
  1864. //
  1865. MyGetWindowsDirectory( SetupLogPath, MAX_PATH );
  1866. ConcatenatePaths( SetupLogPath, TEXT("repair\\setup.log"), MAX_PATH );
  1867. //
  1868. // Find out the actual name of the hal installed
  1869. //
  1870. if (!IsArc()) {
  1871. #ifdef _X86_
  1872. //
  1873. // On BIOS, look for %windir%\system32\hal.dll in the section
  1874. // [Files.WinNt]
  1875. //
  1876. GetSystemDirectory( KeyName, MAX_PATH );
  1877. ConcatenatePaths(KeyName, szHalDll, MAX_PATH );
  1878. SectionName = TEXT("Files.WinNt");
  1879. //
  1880. // While we are at it, see if this is Windows 2000 or higher
  1881. // to see if the hal should be preserved or not
  1882. //
  1883. #ifdef UNICODE
  1884. if (BUILDNUM() >= 2195) {
  1885. PCHAR halName;
  1886. halName = FindRealHalName( KeyName );
  1887. if (halName) {
  1888. WriteAcpiHalValue = TRUE;
  1889. if (!strcmp(halName,"halacpi") ||
  1890. !strcmp(halName,"halmacpi") ||
  1891. !strcmp(halName,"halaacpi")) {
  1892. AcpiHalValue = TRUE;
  1893. }
  1894. }
  1895. }
  1896. #endif // UNICODE
  1897. #endif // _X86_
  1898. } else {
  1899. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  1900. //
  1901. // On ARC, look for hal.dll in the section [Files.SystemPartition]
  1902. //
  1903. lstrcpy( KeyName, szHalDll );
  1904. SectionName = TEXT("Files.SystemPartition");
  1905. #endif // UNICODE
  1906. } // if (!IsArc())
  1907. GetPrivateProfileString( SectionName,
  1908. KeyName,
  1909. TEXT(""),
  1910. HalName,
  1911. sizeof(HalName)/sizeof(TCHAR),
  1912. SetupLogPath );
  1913. //
  1914. // GetPrivateProfileString() will strip the first and last '"' from the logged value,
  1915. // so find the next '"' character and replace it with NUL, and we will end up with
  1916. // the actual hal name.
  1917. //
  1918. if( lstrlen(HalName) &&
  1919. ( p = _tcschr( HalName, TEXT('"') ) )
  1920. ) {
  1921. *p = TEXT('\0');
  1922. //
  1923. // Find out if the hal is listed in [UnsupportedArchitectures] (dosnet.inf)
  1924. //
  1925. SectionName = TEXT("UnsupportedArchitectures");
  1926. b = !InfDoesLineExistInSection( MainInf,
  1927. SectionName,
  1928. HalName );
  1929. UnsupportedName = HalName;
  1930. }
  1931. }
  1932. //
  1933. // If architecture is not supported, look up the description.
  1934. //
  1935. if( !b ) {
  1936. CompEntry->Description = (LPTSTR)InfGetFieldByKey( MainInf,
  1937. SectionName,
  1938. UnsupportedName,
  1939. 0 );
  1940. }
  1941. return( b );
  1942. }
  1943. BOOL
  1944. DoesCurrentSystemHasThirdPartyKernel(
  1945. VOID
  1946. );
  1947. BOOL
  1948. SystemKernelCheck(
  1949. PCOMPAIBILITYCALLBACK CompatibilityCallback,
  1950. LPVOID Context
  1951. )
  1952. {
  1953. BOOL bResult = TRUE;
  1954. PWSTR Buffer;
  1955. #if defined(UNICODE) && defined(_X86_)
  1956. COMPATIBILITY_ENTRY CompEntry;
  1957. if(!DoesCurrentSystemHasThirdPartyKernel()){
  1958. return FALSE;
  1959. }
  1960. FormatMessageW(
  1961. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1962. hInst,
  1963. MSG_SYSTEM_HAS_THIRD_PARTY_KERNEL,
  1964. 0,
  1965. (PWSTR)&Buffer,
  1966. 0,
  1967. NULL
  1968. );
  1969. CompEntry.Description = Buffer;
  1970. CompEntry.HtmlName = TEXT("compdata\\krnlchk.htm");
  1971. CompEntry.TextName = TEXT("compdata\\krnlchk.txt");
  1972. CompEntry.RegKeyName = NULL;
  1973. CompEntry.RegValName = NULL;
  1974. CompEntry.RegValDataSize = 0;
  1975. CompEntry.RegValData = NULL;
  1976. CompEntry.SaveValue = NULL;
  1977. CompEntry.Flags = 0;
  1978. CompEntry.InfName = NULL;
  1979. CompEntry.InfSection = NULL;
  1980. bResult = CompatibilityCallback(&CompEntry, Context);
  1981. LocalFree(Buffer);
  1982. #endif
  1983. return bResult;
  1984. }
  1985. BOOL
  1986. UnsupportedArchitectureCheck(
  1987. PCOMPAIBILITYCALLBACK CompatibilityCallback,
  1988. LPVOID Context
  1989. )
  1990. /*++
  1991. Routine Description:
  1992. Check if the machine is no longer supported by Windows NT.
  1993. This routine is meaningful only when run on NT -- it always succeeds
  1994. on Win95.
  1995. Arguments:
  1996. CompatibilityCallback - pointer to call back function
  1997. Context - context pointer
  1998. Return Value:
  1999. Returns always TRUE.
  2000. --*/
  2001. {
  2002. COMPATIBILITY_ENTRY CompEntry;
  2003. CompEntry.Description = TEXT("mca");//BUGBUG: must be changed
  2004. #ifdef _X86_
  2005. CompEntry.HtmlName = TEXT("mca.htm");
  2006. CompEntry.TextName = TEXT("mca.txt");
  2007. #else
  2008. CompEntry.HtmlName = TEXT("");
  2009. CompEntry.TextName = TEXT("");
  2010. #endif
  2011. CompEntry.RegKeyName = NULL;
  2012. CompEntry.RegValName = NULL;
  2013. CompEntry.RegValDataSize = 0;
  2014. CompEntry.RegValData = NULL;
  2015. CompEntry.SaveValue = NULL;
  2016. CompEntry.Flags = 0;
  2017. CompEntry.InfName = NULL;
  2018. CompEntry.InfSection = NULL;
  2019. if( !IsMachineSupported( &CompEntry ) ) {
  2020. if(!CompatibilityCallback(&CompEntry, Context)){
  2021. DWORD Error;
  2022. Error = GetLastError();
  2023. }
  2024. }
  2025. return( TRUE );
  2026. }
  2027. BOOL
  2028. GetUserPrintableFileSizeString(
  2029. IN DWORDLONG Size,
  2030. OUT LPTSTR Buffer,
  2031. IN DWORD BufferSize
  2032. )
  2033. /*++
  2034. Routine Description:
  2035. Takes a size and comes up with a printable version of this size,
  2036. using the appropriate size format (ie., KB, MB, GB, Bytes, etc.)
  2037. Arguments:
  2038. Size - size to be converted (in bytes)
  2039. Buffer - string buffer to receive the data
  2040. BufferSize - indicates the buffer size, *in characters*
  2041. Return Value:
  2042. TRUE indicates success, FALSE indicates failure. If we fail,
  2043. call GetLastError() to get extended failure status.
  2044. --*/
  2045. {
  2046. LPTSTR NumberString;
  2047. UINT uResource;
  2048. TCHAR ResourceString[100];
  2049. DWORD cb;
  2050. DWORD d;
  2051. BOOL RetVal = FALSE;
  2052. DWORDLONG TopPart;
  2053. DWORDLONG BottomPart;
  2054. //
  2055. // Determine which resource string to use
  2056. //
  2057. if (Size < 1024) {
  2058. uResource = IDS_SIZE_BYTES;
  2059. TopPart = 0;
  2060. BottomPart = 1;
  2061. wsprintf(ResourceString, TEXT("%u"), Size);
  2062. } else if (Size < (1024 * 1024)) {
  2063. uResource = IDS_SIZE_KBYTES;
  2064. TopPart = (Size%1024)*100;
  2065. BottomPart = 1024;
  2066. wsprintf(ResourceString,
  2067. TEXT("%u.%02u"),
  2068. (DWORD) (Size / 1024),
  2069. (DWORD)(TopPart/BottomPart));
  2070. } else if (Size < (1024 * 1024 * 1024)) {
  2071. uResource = IDS_SIZE_MBYTES;
  2072. TopPart = (Size%(1024*1024))*100;
  2073. BottomPart = 1024*1024;
  2074. wsprintf(ResourceString,
  2075. TEXT("%u.%02u"),
  2076. (DWORD)(Size / (1024 * 1024)),
  2077. (DWORD)(TopPart/BottomPart) );
  2078. } else {
  2079. uResource = IDS_SIZE_GBYTES;
  2080. TopPart = (Size%(1024*1024*1024))*100;
  2081. BottomPart = 1024*1024*1024;
  2082. wsprintf(ResourceString,
  2083. TEXT("%u.%02u"),
  2084. (DWORD)(Size / (1024 * 1024 * 1024)),
  2085. (DWORD)(TopPart/BottomPart) );
  2086. }
  2087. // Format the number string
  2088. cb = GetNumberFormat(LOCALE_USER_DEFAULT, 0, ResourceString, NULL, NULL, 0);
  2089. NumberString = (LPTSTR) MALLOC((cb + 1) * sizeof(TCHAR));
  2090. if (!NumberString) {
  2091. d = ERROR_NOT_ENOUGH_MEMORY;
  2092. RetVal = FALSE;
  2093. goto e0;
  2094. }
  2095. GetNumberFormat(LOCALE_USER_DEFAULT, 0, ResourceString, NULL, NumberString, cb);
  2096. LoadString(hInst, uResource, ResourceString, sizeof(ResourceString)/sizeof(TCHAR));
  2097. //
  2098. // it's tricky to know if we really have enough space in the buffer since
  2099. // we're dealing with substitution strings. The below is an
  2100. // approximate check since we assume that the number string is likely
  2101. // larger than our substitution string (%s) that we're filling in.
  2102. //
  2103. if (BufferSize > (DWORD)(lstrlen(ResourceString) + lstrlen(NumberString) + 1)) {
  2104. wsprintf(Buffer, ResourceString, NumberString);
  2105. d = ERROR_SUCCESS;
  2106. RetVal = TRUE;
  2107. } else {
  2108. d = ERROR_INSUFFICIENT_BUFFER;
  2109. RetVal = FALSE;
  2110. }
  2111. FREE(NumberString);
  2112. e0:
  2113. SetLastError(d);
  2114. return(RetVal);
  2115. }
  2116. BOOL
  2117. BuildSystemPartitionPathToFile (
  2118. IN PCTSTR FileName,
  2119. OUT PTSTR Path,
  2120. IN DWORD BufferSizeChars
  2121. )
  2122. {
  2123. //
  2124. // must have a root
  2125. //
  2126. if(SystemPartitionDriveLetter) {
  2127. Path[0] = SystemPartitionDriveLetter;
  2128. Path[1] = TEXT(':');
  2129. Path[2] = 0;
  2130. } else {
  2131. #ifdef UNICODE
  2132. if (SystemPartitionVolumeGuid) {
  2133. lstrcpyn (Path, SystemPartitionVolumeGuid, BufferSizeChars);
  2134. }
  2135. else
  2136. #endif
  2137. {
  2138. MYASSERT (FALSE);
  2139. return FALSE;
  2140. }
  2141. }
  2142. ConcatenatePaths (Path, FileName, BufferSizeChars);
  2143. return TRUE;
  2144. }
  2145. PTSTR
  2146. BuildPath (
  2147. IN PTSTR DestPath,
  2148. IN PCTSTR Path1,
  2149. IN PCTSTR Path2
  2150. )
  2151. {
  2152. PTSTR p;
  2153. p = _tcsrchr (Path1, TEXT('\\'));
  2154. if (p && !p[1]) {
  2155. *p = 0;
  2156. }
  2157. if (*Path2 == TEXT('\\')) {
  2158. Path2++;
  2159. }
  2160. return DestPath + wsprintf (DestPath, TEXT("%s\\%s"), Path1, Path2);
  2161. }
  2162. PTSTR
  2163. BuildPath2 (
  2164. IN PTSTR DestPath,
  2165. IN DWORD Chars,
  2166. IN PCTSTR Path1,
  2167. IN PCTSTR Path2
  2168. )
  2169. {
  2170. INT i = _sntprintf (DestPath, Chars, TEXT("%s\\%s"), Path1, Path2);
  2171. if (i < 0) {
  2172. return NULL;
  2173. }
  2174. return DestPath + i;
  2175. }
  2176. BOOL
  2177. EnumFirstFilePattern (
  2178. OUT PFILEPATTERN_ENUM Enum,
  2179. IN PCTSTR Dir,
  2180. IN PCTSTR FilePattern
  2181. )
  2182. {
  2183. TCHAR pattern[MAX_PATH];
  2184. BuildPath (pattern, Dir, FilePattern);
  2185. Enum->Handle = FindFirstFile (pattern, &Enum->FindData);
  2186. if (Enum->Handle == INVALID_HANDLE_VALUE) {
  2187. return FALSE;
  2188. }
  2189. lstrcpy (Enum->FullPath, Dir);
  2190. Enum->FileName = _tcschr (Enum->FullPath, 0);
  2191. *Enum->FileName++ = TEXT('\\');
  2192. lstrcpy (Enum->FileName, Enum->FindData.cFileName);
  2193. if (Enum->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  2194. if (!lstrcmp (Enum->FindData.cFileName, TEXT (".")) ||
  2195. !lstrcmp (Enum->FindData.cFileName, TEXT (".."))) {
  2196. return EnumNextFilePattern (Enum);
  2197. }
  2198. }
  2199. return TRUE;
  2200. }
  2201. BOOL
  2202. EnumNextFilePattern (
  2203. IN OUT PFILEPATTERN_ENUM Enum
  2204. )
  2205. {
  2206. again:
  2207. if (!FindNextFile (Enum->Handle, &Enum->FindData)) {
  2208. AbortEnumFilePattern (Enum);
  2209. return FALSE;
  2210. }
  2211. lstrcpy (Enum->FileName, Enum->FindData.cFileName);
  2212. if (Enum->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  2213. if (!lstrcmp (Enum->FindData.cFileName, TEXT (".")) ||
  2214. !lstrcmp (Enum->FindData.cFileName, TEXT (".."))) {
  2215. goto again;
  2216. }
  2217. }
  2218. return TRUE;
  2219. }
  2220. VOID
  2221. AbortEnumFilePattern (
  2222. IN OUT PFILEPATTERN_ENUM Enum
  2223. )
  2224. {
  2225. if (Enum->Handle != INVALID_HANDLE_VALUE) {
  2226. FindClose (Enum->Handle);
  2227. Enum->Handle = INVALID_HANDLE_VALUE;
  2228. }
  2229. }
  2230. BOOL
  2231. EnumFirstFilePatternRecursive (
  2232. OUT PFILEPATTERNREC_ENUM Enum,
  2233. IN PCTSTR Dir,
  2234. IN PCTSTR FilePattern,
  2235. IN DWORD ControlFlags
  2236. )
  2237. {
  2238. PFILEENUMLIST dir;
  2239. dir = CreateFileEnumCell (Dir, FilePattern, 0, ENUM_FIRSTFILE);
  2240. if (!dir) {
  2241. return FALSE;
  2242. }
  2243. Enum->FilePattern = DupString (FilePattern);
  2244. if (!Enum->FilePattern) {
  2245. DeleteFileEnumCell (dir);
  2246. return FALSE;
  2247. }
  2248. Enum->DirCurrent = dir;
  2249. Enum->FindData = &dir->Enum.FindData;
  2250. Enum->RootLen = lstrlen (Dir) + 1;
  2251. Enum->ControlFlags = ControlFlags;
  2252. Enum->Handle = INVALID_HANDLE_VALUE;
  2253. return EnumNextFilePatternRecursive (Enum);
  2254. }
  2255. BOOL
  2256. EnumNextFilePatternRecursive (
  2257. IN OUT PFILEPATTERNREC_ENUM Enum
  2258. )
  2259. {
  2260. TCHAR pattern[MAX_PATH];
  2261. WIN32_FIND_DATA fd;
  2262. PFILEENUMLIST dir;
  2263. while (Enum->DirCurrent) {
  2264. if (Enum->ControlFlags & ECF_ABORT_ENUM_DIR) {
  2265. //
  2266. // caller wants to abort enum of this subdir
  2267. // remove the current node from list
  2268. //
  2269. Enum->ControlFlags &= ~ECF_ABORT_ENUM_DIR;
  2270. dir = Enum->DirCurrent->Next;
  2271. DeleteFileEnumCell (Enum->DirCurrent);
  2272. Enum->DirCurrent = dir;
  2273. if (dir) {
  2274. Enum->FindData = &dir->Enum.FindData;
  2275. }
  2276. continue;
  2277. }
  2278. switch (Enum->DirCurrent->EnumState) {
  2279. case ENUM_FIRSTFILE:
  2280. if (EnumFirstFilePattern (&Enum->DirCurrent->Enum, Enum->DirCurrent->Dir, Enum->FilePattern)) {
  2281. Enum->DirCurrent->EnumState = ENUM_NEXTFILE;
  2282. Enum->FullPath = Enum->DirCurrent->Enum.FullPath;
  2283. Enum->SubPath = Enum->FullPath + Enum->RootLen;
  2284. Enum->FileName = Enum->DirCurrent->Enum.FileName;
  2285. return TRUE;
  2286. }
  2287. Enum->DirCurrent->EnumState = ENUM_SUBDIRS;
  2288. break;
  2289. case ENUM_NEXTFILE:
  2290. if (EnumNextFilePattern (&Enum->DirCurrent->Enum)) {
  2291. Enum->FullPath = Enum->DirCurrent->Enum.FullPath;
  2292. Enum->SubPath = Enum->FullPath + Enum->RootLen;
  2293. Enum->FileName = Enum->DirCurrent->Enum.FileName;
  2294. return TRUE;
  2295. }
  2296. Enum->DirCurrent->EnumState = ENUM_SUBDIRS;
  2297. //
  2298. // fall through
  2299. //
  2300. case ENUM_SUBDIRS:
  2301. BuildPath (pattern, Enum->DirCurrent->Dir, TEXT("*.*"));
  2302. Enum->Handle = FindFirstFile (pattern, &fd);
  2303. if (Enum->Handle != INVALID_HANDLE_VALUE) {
  2304. do {
  2305. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  2306. if (!lstrcmp (fd.cFileName, TEXT (".")) ||
  2307. !lstrcmp (fd.cFileName, TEXT (".."))) {
  2308. continue;
  2309. }
  2310. wsprintf (pattern, TEXT("%s\\%s"), Enum->DirCurrent->Dir, fd.cFileName);
  2311. if (!InsertList (
  2312. (PGENERIC_LIST*)&Enum->DirCurrent,
  2313. (PGENERIC_LIST) CreateFileEnumCell (
  2314. pattern,
  2315. Enum->FilePattern,
  2316. fd.dwFileAttributes,
  2317. Enum->ControlFlags & ECF_ENUM_SUBDIRS ?
  2318. ENUM_SUBDIR : ENUM_FIRSTFILE
  2319. )
  2320. )) {
  2321. AbortEnumFilePatternRecursive (Enum);
  2322. return FALSE;
  2323. }
  2324. }
  2325. } while (FindNextFile (Enum->Handle, &fd));
  2326. FindClose (Enum->Handle);
  2327. Enum->Handle = INVALID_HANDLE_VALUE;
  2328. }
  2329. //
  2330. // remove the current node from list
  2331. //
  2332. dir = Enum->DirCurrent->Next;
  2333. DeleteFileEnumCell (Enum->DirCurrent);
  2334. Enum->DirCurrent = dir;
  2335. if (dir) {
  2336. Enum->FindData = &dir->Enum.FindData;
  2337. }
  2338. break;
  2339. case ENUM_SUBDIR:
  2340. Enum->FullPath = Enum->DirCurrent->Dir;
  2341. Enum->SubPath = Enum->FullPath + Enum->RootLen;
  2342. Enum->FileName = _tcsrchr (Enum->FullPath, TEXT('\\')) + 1;
  2343. Enum->DirCurrent->EnumState = ENUM_FIRSTFILE;
  2344. return TRUE;
  2345. }
  2346. }
  2347. return FALSE;
  2348. }
  2349. VOID
  2350. AbortEnumFilePatternRecursive (
  2351. IN OUT PFILEPATTERNREC_ENUM Enum
  2352. )
  2353. {
  2354. if (Enum->DirCurrent) {
  2355. DeleteFileEnumList (Enum->DirCurrent);
  2356. Enum->DirCurrent = NULL;
  2357. }
  2358. if (Enum->Handle != INVALID_HANDLE_VALUE) {
  2359. FindClose (Enum->Handle);
  2360. Enum->Handle = INVALID_HANDLE_VALUE;
  2361. }
  2362. }
  2363. BOOL
  2364. CopyTree (
  2365. IN PCTSTR SourceRoot,
  2366. IN PCTSTR DestRoot
  2367. )
  2368. {
  2369. DWORD rc = ERROR_SUCCESS;
  2370. FILEPATTERNREC_ENUM e;
  2371. TCHAR destFile[MAX_PATH];
  2372. PTSTR p;
  2373. if (EnumFirstFilePatternRecursive (&e, SourceRoot, TEXT("*"), 0)) {
  2374. do {
  2375. BuildPath (destFile, DestRoot, e.SubPath);
  2376. p = _tcsrchr (destFile, TEXT('\\'));
  2377. if (!p) {
  2378. continue;
  2379. }
  2380. *p = 0;
  2381. rc = CreateMultiLevelDirectory (destFile);
  2382. if (rc != ERROR_SUCCESS) {
  2383. AbortEnumFilePatternRecursive (&e);
  2384. break;
  2385. }
  2386. *p = TEXT('\\');
  2387. SetFileAttributes (destFile, FILE_ATTRIBUTE_NORMAL);
  2388. if (!CopyFile (e.FullPath, destFile, FALSE)) {
  2389. rc = GetLastError ();
  2390. AbortEnumFilePatternRecursive (&e);
  2391. break;
  2392. }
  2393. } while (EnumNextFilePatternRecursive (&e));
  2394. } else {
  2395. rc = GetLastError ();
  2396. }
  2397. SetLastError (rc);
  2398. return rc == ERROR_SUCCESS;
  2399. }
  2400. PSTRINGLIST
  2401. CreateStringCell (
  2402. IN PCTSTR String
  2403. )
  2404. {
  2405. PSTRINGLIST p = MALLOC (sizeof (STRINGLIST));
  2406. if (p) {
  2407. ZeroMemory (p, sizeof (STRINGLIST));
  2408. if (String) {
  2409. p->String = DupString (String);
  2410. if (!p->String) {
  2411. FREE (p);
  2412. p = NULL;
  2413. }
  2414. } else {
  2415. p->String = NULL;
  2416. }
  2417. }
  2418. return p;
  2419. }
  2420. VOID
  2421. DeleteStringCell (
  2422. IN PSTRINGLIST Cell
  2423. )
  2424. {
  2425. if (Cell) {
  2426. FREE (Cell->String);
  2427. FREE (Cell);
  2428. }
  2429. }
  2430. VOID
  2431. DeleteStringList (
  2432. IN PSTRINGLIST List
  2433. )
  2434. {
  2435. PSTRINGLIST p, q;
  2436. for (p = List; p; p = q) {
  2437. q = p->Next;
  2438. DeleteStringCell (p);
  2439. }
  2440. }
  2441. BOOL
  2442. FindStringCell (
  2443. IN PSTRINGLIST StringList,
  2444. IN PCTSTR String,
  2445. IN BOOL CaseSensitive
  2446. )
  2447. {
  2448. PSTRINGLIST p;
  2449. INT i;
  2450. if (!StringList || !String) {
  2451. return FALSE;
  2452. }
  2453. for (p = StringList; p; p = p->Next) {
  2454. i = CaseSensitive ? _tcscmp (String, p->String) : _tcsicmp (String, p->String);
  2455. if (i == 0) {
  2456. return TRUE;
  2457. }
  2458. }
  2459. return FALSE;
  2460. }
  2461. PFILEENUMLIST
  2462. CreateFileEnumCell (
  2463. IN PCTSTR Dir,
  2464. IN PCTSTR FilePattern,
  2465. IN DWORD Attributes,
  2466. IN DWORD EnumState
  2467. )
  2468. {
  2469. PFILEENUMLIST p = MALLOC (sizeof (FILEENUMLIST));
  2470. if (p) {
  2471. ZeroMemory (p, sizeof (FILEENUMLIST));
  2472. p->Enum.FindData.dwFileAttributes = Attributes;
  2473. p->EnumState = EnumState;
  2474. p->Dir = DupString (Dir);
  2475. if (!p->Dir) {
  2476. FREE (p);
  2477. p = NULL;
  2478. }
  2479. }
  2480. return p;
  2481. }
  2482. VOID
  2483. DeleteFileEnumCell (
  2484. IN PFILEENUMLIST Cell
  2485. )
  2486. {
  2487. if (Cell) {
  2488. FREE (Cell->Dir);
  2489. FREE (Cell);
  2490. }
  2491. }
  2492. BOOL
  2493. InsertList (
  2494. IN OUT PGENERIC_LIST* List,
  2495. IN PGENERIC_LIST NewList
  2496. )
  2497. {
  2498. PGENERIC_LIST p;
  2499. if (!NewList) {
  2500. return FALSE;
  2501. }
  2502. if (*List) {
  2503. for (p = *List; p->Next; p = p->Next) ;
  2504. p->Next = NewList;
  2505. } else {
  2506. *List = NewList;
  2507. }
  2508. return TRUE;
  2509. }
  2510. VOID
  2511. DeleteFileEnumList (
  2512. IN PFILEENUMLIST NewList
  2513. )
  2514. {
  2515. PFILEENUMLIST p, q;
  2516. for (p = NewList; p; p = q) {
  2517. q = p->Next;
  2518. DeleteFileEnumCell (p);
  2519. }
  2520. }
  2521. PCTSTR
  2522. FindSubString (
  2523. IN PCTSTR String,
  2524. IN TCHAR Separator,
  2525. IN PCTSTR SubStr,
  2526. IN BOOL CaseSensitive
  2527. )
  2528. {
  2529. SIZE_T len1, len2;
  2530. PCTSTR end;
  2531. MYASSERT (Separator);
  2532. MYASSERT (!_istleadbyte (Separator));
  2533. MYASSERT (SubStr);
  2534. MYASSERT (!_tcschr (SubStr, Separator));
  2535. len1 = lstrlen (SubStr);
  2536. MYASSERT (SubStr[len1] == 0);
  2537. while (String) {
  2538. end = _tcschr (String, Separator);
  2539. if (end) {
  2540. len2 = end - String;
  2541. } else {
  2542. len2 = lstrlen (String);
  2543. }
  2544. if ((len1 == len2) &&
  2545. (CaseSensitive ?
  2546. !_tcsncmp (String, SubStr, len1) :
  2547. !_tcsnicmp (String, SubStr, len1)
  2548. )) {
  2549. break;
  2550. }
  2551. if (end) {
  2552. String = end + 1;
  2553. } else {
  2554. String = NULL;
  2555. }
  2556. }
  2557. return String;
  2558. }
  2559. VOID
  2560. GetCurrentWinnt32RegKey (
  2561. OUT PTSTR Key,
  2562. IN DWORD Chars
  2563. )
  2564. {
  2565. _sntprintf (
  2566. Key,
  2567. Chars,
  2568. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\Winnt32\\%u.%u"),
  2569. VER_PRODUCTMAJORVERSION,
  2570. VER_PRODUCTMINORVERSION
  2571. );
  2572. }
  2573. BOOL
  2574. GetFileVersion (
  2575. IN PCTSTR FilePath,
  2576. OUT PTSTR FileVersion
  2577. )
  2578. {
  2579. DWORD dwLength, dwTemp;
  2580. LPVOID lpData;
  2581. VS_FIXEDFILEINFO *VsInfo;
  2582. UINT DataLength;
  2583. BOOL b = FALSE;
  2584. if (FileExists (FilePath, NULL)) {
  2585. if (dwLength = GetFileVersionInfoSize ((PTSTR)FilePath, &dwTemp)) {
  2586. if (lpData = LocalAlloc (LPTR, dwLength)) {
  2587. if (GetFileVersionInfo ((PTSTR)FilePath, 0, dwLength, lpData)) {
  2588. if (VerQueryValue (lpData, TEXT("\\"), &VsInfo, &DataLength)) {
  2589. wsprintf (
  2590. FileVersion,
  2591. TEXT("%u.%u.%u.%u"),
  2592. (UINT)HIWORD(VsInfo->dwFileVersionMS),
  2593. (UINT)LOWORD(VsInfo->dwFileVersionMS),
  2594. (UINT)HIWORD(VsInfo->dwFileVersionLS),
  2595. (UINT)LOWORD(VsInfo->dwFileVersionLS)
  2596. );
  2597. b = TRUE;
  2598. }
  2599. }
  2600. LocalFree (lpData);
  2601. }
  2602. }
  2603. }
  2604. return b;
  2605. }
  2606. BOOL
  2607. IsFileVersionLesser (
  2608. IN PCTSTR FileToCompare,
  2609. IN PCTSTR FileToCompareWith
  2610. )
  2611. {
  2612. TCHAR version[20];
  2613. if (GetFileVersion (FileToCompareWith, version) && CheckForFileVersion (FileToCompare, version)) {
  2614. DebugLog (
  2615. Winnt32LogInformation,
  2616. TEXT("File %1 has a smaller version (%2) than %3"),
  2617. 0,
  2618. FileToCompare,
  2619. version,
  2620. FileToCompareWith
  2621. );
  2622. return TRUE;
  2623. }
  2624. return FALSE;
  2625. }
  2626. BOOL
  2627. FindPathToInstallationFileEx (
  2628. IN PCTSTR FileName,
  2629. OUT PTSTR PathToFile,
  2630. IN DWORD PathToFileBufferSize,
  2631. OUT PBOOL Compressed OPTIONAL
  2632. )
  2633. {
  2634. DWORD i;
  2635. DWORD attr;
  2636. BOOL b;
  2637. HANDLE h;
  2638. WIN32_FIND_DATA fd;
  2639. PTSTR p, q;
  2640. if (!FileName || !*FileName) {
  2641. return FALSE;
  2642. }
  2643. //
  2644. // Search for installation files in this order:
  2645. // 1. AlternateSourcePath (specified on the cmd line with /M:Path
  2646. // 2. Setup Update files (downloaded from the web)
  2647. // 3. NativeSourcePath(s)
  2648. // 4. SourcePath(s)
  2649. //
  2650. if (AlternateSourcePath[0]) {
  2651. lstrcpyn (PathToFile, AlternateSourcePath, PathToFileBufferSize);
  2652. ConcatenatePaths (PathToFile, FileName, PathToFileBufferSize);
  2653. attr = GetFileAttributes (PathToFile);
  2654. if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  2655. return TRUE;
  2656. }
  2657. }
  2658. if (g_DynUpdtStatus->UpdatesPath[0]) {
  2659. BuildPath (PathToFile, g_DynUpdtStatus->UpdatesPath, FileName);
  2660. attr = GetFileAttributes (PathToFile);
  2661. if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  2662. return TRUE;
  2663. }
  2664. }
  2665. for (i = 0; i < SourceCount; i++) {
  2666. lstrcpyn (PathToFile, NativeSourcePaths[i], PathToFileBufferSize);
  2667. ConcatenatePaths (PathToFile, FileName, PathToFileBufferSize);
  2668. p = CharPrev (PathToFile, _tcschr (PathToFile, 0));
  2669. *p = TEXT('?');
  2670. b = FALSE;
  2671. h = FindFirstFile (PathToFile, &fd);
  2672. if (h != INVALID_HANDLE_VALUE) {
  2673. if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  2674. q = CharPrev (fd.cFileName, _tcschr (fd.cFileName, 0));
  2675. *p = *q;
  2676. if (Compressed) {
  2677. *Compressed = (*q == TEXT('_'));
  2678. }
  2679. b = TRUE;
  2680. }
  2681. FindClose (h);
  2682. }
  2683. if (b) {
  2684. return TRUE;
  2685. }
  2686. }
  2687. for (i = 0; i < SourceCount; i++) {
  2688. lstrcpyn (PathToFile, SourcePaths[i], PathToFileBufferSize);
  2689. ConcatenatePaths (PathToFile, FileName, PathToFileBufferSize);
  2690. p = CharPrev (PathToFile, _tcschr (PathToFile, 0));
  2691. *p = TEXT('?');
  2692. b = FALSE;
  2693. h = FindFirstFile (PathToFile, &fd);
  2694. if (h != INVALID_HANDLE_VALUE) {
  2695. if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  2696. q = CharPrev (fd.cFileName, _tcschr (fd.cFileName, 0));
  2697. *p = *q;
  2698. if (Compressed) {
  2699. *Compressed = (*q == TEXT('_'));
  2700. }
  2701. b = TRUE;
  2702. }
  2703. FindClose (h);
  2704. }
  2705. if (b) {
  2706. return TRUE;
  2707. }
  2708. }
  2709. return FALSE;
  2710. }
  2711. BOOL
  2712. FindPathToWinnt32File (
  2713. IN PCTSTR FileRelativePath,
  2714. OUT PTSTR PathToFile,
  2715. IN DWORD PathToFileBufferSize
  2716. )
  2717. {
  2718. DWORD i;
  2719. DWORD attr;
  2720. TCHAR cdFilePath[MAX_PATH];
  2721. PTSTR p;
  2722. if (!FileRelativePath || !*FileRelativePath) {
  2723. return FALSE;
  2724. }
  2725. if (!GetModuleFileName (NULL, cdFilePath, MAX_PATH) ||
  2726. !(p = _tcsrchr (cdFilePath, TEXT('\\')))) {
  2727. return FALSE;
  2728. }
  2729. lstrcpy (p + 1, FileRelativePath);
  2730. //
  2731. // Search for winnt32 files in this order:
  2732. // 1. AlternateSourcePath (specified on the cmd line with /M:Path
  2733. // 2. Setup Update files (downloaded from the web)
  2734. // 3. NativeSourcePath(s)
  2735. // 4. SourcePath(s)
  2736. //
  2737. if (AlternateSourcePath[0]) {
  2738. if (BuildPath2 (PathToFile, PathToFileBufferSize, AlternateSourcePath, FileRelativePath)) {
  2739. attr = GetFileAttributes (PathToFile);
  2740. if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  2741. return TRUE;
  2742. }
  2743. }
  2744. p = _tcsrchr (PathToFile, TEXT('\\'));
  2745. if (p) {
  2746. //
  2747. // try the root of /M too, for backward compatibility with W2K
  2748. //
  2749. if (BuildPath2 (PathToFile, PathToFileBufferSize, AlternateSourcePath, p + 1)) {
  2750. attr = GetFileAttributes (PathToFile);
  2751. if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  2752. return TRUE;
  2753. }
  2754. }
  2755. }
  2756. }
  2757. if (g_DynUpdtStatus && g_DynUpdtStatus->Winnt32Path[0]) {
  2758. BuildPath (PathToFile, g_DynUpdtStatus->Winnt32Path, FileRelativePath);
  2759. attr = GetFileAttributes (PathToFile);
  2760. if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  2761. //
  2762. // check file version relative to the CD version
  2763. //
  2764. if (!IsFileVersionLesser (PathToFile, cdFilePath)) {
  2765. return TRUE;
  2766. }
  2767. }
  2768. }
  2769. #ifndef UNICODE
  2770. //
  2771. // on Win9x systems, first check if the file was downloaded in %windir%\winnt32
  2772. // load it from there if it's present
  2773. //
  2774. if (g_LocalSourcePath) {
  2775. lstrcpynA (PathToFile, g_LocalSourcePath, PathToFileBufferSize);
  2776. ConcatenatePaths (PathToFile, FileRelativePath, PathToFileBufferSize);
  2777. attr = GetFileAttributes (PathToFile);
  2778. if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  2779. return TRUE;
  2780. }
  2781. }
  2782. #endif
  2783. for (i = 0; i < SourceCount; i++) {
  2784. lstrcpyn (PathToFile, NativeSourcePaths[i], PathToFileBufferSize);
  2785. ConcatenatePaths (PathToFile, FileRelativePath, PathToFileBufferSize);
  2786. attr = GetFileAttributes (PathToFile);
  2787. if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  2788. return TRUE;
  2789. }
  2790. }
  2791. for (i = 0; i < SourceCount; i++) {
  2792. lstrcpyn (PathToFile, SourcePaths[i], PathToFileBufferSize);
  2793. ConcatenatePaths (PathToFile, FileRelativePath, PathToFileBufferSize);
  2794. attr = GetFileAttributes (PathToFile);
  2795. if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  2796. return TRUE;
  2797. }
  2798. }
  2799. attr = GetFileAttributes (cdFilePath);
  2800. if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  2801. lstrcpyn (PathToFile, cdFilePath, MAX_PATH);
  2802. return TRUE;
  2803. }
  2804. return FALSE;
  2805. }
  2806. BOOL
  2807. CreateDir (
  2808. IN PCTSTR DirName
  2809. )
  2810. {
  2811. return CreateDirectory (DirName, NULL) || GetLastError () == ERROR_ALREADY_EXISTS;
  2812. }
  2813. BOOL
  2814. GetLinkDate (
  2815. IN PCTSTR FilePath,
  2816. OUT PDWORD LinkDate
  2817. )
  2818. {
  2819. HANDLE hFile;
  2820. HANDLE hFileMapping;
  2821. PVOID pFileBase;
  2822. DWORD fileSize;
  2823. PIMAGE_DOS_HEADER dosHeader;
  2824. PIMAGE_NT_HEADERS pNtHeaders;
  2825. DWORD rc;
  2826. rc = MapFileForRead (FilePath, &fileSize, &hFile, &hFileMapping, &pFileBase);
  2827. if (rc != ERROR_SUCCESS) {
  2828. SetLastError (rc);
  2829. return FALSE;
  2830. }
  2831. __try {
  2832. if (fileSize < sizeof (IMAGE_DOS_HEADER)) {
  2833. rc = ERROR_BAD_FORMAT;
  2834. __leave;
  2835. }
  2836. dosHeader = (PIMAGE_DOS_HEADER)pFileBase;
  2837. if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  2838. rc = ERROR_BAD_FORMAT;
  2839. __leave;
  2840. }
  2841. if ((DWORD)dosHeader->e_lfanew + sizeof (IMAGE_NT_HEADERS) > fileSize) {
  2842. rc = ERROR_BAD_FORMAT;
  2843. __leave;
  2844. }
  2845. pNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)pFileBase + dosHeader->e_lfanew);
  2846. if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
  2847. rc = ERROR_BAD_FORMAT;
  2848. __leave;
  2849. }
  2850. *LinkDate = pNtHeaders->FileHeader.TimeDateStamp;
  2851. rc = ERROR_SUCCESS;
  2852. } __finally {
  2853. UnmapFile (hFileMapping, pFileBase);
  2854. CloseHandle (hFile);
  2855. SetLastError (rc);
  2856. }
  2857. return rc == ERROR_SUCCESS;
  2858. }
  2859. BOOL
  2860. CheckForFileVersionEx (
  2861. LPCTSTR FileName,
  2862. LPCTSTR FileVer, OPTIONAL
  2863. LPCTSTR BinProductVer, OPTIONAL
  2864. LPCTSTR LinkDate OPTIONAL
  2865. )
  2866. /*
  2867. Arguments -
  2868. FileName - Full path to the file to check
  2869. Filever - Version value to check against of the for x.x.x.x
  2870. BinProductVer - Version value to check against of the for x.x.x.x
  2871. LinkDate - Link date of executable
  2872. Function will check the actual file against the fields specified. The depth of the check
  2873. is as deep as specified in "x.x.x.x" i..e if FileVer = 3.5.1 and actual version on the file
  2874. is 3.5.1.4 we only compare upto 3.5.1.
  2875. Return values -
  2876. TRUE - If the version of the file is <= FileVer which means that the file is an incompatible one
  2877. else we return FALSE
  2878. */
  2879. {
  2880. TCHAR Buffer[MAX_PATH];
  2881. TCHAR temp[MAX_PATH];
  2882. DWORD dwLength, dwTemp;
  2883. UINT DataLength;
  2884. LPVOID lpData;
  2885. VS_FIXEDFILEINFO *VsInfo;
  2886. LPTSTR s,e;
  2887. DWORD Vers[5],File_Vers[5];//MajVer, MinVer;
  2888. INT i, Depth;
  2889. BOOL bEqual, bError = FALSE;
  2890. DWORD linkDate, fileLinkDate;
  2891. BOOL bIncompatible;
  2892. BOOL bIncompFileVer, bIncompBinProdVer;
  2893. if (!ExpandEnvironmentStrings( FileName, Buffer, sizeof(Buffer)/sizeof(TCHAR) )) {
  2894. return FALSE;
  2895. }
  2896. if(!FileExists(Buffer, NULL))
  2897. return FALSE;
  2898. bIncompatible = FALSE;
  2899. if(FileVer && *FileVer || BinProductVer && *BinProductVer) {
  2900. //
  2901. // we need to read the version info
  2902. //
  2903. if(dwLength = GetFileVersionInfoSize( Buffer, &dwTemp )) {
  2904. if(lpData = LocalAlloc( LPTR, dwLength )) {
  2905. if(GetFileVersionInfo( Buffer, 0, dwLength, lpData )) {
  2906. if (VerQueryValue( lpData, TEXT("\\"), &VsInfo, &DataLength )) {
  2907. if (FileVer && *FileVer) {
  2908. File_Vers[0] = (HIWORD(VsInfo->dwFileVersionMS));
  2909. File_Vers[1] = (LOWORD(VsInfo->dwFileVersionMS));
  2910. File_Vers[2] = (HIWORD(VsInfo->dwFileVersionLS));
  2911. File_Vers[3] = (LOWORD(VsInfo->dwFileVersionLS));
  2912. lstrcpy (temp, FileVer);
  2913. //
  2914. //Parse and get the depth of versioning we look for
  2915. //
  2916. s = e = temp;
  2917. bEqual = FALSE;
  2918. i = 0;
  2919. if (*e == TEXT('=')) {
  2920. bEqual = TRUE;
  2921. e++;
  2922. s++;
  2923. }
  2924. while (e) {
  2925. if (((*e < TEXT('0')) || (*e > TEXT('9'))) &&
  2926. (*e != TEXT('.')) &&
  2927. (*e != TEXT('\0'))
  2928. ) {
  2929. MYASSERT (FALSE);
  2930. bError = TRUE;
  2931. break;
  2932. }
  2933. if (*e == TEXT('\0')) {
  2934. *e = 0;
  2935. Vers[i] = _ttoi(s);
  2936. break;
  2937. }
  2938. if (*e == TEXT('.')) {
  2939. *e = 0;
  2940. Vers[i++] = _ttoi(s);
  2941. s = e+1;
  2942. }
  2943. e++;
  2944. }// while
  2945. if (!bError) {
  2946. Depth = i + 1;
  2947. if (Depth > 4) {
  2948. Depth = 4;
  2949. }
  2950. for (i = 0; i < Depth; i++) {
  2951. if (File_Vers[i] == Vers[i]) {
  2952. continue;
  2953. }
  2954. if (bEqual) {
  2955. break;
  2956. }
  2957. if (File_Vers[i] > Vers[i]) {
  2958. break;
  2959. }
  2960. bIncompatible = TRUE;
  2961. break;
  2962. }
  2963. if (i == Depth) {
  2964. //
  2965. // everything matched - the file is incompatible
  2966. //
  2967. bIncompatible = TRUE;
  2968. }
  2969. }
  2970. } else {
  2971. bIncompatible = TRUE;
  2972. }
  2973. if (!bError && bIncompatible && BinProductVer && *BinProductVer) {
  2974. //
  2975. // reset status
  2976. //
  2977. bIncompatible = FALSE;
  2978. File_Vers[0] = (HIWORD(VsInfo->dwProductVersionMS));
  2979. File_Vers[1] = (LOWORD(VsInfo->dwProductVersionMS));
  2980. File_Vers[2] = (HIWORD(VsInfo->dwProductVersionLS));
  2981. File_Vers[3] = (LOWORD(VsInfo->dwProductVersionLS));
  2982. lstrcpy (temp, BinProductVer);
  2983. //
  2984. //Parse and get the depth of versioning we look for
  2985. //
  2986. s = e = temp;
  2987. bEqual = FALSE;
  2988. i = 0;
  2989. if (*e == TEXT('=')) {
  2990. bEqual = TRUE;
  2991. e++;
  2992. s++;
  2993. }
  2994. while (e) {
  2995. if (((*e < TEXT('0')) || (*e > TEXT('9'))) &&
  2996. (*e != TEXT('.')) &&
  2997. (*e != TEXT('\0'))
  2998. ) {
  2999. MYASSERT (FALSE);
  3000. bError = TRUE;
  3001. break;
  3002. }
  3003. if (*e == TEXT('\0')) {
  3004. *e = 0;
  3005. Vers[i] = _ttoi(s);
  3006. break;
  3007. }
  3008. if (*e == TEXT('.')) {
  3009. *e = 0;
  3010. Vers[i++] = _ttoi(s);
  3011. s = e+1;
  3012. }
  3013. e++;
  3014. }// while
  3015. if (!bError) {
  3016. Depth = i + 1;
  3017. if (Depth > 4) {
  3018. Depth = 4;
  3019. }
  3020. for (i = 0; i < Depth; i++) {
  3021. if (File_Vers[i] == Vers[i]) {
  3022. continue;
  3023. }
  3024. if (bEqual) {
  3025. break;
  3026. }
  3027. if (File_Vers[i] > Vers[i]) {
  3028. break;
  3029. }
  3030. bIncompatible = TRUE;
  3031. break;
  3032. }
  3033. if (i == Depth) {
  3034. //
  3035. // everything matched - the file is incompatible
  3036. //
  3037. bIncompatible = TRUE;
  3038. }
  3039. }
  3040. }
  3041. }
  3042. }
  3043. LocalFree( lpData );
  3044. }
  3045. }
  3046. } else {
  3047. bIncompatible = TRUE;
  3048. }
  3049. if (!bError && bIncompatible && LinkDate && *LinkDate) {
  3050. bEqual = FALSE;
  3051. if (*LinkDate == TEXT('=')) {
  3052. LinkDate++;
  3053. bEqual = TRUE;
  3054. }
  3055. bIncompatible = FALSE;
  3056. if (StringToInt (LinkDate, &linkDate)) {
  3057. if (GetLinkDate (Buffer, &fileLinkDate)) {
  3058. if (fileLinkDate == linkDate ||
  3059. !bEqual && fileLinkDate < linkDate
  3060. ) {
  3061. bIncompatible = TRUE;
  3062. }
  3063. }
  3064. }
  3065. }
  3066. if (bError) {
  3067. bIncompatible = FALSE;
  3068. }
  3069. return bIncompatible;
  3070. }
  3071. BOOL
  3072. StringToInt (
  3073. IN PCTSTR Field,
  3074. OUT PINT IntegerValue
  3075. )
  3076. /*++
  3077. Routine Description:
  3078. Arguments:
  3079. Return Value:
  3080. Remarks:
  3081. Hexadecimal numbers are also supported. They must be prefixed by '0x' or '0X', with no
  3082. space allowed between the prefix and the number.
  3083. --*/
  3084. {
  3085. INT Value;
  3086. UINT c;
  3087. BOOL Neg;
  3088. UINT Base;
  3089. UINT NextDigitValue;
  3090. INT OverflowCheck;
  3091. BOOL b;
  3092. if(!Field) {
  3093. SetLastError(ERROR_INVALID_PARAMETER);
  3094. return(FALSE);
  3095. }
  3096. if(*Field == TEXT('-')) {
  3097. Neg = TRUE;
  3098. Field++;
  3099. } else {
  3100. Neg = FALSE;
  3101. if(*Field == TEXT('+')) {
  3102. Field++;
  3103. }
  3104. }
  3105. if((*Field == TEXT('0')) &&
  3106. ((*(Field+1) == TEXT('x')) || (*(Field+1) == TEXT('X')))) {
  3107. //
  3108. // The number is in hexadecimal.
  3109. //
  3110. Base = 16;
  3111. Field += 2;
  3112. } else {
  3113. //
  3114. // The number is in decimal.
  3115. //
  3116. Base = 10;
  3117. }
  3118. for(OverflowCheck = Value = 0; *Field; Field++) {
  3119. c = (UINT)*Field;
  3120. if((c >= (UINT)'0') && (c <= (UINT)'9')) {
  3121. NextDigitValue = c - (UINT)'0';
  3122. } else if(Base == 16) {
  3123. if((c >= (UINT)'a') && (c <= (UINT)'f')) {
  3124. NextDigitValue = (c - (UINT)'a') + 10;
  3125. } else if ((c >= (UINT)'A') && (c <= (UINT)'F')) {
  3126. NextDigitValue = (c - (UINT)'A') + 10;
  3127. } else {
  3128. break;
  3129. }
  3130. } else {
  3131. break;
  3132. }
  3133. Value *= Base;
  3134. Value += NextDigitValue;
  3135. //
  3136. // Check for overflow. For decimal numbers, we check to see whether the
  3137. // new value has overflowed into the sign bit (i.e., is less than the
  3138. // previous value. For hexadecimal numbers, we check to make sure we
  3139. // haven't gotten more digits than will fit in a DWORD.
  3140. //
  3141. if(Base == 16) {
  3142. if(++OverflowCheck > (sizeof(INT) * 2)) {
  3143. break;
  3144. }
  3145. } else {
  3146. if(Value < OverflowCheck) {
  3147. break;
  3148. } else {
  3149. OverflowCheck = Value;
  3150. }
  3151. }
  3152. }
  3153. if(*Field) {
  3154. SetLastError(ERROR_INVALID_DATA);
  3155. return(FALSE);
  3156. }
  3157. if(Neg) {
  3158. Value = 0-Value;
  3159. }
  3160. b = TRUE;
  3161. try {
  3162. *IntegerValue = Value;
  3163. } except(EXCEPTION_EXECUTE_HANDLER) {
  3164. b = FALSE;
  3165. }
  3166. if(!b) {
  3167. SetLastError(ERROR_INVALID_PARAMETER);
  3168. }
  3169. return(b);
  3170. }
  3171. BOOLEAN
  3172. CheckForFileVersion (
  3173. LPCTSTR FileName,
  3174. LPCTSTR FileVer
  3175. )
  3176. {
  3177. return (BOOLEAN)CheckForFileVersionEx (FileName, FileVer, NULL, NULL);
  3178. }
  3179. VOID
  3180. FixMissingKnownDlls (
  3181. OUT PSTRINGLIST* MissingKnownDlls,
  3182. IN PCTSTR RestrictedCheckList OPTIONAL
  3183. )
  3184. {
  3185. PCTSTR regStr;
  3186. HKEY key;
  3187. DWORD rc;
  3188. DWORD index;
  3189. TCHAR dllValue[MAX_PATH];
  3190. TCHAR dllName[MAX_PATH];
  3191. DWORD type;
  3192. DWORD size1 = MAX_PATH, size2 = MAX_PATH;
  3193. TCHAR systemDir[MAX_PATH];
  3194. TCHAR dllPath[MAX_PATH];
  3195. BOOL bCheck;
  3196. if (!GetSystemDirectory (systemDir, MAX_PATH)) {
  3197. return;
  3198. }
  3199. #ifdef UNICODE
  3200. regStr = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\KnownDLLs";
  3201. #else
  3202. regStr = "SYSTEM\\CurrentControlSet\\Control\\SessionManager\\KnownDLLs";
  3203. #endif
  3204. rc = RegOpenKey (HKEY_LOCAL_MACHINE, regStr, &key);
  3205. if (rc == ERROR_SUCCESS) {
  3206. index = 0;
  3207. while (RegEnumValue (
  3208. key,
  3209. index++,
  3210. dllValue,
  3211. &size1,
  3212. NULL,
  3213. &type,
  3214. (LPBYTE)dllName,
  3215. &size2
  3216. ) == ERROR_SUCCESS) {
  3217. if (type == REG_SZ) {
  3218. bCheck = TRUE;
  3219. if (RestrictedCheckList) {
  3220. PCTSTR fileName = RestrictedCheckList;
  3221. while (*fileName) {
  3222. if (!lstrcmpi (fileName, dllName)) {
  3223. break;
  3224. }
  3225. fileName = _tcschr (fileName, 0) + 1;
  3226. }
  3227. if (*fileName == 0) {
  3228. //
  3229. // we are not interested in this dll
  3230. //
  3231. bCheck = FALSE;
  3232. }
  3233. }
  3234. if (bCheck) {
  3235. BuildPath (dllPath, systemDir, dllName);
  3236. if (!FileExists (dllPath, NULL)) {
  3237. DebugLog (
  3238. Winnt32LogWarning,
  3239. TEXT("The file %1 doesn't exist, although it's registered as a Known Dll"),
  3240. 0,
  3241. dllPath
  3242. );
  3243. //
  3244. // OK, we found a bogus reg entry; remove the value and remember the data
  3245. //
  3246. if (RegDeleteValue (key, dllValue) == ERROR_SUCCESS) {
  3247. InsertList (
  3248. (PGENERIC_LIST*)MissingKnownDlls,
  3249. (PGENERIC_LIST)CreateStringCell (dllValue)
  3250. );
  3251. InsertList (
  3252. (PGENERIC_LIST*)MissingKnownDlls,
  3253. (PGENERIC_LIST)CreateStringCell (dllName)
  3254. );
  3255. }
  3256. }
  3257. }
  3258. }
  3259. size1 = size2 = MAX_PATH;
  3260. }
  3261. RegCloseKey (key);
  3262. }
  3263. }
  3264. VOID
  3265. UndoFixMissingKnownDlls (
  3266. IN PSTRINGLIST MissingKnownDlls
  3267. )
  3268. {
  3269. PCTSTR regStr;
  3270. HKEY key;
  3271. DWORD rc;
  3272. PSTRINGLIST p, q;
  3273. #ifdef UNICODE
  3274. regStr = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\KnownDLLs";
  3275. #else
  3276. regStr = "SYSTEM\\CurrentControlSet\\Control\\SessionManager\\KnownDLLs";
  3277. #endif
  3278. rc = RegOpenKey (HKEY_LOCAL_MACHINE, regStr, &key);
  3279. if (rc == ERROR_SUCCESS) {
  3280. p = MissingKnownDlls;
  3281. while (p) {
  3282. q = p->Next;
  3283. if (q) {
  3284. RegSetValueEx (
  3285. key,
  3286. p->String,
  3287. 0,
  3288. REG_SZ,
  3289. (const PBYTE)q->String,
  3290. (lstrlen (q->String) + 1) * sizeof (TCHAR)
  3291. );
  3292. p = q->Next;
  3293. } else {
  3294. p = NULL;
  3295. }
  3296. }
  3297. RegCloseKey (key);
  3298. }
  3299. DeleteStringList (MissingKnownDlls);
  3300. }
  3301. #ifndef UNICODE
  3302. /*++
  3303. Routine Description:
  3304. IsPatternMatch compares a string against a pattern that may contain
  3305. standard * or ? wildcards.
  3306. Arguments:
  3307. wstrPattern - A pattern possibly containing wildcards
  3308. wstrStr - The string to compare against the pattern
  3309. Return Value:
  3310. TRUE when wstrStr and wstrPattern match when wildcards are expanded.
  3311. FALSE if wstrStr does not match wstrPattern.
  3312. --*/
  3313. #define MBCHAR INT
  3314. BOOL
  3315. IsPatternMatchA (
  3316. IN PCSTR strPattern,
  3317. IN PCSTR strStr
  3318. )
  3319. {
  3320. MBCHAR chSrc, chPat;
  3321. while (*strStr) {
  3322. chSrc = _mbctolower ((MBCHAR) _mbsnextc (strStr));
  3323. chPat = _mbctolower ((MBCHAR) _mbsnextc (strPattern));
  3324. if (chPat == '*') {
  3325. // Skip all asterisks that are grouped together
  3326. while (_mbsnextc (_mbsinc (strStr)) == '*') {
  3327. strStr = _mbsinc (strStr);
  3328. }
  3329. // Check if asterisk is at the end. If so, we have a match already.
  3330. if (!_mbsnextc (_mbsinc (strPattern))) {
  3331. return TRUE;
  3332. }
  3333. // do recursive check for rest of pattern
  3334. if (IsPatternMatchA (_mbsinc (strPattern), strStr)) {
  3335. return TRUE;
  3336. }
  3337. // Allow any character and continue
  3338. strStr = _mbsinc (strStr);
  3339. continue;
  3340. }
  3341. if (chPat != '?') {
  3342. if (chSrc != chPat) {
  3343. return FALSE;
  3344. }
  3345. }
  3346. strStr = _mbsinc (strStr);
  3347. strPattern = _mbsinc (strPattern);
  3348. }
  3349. //
  3350. // Fail when there is more pattern and pattern does not end in an asterisk
  3351. //
  3352. while (_mbsnextc (strPattern) == '*') {
  3353. strPattern = _mbsinc (strPattern);
  3354. }
  3355. if (_mbsnextc (strPattern)) {
  3356. return FALSE;
  3357. }
  3358. return TRUE;
  3359. }
  3360. #endif
  3361. // Wierd logic here required to make builds work, as this is defined
  3362. // in another file that gets linked in on x86
  3363. #ifdef _WIN64
  3364. BOOL
  3365. IsPatternMatchW (
  3366. IN PCWSTR wstrPattern,
  3367. IN PCWSTR wstrStr
  3368. )
  3369. {
  3370. WCHAR chSrc, chPat;
  3371. while (*wstrStr) {
  3372. chSrc = towlower (*wstrStr);
  3373. chPat = towlower (*wstrPattern);
  3374. if (chPat == L'*') {
  3375. // Skip all asterisks that are grouped together
  3376. while (wstrPattern[1] == L'*')
  3377. wstrPattern++;
  3378. // Check if asterisk is at the end. If so, we have a match already.
  3379. chPat = towlower (wstrPattern[1]);
  3380. if (!chPat)
  3381. return TRUE;
  3382. // Otherwise check if next pattern char matches current char
  3383. if (chPat == chSrc || chPat == L'?') {
  3384. // do recursive check for rest of pattern
  3385. wstrPattern++;
  3386. if (IsPatternMatchW (wstrPattern, wstrStr))
  3387. return TRUE;
  3388. // no, that didn't work, stick with star
  3389. wstrPattern--;
  3390. }
  3391. //
  3392. // Allow any character and continue
  3393. //
  3394. wstrStr++;
  3395. continue;
  3396. }
  3397. if (chPat != L'?') {
  3398. //
  3399. // if next pattern character is not a question mark, src and pat
  3400. // must be identical.
  3401. //
  3402. if (chSrc != chPat)
  3403. return FALSE;
  3404. }
  3405. //
  3406. // Advance when pattern character matches string character
  3407. //
  3408. wstrPattern++;
  3409. wstrStr++;
  3410. }
  3411. //
  3412. // Fail when there is more pattern and pattern does not end in an asterisk
  3413. //
  3414. chPat = *wstrPattern;
  3415. if (chPat && (chPat != L'*' || wstrPattern[1]))
  3416. return FALSE;
  3417. return TRUE;
  3418. }
  3419. #endif
  3420. typedef BOOL (WINAPI * GETDISKFREESPACEEXA)(
  3421. PCSTR lpDirectoryName, // directory name
  3422. PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
  3423. PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
  3424. PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
  3425. );
  3426. typedef BOOL (WINAPI * GETDISKFREESPACEEXW)(
  3427. PCWSTR lpDirectoryName, // directory name
  3428. PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
  3429. PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
  3430. PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
  3431. );
  3432. BOOL
  3433. GetDiskFreeSpaceNewA(
  3434. IN PCSTR DriveName,
  3435. OUT DWORD * OutSectorsPerCluster,
  3436. OUT DWORD * OutBytesPerSector,
  3437. OUT ULARGE_INTEGER * OutNumberOfFreeClusters,
  3438. OUT ULARGE_INTEGER * OutTotalNumberOfClusters
  3439. )
  3440. /*++
  3441. Routine Description:
  3442. On Win9x GetDiskFreeSpace never return free/total space more than 2048MB.
  3443. GetDiskFreeSpaceNew use GetDiskFreeSpaceEx to calculate real number of free/total clusters.
  3444. Has same declaration as GetDiskFreeSpaceA.
  3445. Arguments:
  3446. DriveName - supplies directory name
  3447. OutSectorsPerCluster - receive number of sectors per cluster
  3448. OutBytesPerSector - receive number of bytes per sector
  3449. OutNumberOfFreeClusters - receive number of free clusters
  3450. OutTotalNumberOfClusters - receive number of total clusters
  3451. Return Value:
  3452. TRUE if the function succeeds.
  3453. If the function fails, the return value is FALSE. To get extended error information, call GetLastError
  3454. --*/
  3455. {
  3456. ULARGE_INTEGER TotalNumberOfFreeBytes = {0, 0};
  3457. ULARGE_INTEGER TotalNumberOfBytes = {0, 0};
  3458. ULARGE_INTEGER DonotCare;
  3459. HMODULE hKernel32;
  3460. GETDISKFREESPACEEXA pGetDiskFreeSpaceExA;
  3461. ULARGE_INTEGER NumberOfFreeClusters = {0, 0};
  3462. ULARGE_INTEGER TotalNumberOfClusters = {0, 0};
  3463. DWORD SectorsPerCluster;
  3464. DWORD BytesPerSector;
  3465. if(!GetDiskFreeSpaceA(DriveName,
  3466. &SectorsPerCluster,
  3467. &BytesPerSector,
  3468. &NumberOfFreeClusters.LowPart,
  3469. &TotalNumberOfClusters.LowPart)){
  3470. DebugLog (
  3471. Winnt32LogError,
  3472. TEXT("GetDiskFreeSpaceNewA: GetDiskFreeSpaceA failed on drive %1"),
  3473. 0,
  3474. DriveName);
  3475. return FALSE;
  3476. }
  3477. hKernel32 = LoadLibraryA("kernel32.dll");
  3478. pGetDiskFreeSpaceExA = (GETDISKFREESPACEEXA)GetProcAddress(hKernel32, "GetDiskFreeSpaceExA");
  3479. if(pGetDiskFreeSpaceExA &&
  3480. pGetDiskFreeSpaceExA(DriveName, &DonotCare, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)){
  3481. NumberOfFreeClusters.QuadPart = TotalNumberOfFreeBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
  3482. TotalNumberOfClusters.QuadPart = TotalNumberOfBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
  3483. }
  3484. else{
  3485. DebugLog (
  3486. Winnt32LogWarning,
  3487. pGetDiskFreeSpaceExA?
  3488. TEXT("GetDiskFreeSpaceNewA: GetDiskFreeSpaceExA is failed"):
  3489. TEXT("GetDiskFreeSpaceNewA: GetDiskFreeSpaceExA function is not in kernel32.dll"),
  3490. 0);
  3491. }
  3492. FreeLibrary(hKernel32);
  3493. if(OutSectorsPerCluster){
  3494. *OutSectorsPerCluster = SectorsPerCluster;
  3495. }
  3496. if(OutBytesPerSector){
  3497. *OutBytesPerSector = BytesPerSector;
  3498. }
  3499. if(OutNumberOfFreeClusters){
  3500. OutNumberOfFreeClusters->QuadPart = NumberOfFreeClusters.QuadPart;
  3501. }
  3502. if(OutTotalNumberOfClusters){
  3503. OutTotalNumberOfClusters->QuadPart = TotalNumberOfClusters.QuadPart;
  3504. }
  3505. return TRUE;
  3506. }
  3507. BOOL
  3508. GetDiskFreeSpaceNewW(
  3509. IN PCWSTR DriveName,
  3510. OUT DWORD * OutSectorsPerCluster,
  3511. OUT DWORD * OutBytesPerSector,
  3512. OUT ULARGE_INTEGER * OutNumberOfFreeClusters,
  3513. OUT ULARGE_INTEGER * OutTotalNumberOfClusters
  3514. )
  3515. /*++
  3516. Routine Description:
  3517. Correct NumberOfFreeClusters and TotalNumberOfClusters out parameters
  3518. with using GetDiskFreeSpace and GetDiskFreeSpaceEx
  3519. Arguments:
  3520. DriveName - supplies directory name
  3521. OutSectorsPerCluster - receive number of sectors per cluster
  3522. OutBytesPerSector - receive number of bytes per sector
  3523. OutNumberOfFreeClusters - receive number of free clusters
  3524. OutTotalNumberOfClusters - receive number of total clusters
  3525. Return Value:
  3526. TRUE if the function succeeds.
  3527. If the function fails, the return value is FALSE. To get extended error information, call GetLastError
  3528. --*/
  3529. {
  3530. ULARGE_INTEGER TotalNumberOfFreeBytes = {0, 0};
  3531. ULARGE_INTEGER TotalNumberOfBytes = {0, 0};
  3532. ULARGE_INTEGER DonotCare;
  3533. HMODULE hKernel32;
  3534. GETDISKFREESPACEEXW pGetDiskFreeSpaceExW;
  3535. ULARGE_INTEGER NumberOfFreeClusters = {0, 0};
  3536. ULARGE_INTEGER TotalNumberOfClusters = {0, 0};
  3537. DWORD SectorsPerCluster;
  3538. DWORD BytesPerSector;
  3539. if(!GetDiskFreeSpaceW(DriveName,
  3540. &SectorsPerCluster,
  3541. &BytesPerSector,
  3542. &NumberOfFreeClusters.LowPart,
  3543. &TotalNumberOfClusters.LowPart)){
  3544. DebugLog (
  3545. Winnt32LogError,
  3546. TEXT("GetDiskFreeSpaceNewW: GetDiskFreeSpaceW failed on drive %1"),
  3547. 0,
  3548. DriveName);
  3549. return FALSE;
  3550. }
  3551. hKernel32 = LoadLibraryA("kernel32.dll");
  3552. pGetDiskFreeSpaceExW = (GETDISKFREESPACEEXW)GetProcAddress(hKernel32, "GetDiskFreeSpaceExW");
  3553. if(pGetDiskFreeSpaceExW &&
  3554. pGetDiskFreeSpaceExW(DriveName, &DonotCare, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)){
  3555. NumberOfFreeClusters.QuadPart = TotalNumberOfFreeBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
  3556. TotalNumberOfClusters.QuadPart = TotalNumberOfBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
  3557. }
  3558. else{
  3559. DebugLog (
  3560. Winnt32LogWarning,
  3561. pGetDiskFreeSpaceExW?
  3562. TEXT("GetDiskFreeSpaceNewW: GetDiskFreeSpaceExW is failed"):
  3563. TEXT("GetDiskFreeSpaceNewW: GetDiskFreeSpaceExW function is not in kernel32.dll"),
  3564. 0);
  3565. }
  3566. FreeLibrary(hKernel32);
  3567. if(OutSectorsPerCluster){
  3568. *OutSectorsPerCluster = SectorsPerCluster;
  3569. }
  3570. if(OutBytesPerSector){
  3571. *OutBytesPerSector = BytesPerSector;
  3572. }
  3573. if(OutNumberOfFreeClusters){
  3574. OutNumberOfFreeClusters->QuadPart = NumberOfFreeClusters.QuadPart;
  3575. }
  3576. if(OutTotalNumberOfClusters){
  3577. OutTotalNumberOfClusters->QuadPart = TotalNumberOfClusters.QuadPart;
  3578. }
  3579. return TRUE;
  3580. }
  3581. BOOL
  3582. ReplaceSubStr(
  3583. IN OUT LPTSTR SrcStr,
  3584. IN LPTSTR SrcSubStr,
  3585. IN LPTSTR DestSubStr
  3586. )
  3587. /*++
  3588. Routine Description:
  3589. Replaces the source substr with the destination substr in the source
  3590. string.
  3591. NOTE : SrcSubStr needs to be longer than or equal in length to
  3592. DestSubStr.
  3593. Arguments:
  3594. SrcStr : The source to operate upon. Also receives the new string.
  3595. SrcSubStr : The source substring to search for and replace.
  3596. DestSubStr : The substring to replace with for the occurences
  3597. of SrcSubStr in SrcStr.
  3598. Return Value:
  3599. TRUE if successful, otherwise FALSE.
  3600. --*/
  3601. {
  3602. BOOL Result = FALSE;
  3603. //
  3604. // Validate the arguments
  3605. //
  3606. if (SrcStr && SrcSubStr && *SrcSubStr &&
  3607. (!DestSubStr || (_tcslen(SrcSubStr) >= _tcslen(DestSubStr)))) {
  3608. if (!DestSubStr || _tcsicmp(SrcSubStr, DestSubStr)) {
  3609. ULONG SrcStrLen = _tcslen(SrcStr);
  3610. ULONG SrcSubStrLen = _tcslen(SrcSubStr);
  3611. ULONG DestSubStrLen = DestSubStr ? _tcslen(DestSubStr) : 0;
  3612. LPTSTR DestStr = malloc((SrcStrLen + 1) * sizeof(TCHAR));
  3613. if (DestStr) {
  3614. LPTSTR CurrDestStr = DestStr;
  3615. LPTSTR PrevSrcStr = SrcStr;
  3616. LPTSTR CurrSrcStr = _tcsstr(SrcStr, SrcSubStr);
  3617. while (CurrSrcStr) {
  3618. //
  3619. // Skip starting substr & copy previous unmatched pattern
  3620. //
  3621. if (PrevSrcStr != CurrSrcStr) {
  3622. _tcsncpy(CurrDestStr, PrevSrcStr, (CurrSrcStr - PrevSrcStr));
  3623. CurrDestStr += (CurrSrcStr - PrevSrcStr);
  3624. *CurrDestStr = TEXT('\0');
  3625. }
  3626. //
  3627. // Copy destination substr
  3628. //
  3629. if (DestSubStr) {
  3630. _tcscpy(CurrDestStr, DestSubStr);
  3631. CurrDestStr += DestSubStrLen;
  3632. *CurrDestStr = TEXT('\0');
  3633. }
  3634. //
  3635. // Look for next substr
  3636. //
  3637. CurrSrcStr += SrcSubStrLen;
  3638. PrevSrcStr = CurrSrcStr;
  3639. CurrSrcStr = _tcsstr(CurrSrcStr, SrcSubStr);
  3640. }
  3641. //
  3642. // Copy remaining src string if any
  3643. //
  3644. if (!_tcsstr(PrevSrcStr, SrcSubStr)) {
  3645. _tcscpy(CurrDestStr, PrevSrcStr);
  3646. }
  3647. //
  3648. // Copy the new string back to the src string
  3649. //
  3650. _tcscpy(SrcStr, DestStr);
  3651. free(DestStr);
  3652. Result = TRUE;
  3653. }
  3654. } else {
  3655. Result = TRUE;
  3656. }
  3657. }
  3658. return Result;
  3659. }
  3660. VOID
  3661. RemoveTrailingWack (
  3662. PTSTR String
  3663. )
  3664. {
  3665. if (String) {
  3666. PTSTR p = _tcsrchr (String, TEXT('\\'));
  3667. if (p && p[1] == 0) {
  3668. *p = 0;
  3669. }
  3670. }
  3671. }
  3672. ULONGLONG
  3673. SystemTimeToFileTime64 (
  3674. IN PSYSTEMTIME SystemTime
  3675. )
  3676. {
  3677. FILETIME ft;
  3678. ULARGE_INTEGER result;
  3679. SystemTimeToFileTime (SystemTime, &ft);
  3680. result.LowPart = ft.dwLowDateTime;
  3681. result.HighPart = ft.dwHighDateTime;
  3682. return result.QuadPart;
  3683. }