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.

2619 lines
88 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. copy.c
  5. Abstract:
  6. High-level file copy/installation functions
  7. Author:
  8. Ted Miller (tedm) 14-Feb-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <winioctl.h>
  14. #define FILE_COMPARE_BLOCK_SIZE (0x1000000)
  15. ULONG
  16. _cdecl
  17. DbgPrint(
  18. PCH Format,
  19. ...
  20. );
  21. //
  22. // Mask for all copy flags that will require us to determine
  23. // version information.
  24. //
  25. #define SP_COPY_MASK_NEEDVERINFO (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER | SP_COPY_LANGUAGEAWARE)
  26. VOID
  27. pGetVersionText(
  28. OUT PTSTR VersionText,
  29. IN DWORDLONG Version
  30. )
  31. /*++
  32. Routine Description:
  33. Convert a 64-bit version number into either
  34. n.n.n.n or "0"
  35. Arguments:
  36. VersionText - buffer, big enough to hold 4x16 bit numbers
  37. Version - 64-bit version, or 0 if no version
  38. Return Value:
  39. none
  40. --*/
  41. {
  42. if (Version == 0) {
  43. lstrcpy(VersionText,TEXT("0"));
  44. } else {
  45. int m1 = (int)((Version >> 48) & 0xffff);
  46. int m2 = (int)((Version >> 32) & 0xffff);
  47. int m3 = (int)((Version >> 16) & 0xffff);
  48. int m4 = (int)(Version & 0xffff);
  49. wsprintf(VersionText,TEXT("%d.%d.%d.%d"),m1,m2,m3,m4);
  50. }
  51. }
  52. DWORD
  53. CreateTargetAsLinkToMaster(
  54. IN PSP_FILE_QUEUE Queue,
  55. IN PCTSTR FullSourceFilename,
  56. IN PCTSTR FullTargetFilename,
  57. IN PVOID CopyMsgHandler OPTIONAL,
  58. IN PVOID Context OPTIONAL,
  59. IN BOOL IsMsgHandlerNativeCharWidth
  60. )
  61. {
  62. #ifdef ANSI_SETUPAPI
  63. return ERROR_CALL_NOT_IMPLEMENTED;
  64. #else
  65. PTSTR p;
  66. TCHAR c;
  67. DWORD bytesReturned;
  68. DWORD error;
  69. BOOL ok;
  70. DWORD sourceLength;
  71. DWORD targetLength;
  72. DWORD sourceDosDevLength;
  73. DWORD targetDosDevLength;
  74. DWORD copyFileSize;
  75. PSI_COPYFILE copyFile;
  76. PCHAR s;
  77. HANDLE targetHandle;
  78. //
  79. // Get the name of the source directory.
  80. //
  81. p = _tcsrchr( FullSourceFilename, TEXT('\\') );
  82. if ( (p == NULL) || (p == FullSourceFilename) ) {
  83. return ERROR_FILE_NOT_FOUND; // copy by usual means
  84. }
  85. if ( *(p-1) == TEXT(':') ) {
  86. p++;
  87. }
  88. c = *p;
  89. *p = 0;
  90. //
  91. // If this is the same as the previous source directory, then we already
  92. // have a handle to the directory; otherwise, close the old handle and
  93. // open a handle to this directory.
  94. //
  95. if ( (Queue->SisSourceDirectory == NULL) ||
  96. (_tcsicmp(FullSourceFilename, Queue->SisSourceDirectory) != 0) ) {
  97. if ( Queue->SisSourceHandle != INVALID_HANDLE_VALUE ) {
  98. CloseHandle( Queue->SisSourceHandle );
  99. }
  100. Queue->SisSourceHandle = CreateFile(
  101. FullSourceFilename,
  102. GENERIC_READ,
  103. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  104. NULL,
  105. OPEN_EXISTING,
  106. FILE_FLAG_BACKUP_SEMANTICS,
  107. NULL
  108. );
  109. if ( Queue->SisSourceHandle == INVALID_HANDLE_VALUE ) {
  110. return ERROR_FILE_NOT_FOUND;
  111. }
  112. if ( Queue->SisSourceDirectory != NULL ) {
  113. MyFree( Queue->SisSourceDirectory );
  114. }
  115. Queue->SisSourceDirectory = DuplicateString( FullSourceFilename );
  116. //
  117. // If the DuplicateString fails, we press on. Because SisSourceDirectory
  118. // is NULL, we'll reopen the source directory next time.
  119. //
  120. }
  121. *p = c;
  122. //
  123. // Build the FSCTL command buffer.
  124. //
  125. sourceLength = (_tcslen(FullSourceFilename) + 1) * sizeof(TCHAR);
  126. if ( *FullSourceFilename != TEXT('\\') ) {
  127. sourceDosDevLength = _tcslen(TEXT("\\??\\")) * sizeof(TCHAR);
  128. } else {
  129. sourceDosDevLength = 0;
  130. }
  131. targetLength = (_tcslen(FullTargetFilename) + 1) * sizeof(TCHAR);
  132. if ( *FullTargetFilename != TEXT('\\') ) {
  133. targetDosDevLength = _tcslen(TEXT("\\??\\")) * sizeof(TCHAR);
  134. } else {
  135. targetDosDevLength = 0;
  136. }
  137. copyFileSize = FIELD_OFFSET(SI_COPYFILE, FileNameBuffer) +
  138. sourceDosDevLength + sourceLength +
  139. targetDosDevLength + targetLength;
  140. copyFile = MyMalloc( copyFileSize );
  141. if ( copyFile == NULL ) {
  142. return ERROR_FILE_NOT_FOUND;
  143. }
  144. copyFile->SourceFileNameLength = sourceDosDevLength + sourceLength;
  145. copyFile->DestinationFileNameLength = targetDosDevLength + targetLength;
  146. copyFile->Flags = COPYFILE_SIS_REPLACE;
  147. s = (PCHAR)copyFile->FileNameBuffer;
  148. if ( sourceDosDevLength != 0 ) {
  149. RtlCopyMemory(
  150. s,
  151. TEXT("\\??\\"),
  152. sourceDosDevLength
  153. );
  154. s += sourceDosDevLength;
  155. }
  156. RtlCopyMemory(
  157. s,
  158. FullSourceFilename,
  159. sourceLength
  160. );
  161. s += sourceLength;
  162. if ( targetDosDevLength != 0 ) {
  163. RtlCopyMemory(
  164. s,
  165. TEXT("\\??\\"),
  166. targetDosDevLength
  167. );
  168. s += targetDosDevLength;
  169. }
  170. RtlCopyMemory(
  171. s,
  172. FullTargetFilename,
  173. targetLength
  174. );
  175. //
  176. // Invoke the SIS CopyFile FsCtrl.
  177. //
  178. ok = DeviceIoControl(
  179. Queue->SisSourceHandle,
  180. FSCTL_SIS_COPYFILE,
  181. copyFile, // Input buffer
  182. copyFileSize, // Input buffer length
  183. NULL, // Output buffer
  184. 0, // Output buffer length
  185. &bytesReturned,
  186. NULL
  187. );
  188. error = GetLastError( );
  189. MyFree( copyFile );
  190. if ( ok ) {
  191. //DbgPrint( "\n\nCreateTargetAsLinkToMaster: SIS copy %ws->%ws succeeded\n\n\n", FullSourceFilename, FullTargetFilename );
  192. //
  193. // Open the target file so that CSC knows about it and pins it,
  194. // if necessary.
  195. //
  196. targetHandle = CreateFile(
  197. FullTargetFilename,
  198. GENERIC_READ,
  199. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  200. NULL,
  201. OPEN_EXISTING,
  202. 0,
  203. NULL
  204. );
  205. if ( targetHandle == INVALID_HANDLE_VALUE ) {
  206. error = GetLastError();
  207. DbgPrint( "\n\nCreateTargetAsLinkToMaster: SIS copy %ws->%ws succeeded, but open failed: %d\n\n\n", FullSourceFilename, FullTargetFilename, error );
  208. } else {
  209. CloseHandle( targetHandle );
  210. }
  211. error = NO_ERROR;
  212. } else {
  213. //DbgPrint( "\n\nCreateTargetAsLinkToMaster: SIS copy %ws->%ws failed: %d\n\n\n", FullSourceFilename, FullTargetFilename, error );
  214. //
  215. // If it looks like SIS isn't active on the remote file system, close
  216. // the SIS root handle so that we can avoid repeatedly getting this
  217. // error.
  218. //
  219. // Note: NTFS returns STATUS_INVALID_PARAMETER (ERROR_INVALID_PARAMETER).
  220. // FAT returns STATUS_INVALID_DEVICE_REQUEST (ERROR_INVALID_FUNCTION).
  221. //
  222. if ( (error == ERROR_INVALID_PARAMETER) ||
  223. (error == ERROR_INVALID_FUNCTION) ) {
  224. CloseHandle( Queue->SisSourceHandle );
  225. Queue->SisSourceHandle = INVALID_HANDLE_VALUE;
  226. if ( Queue->SisSourceDirectory != NULL ) {
  227. MyFree( Queue->SisSourceDirectory );
  228. Queue->SisSourceDirectory = NULL;
  229. }
  230. Queue->Flags &= ~FQF_TRY_SIS_COPY;
  231. }
  232. }
  233. return error;
  234. #endif
  235. }
  236. BOOL
  237. pCompareFilesExact(
  238. IN PCTSTR File1,
  239. IN PCTSTR File2
  240. )
  241. /*++
  242. Routine Description:
  243. Determine if File1 and File2 are byte-for-byte exactly the same. If they are, we don't need to do anything.
  244. Arguments:
  245. File1 - the two files to compare. The order does not matter
  246. File2
  247. Return Value:
  248. TRUE if the files are exactly the same
  249. Note that we have to allow for potentially huge files.
  250. --*/
  251. {
  252. HANDLE hFile1,hFile2;
  253. HANDLE hMap1,hMap2;
  254. LPVOID View1,View2;
  255. ULARGE_INTEGER Size1,Size2,Offset;
  256. SIZE_T BlockSize;
  257. SIZE_T ChunkSize;
  258. BOOL match;
  259. match = FALSE;
  260. hFile1=hFile2=INVALID_HANDLE_VALUE;
  261. hMap1=hMap2=NULL;
  262. View1=View2=NULL;
  263. try {
  264. hFile1 = CreateFile(File1,
  265. GENERIC_READ,
  266. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  267. NULL,
  268. OPEN_EXISTING,
  269. FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,
  270. NULL);
  271. if (hFile1 == INVALID_HANDLE_VALUE) {
  272. leave;
  273. }
  274. hFile2 = CreateFile(File2,
  275. GENERIC_READ,
  276. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  277. NULL,
  278. OPEN_EXISTING,
  279. FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,
  280. NULL);
  281. if (hFile2 == INVALID_HANDLE_VALUE) {
  282. leave;
  283. }
  284. Size1.LowPart = GetFileSize(hFile1,&Size1.HighPart);
  285. if(Size1.LowPart == (DWORD)(-1) && GetLastError()) {
  286. //
  287. // get file size failed
  288. //
  289. leave;
  290. }
  291. Size2.LowPart = GetFileSize(hFile2,&Size2.HighPart);
  292. if(Size2.LowPart == (DWORD)(-1) && GetLastError()) {
  293. //
  294. // get file size failed
  295. //
  296. leave;
  297. }
  298. if (Size1.QuadPart != Size2.QuadPart) {
  299. leave;
  300. }
  301. if (Size1.QuadPart == 0) {
  302. //
  303. // both files are zero length, nothing to do
  304. //
  305. match = TRUE;
  306. leave;
  307. }
  308. //
  309. // basic checks done, we'll mark both files as mappable to do the byte-checks
  310. //
  311. hMap1 = CreateFileMapping(hFile1,
  312. NULL,
  313. PAGE_READONLY,
  314. Size1.HighPart,
  315. Size1.LowPart,
  316. NULL);
  317. if (hMap1 == NULL) {
  318. //
  319. // mapping failed
  320. //
  321. leave;
  322. }
  323. hMap2 = CreateFileMapping(hFile2,
  324. NULL,
  325. PAGE_READONLY,
  326. Size1.HighPart,
  327. Size1.LowPart,
  328. NULL);
  329. if (hMap2 == NULL) {
  330. //
  331. // mapping failed
  332. //
  333. leave;
  334. }
  335. if (Size1.QuadPart > FILE_COMPARE_BLOCK_SIZE) {
  336. BlockSize = FILE_COMPARE_BLOCK_SIZE;
  337. } else {
  338. BlockSize = (SIZE_T)Size1.QuadPart;
  339. MYASSERT(BlockSize);
  340. }
  341. //
  342. // now proceed in BlockSize chunks comparing the two files
  343. //
  344. Offset.QuadPart = 0;
  345. do {
  346. if ((Size1.QuadPart - Offset.QuadPart) < BlockSize) {
  347. ChunkSize = (SIZE_T)(Size1.QuadPart - Offset.QuadPart);
  348. MYASSERT(ChunkSize);
  349. } else {
  350. ChunkSize = BlockSize;
  351. }
  352. //
  353. // map and compare the two views
  354. // for most files, we will only need to do this once
  355. // for big files, we'll do this approx (Size1+BlockSize-1)/BlockSize times
  356. //
  357. View1 = MapViewOfFile(hMap1,
  358. FILE_MAP_READ,
  359. Offset.HighPart,
  360. Offset.LowPart,
  361. ChunkSize);
  362. if (View1 == NULL) {
  363. //
  364. // get view failed
  365. //
  366. leave;
  367. }
  368. View2 = MapViewOfFile(hMap2,
  369. FILE_MAP_READ,
  370. Offset.HighPart,
  371. Offset.LowPart,
  372. ChunkSize);
  373. if (View2 == NULL) {
  374. //
  375. // get view failed
  376. //
  377. leave;
  378. }
  379. if(memcmp(View1,View2,ChunkSize) != 0) {
  380. //
  381. // file chunks mismatch
  382. //
  383. leave;
  384. }
  385. UnmapViewOfFile(View1);
  386. UnmapViewOfFile(View2);
  387. View1 = NULL;
  388. View2 = NULL;
  389. Offset.QuadPart += ChunkSize;
  390. } while (Offset.QuadPart<Size1.QuadPart);
  391. //
  392. // if we get here, we have a 100% match
  393. //
  394. match = TRUE;
  395. } except(EXCEPTION_EXECUTE_HANDLER) {
  396. }
  397. if (View1 != NULL) {
  398. UnmapViewOfFile(View1);
  399. }
  400. if (View2 != NULL) {
  401. UnmapViewOfFile(View2);
  402. }
  403. if (hMap1 != NULL) {
  404. CloseHandle(hMap1);
  405. }
  406. if (hMap2 != NULL) {
  407. CloseHandle(hMap2);
  408. }
  409. if (hFile1 != INVALID_HANDLE_VALUE) {
  410. CloseHandle(hFile1);
  411. }
  412. if (hFile2 != INVALID_HANDLE_VALUE) {
  413. CloseHandle(hFile2);
  414. }
  415. return match;
  416. }
  417. BOOL
  418. _SetupInstallFileEx(
  419. IN PSP_FILE_QUEUE Queue, OPTIONAL
  420. IN PSP_FILE_QUEUE_NODE QueueNode, OPTIONAL
  421. IN HINF InfHandle, OPTIONAL
  422. IN PINFCONTEXT InfContext, OPTIONAL
  423. IN PCTSTR SourceFile, OPTIONAL
  424. IN PCTSTR SourcePathRoot, OPTIONAL
  425. IN PCTSTR DestinationName, OPTIONAL
  426. IN DWORD CopyStyle,
  427. IN PVOID CopyMsgHandler, OPTIONAL
  428. IN PVOID Context, OPTIONAL
  429. OUT PBOOL FileWasInUse,
  430. IN BOOL IsMsgHandlerNativeCharWidth,
  431. OUT PBOOL SignatureVerifyFailed
  432. )
  433. /*++
  434. Routine Description:
  435. Actual implementation of SetupInstallFileEx. Handles either ANSI or
  436. Unicode callback routine.
  437. Arguments:
  438. Same as SetupInstallFileEx().
  439. QueueNode - must be specified if Queue is supplied. This parameter gives
  440. us the queue node for this operation so we can get at the pertinent
  441. catalog info for driver signing.
  442. IsMsgHandlerNativeCharWidth - supplies a flag indicating whether
  443. CopyMsgHandler expects native char widths args (or ansi ones, in the
  444. unicode build of the dll).
  445. SignatureVerifyFailed - supplies the address of a boolean variable that is
  446. set to indicate whether or not digital signature verification failed for
  447. the source file. This will be set to FALSE if some other failure caused
  448. us to abort prior to attempting the signature verification. This is
  449. used by the queue commit routines to determine whether or not the queue
  450. callback routine should be given a chance to handle a copy failure
  451. (skip, retry, etc.). Digital signature verification failures are
  452. handled within this routine (including user prompting, if policy
  453. requires it), and queue callback routines _are not_ allowed to override
  454. the behavior.
  455. Return Value:
  456. Same as SetupInstallFileEx().
  457. --*/
  458. {
  459. BOOL b;
  460. BOOL Ok;
  461. DWORD rc = NO_ERROR;
  462. DWORD SigVerifRc;
  463. UINT SourceId;
  464. TCHAR Buffer1[MAX_PATH];
  465. TCHAR Buffer2[MAX_PATH];
  466. PCTSTR FullSourceFilename;
  467. PCTSTR FullTargetFilename;
  468. PCTSTR SourceFilenamePart;
  469. PTSTR ActualSourceFilename;
  470. PTSTR TemporaryTargetFile;
  471. UINT CompressionType;
  472. DWORD SourceFileSize;
  473. DWORD TargetFileSize;
  474. PTSTR p;
  475. DWORDLONG SourceVersion, TargetVersion;
  476. TCHAR SourceVersionText[50], TargetVersionText[50];
  477. LANGID SourceLanguage;
  478. LANGID TargetLanguage;
  479. WIN32_FIND_DATA SourceFindData;
  480. UINT NotifyFlags;
  481. PSECURITY_DESCRIPTOR SecurityInfo;
  482. FILEPATHS FilePaths;
  483. UINT param;
  484. FILETIME sFileTime,tFileTime;
  485. WORD sDosTime,sDosDate,tDosTime,tDosDate;
  486. BOOL Moved;
  487. SetupapiVerifyProblem Problem;
  488. BOOL ExistingTargetFileWasSigned;
  489. PSETUP_LOG_CONTEXT lc = NULL;
  490. DWORD slot_fileop = 0;
  491. SP_TARGET_ENT TargetInfo;
  492. PCTSTR ExistingFile = NULL;
  493. PCTSTR CompareFile = NULL;
  494. PCTSTR BackupFileName = NULL;
  495. BOOL CompareSameFilename = FALSE;
  496. BOOL FileUnchanged = FALSE;
  497. PLOADED_INF LoadedInf = NULL;
  498. DWORD ExemptCopyFlags = 0;
  499. BOOL DoingDeviceInstall;
  500. DWORD DriverSigningPolicy;
  501. PSP_ALTPLATFORM_INFO_V2 ValidationPlatform = NULL;
  502. PTSTR DeviceDesc = NULL;
  503. if (Queue) {
  504. lc = Queue->LogContext;
  505. } else if (InfHandle && InfHandle != INVALID_HANDLE_VALUE) {
  506. //
  507. // Lock INF for the duration of this routine.
  508. //
  509. try {
  510. if(!LockInf((PLOADED_INF)InfHandle)) {
  511. rc = ERROR_INVALID_HANDLE;
  512. }
  513. } except(EXCEPTION_EXECUTE_HANDLER) {
  514. //
  515. // Assume InfHandle was bad pointer
  516. //
  517. rc = ERROR_INVALID_HANDLE;
  518. }
  519. if(rc != NO_ERROR) {
  520. SetLastError(rc);
  521. return FALSE;
  522. }
  523. LoadedInf = (PLOADED_INF)InfHandle;
  524. lc = LoadedInf->LogContext;
  525. }
  526. //
  527. // If Queue is specified, then so must QueueNode (and vice versa).
  528. //
  529. MYASSERT((Queue && QueueNode) || !(Queue || QueueNode));
  530. *SignatureVerifyFailed = FALSE;
  531. SigVerifRc = NO_ERROR;
  532. //
  533. // Assume failure.
  534. //
  535. Ok = FALSE;
  536. SecurityInfo = NULL;
  537. Moved = FALSE;
  538. try {
  539. *FileWasInUse = FALSE;
  540. } except(EXCEPTION_EXECUTE_HANDLER) {
  541. rc = ERROR_INVALID_PARAMETER;
  542. }
  543. if((rc == NO_ERROR) && InfContext) {
  544. if(!InfHandle || (InfHandle == INVALID_HANDLE_VALUE)) {
  545. rc = ERROR_INVALID_PARAMETER;
  546. }
  547. }
  548. if(rc != NO_ERROR) {
  549. goto clean0;
  550. }
  551. //
  552. // Determine the full source path and filename of the file.
  553. //
  554. if(CopyStyle & SP_COPY_SOURCE_ABSOLUTE) {
  555. if (!SourceFile) {
  556. rc = ERROR_INVALID_PARAMETER;
  557. goto clean0;
  558. }
  559. FullSourceFilename = DuplicateString(SourceFile);
  560. } else {
  561. //
  562. // Get the relative path for this file if necessary.
  563. //
  564. if(CopyStyle & SP_COPY_SOURCEPATH_ABSOLUTE) {
  565. Buffer2[0] = TEXT('\0');
  566. b = TRUE;
  567. } else {
  568. b = _SetupGetSourceFileLocation(
  569. InfHandle,
  570. InfContext,
  571. SourceFile,
  572. (Queue && (Queue->Flags & FQF_USE_ALT_PLATFORM))
  573. ? &(Queue->AltPlatformInfo)
  574. : NULL,
  575. &SourceId,
  576. Buffer2,
  577. MAX_PATH,
  578. NULL,
  579. NULL
  580. );
  581. }
  582. //
  583. // Concatenate the relative path and the filename to the source root.
  584. //
  585. if(!b) {
  586. rc = (GetLastError() == ERROR_INSUFFICIENT_BUFFER
  587. ? ERROR_FILENAME_EXCED_RANGE : GetLastError());
  588. goto clean0;
  589. }
  590. if (SourcePathRoot) {
  591. lstrcpyn(Buffer1,SourcePathRoot,MAX_PATH);
  592. } else {
  593. Buffer1[0] = TEXT('\0');
  594. }
  595. if(!pSetupConcatenatePaths(Buffer1,Buffer2,MAX_PATH,NULL)
  596. || !pSetupConcatenatePaths(Buffer1,SourceFile,MAX_PATH,NULL)) {
  597. rc = ERROR_FILENAME_EXCED_RANGE;
  598. goto clean0;
  599. }
  600. FullSourceFilename = DuplicateString(Buffer1);
  601. }
  602. if(!FullSourceFilename) {
  603. rc = ERROR_NOT_ENOUGH_MEMORY;
  604. goto clean0;
  605. }
  606. SourceFilenamePart = pSetupGetFileTitle(FullSourceFilename);
  607. //
  608. // Determine the full target path and filename of the file.
  609. // For now ignore the issues regarding compressed vs. uncompressed names.
  610. //
  611. if(InfContext) {
  612. //
  613. // DestinationName is the filename only (no path) of the target.
  614. // We'll need to fetch the target path information for the section
  615. // that InfContext references.
  616. //
  617. b = SetupGetTargetPath(
  618. InfHandle,
  619. InfContext,
  620. NULL,
  621. Buffer1,
  622. MAX_PATH,
  623. NULL
  624. );
  625. if(!b) {
  626. rc = (GetLastError() == ERROR_INSUFFICIENT_BUFFER
  627. ? ERROR_FILENAME_EXCED_RANGE : GetLastError());
  628. goto clean1;
  629. }
  630. lstrcpyn(Buffer2,Buffer1,MAX_PATH);
  631. b = pSetupConcatenatePaths(
  632. Buffer2,
  633. DestinationName ? DestinationName : SourceFilenamePart,
  634. MAX_PATH,
  635. NULL
  636. );
  637. if(!b) {
  638. rc = ERROR_FILENAME_EXCED_RANGE;
  639. goto clean1;
  640. }
  641. FullTargetFilename = DuplicateString(Buffer2);
  642. } else {
  643. //
  644. // DestinationName is the full path and filename of the target file.
  645. //
  646. FullTargetFilename = DuplicateString(DestinationName);
  647. }
  648. if(!FullTargetFilename) {
  649. rc = ERROR_NOT_ENOUGH_MEMORY;
  650. goto clean1;
  651. }
  652. //
  653. // Log the file copy - only if we log something else
  654. // note that once we've determined temporary name, we'll change this message
  655. //
  656. slot_fileop = AllocLogInfoSlot(lc,FALSE); // for conditional display of extra logging info
  657. WriteLogEntry(
  658. lc,
  659. slot_fileop,
  660. MSG_LOG_COPYING_FILE,
  661. NULL,
  662. FullSourceFilename,
  663. FullTargetFilename);
  664. //
  665. // Make sure the target path exists.
  666. //
  667. rc = pSetupMakeSurePathExists(FullTargetFilename);
  668. if(rc != NO_ERROR) {
  669. rc = ERROR_INVALID_TARGET;
  670. goto clean2;
  671. }
  672. //
  673. // Determine if the source file is compressed and get compression type
  674. // if so.
  675. //
  676. rc = SetupInternalGetFileCompressionInfo(
  677. FullSourceFilename,
  678. &ActualSourceFilename,
  679. &SourceFindData,
  680. &TargetFileSize,
  681. &CompressionType
  682. );
  683. //
  684. // If the source doesn't exist but the target does, and we don't want to
  685. // overwrite it, then there is no error and we're finished.
  686. //
  687. // When doing a driver uninstall (i.e., re-installing the
  688. // previous driver from the backup directory), it's possible that not all
  689. // source files will be present in that directory (i.e., only those files
  690. // that were modified got backed up). In that case, we want to consider a
  691. // source file-not-found error here to be OK, even if the force-nooverwrite
  692. // flag isn't set.
  693. //
  694. // Note that driver signing isn't relevant here, because if an INF was signed
  695. // with the force-nooverwrite flag, then the signer (i.e., WHQL) must've been
  696. // satisfied that the file in question was not crucial to the package's
  697. // integrity/operation (a default INI file would be an example of this).
  698. //
  699. if(rc == ERROR_FILE_NOT_FOUND &&
  700. CopyStyle & SP_COPY_FORCE_NOOVERWRITE &&
  701. FileExists(FullTargetFilename,NULL)
  702. ) {
  703. rc = NO_ERROR;
  704. goto clean2;
  705. } else if(rc != NO_ERROR) {
  706. goto clean2;
  707. }
  708. //
  709. // Got the actual source file name now.
  710. //
  711. MyFree(FullSourceFilename);
  712. FullSourceFilename = ActualSourceFilename;
  713. SourceFilenamePart = pSetupGetFileTitle(FullSourceFilename);
  714. //
  715. // If the file to be copied is a .CAB and the source and destination
  716. // filenames are the same, then we don't want to attempt to decompress it
  717. // (because if we do, we'd just be pulling the first file out of the cab
  718. // and renaming it to the destination filename, which is never the desired
  719. // behavior.
  720. //
  721. if(!lstrcmpi(SourceFilenamePart, pSetupGetFileTitle(FullTargetFilename))) {
  722. p = _tcsrchr(SourceFilenamePart, TEXT('.'));
  723. if(p && !lstrcmpi(p, TEXT(".CAB"))) {
  724. CopyStyle |= SP_COPY_NODECOMP;
  725. }
  726. }
  727. //
  728. // If SP_COPY_NODECOMP flag is set, adjust the target filename so that
  729. // the filename part is the same as the actual name of the source.
  730. // We do this regardless of whether the source file is compressed.
  731. //
  732. // Note: For driver signing, the fact that this file is installed in its
  733. // compressed form means we must have an entry for the compressed file in
  734. // the catalog. However, if at some point in the future this file is going
  735. // to be expanded (as is typically the case), then we need to have the
  736. // expanded file's signature in the catalog as well, so that sigverif
  737. // doesn't consider this expanded file to be from a non-certified package.
  738. //
  739. if(CopyStyle & SP_COPY_ALREADYDECOMP) {
  740. //
  741. // this flag indicates we've decompressed it as far as we want
  742. // (used when restoring backup)
  743. //
  744. CompressionType = FILE_COMPRESSION_NONE;
  745. } else if(CopyStyle & SP_COPY_NODECOMP) {
  746. //
  747. // Strip out version-related bits and ensure that we treat the file
  748. // as uncompressed.
  749. //
  750. CopyStyle &= ~SP_COPY_MASK_NEEDVERINFO;
  751. CompressionType = FILE_COMPRESSION_NONE;
  752. //
  753. // Isolate the path part of the target filename.
  754. //
  755. lstrcpyn(Buffer1, FullTargetFilename, MAX_PATH);
  756. *((PTSTR)pSetupGetFileTitle(Buffer1)) = TEXT('\0');
  757. //
  758. // Concatenate the source filename onto the target pathname.
  759. //
  760. if(!pSetupConcatenatePaths(Buffer1,SourceFilenamePart,MAX_PATH,NULL)) {
  761. rc = ERROR_FILENAME_EXCED_RANGE;
  762. goto clean2;
  763. }
  764. p = DuplicateString(Buffer1);
  765. if(!p) {
  766. rc = ERROR_NOT_ENOUGH_MEMORY;
  767. goto clean2;
  768. }
  769. MyFree(FullTargetFilename);
  770. FullTargetFilename = p;
  771. }
  772. //
  773. // See if the target file exists, either as a renamed file (i.e., because
  774. // we're replacing a boot file), or as a file presently existing at the
  775. // target location.
  776. //
  777. if(Queue && (CopyStyle & SP_COPY_REPLACE_BOOT_FILE)) {
  778. //
  779. // First, we need to find the corresponding target info node so
  780. // we can find out what temporary name our file was renamed to.
  781. //
  782. rc = pSetupBackupGetTargetByPath((HSPFILEQ)Queue,
  783. NULL, // use Queue's string table
  784. FullTargetFilename,
  785. QueueNode->TargetDirectory,
  786. -1,
  787. QueueNode->TargetFilename,
  788. NULL,
  789. &TargetInfo
  790. );
  791. if(rc == NO_ERROR) {
  792. //
  793. // Has the file previously been renamed (and not yet restored)?
  794. //
  795. if((TargetInfo.InternalFlags & (SP_TEFLG_MOVED | SP_TEFLG_RESTORED)) == SP_TEFLG_MOVED) {
  796. CompareFile = ExistingFile =
  797. pSetupStringTableStringFromId(
  798. Queue->StringTable,
  799. TargetInfo.NewTargetFilename
  800. );
  801. MYASSERT(ExistingFile);
  802. }
  803. }
  804. }
  805. if(!ExistingFile && FileExists(FullTargetFilename, NULL)) {
  806. CompareFile = ExistingFile = FullTargetFilename;
  807. CompareSameFilename = TRUE; // allows optimization later
  808. }
  809. if(ExistingFile) {
  810. if(CopyStyle & SP_COPY_FORCE_NOOVERWRITE) {
  811. //
  812. // No overwrite and no callback notification either
  813. //
  814. // Note that driver signing isn't relevant here, because if an INF
  815. // was signed with the force-nooverwrite flag, then the signer
  816. // (i.e., WHQL) must've been satisfied that the file in question was
  817. // not crucial to the package's integrity/operation (a default INI
  818. // file would be an example of this).
  819. //
  820. rc = NO_ERROR;
  821. goto clean2;
  822. }
  823. if(CopyStyle & SP_COPY_MASK_NEEDVERINFO) {
  824. if(!GetVersionInfoFromImage(ExistingFile, &TargetVersion, &TargetLanguage)) {
  825. TargetVersion = 0;
  826. TargetLanguage = 0;
  827. }
  828. }
  829. //
  830. // If the target file exists we'll want to preserve security info on it.
  831. //
  832. if(RetreiveFileSecurity(ExistingFile, &SecurityInfo) != NO_ERROR) {
  833. SecurityInfo = NULL;
  834. }
  835. } else {
  836. if(CopyStyle & SP_COPY_REPLACEONLY) {
  837. //
  838. // Target file doesn't exist, so there's nothing to do.
  839. //
  840. rc = NO_ERROR;
  841. goto clean2;
  842. }
  843. if(Queue && ((Queue->Flags & FQF_FILES_MODIFIED)==0)) {
  844. //
  845. // maybe the file was renamed/deleted first
  846. // so we might still want to compare against backup
  847. // to determine if it was "modified"
  848. //
  849. rc = pSetupBackupGetTargetByPath((HSPFILEQ)Queue,
  850. NULL, // use Queue's string table
  851. FullTargetFilename,
  852. QueueNode->TargetDirectory,
  853. -1,
  854. QueueNode->TargetFilename,
  855. NULL,
  856. &TargetInfo
  857. );
  858. if((rc == NO_ERROR) &&
  859. ((TargetInfo.InternalFlags & (SP_TEFLG_MOVED | SP_TEFLG_SAVED)) != 0)) {
  860. //
  861. // get filename of copy of original file, if there is one
  862. //
  863. CompareFile = BackupFileName =
  864. pSetupFormFullPath(Queue->StringTable,
  865. TargetInfo.TargetRoot,
  866. TargetInfo.TargetSubDir,
  867. TargetInfo.TargetFilename
  868. );
  869. }
  870. }
  871. }
  872. //
  873. // If the source is not compressed (LZ or cabinet), and SIS is (or might be)
  874. // present, create the target as an SIS link to the master instead of copying it.
  875. //
  876. // If the target exists, and NOOVERWRITE was specified, don't try to create
  877. // an SIS link. Instead, fall through to the normal copy code. The overwrite
  878. // semantics are wrong if the file already exists.
  879. //
  880. if((CompressionType == FILE_COMPRESSION_NONE) &&
  881. (!ExistingFile || ((CopyStyle & SP_COPY_NOOVERWRITE) == 0)) &&
  882. (Queue != NULL) &&
  883. ((Queue->Flags & FQF_TRY_SIS_COPY) != 0)) {
  884. //
  885. // First, verify that the sourcefile is signed. If it is not, but the
  886. // user elects to proceed with the copy (or if the policy is 'ignore')
  887. // then we'll go ahead and attempt to setup the SIS link.
  888. //
  889. ValidationPlatform = (Queue->Flags & FQF_USE_ALT_PLATFORM)
  890. ? &(Queue->AltPlatformInfo)
  891. : Queue->ValidationPlatform;
  892. rc = VerifySourceFile(lc,
  893. Queue,
  894. QueueNode,
  895. pSetupGetFileTitle(FullTargetFilename),
  896. FullSourceFilename,
  897. NULL,
  898. ValidationPlatform,
  899. VERIFY_FILE_USE_OEM_CATALOGS | VERIFY_FILE_FAIL_COPIED_INFS,
  900. &Problem,
  901. Buffer1,
  902. NULL,
  903. NULL,
  904. NULL
  905. );
  906. if(rc != NO_ERROR) {
  907. *SignatureVerifyFailed = TRUE;
  908. SigVerifRc = rc;
  909. if(Queue->Flags & FQF_QUEUE_FORCE_BLOCK_POLICY) {
  910. goto clean2;
  911. }
  912. if (Problem != SetupapiVerifyDriverBlocked) {
  913. //
  914. // If this is a device installation and the policy is "Ignore",
  915. // then crank it up to "Warn" if the file is under SFP's
  916. // protection. This will allow the user to update a driver that
  917. // ships in our box for which no WHQL certification program
  918. // exists.
  919. //
  920. if((Queue->Flags & FQF_DEVICE_INSTALL) &&
  921. (Queue->DriverSigningPolicy == DRIVERSIGN_NONE) &&
  922. IsFileProtected(FullTargetFilename, lc, NULL)) {
  923. Queue->DriverSigningPolicy = DRIVERSIGN_WARNING;
  924. //
  925. // Log the fact that policy was elevated.
  926. //
  927. WriteLogEntry(lc,
  928. SETUP_LOG_ERROR,
  929. MSG_LOG_POLICY_ELEVATED_FOR_SFC,
  930. NULL
  931. );
  932. }
  933. }
  934. if(!pSetupHandleFailedVerification(
  935. Queue->hWndDriverSigningUi,
  936. Problem,
  937. (Problem == SetupapiVerifyDriverBlocked)
  938. ? FullSourceFilename : Buffer1,
  939. ((Queue->DeviceDescStringId == -1)
  940. ? NULL
  941. : pStringTableStringFromId(Queue->StringTable, Queue->DeviceDescStringId)),
  942. Queue->DriverSigningPolicy,
  943. (Queue->Flags & FQF_DIGSIG_ERRORS_NOUI),
  944. rc,
  945. lc,
  946. (((Queue->Flags & FQF_ABORT_IF_UNSIGNED) &&
  947. (Problem != SetupapiVerifyDriverBlocked))
  948. ? NULL : &ExemptCopyFlags),
  949. (((Queue->Flags & FQF_ABORT_IF_UNSIGNED) &&
  950. (Problem != SetupapiVerifyDriverBlocked))
  951. ? NULL : FullTargetFilename)))
  952. {
  953. //
  954. // User elected not to install the unsigned file (or was blocked
  955. // by policy from doing so).
  956. //
  957. goto clean2;
  958. }
  959. //
  960. // The user wants to proceed with the unsigned installation (or
  961. // policy is ignore, so they weren't even informed). If the
  962. // caller wants a chance to set a system restore point prior to
  963. // doing any unsigned installations, then we abort now with a
  964. // "special" error code that tells them what to do...
  965. //
  966. if(Queue->Flags & FQF_ABORT_IF_UNSIGNED) {
  967. //
  968. // We don't want the user to see the driver signing UI again
  969. // when the queue is re-committed...
  970. //
  971. if(Queue->DriverSigningPolicy != DRIVERSIGN_NONE) {
  972. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  973. }
  974. rc = ERROR_SET_SYSTEM_RESTORE_POINT;
  975. goto clean2;
  976. }
  977. //
  978. // Set a flag in the queue that indicates the user has been informed
  979. // of a signature problem with this queue, and has elected to go
  980. // ahead and install anyway. Don't set this flag if the queue's
  981. // policy is "Ignore", on the chance that the policy might be
  982. // altered later, and we'd want the user to get informed on any
  983. // subsequent errors.
  984. //
  985. if(Queue->DriverSigningPolicy != DRIVERSIGN_NONE) {
  986. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  987. }
  988. if (QueueNode) {
  989. QueueNode->InternalFlags |= ExemptCopyFlags;
  990. }
  991. //
  992. // Reset rc to NO_ERROR and carry on.
  993. //
  994. rc = NO_ERROR;
  995. }
  996. if(rc == NO_ERROR) {
  997. rc = CreateTargetAsLinkToMaster(
  998. Queue,
  999. FullSourceFilename,
  1000. FullTargetFilename,
  1001. CopyMsgHandler,
  1002. Context,
  1003. IsMsgHandlerNativeCharWidth
  1004. );
  1005. }
  1006. if(rc == NO_ERROR) {
  1007. //
  1008. // ISSUE JamieHun-2001/03/20 Is this best thing to do for SIS link?
  1009. //
  1010. Queue->Flags |= FQF_FILES_MODIFIED;
  1011. //
  1012. // We're done!
  1013. //
  1014. Ok = TRUE;
  1015. goto clean2;
  1016. }
  1017. }
  1018. //
  1019. // We will copy the file to a temporary location. This makes version checks
  1020. // possible in all cases (even when the source is compressed) and simplifies
  1021. // the logic below. Start by forming the name of the temporary file.
  1022. //
  1023. lstrcpyn(Buffer1, FullTargetFilename, MAX_PATH);
  1024. *((PTSTR)pSetupGetFileTitle(Buffer1)) = TEXT('\0');
  1025. if(!GetTempFileName(Buffer1, TEXT("SETP"), 0, Buffer2)) {
  1026. rc = ERROR_INVALID_TARGET;
  1027. goto clean2;
  1028. }
  1029. TemporaryTargetFile = DuplicateString(Buffer2);
  1030. if(!TemporaryTargetFile) {
  1031. rc = ERROR_NOT_ENOUGH_MEMORY;
  1032. goto clean2;
  1033. }
  1034. //
  1035. // Log the file copy - only if we log something else unless at Info level
  1036. //
  1037. ReleaseLogInfoSlot(lc,slot_fileop);
  1038. slot_fileop = AllocLogInfoSlotOrLevel(lc,SETUP_LOG_INFO,FALSE); // for conditional display of extra logging info
  1039. WriteLogEntry(
  1040. lc,
  1041. slot_fileop,
  1042. MSG_LOG_COPYING_FILE_VIA,
  1043. NULL,
  1044. FullSourceFilename,
  1045. FullTargetFilename,
  1046. TemporaryTargetFile);
  1047. //
  1048. // Perform the actual file copy. This creates the temporary target file.
  1049. // Move is allowed as an optimization if we're deleting the source file.
  1050. // The call we make below will not use move if the file is compressed
  1051. // and we are supposed to decompress it, so the right thing will happen
  1052. // in all cases.
  1053. //
  1054. // There are 2 potential issues:
  1055. //
  1056. // 1) When we call the callback function below for a version check,
  1057. // the source file won't exist any more if the file was moved. Oh well.
  1058. //
  1059. // 2) If the MoveFileEx below fails, the source will have still been 'deleted'.
  1060. // This is different from the non-move case, where the source remains
  1061. // intact unless this function is successful.
  1062. //
  1063. // Otherwise this is a non-issue since any compressed file will be decompressed
  1064. // by this call, so version gathering, etc, will all work properly.
  1065. //
  1066. rc = pSetupDecompressOrCopyFile(
  1067. FullSourceFilename,
  1068. TemporaryTargetFile,
  1069. &CompressionType,
  1070. ((CopyStyle & SP_COPY_DELETESOURCE) != 0),
  1071. &Moved
  1072. );
  1073. if(rc != NO_ERROR) {
  1074. goto clean3;
  1075. }
  1076. //
  1077. // Do digital signature check on source file, now that it exists in its
  1078. // final form under a temp name. Note that for signed files, we ignore
  1079. // version checking since they're an inherently unreliable mechanism for
  1080. // comparing files provided from two different vendors (who use different
  1081. // versioning schemes, etc.)
  1082. //
  1083. // To see why we ignore version numbers, consider the decision tree we'd
  1084. // use if we were paying attention to version numbers as well as digital
  1085. // signatures. In the discussion that follows, NewFile is the (signed) file
  1086. // we're going to copy, and OldFile is the file that will be overwritten if
  1087. // the copy goes through...
  1088. //
  1089. // if NewFile is versioned {
  1090. // if OldFile is signed {
  1091. // if OldFile is versioned {
  1092. // //
  1093. // // Both NewFile and OldFile are signed and versioned.
  1094. // //
  1095. // if OldFile is a newer version {
  1096. // //
  1097. // // This is the controversial case. Since these two incarnations could've come from different vendors
  1098. // // with different versioning schemes, we really can't use versioning as a very accurate method of determining
  1099. // // which file is 'better'. So there are two options:
  1100. // // 1. Leave OldFile alone, and if the package being installed can't work with OldFile, then the user must 'undo'
  1101. // // the installation, and then call their vendor to gripe--there'll be no way for them to get the new package to
  1102. // // work, even though WHQL certified it.
  1103. // // 2. Overwrite OldFile. Since we're then guaranteeing that every file signed as part of the package will be
  1104. // // present, then we can have a much higher degree of certainty that our WHQL certification will hold true
  1105. // // for every user's machine. If replacing OldFile breaks someone else (e.g., the previously-installed package
  1106. // // that uses it, then the user can 'undo' the installation. This scenario is better because even though the old
  1107. // // and new packages can't be used simultaneously, at least one or the other can be made to work
  1108. // // independently.
  1109. // //
  1110. // overwrite OldFile
  1111. // } else { // NewFile is a newer version
  1112. // overwrite OldFile
  1113. // }
  1114. // } else { // OldFile isn't versioned--NewFile wins
  1115. // overwrite OldFile
  1116. // }
  1117. // } else { // OldFile isn't signed--we don't care what its version is
  1118. // overwrite OldFile
  1119. // }
  1120. // } else { // NewFile isn't versioned
  1121. // if OldFile is versioned {
  1122. // if OldFile is signed {
  1123. // //
  1124. // // (See discussion above where both OldFile and NewFile are signed and versioned, and OldFile is newer. Note
  1125. // // that something funny is going on if we've been asked to replace a versionable file with an unversionable one!)
  1126. // //
  1127. // overwrite OldFile
  1128. // } else { // OldFile isn't signed
  1129. // overwrite OldFile
  1130. // }
  1131. // } else { // OldFile isn't versioned either
  1132. // overwrite OldFile
  1133. // }
  1134. // }
  1135. //
  1136. //
  1137. // Check to see if the source file is signed. (Note--we may have already
  1138. // checked this previously in determining whether an SIS link could be
  1139. // created. If we failed to verify the file's digital signature then,
  1140. // there's no use in re-verifying here.)
  1141. //
  1142. if(*SignatureVerifyFailed) {
  1143. //
  1144. // We saved the signature verification failure error when we previously
  1145. // attempted to verify this file. Restore that code to rc now, because
  1146. // the code below relies on the value of rc.
  1147. //
  1148. MYASSERT(SigVerifRc != NO_ERROR);
  1149. rc = SigVerifRc;
  1150. } else {
  1151. if(Queue) {
  1152. ValidationPlatform = (Queue->Flags & FQF_USE_ALT_PLATFORM)
  1153. ? &(Queue->AltPlatformInfo)
  1154. : Queue->ValidationPlatform;
  1155. } else {
  1156. //
  1157. // Since we aren't dealing with a queue, we need to retrieve the
  1158. // appropriate validation platform information, if any, for our INF.
  1159. //
  1160. DoingDeviceInstall = IsInfForDeviceInstall(lc,
  1161. NULL,
  1162. LoadedInf,
  1163. &DeviceDesc,
  1164. &ValidationPlatform,
  1165. &DriverSigningPolicy,
  1166. NULL
  1167. );
  1168. }
  1169. rc = VerifySourceFile(lc,
  1170. Queue,
  1171. QueueNode,
  1172. pSetupGetFileTitle(FullTargetFilename),
  1173. TemporaryTargetFile,
  1174. FullSourceFilename,
  1175. ValidationPlatform,
  1176. VERIFY_FILE_USE_OEM_CATALOGS | VERIFY_FILE_FAIL_COPIED_INFS,
  1177. &Problem,
  1178. Buffer1,
  1179. NULL,
  1180. NULL,
  1181. NULL
  1182. );
  1183. *SignatureVerifyFailed = (rc != NO_ERROR);
  1184. }
  1185. //
  1186. // Don't muck with the value of rc below unless you're setting it
  1187. // immediately before jumping to clean4. The return value from
  1188. // VerifySourceFile needs to be preserved until we finish with the
  1189. // pSetupHandleFailedVerification stuff.
  1190. //
  1191. //
  1192. // If we are going to perform version checks, fetch the version data
  1193. // of the source (which is now the temporary target file).
  1194. //
  1195. NotifyFlags = 0;
  1196. if(ExistingFile) {
  1197. param = 0;
  1198. //
  1199. // If we're not supposed to overwrite existing files,
  1200. // then the overwrite check fails.
  1201. //
  1202. if(CopyStyle & SP_COPY_NOOVERWRITE) {
  1203. NotifyFlags |= SPFILENOTIFY_TARGETEXISTS;
  1204. }
  1205. //
  1206. // Even if the source file has a verified digital signature, we still
  1207. // want to retrieve version information for the source and target. We
  1208. // do this so that we can detect when we've overwritten a newer-
  1209. // versioned file with an older-versioned one. If we discover that
  1210. // this is the case, then we generate an exception log entry that will
  1211. // help PSS troubleshoot any problems that result.
  1212. //
  1213. if(!GetVersionInfoFromImage(TemporaryTargetFile, &SourceVersion, &SourceLanguage)) {
  1214. SourceVersion = 0;
  1215. SourceLanguage = 0;
  1216. }
  1217. //
  1218. // If we're not supposed to overwrite files in a different language
  1219. // and the languages differ, then the language check fails.
  1220. // If either file doesn't have language data, then don't do a language
  1221. // check.
  1222. //
  1223. //
  1224. // Special case:
  1225. //
  1226. // If
  1227. // a) the source version is greater than the target version
  1228. // b) the source doesn't have a lang id
  1229. // c) the target does have a lang id
  1230. // Then
  1231. // we will do a language check, and we will consider this language check
  1232. // as passed since we are replacing an older language specific file with
  1233. // a language neutral file, which is an OK thing.
  1234. //
  1235. //
  1236. if(CopyStyle & SP_COPY_LANGUAGEAWARE) {
  1237. if ( SourceLanguage
  1238. && TargetLanguage
  1239. && (SourceLanguage != TargetLanguage) ) {
  1240. NotifyFlags |= SPFILENOTIFY_LANGMISMATCH;
  1241. param = (UINT)MAKELONG(SourceLanguage, TargetLanguage);
  1242. } else if ( !SourceLanguage
  1243. && TargetLanguage
  1244. && (TargetVersion >= SourceVersion) ) {
  1245. NotifyFlags |= SPFILENOTIFY_LANGMISMATCH;
  1246. param = (UINT)MAKELONG(SourceLanguage, TargetLanguage);
  1247. }
  1248. }
  1249. //
  1250. // If we're not supposed to overwrite newer versions and the target is
  1251. // newer than the source, then the version check fails. If either file
  1252. // doesn't have version info, fall back to timestamp comparison.
  1253. //
  1254. // If the files are the same version/timestamp, assume that either
  1255. // replacing the existing one is a benevolent operation, or that
  1256. // we are upgrading an existing file whose version info is unimportant.
  1257. // In this case we just go ahead and copy the file (unless the
  1258. // SP_COPY_NEWER_ONLY flag is set).
  1259. //
  1260. // Note that the version checks below are made without regard to presence
  1261. // or absence of digital signatures on either the source or target files.
  1262. // That will be handled later. We want to see what would've happened
  1263. // without driver signing, so we can generate a PSS exception log when
  1264. // something weird happens.
  1265. //
  1266. if(SourceVersion || TargetVersion) {
  1267. b = (CopyStyle & SP_COPY_NEWER_ONLY)
  1268. ? (TargetVersion >= SourceVersion)
  1269. : (TargetVersion > SourceVersion);
  1270. } else {
  1271. #if 0
  1272. //
  1273. // (tedm) removed timestamp-based checking. It's just not a reliable
  1274. // way of doing things.
  1275. //
  1276. //
  1277. // File time on FAT is only guaranteed accurate to within 2 seconds.
  1278. // Round the filetimes before comparison by converting to DOS time
  1279. // and back. If the conversions fail then just use the original values.
  1280. //
  1281. if(!FileTimeToDosDateTime(&SourceFindData.ftLastWriteTime,&sDosDate,&sDosTime)
  1282. || !FileTimeToDosDateTime(&TargetFindData.ftLastWriteTime,&tDosDate,&tDosTime)
  1283. || !DosDateTimeToFileTime(sDosDate,sDosTime,&sFileTime)
  1284. || !DosDateTimeToFileTime(tDosDate,tDosTime,&tFileTime)) {
  1285. sFileTime = SourceFindData.ftLastWriteTime;
  1286. tFileTime = TargetFindData.ftLastWriteTime;
  1287. }
  1288. //
  1289. // If the FORCE_NEWER flag is set then don't use timestamps
  1290. // for versioning. This more closely matches Win95's setupx behavior.
  1291. //
  1292. b = (CopyStyle & SP_COPY_FORCE_NEWER)
  1293. ? FALSE
  1294. : (CompareFileTime(&tFileTime,&sFileTime) > 0);
  1295. #else
  1296. b = FALSE;
  1297. #endif
  1298. }
  1299. //
  1300. // At this point, if b is TRUE then the target file has a later (newer)
  1301. // version than the sourcefile. If we've been asked to pay attention to
  1302. // that, then set the NotifyFlags to indicate this problem.
  1303. // Note that this may get reset later if the source file is signed. We
  1304. // still wanted to get this information so we could put it in our PSS
  1305. // logfile.
  1306. //
  1307. if(b &&
  1308. (CopyStyle & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))) {
  1309. NotifyFlags |= SPFILENOTIFY_TARGETNEWER;
  1310. }
  1311. }
  1312. if(NotifyFlags & SPFILENOTIFY_TARGETNEWER) {
  1313. if(!*SignatureVerifyFailed) {
  1314. //
  1315. // Source file is signed, but the target file is newer. We know
  1316. // that we still want to replace the existing targetfile with the
  1317. // sourcefile, regardless of version numbers. However, we need to
  1318. // make note of that in our PSS logfile.
  1319. //
  1320. NotifyFlags &= ~SPFILENOTIFY_TARGETNEWER;
  1321. //
  1322. // Check to see if the target file is signed, in order to include
  1323. // this information in our PSS logfile.
  1324. //
  1325. ExistingTargetFileWasSigned = (NO_ERROR == _VerifyFile(
  1326. lc,
  1327. (Queue ? &(Queue->hCatAdmin) : NULL),
  1328. NULL,
  1329. NULL,
  1330. NULL,
  1331. 0,
  1332. pSetupGetFileTitle(FullTargetFilename),
  1333. ExistingFile,
  1334. NULL,
  1335. NULL,
  1336. FALSE,
  1337. ValidationPlatform,
  1338. (VERIFY_FILE_USE_OEM_CATALOGS | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  1339. NULL,
  1340. NULL,
  1341. NULL,
  1342. NULL
  1343. ));
  1344. //
  1345. // SPLOG -- report that newer target was overwritten by older (signed)
  1346. // source, whether target was signed, both files' versions, etc.
  1347. // Also probably want to throw in the fact that the SP_COPY_FORCE_NEWER
  1348. // flag was ignored, if it's set.
  1349. //
  1350. pGetVersionText(SourceVersionText,SourceVersion);
  1351. pGetVersionText(TargetVersionText,TargetVersion);
  1352. WriteLogEntry(
  1353. lc,
  1354. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1355. MSG_LOG_NEWER_FILE_OVERWRITTEN,
  1356. NULL,
  1357. FullTargetFilename,
  1358. SourceVersionText,
  1359. TargetVersionText);
  1360. if (CopyStyle & SP_COPY_FORCE_NEWER) {
  1361. WriteLogEntry(
  1362. lc,
  1363. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1364. MSG_LOG_FLAG_FORCE_NEWER_IGNORED,
  1365. NULL);
  1366. }
  1367. WriteLogEntry(
  1368. lc,
  1369. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1370. (ExistingTargetFileWasSigned ?
  1371. MSG_LOG_TARGET_WAS_SIGNED :
  1372. MSG_LOG_TARGET_WAS_NOT_SIGNED),
  1373. NULL);
  1374. //
  1375. // flush the log buffer
  1376. //
  1377. WriteLogEntry(
  1378. lc,
  1379. SETUP_LOG_WARNING,
  1380. 0,
  1381. TEXT("\n"));
  1382. } else {
  1383. //
  1384. // Source file isn't signed, so we'll let the old behavior apply.
  1385. // If version dialogs are allowed, for example, the user will be
  1386. // prompted that they're attempting to overwrite a newer file with an
  1387. // older one. If they say "go ahead and copy over the older version",
  1388. // _then_ they'll get a prompt about the file not having a valid
  1389. // signature.
  1390. //
  1391. // Check special case where a flag is set indicating that we should
  1392. // just silently not copy the newer file.
  1393. //
  1394. if(CopyStyle & SP_COPY_FORCE_NEWER) {
  1395. //
  1396. // Target is newer; don't copy the file.
  1397. //
  1398. rc = NO_ERROR;
  1399. goto clean4;
  1400. }
  1401. }
  1402. }
  1403. //
  1404. // If we have any reason to notify the caller via the callback,
  1405. // do that here. If there is no callback, then don't copy the file,
  1406. // because one of the conditions has not been met.
  1407. //
  1408. if((NotifyFlags & SPFILENOTIFY_LANGMISMATCH) && ! *SignatureVerifyFailed) {
  1409. //
  1410. //
  1411. //
  1412. // if the source was signed, we will ignore a language mismatch
  1413. // as this is a package deal
  1414. // NTRAID9#498046-2001/11/20-JamieHun handle LANGMISMATCH better
  1415. //
  1416. NotifyFlags &=~SPFILENOTIFY_LANGMISMATCH;
  1417. WriteLogEntry(
  1418. lc,
  1419. SETUP_LOG_WARNING,
  1420. MSG_LOG_NOTIFY_LANGMISMATCH,
  1421. NULL);
  1422. }
  1423. if(NotifyFlags) {
  1424. FilePaths.Source = FullSourceFilename;
  1425. FilePaths.Target = FullTargetFilename;
  1426. FilePaths.Win32Error = NO_ERROR;
  1427. if(!CopyMsgHandler
  1428. || !pSetupCallMsgHandler(
  1429. lc,
  1430. CopyMsgHandler,
  1431. IsMsgHandlerNativeCharWidth,
  1432. Context,
  1433. NotifyFlags,
  1434. (UINT_PTR)&FilePaths,
  1435. param))
  1436. {
  1437. if(ExistingFile) {
  1438. //
  1439. // Check to see if the target file is signed, in order to include
  1440. // this information in our PSS logfile.
  1441. //
  1442. ExistingTargetFileWasSigned = (NO_ERROR == _VerifyFile(
  1443. lc,
  1444. (Queue ? &(Queue->hCatAdmin) : NULL),
  1445. NULL,
  1446. NULL,
  1447. NULL,
  1448. 0,
  1449. pSetupGetFileTitle(FullTargetFilename),
  1450. ExistingFile,
  1451. NULL,
  1452. NULL,
  1453. FALSE,
  1454. ValidationPlatform,
  1455. (VERIFY_FILE_USE_OEM_CATALOGS | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  1456. NULL,
  1457. NULL,
  1458. NULL,
  1459. NULL
  1460. ));
  1461. }
  1462. //
  1463. // SPLOG -- error that occurred, info on whether source and target
  1464. // files were signed, what their versions were, etc.
  1465. //
  1466. pGetVersionText(SourceVersionText,SourceVersion);
  1467. pGetVersionText(TargetVersionText,TargetVersion);
  1468. WriteLogEntry(
  1469. lc,
  1470. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1471. MSG_LOG_FILE_NOT_OVERWRITTEN,
  1472. NULL,
  1473. SourceVersionText,
  1474. TargetVersionText);
  1475. if (NotifyFlags & SPFILENOTIFY_TARGETEXISTS) {
  1476. WriteLogEntry(
  1477. lc,
  1478. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1479. MSG_LOG_NOTIFY_TARGETEXISTS,
  1480. NULL);
  1481. }
  1482. if (NotifyFlags & SPFILENOTIFY_LANGMISMATCH) {
  1483. WriteLogEntry(
  1484. lc,
  1485. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1486. MSG_LOG_NOTIFY_LANGMISMATCH,
  1487. NULL);
  1488. }
  1489. if (NotifyFlags & SPFILENOTIFY_TARGETNEWER) {
  1490. WriteLogEntry(
  1491. lc,
  1492. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1493. MSG_LOG_NOTIFY_TARGETNEWER,
  1494. NULL);
  1495. }
  1496. WriteLogEntry(
  1497. lc,
  1498. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1499. (ExistingTargetFileWasSigned ?
  1500. MSG_LOG_TARGET_WAS_SIGNED :
  1501. MSG_LOG_TARGET_WAS_NOT_SIGNED),
  1502. NULL);
  1503. WriteLogEntry(
  1504. lc,
  1505. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1506. (*SignatureVerifyFailed ?
  1507. MSG_LOG_SOURCE_WAS_NOT_SIGNED :
  1508. MSG_LOG_SOURCE_WAS_SIGNED),
  1509. NULL);
  1510. WriteLogError(
  1511. lc,
  1512. SETUP_LOG_WARNING,
  1513. rc);
  1514. rc = NO_ERROR;
  1515. goto clean4;
  1516. }
  1517. }
  1518. //
  1519. // OK, now that all non-codesigning stuff is done, tell the user about
  1520. // any digital signature problems we found with the source file.
  1521. //
  1522. // NOTE: If SigVerifRc is set to something other than NO_ERROR, then we know
  1523. // that the pSetupHandleFailedVerification routine has already been called, thus
  1524. // we don't want to call it again or otherwise the user may get multiple
  1525. // prompts about a bad signature for the same file.
  1526. //
  1527. if(*SignatureVerifyFailed) {
  1528. if(SigVerifRc == NO_ERROR) {
  1529. MYASSERT(ExemptCopyFlags == 0);
  1530. //
  1531. // Save away the verification error in SigVerifRc, so we can use
  1532. // this later to determine whether we're dealing with an unsigned
  1533. // file.
  1534. //
  1535. MYASSERT(rc != NO_ERROR);
  1536. SigVerifRc = rc;
  1537. //
  1538. // If we're using a file queue, the retrieve information from the
  1539. // queue regarding policy, whether it's a device install (and if
  1540. // so, what description to use), etc. There's no need to do this
  1541. // in the non-queue case, because we already did this previously.
  1542. //
  1543. if(Queue) {
  1544. //
  1545. // if we're set to block on a per queue basis, then bail out
  1546. // here
  1547. //
  1548. if(Queue->Flags & FQF_QUEUE_FORCE_BLOCK_POLICY) {
  1549. goto clean4;
  1550. }
  1551. if(Queue->DeviceDescStringId != -1) {
  1552. DeviceDesc = pStringTableStringFromId(
  1553. Queue->StringTable,
  1554. Queue->DeviceDescStringId
  1555. );
  1556. MYASSERT(DeviceDesc);
  1557. } else {
  1558. DeviceDesc = NULL;
  1559. }
  1560. DoingDeviceInstall = Queue->Flags & FQF_DEVICE_INSTALL;
  1561. DriverSigningPolicy = Queue->DriverSigningPolicy;
  1562. }
  1563. if (Problem != SetupapiVerifyDriverBlocked) {
  1564. //
  1565. // If this is a device installation and the policy is "Ignore",
  1566. // then crank it up to "Warn" if the file is under SFP's
  1567. // protection. This will allow the user to update a driver that
  1568. // ships in our box for which no WHQL certification program
  1569. // exists.
  1570. //
  1571. if(DoingDeviceInstall && (DriverSigningPolicy == DRIVERSIGN_NONE) &&
  1572. IsFileProtected(FullTargetFilename, lc, NULL)) {
  1573. DriverSigningPolicy = DRIVERSIGN_WARNING;
  1574. //
  1575. // If we have a queue, update the queue's policy as well.
  1576. //
  1577. if(Queue) {
  1578. Queue->DriverSigningPolicy = DRIVERSIGN_WARNING;
  1579. }
  1580. //
  1581. // Log the fact that policy was elevated.
  1582. //
  1583. WriteLogEntry(lc,
  1584. SETUP_LOG_ERROR,
  1585. MSG_LOG_POLICY_ELEVATED_FOR_SFC,
  1586. NULL
  1587. );
  1588. }
  1589. }
  1590. if(!pSetupHandleFailedVerification(
  1591. (Queue ? Queue->hWndDriverSigningUi : NULL),
  1592. Problem,
  1593. (Problem == SetupapiVerifyDriverBlocked)
  1594. ? FullSourceFilename : Buffer1,
  1595. DeviceDesc,
  1596. DriverSigningPolicy,
  1597. (Queue ? (Queue->Flags & FQF_DIGSIG_ERRORS_NOUI) : FALSE),
  1598. rc,
  1599. lc,
  1600. (((Queue && (Queue->Flags & FQF_ABORT_IF_UNSIGNED)) &&
  1601. (Problem != SetupapiVerifyDriverBlocked))
  1602. ? NULL : &ExemptCopyFlags),
  1603. (((Queue && (Queue->Flags & FQF_ABORT_IF_UNSIGNED)) &&
  1604. (Problem != SetupapiVerifyDriverBlocked))
  1605. ? NULL : FullTargetFilename)))
  1606. {
  1607. //
  1608. // User elected not to install the unsigned file (or was blocked
  1609. // by policy from doing so).
  1610. //
  1611. goto clean4;
  1612. }
  1613. }
  1614. if(Queue) {
  1615. //
  1616. // If the caller wants a chance to set a system restore point prior
  1617. // to doing any unsigned installations, then we abort now with a
  1618. // "special" error code that tells them what to do...
  1619. //
  1620. if(Queue->Flags & FQF_ABORT_IF_UNSIGNED) {
  1621. //
  1622. // We don't want the user to see the driver signing UI again
  1623. // when the queue is re-committed...
  1624. //
  1625. if(Queue->DriverSigningPolicy != DRIVERSIGN_NONE) {
  1626. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  1627. }
  1628. rc = ERROR_SET_SYSTEM_RESTORE_POINT;
  1629. goto clean4;
  1630. }
  1631. //
  1632. // Set a flag in the queue that indicates the user has been informed
  1633. // of a signature problem with this queue, and has elected to go
  1634. // ahead and install anyway. Don't set this flag if the queue's
  1635. // policy is "Ignore", on the chance that the policy might be
  1636. // altered later, and we'd want the user to get informed on any
  1637. // subsequent errors.
  1638. //
  1639. if(Queue->DriverSigningPolicy != DRIVERSIGN_NONE) {
  1640. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  1641. }
  1642. if (QueueNode) {
  1643. QueueNode->InternalFlags |= ExemptCopyFlags;
  1644. }
  1645. }
  1646. //
  1647. // Reset rc to NO_ERROR and carry on.
  1648. //
  1649. rc = NO_ERROR;
  1650. }
  1651. //
  1652. // Move the target file into its final location.
  1653. //
  1654. SetFileAttributes(FullTargetFilename, FILE_ATTRIBUTE_NORMAL);
  1655. if(Queue && ((Queue->Flags & FQF_FILES_MODIFIED)==0)) {
  1656. //
  1657. // so far we haven't flagged that any files are modified
  1658. //
  1659. if(CompareFile) {
  1660. //
  1661. // we have an "original" file
  1662. //
  1663. if(pCompareFilesExact(TemporaryTargetFile,CompareFile)) {
  1664. //
  1665. // new file of this name is same as original file of same name
  1666. //
  1667. if(CompareSameFilename) {
  1668. //
  1669. // original is already in place
  1670. // don't need to do a delayed-rename
  1671. //
  1672. FileUnchanged = TRUE;
  1673. }
  1674. } else {
  1675. //
  1676. // file appears to have been modified
  1677. //
  1678. Queue->Flags |= FQF_FILES_MODIFIED;
  1679. }
  1680. } else {
  1681. //
  1682. // be safe, copying over nothing = modified
  1683. //
  1684. Queue->Flags |= FQF_FILES_MODIFIED;
  1685. }
  1686. }
  1687. //
  1688. // If the target exists and the force-in-use flag is set, then don't try to
  1689. // move the file into place now -- automatically drop into in-use behavior.
  1690. //
  1691. // Want to use MoveFileEx but it didn't exist in Win95. Ugh.
  1692. //
  1693. if(!(ExistingFile && (CopyStyle & SP_COPY_FORCE_IN_USE))
  1694. && (b = DoMove(TemporaryTargetFile, FullTargetFilename))) {
  1695. //
  1696. // Place security information on the target file if necessary.
  1697. // Ignore errors. The theory here is that the file is already on
  1698. // the target, so if this fails the worst case is that the file is
  1699. // not secure. But the user can still use the system.
  1700. //
  1701. if(SecurityInfo) {
  1702. DWORD err = StampFileSecurity(FullTargetFilename, SecurityInfo);
  1703. if(err != NO_ERROR) {
  1704. WriteLogEntry(lc,
  1705. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  1706. MSG_LOG_FILE_SECURITY_FAILED,
  1707. NULL,
  1708. FullTargetFilename
  1709. );
  1710. WriteLogError(lc,SETUP_LOG_ERROR,err);
  1711. } else {
  1712. WriteLogEntry(lc,
  1713. SETUP_LOG_VERBOSE,
  1714. MSG_LOG_SET_FILE_SECURITY,
  1715. NULL,
  1716. FullTargetFilename
  1717. );
  1718. }
  1719. }
  1720. } else {
  1721. //
  1722. // If this fails, assume the file is in use and mark it for copy on next
  1723. // boot (except in the case where we're copying a boot file, in which
  1724. // case this is a catastrophic failure).
  1725. //
  1726. if(ExistingFile != FullTargetFilename) {
  1727. WriteLogEntry(lc,
  1728. SETUP_LOG_ERROR,
  1729. MSG_LOG_REPLACE_BOOT_FILE_FAILED,
  1730. NULL,
  1731. FullTargetFilename
  1732. );
  1733. b = FALSE;
  1734. SetLastError(ERROR_ACCESS_DENIED);
  1735. } else if (((CopyStyle & SP_COPY_FORCE_IN_USE) == 0) &&
  1736. (FileUnchanged || pCompareFilesExact(TemporaryTargetFile,FullTargetFilename))) {
  1737. //
  1738. // It turns out that new file and old file are exactly the same
  1739. // we can optimize out the delayed move and delete the temporary file
  1740. //
  1741. WriteLogEntry(lc,
  1742. SETUP_LOG_INFO,
  1743. MSG_LOG_COPY_IDENTICAL,
  1744. NULL,
  1745. FullTargetFilename,
  1746. TemporaryTargetFile
  1747. );
  1748. if(SecurityInfo) {
  1749. //
  1750. // we still need to adjust security on it though
  1751. //
  1752. DWORD err = StampFileSecurity(FullTargetFilename, SecurityInfo);
  1753. if(err != NO_ERROR) {
  1754. WriteLogEntry(lc,
  1755. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  1756. MSG_LOG_FILE_SECURITY_FAILED,
  1757. NULL,
  1758. FullTargetFilename
  1759. );
  1760. WriteLogError(lc,SETUP_LOG_ERROR,err);
  1761. } else {
  1762. WriteLogEntry(lc,
  1763. SETUP_LOG_VERBOSE,
  1764. MSG_LOG_SET_FILE_SECURITY,
  1765. NULL,
  1766. FullTargetFilename
  1767. );
  1768. }
  1769. }
  1770. SetFileAttributes(TemporaryTargetFile, FILE_ATTRIBUTE_NORMAL);
  1771. DeleteFile(TemporaryTargetFile);
  1772. b = TRUE;
  1773. } else {
  1774. b = TRUE;
  1775. try {
  1776. *FileWasInUse = TRUE;
  1777. } except(EXCEPTION_EXECUTE_HANDLER) {
  1778. b = FALSE;
  1779. }
  1780. if(b) {
  1781. //
  1782. // If we're trying to do a delayed move to replace a protected
  1783. // system file (using an unsigned one), and we've not been
  1784. // granted an exception to do so, then we should skip the
  1785. // operation altogether (and make a log entry about it)
  1786. //
  1787. if((SigVerifRc != NO_ERROR) &&
  1788. ((ExemptCopyFlags & (IQF_TARGET_PROTECTED | IQF_ALLOW_UNSIGNED)) == IQF_TARGET_PROTECTED)) {
  1789. WriteLogEntry(lc,
  1790. SETUP_LOG_ERROR,
  1791. MSG_LOG_DELAYED_MOVE_SKIPPED_FOR_SFC,
  1792. NULL,
  1793. FullTargetFilename
  1794. );
  1795. //
  1796. // Delete the source file.
  1797. //
  1798. SetFileAttributes(TemporaryTargetFile, FILE_ATTRIBUTE_NORMAL);
  1799. DeleteFile(TemporaryTargetFile);
  1800. } else {
  1801. BOOL TargetIsProtected = IsFileProtected(FullTargetFilename, lc, NULL);
  1802. if(Queue == NULL) {
  1803. b = DelayedMove(
  1804. TemporaryTargetFile,
  1805. FullTargetFilename
  1806. );
  1807. if(b && TargetIsProtected) {
  1808. //
  1809. // we have to explicitly tell the session manager it's ok
  1810. // to replace the changed files on reboot.
  1811. //
  1812. // in the case that we're using a queue, we post the
  1813. // delayed move and set this flag only if all the delayed
  1814. // move operations succeed
  1815. //
  1816. pSetupProtectedRenamesFlag(TRUE);
  1817. }
  1818. } else {
  1819. b = PostDelayedMove(
  1820. Queue,
  1821. TemporaryTargetFile,
  1822. FullTargetFilename,
  1823. QueueNode->SecurityDesc,
  1824. TargetIsProtected
  1825. );
  1826. }
  1827. if(b) {
  1828. //
  1829. // Couldn't set security info on the actual target, so at least
  1830. // set it on the temp file that will become the target.
  1831. //
  1832. if(SecurityInfo) {
  1833. StampFileSecurity(TemporaryTargetFile,SecurityInfo);
  1834. }
  1835. if (lc) {
  1836. WriteLogEntry(lc,
  1837. SETUP_LOG_WARNING,
  1838. MSG_LOG_COPY_DELAYED,
  1839. NULL,
  1840. FullTargetFilename,
  1841. TemporaryTargetFile
  1842. );
  1843. }
  1844. //
  1845. // Tell the callback that we queued this file for delayed copy.
  1846. //
  1847. if(CopyMsgHandler) {
  1848. FilePaths.Source = TemporaryTargetFile;
  1849. FilePaths.Target = FullTargetFilename;
  1850. FilePaths.Win32Error = NO_ERROR;
  1851. FilePaths.Flags = FILEOP_COPY;
  1852. pSetupCallMsgHandler(
  1853. lc,
  1854. CopyMsgHandler,
  1855. IsMsgHandlerNativeCharWidth,
  1856. Context,
  1857. SPFILENOTIFY_FILEOPDELAYED,
  1858. (UINT_PTR)&FilePaths,
  1859. 0
  1860. );
  1861. }
  1862. }
  1863. }
  1864. } else {
  1865. //
  1866. // FileWasInUse pointer went bad
  1867. //
  1868. SetLastError(ERROR_INVALID_PARAMETER);
  1869. }
  1870. }
  1871. }
  1872. if(!b) {
  1873. rc = GetLastError();
  1874. goto clean4;
  1875. }
  1876. //
  1877. // We're done. Delete the source if necessary and return.
  1878. //
  1879. if((CopyStyle & SP_COPY_DELETESOURCE) && !Moved) {
  1880. DeleteFile(FullSourceFilename);
  1881. }
  1882. rc = NO_ERROR;
  1883. Ok = TRUE;
  1884. goto clean3;
  1885. clean4:
  1886. //
  1887. // Remove temporary target file.
  1888. // In case pSetupDecompressOrCopyFile MoveFile'd the source,
  1889. // we really need to try to move it back, so the source file isn't
  1890. // blown away when this routine fails.
  1891. //
  1892. if(Moved) {
  1893. MoveFile(TemporaryTargetFile,FullSourceFilename);
  1894. } else {
  1895. SetFileAttributes(TemporaryTargetFile,FILE_ATTRIBUTE_NORMAL);
  1896. DeleteFile(TemporaryTargetFile);
  1897. }
  1898. clean3:
  1899. MyFree(TemporaryTargetFile);
  1900. //
  1901. // If we didn't have a file queue, then we may have allocated a device
  1902. // description and validation platform structure when we called
  1903. // IsInfForDeviceInstall. Clean those up now.
  1904. //
  1905. if(!Queue) {
  1906. if(DeviceDesc) {
  1907. MyFree(DeviceDesc);
  1908. }
  1909. if(ValidationPlatform) {
  1910. MyFree(ValidationPlatform);
  1911. }
  1912. }
  1913. clean2:
  1914. if (BackupFileName) {
  1915. MyFree(BackupFileName);
  1916. }
  1917. MyFree(FullTargetFilename);
  1918. clean1:
  1919. MyFree(FullSourceFilename);
  1920. clean0:
  1921. if(SecurityInfo) {
  1922. MyFree(SecurityInfo);
  1923. }
  1924. //
  1925. // if there was an error of some sort, log it
  1926. //
  1927. if (rc != NO_ERROR) {
  1928. //
  1929. // maybe we ought to embelish this a bit.
  1930. //
  1931. WriteLogEntry(
  1932. lc,
  1933. SETUP_LOG_ERROR,
  1934. rc,
  1935. NULL);
  1936. }
  1937. if(slot_fileop) {
  1938. ReleaseLogInfoSlot(lc, slot_fileop);
  1939. }
  1940. if(LoadedInf) {
  1941. UnlockInf(LoadedInf);
  1942. }
  1943. SetLastError(rc);
  1944. return(Ok);
  1945. }
  1946. #ifdef UNICODE
  1947. //
  1948. // ANSI version
  1949. //
  1950. BOOL
  1951. SetupInstallFileExA(
  1952. IN HINF InfHandle, OPTIONAL
  1953. IN PINFCONTEXT InfContext, OPTIONAL
  1954. IN PCSTR SourceFile, OPTIONAL
  1955. IN PCSTR SourcePathRoot, OPTIONAL
  1956. IN PCSTR DestinationName, OPTIONAL
  1957. IN DWORD CopyStyle,
  1958. IN PSP_FILE_CALLBACK_A CopyMsgHandler, OPTIONAL
  1959. IN PVOID Context, OPTIONAL
  1960. OUT PBOOL FileWasInUse
  1961. )
  1962. {
  1963. PCWSTR sourceFile,sourcePathRoot,destinationName;
  1964. BOOL b, DontCare;
  1965. DWORD rc;
  1966. sourceFile = NULL;
  1967. sourcePathRoot = NULL;
  1968. destinationName = NULL;
  1969. rc = NO_ERROR;
  1970. if(SourceFile) {
  1971. rc = pSetupCaptureAndConvertAnsiArg(SourceFile,&sourceFile);
  1972. }
  1973. if((rc == NO_ERROR) && SourcePathRoot) {
  1974. rc = pSetupCaptureAndConvertAnsiArg(SourcePathRoot,&sourcePathRoot);
  1975. }
  1976. if((rc == NO_ERROR) && DestinationName) {
  1977. rc = pSetupCaptureAndConvertAnsiArg(DestinationName,&destinationName);
  1978. }
  1979. if(rc == NO_ERROR) {
  1980. b = _SetupInstallFileEx(
  1981. NULL,
  1982. NULL,
  1983. InfHandle,
  1984. InfContext,
  1985. sourceFile,
  1986. sourcePathRoot,
  1987. destinationName,
  1988. CopyStyle,
  1989. CopyMsgHandler,
  1990. Context,
  1991. FileWasInUse,
  1992. FALSE,
  1993. &DontCare
  1994. );
  1995. rc = b ? NO_ERROR : GetLastError();
  1996. } else {
  1997. b = FALSE;
  1998. }
  1999. if(sourceFile) {
  2000. MyFree(sourceFile);
  2001. }
  2002. if(sourcePathRoot) {
  2003. MyFree(sourcePathRoot);
  2004. }
  2005. if(destinationName) {
  2006. MyFree(destinationName);
  2007. }
  2008. SetLastError(rc);
  2009. return b;
  2010. }
  2011. #else
  2012. //
  2013. // Unicode stub
  2014. //
  2015. BOOL
  2016. SetupInstallFileExW(
  2017. IN HINF InfHandle, OPTIONAL
  2018. IN PINFCONTEXT InfContext, OPTIONAL
  2019. IN PCWSTR SourceFile, OPTIONAL
  2020. IN PCWSTR SourcePathRoot, OPTIONAL
  2021. IN PCWSTR DestinationName, OPTIONAL
  2022. IN DWORD CopyStyle,
  2023. IN PSP_FILE_CALLBACK_W CopyMsgHandler, OPTIONAL
  2024. IN PVOID Context, OPTIONAL
  2025. OUT PBOOL FileWasInUse
  2026. )
  2027. {
  2028. UNREFERENCED_PARAMETER(InfHandle);
  2029. UNREFERENCED_PARAMETER(InfContext);
  2030. UNREFERENCED_PARAMETER(SourceFile);
  2031. UNREFERENCED_PARAMETER(SourcePathRoot);
  2032. UNREFERENCED_PARAMETER(DestinationName);
  2033. UNREFERENCED_PARAMETER(CopyStyle);
  2034. UNREFERENCED_PARAMETER(CopyMsgHandler);
  2035. UNREFERENCED_PARAMETER(Context);
  2036. UNREFERENCED_PARAMETER(FileWasInUse);
  2037. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  2038. return(FALSE);
  2039. }
  2040. #endif
  2041. BOOL
  2042. SetupInstallFileEx(
  2043. IN HINF InfHandle, OPTIONAL
  2044. IN PINFCONTEXT InfContext, OPTIONAL
  2045. IN PCTSTR SourceFile, OPTIONAL
  2046. IN PCTSTR SourcePathRoot, OPTIONAL
  2047. IN PCTSTR DestinationName, OPTIONAL
  2048. IN DWORD CopyStyle,
  2049. IN PSP_FILE_CALLBACK CopyMsgHandler, OPTIONAL
  2050. IN PVOID Context, OPTIONAL
  2051. OUT PBOOL FileWasInUse
  2052. )
  2053. /*++
  2054. Routine Description:
  2055. Same as SetupInstallFile().
  2056. Arguments:
  2057. Same as SetupInstallFile().
  2058. FileWasInUse - receives flag indicating whether the file was in use.
  2059. Return Value:
  2060. Same as SetupInstallFile().
  2061. --*/
  2062. {
  2063. BOOL b, DontCare;
  2064. PCTSTR sourceFile,sourcePathRoot,destinationName;
  2065. PCTSTR p;
  2066. DWORD rc;
  2067. //
  2068. // Capture args.
  2069. //
  2070. if(SourceFile) {
  2071. rc = CaptureStringArg(SourceFile,&p);
  2072. if(rc != NO_ERROR) {
  2073. SetLastError(rc);
  2074. return FALSE;
  2075. }
  2076. sourceFile = p;
  2077. } else {
  2078. sourceFile = NULL;
  2079. }
  2080. if(SourcePathRoot) {
  2081. rc = CaptureStringArg(SourcePathRoot,&p);
  2082. if(rc != NO_ERROR) {
  2083. if(sourceFile) {
  2084. MyFree(sourceFile);
  2085. }
  2086. SetLastError(rc);
  2087. return FALSE;
  2088. }
  2089. sourcePathRoot = p;
  2090. } else {
  2091. sourcePathRoot = NULL;
  2092. }
  2093. if(DestinationName) {
  2094. rc = CaptureStringArg(DestinationName,&p);
  2095. if(rc != NO_ERROR) {
  2096. if(sourceFile) {
  2097. MyFree(sourceFile);
  2098. }
  2099. if(sourcePathRoot) {
  2100. MyFree(sourcePathRoot);
  2101. }
  2102. SetLastError(rc);
  2103. return FALSE;
  2104. }
  2105. destinationName = p;
  2106. } else {
  2107. destinationName = NULL;
  2108. }
  2109. b = _SetupInstallFileEx(
  2110. NULL,
  2111. NULL,
  2112. InfHandle,
  2113. InfContext,
  2114. sourceFile,
  2115. sourcePathRoot,
  2116. destinationName,
  2117. CopyStyle,
  2118. CopyMsgHandler,
  2119. Context,
  2120. FileWasInUse,
  2121. TRUE,
  2122. &DontCare
  2123. );
  2124. //
  2125. // We GetLastError and then set it back again before returning, so that
  2126. // the memory frees we do below can't blow away the error code.
  2127. //
  2128. rc = b ? NO_ERROR : GetLastError();
  2129. if(sourceFile) {
  2130. MyFree(sourceFile);
  2131. }
  2132. if(sourcePathRoot) {
  2133. MyFree(sourcePathRoot);
  2134. }
  2135. if(destinationName) {
  2136. MyFree(destinationName);
  2137. }
  2138. SetLastError(rc);
  2139. return b;
  2140. }
  2141. #ifdef UNICODE
  2142. //
  2143. // ANSI version
  2144. //
  2145. BOOL
  2146. SetupInstallFileA(
  2147. IN HINF InfHandle, OPTIONAL
  2148. IN PINFCONTEXT InfContext, OPTIONAL
  2149. IN PCSTR SourceFile, OPTIONAL
  2150. IN PCSTR SourcePathRoot, OPTIONAL
  2151. IN PCSTR DestinationName, OPTIONAL
  2152. IN DWORD CopyStyle,
  2153. IN PSP_FILE_CALLBACK_A CopyMsgHandler, OPTIONAL
  2154. IN PVOID Context OPTIONAL
  2155. )
  2156. {
  2157. BOOL b;
  2158. BOOL InUse;
  2159. b = SetupInstallFileExA(
  2160. InfHandle,
  2161. InfContext,
  2162. SourceFile,
  2163. SourcePathRoot,
  2164. DestinationName,
  2165. CopyStyle,
  2166. CopyMsgHandler,
  2167. Context,
  2168. &InUse
  2169. );
  2170. return(b);
  2171. }
  2172. #else
  2173. //
  2174. // Unicode stub
  2175. //
  2176. BOOL
  2177. SetupInstallFileW(
  2178. IN HINF InfHandle, OPTIONAL
  2179. IN PINFCONTEXT InfContext, OPTIONAL
  2180. IN PCWSTR SourceFile, OPTIONAL
  2181. IN PCWSTR SourcePathRoot, OPTIONAL
  2182. IN PCWSTR DestinationName, OPTIONAL
  2183. IN DWORD CopyStyle,
  2184. IN PSP_FILE_CALLBACK_W CopyMsgHandler, OPTIONAL
  2185. IN PVOID Context OPTIONAL
  2186. )
  2187. {
  2188. UNREFERENCED_PARAMETER(InfHandle);
  2189. UNREFERENCED_PARAMETER(InfContext);
  2190. UNREFERENCED_PARAMETER(SourceFile);
  2191. UNREFERENCED_PARAMETER(SourcePathRoot);
  2192. UNREFERENCED_PARAMETER(DestinationName);
  2193. UNREFERENCED_PARAMETER(CopyStyle);
  2194. UNREFERENCED_PARAMETER(CopyMsgHandler);
  2195. UNREFERENCED_PARAMETER(Context);
  2196. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  2197. return(FALSE);
  2198. }
  2199. #endif
  2200. BOOL
  2201. SetupInstallFile(
  2202. IN HINF InfHandle, OPTIONAL
  2203. IN PINFCONTEXT InfContext, OPTIONAL
  2204. IN PCTSTR SourceFile, OPTIONAL
  2205. IN PCTSTR SourcePathRoot, OPTIONAL
  2206. IN PCTSTR DestinationName, OPTIONAL
  2207. IN DWORD CopyStyle,
  2208. IN PSP_FILE_CALLBACK CopyMsgHandler, OPTIONAL
  2209. IN PVOID Context OPTIONAL
  2210. )
  2211. /*++
  2212. Routine Description:
  2213. Note: no disk prompting is performed by this routine. The caller must
  2214. ensure that the source specified in SourcePathRoot or SourceFile
  2215. (see below) is accessible.
  2216. Arguments:
  2217. InfHandle - handle of inf file containing [SourceDisksNames]
  2218. and [SourceDisksFiles] sections. If InfContext is not specified
  2219. and CopyFlags includes SP_COPY_SOURCE_ABSOLUTE or
  2220. SP_COPY_SOURCEPATH_ABSOLUTE, then InfHandle is ignored.
  2221. InfContext - if specified, supplies context for a line in a copy file
  2222. section in an inf file. The routine looks this file up in the
  2223. [SourceDisksFiles] section of InfHandle to get file copy info.
  2224. If not specified, SourceFile must be. If this parameter is specified,
  2225. then InfHandle must also be specified.
  2226. SourceFile - if specified, supplies the file name (no path) of the file
  2227. to be copied. The file is looked up in [SourceDisksFiles].
  2228. Must be specified if InfContext is not; ignored if InfContext
  2229. is specified.
  2230. SourcePathRoot - Supplies the root path for the source (for example,
  2231. a:\ or f:\). Paths in [SourceDisksNames] are appended to this path.
  2232. Ignored if CopyStyle includes SP_COPY_SOURCE_ABSOLUTE.
  2233. DestinationName - if InfContext is specified, supplies the filename only
  2234. (no path) of the target file. Can be NULL to indicate that the
  2235. target file is to have the same name as the source file. If InfContext is
  2236. not specified, supplies the full target path and filename for the target
  2237. file.
  2238. CopyStyle - supplies flags that control the behavior of the copy operation.
  2239. SP_COPY_DELETESOURCE - Delete the source file upon successful copy.
  2240. The caller receives no notification if the delete fails.
  2241. SP_COPY_REPLACEONLY - Copy the file only if doing so would overwrite
  2242. a file at the destination path.
  2243. SP_COPY_NEWER - Examine each file being copied to see if its version resources
  2244. (or timestamps for non-image files) indicate that it it is not newer than
  2245. an existing copy on the target. If so, and a CopyMsgHandler is specified,
  2246. the caller is notified and may veto the copy. If CopyMsgHandler is not
  2247. specified, the file is not copied.
  2248. SP_COPY_NOOVERWRITE - Check whether the target file exists, and, if so,
  2249. notify the caller who may veto the copy. If no CopyMsgHandler is specified,
  2250. the file is not overwritten.
  2251. SP_COPY_NODECOMP - Do not decompress the file. When this option is given,
  2252. the target file is not given the uncompressed form of the source name
  2253. (if appropriate). For example, copying f:\mips\cmd.ex_ to \\foo\bar
  2254. will result a target file \\foo\bar\cmd.ex_. (If this flag wasn't specified
  2255. the file would be decompressed and the target would be called
  2256. \\foo\bar\cmd.exe). The filename part of the target file name
  2257. is stripped and replaced with the filename of the soruce. When this option
  2258. is given, SP_COPY_LANGUAGEAWARE and SP_COPY_NEWER are ignored.
  2259. SP_COPY_ALREADYDECOMP - assume file to be decompressed but may have
  2260. compressed source name. In this case, rename the file on copy and
  2261. check SP_COPY_LANGUAGEAWARE/SP_COPY_NEWER, but don't attempt to
  2262. decompress the file any further.
  2263. SP_COPY_LANGUAGEAWARE - Examine each file being copied to see if its language
  2264. differs from the language of any existing file already on the target.
  2265. If so, and a CopyMsgHandler is specified, the caller is notified and
  2266. may veto the copy. If CopyMsgHandler is not specified, the file is not copied.
  2267. SP_COPY_SOURCE_ABSOLUTE - SourceFile is a full source path.
  2268. Do not attempt to look it up in [SourceDisksNames].
  2269. SP_COPY_SOURCEPATH_ABSOLUTE - SourcePathRoot is the full path part of the
  2270. source file. Ignore the relative source specified in the [SourceDisksNames]
  2271. section of the inf file for the source media where the file is located.
  2272. Ignored if SP_COPY_SOURCE_ABSOLUTE is specified.
  2273. SP_COPY_FORCE_IN_USE - if the target exists, behave as if it is in use and
  2274. queue the file for copy on next reboot.
  2275. CopyMsgHandler - if specified, supplies a callback function to be notified of
  2276. various conditions that may arise during the file copy.
  2277. Context - supplies a caller-defined value to be passed as the first
  2278. parameter to CopyMsgHandler.
  2279. Return Value:
  2280. TRUE if a file was copied. FALSE if not. Use GetLastError for extended
  2281. error information. If GetLastError returns NO_ERROR, then the file copy was
  2282. aborted because (a) it wasn't needed or (b) a callback function returned
  2283. FALSE.
  2284. --*/
  2285. {
  2286. BOOL b;
  2287. BOOL InUse;
  2288. b = SetupInstallFileEx(
  2289. InfHandle,
  2290. InfContext,
  2291. SourceFile,
  2292. SourcePathRoot,
  2293. DestinationName,
  2294. CopyStyle,
  2295. CopyMsgHandler,
  2296. Context,
  2297. &InUse
  2298. );
  2299. return(b);
  2300. }