Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2808 lines
99 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
  447. for the source file. This will be set to FALSE if some other failure
  448. caused us to abort prior to attempting the signature verification.
  449. This is used by the queue commit routines to determine whether or not
  450. the queue callback routine should be given a chance to handle a copy
  451. failure (skip, retry, etc.). Digital signature verification failures
  452. are 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 && !_tcsicmp(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. 0,
  900. &Problem,
  901. Buffer1,
  902. NULL,
  903. NULL,
  904. NULL,
  905. NULL
  906. );
  907. if(rc != NO_ERROR) {
  908. //
  909. // Store the error away from the above validation failure. We'll
  910. // refrain from setting the "SignatureVerifyFailed" flag until we
  911. // figure out whether the file is Authenticode-signed.
  912. //
  913. SigVerifRc = rc;
  914. //
  915. // If policy is forced to Block, then we don't even try to
  916. // validate the file using Authenticode policy. This is done by
  917. // Windows File Protection, for example, which doesn't respect
  918. // Authenticode signatures, and we mustn't either.
  919. //
  920. if(Queue->Flags & FQF_QUEUE_FORCE_BLOCK_POLICY) {
  921. *SignatureVerifyFailed = TRUE;
  922. goto clean2;
  923. }
  924. if(IsFileProtected(FullTargetFilename, lc, NULL)) {
  925. //
  926. // If the file is protected, then Authenticode can't save us!
  927. //
  928. *SignatureVerifyFailed = TRUE;
  929. if(QueueNode && QueueNode->CatalogInfo) {
  930. //
  931. // We never allow Authenticode-signed files to replace
  932. // system-protected files. In fact, when we detect such a
  933. // trick, we abort the whole installation!
  934. //
  935. if(QueueNode->CatalogInfo->Flags & CATINFO_FLAG_AUTHENTICODE_SIGNED) {
  936. WriteLogEntry(lc,
  937. SETUP_LOG_ERROR,
  938. MSG_LOG_AUTHENTICODE_SIGNATURE_BLOCKED_FOR_SFC_SIS,
  939. NULL,
  940. FullTargetFilename,
  941. FullSourceFilename
  942. );
  943. goto clean2;
  944. }
  945. }
  946. if(Problem != SetupapiVerifyDriverBlocked) {
  947. //
  948. // If this is a device installation and the policy is
  949. // "Ignore", then crank it up to "Warn" if the file is
  950. // under SFP's protection. This will allow the user to
  951. // update a driver that ships in our box for which no WHQL
  952. // certification program exists.
  953. //
  954. if((Queue->Flags & FQF_DEVICE_INSTALL) &&
  955. ((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  956. == DRIVERSIGN_NONE)) {
  957. //
  958. // (We don't care if we blow away the Authenticode bit,
  959. // since that's not valid for this queue, now that
  960. // we've discovered it's trying to replace system
  961. // protected files.)
  962. //
  963. Queue->DriverSigningPolicy = DRIVERSIGN_WARNING;
  964. //
  965. // Log the fact that policy was elevated.
  966. //
  967. WriteLogEntry(lc,
  968. SETUP_LOG_ERROR,
  969. MSG_LOG_POLICY_ELEVATED_FOR_SFC,
  970. NULL
  971. );
  972. }
  973. }
  974. } else {
  975. //
  976. // If the file may be validated by an Authenticode-signed
  977. // catalog, then check for that now. If that validation fails,
  978. // then we simply want to bail, because that indicates
  979. // tampering. At this point, we've already confirmed that the
  980. // signer should be trusted, so there's no need for UI (i.e.,
  981. // we don't need to call _HandleFailedVerification).
  982. //
  983. if((rc != ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH) &&
  984. QueueNode &&
  985. QueueNode->CatalogInfo &&
  986. (QueueNode->CatalogInfo->Flags & CATINFO_FLAG_AUTHENTICODE_SIGNED)) {
  987. rc = VerifySourceFile(lc,
  988. Queue,
  989. QueueNode,
  990. pSetupGetFileTitle(FullTargetFilename),
  991. FullSourceFilename,
  992. NULL,
  993. ValidationPlatform,
  994. VERIFY_FILE_USE_AUTHENTICODE_CATALOG,
  995. &Problem,
  996. Buffer1,
  997. NULL,
  998. NULL,
  999. NULL,
  1000. NULL
  1001. );
  1002. if((rc == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  1003. (rc == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  1004. SigVerifRc = rc = NO_ERROR;
  1005. } else {
  1006. *SignatureVerifyFailed = TRUE;
  1007. goto clean2;
  1008. }
  1009. } else {
  1010. //
  1011. // File isn't associated with an Authenticode catalog, so
  1012. // we can finally say with certainty we had a signature
  1013. // verification failure.
  1014. //
  1015. *SignatureVerifyFailed = TRUE;
  1016. }
  1017. }
  1018. //
  1019. // Unless we were saved by an Authenticode signature, we need to
  1020. // handle the verification failure...
  1021. //
  1022. if(*SignatureVerifyFailed) {
  1023. if(!_HandleFailedVerification(
  1024. Queue->hWndDriverSigningUi,
  1025. Problem,
  1026. (Problem == SetupapiVerifyDriverBlocked)
  1027. ? FullSourceFilename : Buffer1,
  1028. ((Queue->DeviceDescStringId == -1)
  1029. ? NULL
  1030. : pStringTableStringFromId(Queue->StringTable, Queue->DeviceDescStringId)),
  1031. Queue->DriverSigningPolicy,
  1032. (Queue->Flags & FQF_DIGSIG_ERRORS_NOUI),
  1033. rc,
  1034. lc,
  1035. (((Queue->Flags & FQF_ABORT_IF_UNSIGNED) &&
  1036. (Problem != SetupapiVerifyDriverBlocked))
  1037. ? NULL : &ExemptCopyFlags),
  1038. (((Queue->Flags & FQF_ABORT_IF_UNSIGNED) &&
  1039. (Problem != SetupapiVerifyDriverBlocked))
  1040. ? NULL : FullTargetFilename),
  1041. NULL))
  1042. {
  1043. //
  1044. // User elected not to install the unsigned file (or was
  1045. // blocked by policy from doing so).
  1046. //
  1047. goto clean2;
  1048. }
  1049. //
  1050. // The user wants to proceed with the unsigned installation (or
  1051. // policy is ignore, so they weren't even informed). If the
  1052. // caller wants a chance to set a system restore point prior to
  1053. // doing any unsigned installations, then we abort now with a
  1054. // "special" error code that tells them what to do...
  1055. //
  1056. if(Queue->Flags & FQF_ABORT_IF_UNSIGNED) {
  1057. //
  1058. // We don't want the user to see the driver signing UI
  1059. // again when the queue is re-committed...
  1060. //
  1061. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  1062. != DRIVERSIGN_NONE) {
  1063. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  1064. }
  1065. rc = ERROR_SET_SYSTEM_RESTORE_POINT;
  1066. goto clean2;
  1067. }
  1068. //
  1069. // Set a flag in the queue that indicates the user has been informed
  1070. // of a signature problem with this queue, and has elected to go
  1071. // ahead and install anyway. Don't set this flag if the queue's
  1072. // policy is "Ignore", on the chance that the policy might be
  1073. // altered later, and we'd want the user to get informed on any
  1074. // subsequent errors.
  1075. //
  1076. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  1077. != DRIVERSIGN_NONE) {
  1078. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  1079. }
  1080. if(QueueNode) {
  1081. QueueNode->InternalFlags |= ExemptCopyFlags;
  1082. }
  1083. //
  1084. // Reset rc to NO_ERROR and carry on.
  1085. //
  1086. rc = NO_ERROR;
  1087. }
  1088. }
  1089. if(rc == NO_ERROR) {
  1090. rc = CreateTargetAsLinkToMaster(
  1091. Queue,
  1092. FullSourceFilename,
  1093. FullTargetFilename,
  1094. CopyMsgHandler,
  1095. Context,
  1096. IsMsgHandlerNativeCharWidth
  1097. );
  1098. }
  1099. if(rc == NO_ERROR) {
  1100. //
  1101. // ISSUE JamieHun-2001/03/20 Is this best thing to do for SIS link?
  1102. //
  1103. Queue->Flags |= FQF_FILES_MODIFIED;
  1104. //
  1105. // We're done!
  1106. //
  1107. Ok = TRUE;
  1108. goto clean2;
  1109. }
  1110. }
  1111. //
  1112. // We will copy the file to a temporary location. This makes version checks
  1113. // possible in all cases (even when the source is compressed) and simplifies
  1114. // the logic below. Start by forming the name of the temporary file.
  1115. //
  1116. lstrcpyn(Buffer1, FullTargetFilename, MAX_PATH);
  1117. *((PTSTR)pSetupGetFileTitle(Buffer1)) = TEXT('\0');
  1118. if(!GetTempFileName(Buffer1, TEXT("SETP"), 0, Buffer2)) {
  1119. rc = ERROR_INVALID_TARGET;
  1120. goto clean2;
  1121. }
  1122. TemporaryTargetFile = DuplicateString(Buffer2);
  1123. if(!TemporaryTargetFile) {
  1124. rc = ERROR_NOT_ENOUGH_MEMORY;
  1125. goto clean2;
  1126. }
  1127. //
  1128. // Log the file copy - only if we log something else unless at Info level
  1129. //
  1130. ReleaseLogInfoSlot(lc,slot_fileop);
  1131. slot_fileop = AllocLogInfoSlotOrLevel(lc,SETUP_LOG_INFO,FALSE); // for conditional display of extra logging info
  1132. WriteLogEntry(
  1133. lc,
  1134. slot_fileop,
  1135. MSG_LOG_COPYING_FILE_VIA,
  1136. NULL,
  1137. FullSourceFilename,
  1138. FullTargetFilename,
  1139. TemporaryTargetFile);
  1140. //
  1141. // Perform the actual file copy. This creates the temporary target file.
  1142. // Move is allowed as an optimization if we're deleting the source file.
  1143. // The call we make below will not use move if the file is compressed
  1144. // and we are supposed to decompress it, so the right thing will happen
  1145. // in all cases.
  1146. //
  1147. // There are 2 potential issues:
  1148. //
  1149. // 1) When we call the callback function below for a version check,
  1150. // the source file won't exist any more if the file was moved. Oh well.
  1151. //
  1152. // 2) If the MoveFileEx below fails, the source will have still been 'deleted'.
  1153. // This is different from the non-move case, where the source remains
  1154. // intact unless this function is successful.
  1155. //
  1156. // Otherwise this is a non-issue since any compressed file will be decompressed
  1157. // by this call, so version gathering, etc, will all work properly.
  1158. //
  1159. rc = pSetupDecompressOrCopyFile(
  1160. FullSourceFilename,
  1161. TemporaryTargetFile,
  1162. &CompressionType,
  1163. ((CopyStyle & SP_COPY_DELETESOURCE) != 0),
  1164. &Moved
  1165. );
  1166. if(rc != NO_ERROR) {
  1167. goto clean3;
  1168. }
  1169. //
  1170. // Do digital signature check on source file, now that it exists in its
  1171. // final form under a temp name. Note that for signed files, we ignore
  1172. // version checking since they're an inherently unreliable mechanism for
  1173. // comparing files provided from two different vendors (who use different
  1174. // versioning schemes, etc.)
  1175. //
  1176. // To see why we ignore version numbers, consider the decision tree we'd
  1177. // use if we were paying attention to version numbers as well as digital
  1178. // signatures. In the discussion that follows, NewFile is the (signed)
  1179. // file we're going to copy, and OldFile is the file that will be
  1180. // overwritten if the copy goes through...
  1181. //
  1182. // if NewFile is versioned {
  1183. // if OldFile is signed {
  1184. // if OldFile is versioned {
  1185. // //
  1186. // // Both NewFile and OldFile are signed and versioned.
  1187. // //
  1188. // if OldFile is a newer version {
  1189. // //
  1190. // // This is the controversial case. Since these two incarnations could've come from different vendors
  1191. // // with different versioning schemes, we really can't use versioning as a very accurate method of determining
  1192. // // which file is 'better'. So there are two options:
  1193. // // 1. Leave OldFile alone, and if the package being installed can't work with OldFile, then the user must 'undo'
  1194. // // the installation, and then call their vendor to gripe--there'll be no way for them to get the new package to
  1195. // // work, even though WHQL certified it.
  1196. // // 2. Overwrite OldFile. Since we're then guaranteeing that every file signed as part of the package will be
  1197. // // present, then we can have a much higher degree of certainty that our WHQL certification will hold true
  1198. // // for every user's machine. If replacing OldFile breaks someone else (e.g., the previously-installed package
  1199. // // that uses it, then the user can 'undo' the installation. This scenario is better because even though the old
  1200. // // and new packages can't be used simultaneously, at least one or the other can be made to work
  1201. // // independently.
  1202. // //
  1203. // overwrite OldFile
  1204. // } else { // NewFile is a newer version
  1205. // overwrite OldFile
  1206. // }
  1207. // } else { // OldFile isn't versioned--NewFile wins
  1208. // overwrite OldFile
  1209. // }
  1210. // } else { // OldFile isn't signed--we don't care what its version is
  1211. // overwrite OldFile
  1212. // }
  1213. // } else { // NewFile isn't versioned
  1214. // if OldFile is versioned {
  1215. // if OldFile is signed {
  1216. // //
  1217. // // (See discussion above where both OldFile and NewFile are signed and versioned, and OldFile is newer. Note
  1218. // // that something funny is going on if we've been asked to replace a versionable file with an unversionable one!)
  1219. // //
  1220. // overwrite OldFile
  1221. // } else { // OldFile isn't signed
  1222. // overwrite OldFile
  1223. // }
  1224. // } else { // OldFile isn't versioned either
  1225. // overwrite OldFile
  1226. // }
  1227. // }
  1228. //
  1229. //
  1230. // Check to see if the source file is signed. (Note--we may have already
  1231. // checked this previously in determining whether an SIS link could be
  1232. // created. If we failed to verify the file's digital signature then,
  1233. // there's no use in re-verifying here.)
  1234. //
  1235. if(*SignatureVerifyFailed) {
  1236. //
  1237. // We saved the signature verification failure error when we previously
  1238. // attempted to verify this file. Restore that code to rc now, because
  1239. // the code below relies on the value of rc.
  1240. //
  1241. MYASSERT(SigVerifRc != NO_ERROR);
  1242. rc = SigVerifRc;
  1243. } else {
  1244. if(Queue) {
  1245. ValidationPlatform = (Queue->Flags & FQF_USE_ALT_PLATFORM)
  1246. ? &(Queue->AltPlatformInfo)
  1247. : Queue->ValidationPlatform;
  1248. } else {
  1249. //
  1250. // Since we aren't dealing with a queue, we need to retrieve the
  1251. // appropriate validation platform information, if any, for our INF.
  1252. //
  1253. DoingDeviceInstall = IsInfForDeviceInstall(
  1254. lc,
  1255. NULL,
  1256. LoadedInf,
  1257. &DeviceDesc,
  1258. &ValidationPlatform,
  1259. &DriverSigningPolicy,
  1260. NULL,
  1261. TRUE // use non-driver signing policy unless it's a WHQL class
  1262. );
  1263. }
  1264. rc = VerifySourceFile(lc,
  1265. Queue,
  1266. QueueNode,
  1267. pSetupGetFileTitle(FullTargetFilename),
  1268. TemporaryTargetFile,
  1269. FullSourceFilename,
  1270. ValidationPlatform,
  1271. 0,
  1272. &Problem,
  1273. Buffer1,
  1274. NULL,
  1275. NULL,
  1276. NULL,
  1277. NULL
  1278. );
  1279. if(rc != NO_ERROR) {
  1280. if(Queue) {
  1281. //
  1282. // If policy is forced to Block, then we don't even try to
  1283. // validate the file using Authenticode policy. This is done by
  1284. // Windows File Protection, for example, which doesn't respect
  1285. // Authenticode signatures, and we mustn't either.
  1286. //
  1287. if(Queue->Flags & FQF_QUEUE_FORCE_BLOCK_POLICY) {
  1288. *SignatureVerifyFailed = TRUE;
  1289. goto clean4;
  1290. }
  1291. if(IsFileProtected(FullTargetFilename, lc, NULL)) {
  1292. //
  1293. // If the file is protected, then Authenticode can't save
  1294. // us!
  1295. //
  1296. *SignatureVerifyFailed = TRUE;
  1297. if(QueueNode && QueueNode->CatalogInfo) {
  1298. //
  1299. // We never allow Authenticode-signed files to replace
  1300. // system-protected files. In fact, when we detect
  1301. // such a trick, we abort the whole installation!
  1302. //
  1303. if(QueueNode->CatalogInfo->Flags & CATINFO_FLAG_AUTHENTICODE_SIGNED) {
  1304. WriteLogEntry(lc,
  1305. SETUP_LOG_ERROR,
  1306. MSG_LOG_AUTHENTICODE_SIGNATURE_BLOCKED_FOR_SFC,
  1307. NULL,
  1308. FullTargetFilename
  1309. );
  1310. goto clean4;
  1311. }
  1312. }
  1313. } else {
  1314. //
  1315. // If the file may be validated by an Authenticode-signed
  1316. // catalog, then check for that now. If that validation
  1317. // fails, then we simply want to bail, because that
  1318. // indicates tampering. At this point, we've already
  1319. // confirmed that the signer should be trusted, so there's
  1320. // no need for UI (i.e., we don't need to call
  1321. // _HandleFailedVerification).
  1322. //
  1323. if((rc != ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH) &&
  1324. QueueNode &&
  1325. QueueNode->CatalogInfo &&
  1326. (QueueNode->CatalogInfo->Flags & CATINFO_FLAG_AUTHENTICODE_SIGNED)) {
  1327. rc = VerifySourceFile(lc,
  1328. Queue,
  1329. QueueNode,
  1330. pSetupGetFileTitle(FullTargetFilename),
  1331. TemporaryTargetFile,
  1332. FullSourceFilename,
  1333. ValidationPlatform,
  1334. VERIFY_FILE_USE_AUTHENTICODE_CATALOG,
  1335. &Problem,
  1336. Buffer1,
  1337. NULL,
  1338. NULL,
  1339. NULL,
  1340. NULL
  1341. );
  1342. if((rc == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  1343. (rc == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  1344. rc = NO_ERROR;
  1345. } else {
  1346. *SignatureVerifyFailed = TRUE;
  1347. goto clean4;
  1348. }
  1349. } else {
  1350. //
  1351. // File isn't associated with an Authenticode catalog,
  1352. // so we can finally say with certainty we had a
  1353. // signature verification failure.
  1354. //
  1355. *SignatureVerifyFailed = TRUE;
  1356. }
  1357. }
  1358. } else {
  1359. //
  1360. // We don't have a queue, so we know there's no possibility of
  1361. // validating via an Authenticode catalog.
  1362. //
  1363. *SignatureVerifyFailed = TRUE;
  1364. }
  1365. }
  1366. }
  1367. //
  1368. // Don't muck with the value of rc below unless you're setting it
  1369. // immediately before jumping to clean4. The return value from
  1370. // VerifySourceFile needs to be preserved until we finish with the
  1371. // _HandleFailedVerification stuff.
  1372. //
  1373. //
  1374. // If we are going to perform version checks, fetch the version data
  1375. // of the source (which is now the temporary target file).
  1376. //
  1377. NotifyFlags = 0;
  1378. if(ExistingFile) {
  1379. param = 0;
  1380. //
  1381. // If we're not supposed to overwrite existing files,
  1382. // then the overwrite check fails.
  1383. //
  1384. if(CopyStyle & SP_COPY_NOOVERWRITE) {
  1385. NotifyFlags |= SPFILENOTIFY_TARGETEXISTS;
  1386. }
  1387. //
  1388. // Even if the source file has a verified digital signature, we still
  1389. // want to retrieve version information for the source and target. We
  1390. // do this so that we can detect when we've overwritten a newer-
  1391. // versioned file with an older-versioned one. If we discover that
  1392. // this is the case, then we generate an exception log entry that will
  1393. // help PSS troubleshoot any problems that result.
  1394. //
  1395. if(!GetVersionInfoFromImage(TemporaryTargetFile, &SourceVersion, &SourceLanguage)) {
  1396. SourceVersion = 0;
  1397. SourceLanguage = 0;
  1398. }
  1399. //
  1400. // If we're not supposed to overwrite files in a different language
  1401. // and the languages differ, then the language check fails.
  1402. // If either file doesn't have language data, then don't do a language
  1403. // check.
  1404. //
  1405. //
  1406. // Special case:
  1407. //
  1408. // If
  1409. // a) the source version is greater than the target version
  1410. // b) the source doesn't have a lang id
  1411. // c) the target does have a lang id
  1412. // Then
  1413. // we will do a language check, and we will consider this language check
  1414. // as passed since we are replacing an older language specific file with
  1415. // a language neutral file, which is an OK thing.
  1416. //
  1417. //
  1418. if(CopyStyle & SP_COPY_LANGUAGEAWARE) {
  1419. if ( SourceLanguage
  1420. && TargetLanguage
  1421. && (SourceLanguage != TargetLanguage) ) {
  1422. NotifyFlags |= SPFILENOTIFY_LANGMISMATCH;
  1423. param = (UINT)MAKELONG(SourceLanguage, TargetLanguage);
  1424. } else if ( !SourceLanguage
  1425. && TargetLanguage
  1426. && (TargetVersion >= SourceVersion) ) {
  1427. NotifyFlags |= SPFILENOTIFY_LANGMISMATCH;
  1428. param = (UINT)MAKELONG(SourceLanguage, TargetLanguage);
  1429. }
  1430. }
  1431. //
  1432. // If we're not supposed to overwrite newer versions and the target is
  1433. // newer than the source, then the version check fails. If either file
  1434. // doesn't have version info, fall back to timestamp comparison.
  1435. //
  1436. // If the files are the same version/timestamp, assume that either
  1437. // replacing the existing one is a benevolent operation, or that
  1438. // we are upgrading an existing file whose version info is unimportant.
  1439. // In this case we just go ahead and copy the file (unless the
  1440. // SP_COPY_NEWER_ONLY flag is set).
  1441. //
  1442. // Note that the version checks below are made without regard to presence
  1443. // or absence of digital signatures on either the source or target files.
  1444. // That will be handled later. We want to see what would've happened
  1445. // without driver signing, so we can generate a PSS exception log when
  1446. // something weird happens.
  1447. //
  1448. if(SourceVersion || TargetVersion) {
  1449. b = (CopyStyle & SP_COPY_NEWER_ONLY)
  1450. ? (TargetVersion >= SourceVersion)
  1451. : (TargetVersion > SourceVersion);
  1452. } else {
  1453. //
  1454. // Assume the target file is older. Doing timestamp-based checking
  1455. // is simply too unreliable.
  1456. //
  1457. b = FALSE;
  1458. }
  1459. //
  1460. // At this point, if b is TRUE then the target file has a later (newer)
  1461. // version than the sourcefile. If we've been asked to pay attention
  1462. // to that, then set the NotifyFlags to indicate this problem.
  1463. // Note that this may get reset later if the source file is signed. We
  1464. // still wanted to get this information so we could put it in our PSS
  1465. // logfile.
  1466. //
  1467. if(b &&
  1468. (CopyStyle & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))) {
  1469. NotifyFlags |= SPFILENOTIFY_TARGETNEWER;
  1470. }
  1471. }
  1472. if(NotifyFlags & SPFILENOTIFY_TARGETNEWER) {
  1473. if(!*SignatureVerifyFailed) {
  1474. //
  1475. // Source file is signed, but the target file is newer. We know
  1476. // that we still want to replace the existing targetfile with the
  1477. // sourcefile, regardless of version numbers. However, we need to
  1478. // make note of that in our PSS logfile.
  1479. //
  1480. NotifyFlags &= ~SPFILENOTIFY_TARGETNEWER;
  1481. //
  1482. // Check to see if the target file is signed, in order to include
  1483. // this information in our PSS logfile.
  1484. //
  1485. ExistingTargetFileWasSigned =
  1486. (NO_ERROR == _VerifyFile(lc,
  1487. (Queue
  1488. ? &(Queue->VerifyContext)
  1489. : NULL),
  1490. NULL,
  1491. NULL,
  1492. 0,
  1493. pSetupGetFileTitle(FullTargetFilename),
  1494. ExistingFile,
  1495. NULL,
  1496. NULL,
  1497. FALSE,
  1498. ValidationPlatform,
  1499. (VERIFY_FILE_USE_OEM_CATALOGS
  1500. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  1501. NULL,
  1502. NULL,
  1503. NULL,
  1504. NULL,
  1505. NULL));
  1506. //
  1507. // SPLOG -- report that newer target was overwritten by older (signed)
  1508. // source, whether target was signed, both files' versions, etc.
  1509. // Also probably want to throw in the fact that the SP_COPY_FORCE_NEWER
  1510. // flag was ignored, if it's set.
  1511. //
  1512. pGetVersionText(SourceVersionText,SourceVersion);
  1513. pGetVersionText(TargetVersionText,TargetVersion);
  1514. WriteLogEntry(
  1515. lc,
  1516. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1517. MSG_LOG_NEWER_FILE_OVERWRITTEN,
  1518. NULL,
  1519. FullTargetFilename,
  1520. SourceVersionText,
  1521. TargetVersionText);
  1522. if (CopyStyle & SP_COPY_FORCE_NEWER) {
  1523. WriteLogEntry(
  1524. lc,
  1525. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1526. MSG_LOG_FLAG_FORCE_NEWER_IGNORED,
  1527. NULL);
  1528. }
  1529. WriteLogEntry(
  1530. lc,
  1531. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1532. (ExistingTargetFileWasSigned ?
  1533. MSG_LOG_TARGET_WAS_SIGNED :
  1534. MSG_LOG_TARGET_WAS_NOT_SIGNED),
  1535. NULL);
  1536. //
  1537. // flush the log buffer
  1538. //
  1539. WriteLogEntry(
  1540. lc,
  1541. SETUP_LOG_WARNING,
  1542. 0,
  1543. TEXT("\n"));
  1544. } else {
  1545. //
  1546. // Source file isn't signed, so we'll let the old behavior apply.
  1547. // If version dialogs are allowed, for example, the user will be
  1548. // prompted that they're attempting to overwrite a newer file with
  1549. // an older one. If they say "go ahead and copy over the older
  1550. // version", _then_ they'll get a prompt about the file not having
  1551. // a valid signature.
  1552. //
  1553. // Check special case where a flag is set indicating that we should
  1554. // just silently not copy the newer file.
  1555. //
  1556. if(CopyStyle & SP_COPY_FORCE_NEWER) {
  1557. //
  1558. // Target is newer; don't copy the file.
  1559. //
  1560. rc = NO_ERROR;
  1561. goto clean4;
  1562. }
  1563. }
  1564. }
  1565. //
  1566. // If we have any reason to notify the caller via the callback,
  1567. // do that here. If there is no callback, then don't copy the file,
  1568. // because one of the conditions has not been met.
  1569. //
  1570. if((NotifyFlags & SPFILENOTIFY_LANGMISMATCH) && ! *SignatureVerifyFailed) {
  1571. //
  1572. // if the source was signed, we will ignore a language mismatch
  1573. // as this is a package deal
  1574. // NTRAID9#498046-2001/11/20-JamieHun handle LANGMISMATCH better
  1575. //
  1576. NotifyFlags &=~SPFILENOTIFY_LANGMISMATCH;
  1577. WriteLogEntry(
  1578. lc,
  1579. SETUP_LOG_WARNING,
  1580. MSG_LOG_LANGMISMATCH_IGNORED,
  1581. NULL,
  1582. FullTargetFilename,
  1583. SourceLanguage,
  1584. TargetLanguage);
  1585. }
  1586. if(NotifyFlags) {
  1587. FilePaths.Source = FullSourceFilename;
  1588. FilePaths.Target = FullTargetFilename;
  1589. FilePaths.Win32Error = NO_ERROR;
  1590. if(!CopyMsgHandler
  1591. || !pSetupCallMsgHandler(
  1592. lc,
  1593. CopyMsgHandler,
  1594. IsMsgHandlerNativeCharWidth,
  1595. Context,
  1596. NotifyFlags,
  1597. (UINT_PTR)&FilePaths,
  1598. param))
  1599. {
  1600. if(ExistingFile) {
  1601. //
  1602. // Check to see if the target file is signed, in order to
  1603. // include this information in our PSS logfile.
  1604. //
  1605. ExistingTargetFileWasSigned =
  1606. (NO_ERROR == _VerifyFile(lc,
  1607. (Queue
  1608. ? &(Queue->VerifyContext)
  1609. : NULL),
  1610. NULL,
  1611. NULL,
  1612. 0,
  1613. pSetupGetFileTitle(FullTargetFilename),
  1614. ExistingFile,
  1615. NULL,
  1616. NULL,
  1617. FALSE,
  1618. ValidationPlatform,
  1619. (VERIFY_FILE_USE_OEM_CATALOGS
  1620. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  1621. NULL,
  1622. NULL,
  1623. NULL,
  1624. NULL,
  1625. NULL));
  1626. }
  1627. //
  1628. // SPLOG -- error that occurred, info on whether source and target
  1629. // files were signed, what their versions were, etc.
  1630. //
  1631. pGetVersionText(SourceVersionText,SourceVersion);
  1632. pGetVersionText(TargetVersionText,TargetVersion);
  1633. WriteLogEntry(
  1634. lc,
  1635. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1636. MSG_LOG_FILE_NOT_OVERWRITTEN,
  1637. NULL,
  1638. SourceVersionText,
  1639. TargetVersionText);
  1640. if (NotifyFlags & SPFILENOTIFY_TARGETEXISTS) {
  1641. WriteLogEntry(
  1642. lc,
  1643. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1644. MSG_LOG_NOTIFY_TARGETEXISTS,
  1645. NULL);
  1646. }
  1647. if (NotifyFlags & SPFILENOTIFY_LANGMISMATCH) {
  1648. WriteLogEntry(
  1649. lc,
  1650. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1651. MSG_LOG_NOTIFY_LANGMISMATCH,
  1652. NULL);
  1653. }
  1654. if (NotifyFlags & SPFILENOTIFY_TARGETNEWER) {
  1655. WriteLogEntry(
  1656. lc,
  1657. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1658. MSG_LOG_NOTIFY_TARGETNEWER,
  1659. NULL);
  1660. }
  1661. WriteLogEntry(
  1662. lc,
  1663. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1664. (ExistingTargetFileWasSigned ?
  1665. MSG_LOG_TARGET_WAS_SIGNED :
  1666. MSG_LOG_TARGET_WAS_NOT_SIGNED),
  1667. NULL);
  1668. WriteLogEntry(
  1669. lc,
  1670. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  1671. (*SignatureVerifyFailed ?
  1672. MSG_LOG_SOURCE_WAS_NOT_SIGNED :
  1673. MSG_LOG_SOURCE_WAS_SIGNED),
  1674. NULL);
  1675. WriteLogError(
  1676. lc,
  1677. SETUP_LOG_WARNING,
  1678. rc);
  1679. rc = NO_ERROR;
  1680. goto clean4;
  1681. }
  1682. }
  1683. //
  1684. // OK, now that all non-codesigning stuff is done, tell the user about
  1685. // any digital signature problems we found with the source file.
  1686. //
  1687. // NOTE: If SigVerifRc is set to something other than NO_ERROR, then we
  1688. // know that the _HandleFailedVerification routine has already been
  1689. // called, thus we don't want to call it again or otherwise the user may
  1690. // get multiple prompts about a bad signature for the same file.
  1691. //
  1692. if(*SignatureVerifyFailed) {
  1693. if(SigVerifRc == NO_ERROR) {
  1694. MYASSERT(ExemptCopyFlags == 0);
  1695. //
  1696. // Save away the verification error in SigVerifRc, so we can use
  1697. // this later to determine whether we're dealing with an unsigned
  1698. // file.
  1699. //
  1700. MYASSERT(rc != NO_ERROR);
  1701. SigVerifRc = rc;
  1702. //
  1703. // If we're using a file queue, then retrieve information from the
  1704. // queue regarding policy, whether it's a device install (and if
  1705. // so, what description to use), etc. There's no need to do this
  1706. // in the non-queue case, because we already did this previously.
  1707. //
  1708. if(Queue) {
  1709. if(Queue->DeviceDescStringId != -1) {
  1710. DeviceDesc = pStringTableStringFromId(
  1711. Queue->StringTable,
  1712. Queue->DeviceDescStringId
  1713. );
  1714. MYASSERT(DeviceDesc);
  1715. } else {
  1716. DeviceDesc = NULL;
  1717. }
  1718. DoingDeviceInstall = Queue->Flags & FQF_DEVICE_INSTALL;
  1719. DriverSigningPolicy = Queue->DriverSigningPolicy;
  1720. }
  1721. if(Problem != SetupapiVerifyDriverBlocked) {
  1722. //
  1723. // If this is a device installation and the policy is "Ignore",
  1724. // then crank it up to "Warn" if the file is under SFP's
  1725. // protection. This will allow the user to update a driver
  1726. // that ships in our box for which no WHQL certification
  1727. // program exists.
  1728. //
  1729. if(DoingDeviceInstall &&
  1730. ((DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE) == DRIVERSIGN_NONE) &&
  1731. IsFileProtected(FullTargetFilename, lc, NULL)) {
  1732. //
  1733. // (We don't care if we blow away the Authenticode bit,
  1734. // since that's no longer an option now that we've caught
  1735. // an attempted replacement of a system-protected file!)
  1736. //
  1737. DriverSigningPolicy = DRIVERSIGN_WARNING;
  1738. //
  1739. // If we have a queue, update the queue's policy as well.
  1740. //
  1741. if(Queue) {
  1742. Queue->DriverSigningPolicy = DRIVERSIGN_WARNING;
  1743. }
  1744. //
  1745. // Log the fact that policy was elevated.
  1746. //
  1747. WriteLogEntry(lc,
  1748. SETUP_LOG_ERROR,
  1749. MSG_LOG_POLICY_ELEVATED_FOR_SFC,
  1750. NULL
  1751. );
  1752. }
  1753. }
  1754. if(!_HandleFailedVerification(
  1755. (Queue ? Queue->hWndDriverSigningUi : NULL),
  1756. Problem,
  1757. (Problem == SetupapiVerifyDriverBlocked)
  1758. ? FullSourceFilename : Buffer1,
  1759. DeviceDesc,
  1760. DriverSigningPolicy,
  1761. (Queue ? (Queue->Flags & FQF_DIGSIG_ERRORS_NOUI) : FALSE),
  1762. rc,
  1763. lc,
  1764. (((Queue && (Queue->Flags & FQF_ABORT_IF_UNSIGNED)) &&
  1765. (Problem != SetupapiVerifyDriverBlocked))
  1766. ? NULL : &ExemptCopyFlags),
  1767. (((Queue && (Queue->Flags & FQF_ABORT_IF_UNSIGNED)) &&
  1768. (Problem != SetupapiVerifyDriverBlocked))
  1769. ? NULL : FullTargetFilename),
  1770. NULL))
  1771. {
  1772. //
  1773. // User elected not to install the unsigned file (or was
  1774. // blocked by policy from doing so).
  1775. //
  1776. goto clean4;
  1777. }
  1778. }
  1779. if(Queue) {
  1780. //
  1781. // If the caller wants a chance to set a system restore point prior
  1782. // to doing any unsigned installations, then we abort now with a
  1783. // "special" error code that tells them what to do...
  1784. //
  1785. if(Queue->Flags & FQF_ABORT_IF_UNSIGNED) {
  1786. //
  1787. // We don't want the user to see the driver signing UI again
  1788. // when the queue is re-committed...
  1789. //
  1790. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  1791. != DRIVERSIGN_NONE) {
  1792. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  1793. }
  1794. rc = ERROR_SET_SYSTEM_RESTORE_POINT;
  1795. goto clean4;
  1796. }
  1797. //
  1798. // Set a flag in the queue that indicates the user has been
  1799. // informed of a signature problem with this queue, and has elected
  1800. // to go ahead and install anyway. Don't set this flag if the
  1801. // queue's policy is "Ignore", on the chance that the policy might
  1802. // be altered later, and we'd want the user to get informed on any
  1803. // subsequent errors.
  1804. //
  1805. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  1806. != DRIVERSIGN_NONE) {
  1807. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  1808. }
  1809. if (QueueNode) {
  1810. QueueNode->InternalFlags |= ExemptCopyFlags;
  1811. }
  1812. }
  1813. //
  1814. // Reset rc to NO_ERROR and carry on.
  1815. //
  1816. rc = NO_ERROR;
  1817. }
  1818. //
  1819. // Move the target file into its final location.
  1820. //
  1821. SetFileAttributes(FullTargetFilename, FILE_ATTRIBUTE_NORMAL);
  1822. if(Queue && ((Queue->Flags & FQF_FILES_MODIFIED)==0)) {
  1823. //
  1824. // so far we haven't flagged that any files are modified
  1825. //
  1826. if(CompareFile) {
  1827. //
  1828. // we have an "original" file
  1829. //
  1830. if(pCompareFilesExact(TemporaryTargetFile,CompareFile)) {
  1831. //
  1832. // new file of this name is same as original file of same name
  1833. //
  1834. if(CompareSameFilename) {
  1835. //
  1836. // original is already in place
  1837. // don't need to do a delayed-rename
  1838. //
  1839. FileUnchanged = TRUE;
  1840. }
  1841. } else {
  1842. //
  1843. // file appears to have been modified
  1844. //
  1845. Queue->Flags |= FQF_FILES_MODIFIED;
  1846. }
  1847. } else {
  1848. //
  1849. // be safe, copying over nothing = modified
  1850. //
  1851. Queue->Flags |= FQF_FILES_MODIFIED;
  1852. }
  1853. }
  1854. //
  1855. // If the target exists and the force-in-use flag is set, then don't try to
  1856. // move the file into place now -- automatically drop into in-use behavior.
  1857. //
  1858. // Want to use MoveFileEx but it didn't exist in Win95. Ugh.
  1859. //
  1860. if(!(ExistingFile && (CopyStyle & SP_COPY_FORCE_IN_USE))
  1861. && (b = DoMove(TemporaryTargetFile, FullTargetFilename))) {
  1862. //
  1863. // Place security information on the target file if necessary.
  1864. // Ignore errors. The theory here is that the file is already on
  1865. // the target, so if this fails the worst case is that the file is
  1866. // not secure. But the user can still use the system.
  1867. //
  1868. if(SecurityInfo) {
  1869. DWORD err = StampFileSecurity(FullTargetFilename, SecurityInfo);
  1870. if(err != NO_ERROR) {
  1871. WriteLogEntry(lc,
  1872. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  1873. MSG_LOG_FILE_SECURITY_FAILED,
  1874. NULL,
  1875. FullTargetFilename
  1876. );
  1877. WriteLogError(lc,SETUP_LOG_ERROR,err);
  1878. } else {
  1879. WriteLogEntry(lc,
  1880. SETUP_LOG_VERBOSE,
  1881. MSG_LOG_SET_FILE_SECURITY,
  1882. NULL,
  1883. FullTargetFilename
  1884. );
  1885. }
  1886. }
  1887. } else {
  1888. //
  1889. // If this fails, assume the file is in use and mark it for copy on next
  1890. // boot (except in the case where we're copying a boot file, in which
  1891. // case this is a catastrophic failure).
  1892. //
  1893. if(ExistingFile != FullTargetFilename) {
  1894. WriteLogEntry(lc,
  1895. SETUP_LOG_ERROR,
  1896. MSG_LOG_REPLACE_BOOT_FILE_FAILED,
  1897. NULL,
  1898. FullTargetFilename
  1899. );
  1900. b = FALSE;
  1901. SetLastError(ERROR_ACCESS_DENIED);
  1902. } else if (((CopyStyle & SP_COPY_FORCE_IN_USE) == 0) &&
  1903. (FileUnchanged || pCompareFilesExact(TemporaryTargetFile,FullTargetFilename))) {
  1904. //
  1905. // It turns out that new file and old file are exactly the same
  1906. // we can optimize out the delayed move and delete the temporary file
  1907. //
  1908. WriteLogEntry(lc,
  1909. SETUP_LOG_INFO,
  1910. MSG_LOG_COPY_IDENTICAL,
  1911. NULL,
  1912. FullTargetFilename,
  1913. TemporaryTargetFile
  1914. );
  1915. if(SecurityInfo) {
  1916. //
  1917. // we still need to adjust security on it though
  1918. //
  1919. DWORD err = StampFileSecurity(FullTargetFilename, SecurityInfo);
  1920. if(err != NO_ERROR) {
  1921. WriteLogEntry(lc,
  1922. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  1923. MSG_LOG_FILE_SECURITY_FAILED,
  1924. NULL,
  1925. FullTargetFilename
  1926. );
  1927. WriteLogError(lc,SETUP_LOG_ERROR,err);
  1928. } else {
  1929. WriteLogEntry(lc,
  1930. SETUP_LOG_VERBOSE,
  1931. MSG_LOG_SET_FILE_SECURITY,
  1932. NULL,
  1933. FullTargetFilename
  1934. );
  1935. }
  1936. }
  1937. SetFileAttributes(TemporaryTargetFile, FILE_ATTRIBUTE_NORMAL);
  1938. DeleteFile(TemporaryTargetFile);
  1939. b = TRUE;
  1940. } else {
  1941. b = TRUE;
  1942. try {
  1943. *FileWasInUse = TRUE;
  1944. } except(EXCEPTION_EXECUTE_HANDLER) {
  1945. b = FALSE;
  1946. }
  1947. if(b) {
  1948. //
  1949. // If we're trying to do a delayed move to replace a protected
  1950. // system file (using an unsigned one), and we've not been
  1951. // granted an exception to do so, then we should skip the
  1952. // operation altogether (and make a log entry about it)
  1953. //
  1954. if((SigVerifRc != NO_ERROR) &&
  1955. ((ExemptCopyFlags & (IQF_TARGET_PROTECTED | IQF_ALLOW_UNSIGNED)) == IQF_TARGET_PROTECTED)) {
  1956. WriteLogEntry(lc,
  1957. SETUP_LOG_ERROR,
  1958. MSG_LOG_DELAYED_MOVE_SKIPPED_FOR_SFC,
  1959. NULL,
  1960. FullTargetFilename
  1961. );
  1962. //
  1963. // Delete the source file.
  1964. //
  1965. SetFileAttributes(TemporaryTargetFile, FILE_ATTRIBUTE_NORMAL);
  1966. DeleteFile(TemporaryTargetFile);
  1967. } else {
  1968. BOOL TargetIsProtected = IsFileProtected(FullTargetFilename, lc, NULL);
  1969. if(Queue == NULL) {
  1970. b = DelayedMove(
  1971. TemporaryTargetFile,
  1972. FullTargetFilename
  1973. );
  1974. if(b && TargetIsProtected) {
  1975. //
  1976. // we have to explicitly tell the session manager it's ok
  1977. // to replace the changed files on reboot.
  1978. //
  1979. // in the case that we're using a queue, we post the
  1980. // delayed move and set this flag only if all the delayed
  1981. // move operations succeed
  1982. //
  1983. pSetupProtectedRenamesFlag(TRUE);
  1984. }
  1985. } else {
  1986. b = PostDelayedMove(
  1987. Queue,
  1988. TemporaryTargetFile,
  1989. FullTargetFilename,
  1990. QueueNode->SecurityDesc,
  1991. TargetIsProtected
  1992. );
  1993. }
  1994. if(b) {
  1995. //
  1996. // Couldn't set security info on the actual target, so at least
  1997. // set it on the temp file that will become the target.
  1998. //
  1999. if(SecurityInfo) {
  2000. StampFileSecurity(TemporaryTargetFile,SecurityInfo);
  2001. }
  2002. if (lc) {
  2003. WriteLogEntry(lc,
  2004. SETUP_LOG_WARNING,
  2005. MSG_LOG_COPY_DELAYED,
  2006. NULL,
  2007. FullTargetFilename,
  2008. TemporaryTargetFile
  2009. );
  2010. }
  2011. //
  2012. // Tell the callback that we queued this file for delayed copy.
  2013. //
  2014. if(CopyMsgHandler) {
  2015. FilePaths.Source = TemporaryTargetFile;
  2016. FilePaths.Target = FullTargetFilename;
  2017. FilePaths.Win32Error = NO_ERROR;
  2018. FilePaths.Flags = FILEOP_COPY;
  2019. pSetupCallMsgHandler(
  2020. lc,
  2021. CopyMsgHandler,
  2022. IsMsgHandlerNativeCharWidth,
  2023. Context,
  2024. SPFILENOTIFY_FILEOPDELAYED,
  2025. (UINT_PTR)&FilePaths,
  2026. 0
  2027. );
  2028. }
  2029. }
  2030. }
  2031. } else {
  2032. //
  2033. // FileWasInUse pointer went bad
  2034. //
  2035. SetLastError(ERROR_INVALID_PARAMETER);
  2036. }
  2037. }
  2038. }
  2039. if(!b) {
  2040. rc = GetLastError();
  2041. goto clean4;
  2042. }
  2043. //
  2044. // We're done. Delete the source if necessary and return.
  2045. //
  2046. if((CopyStyle & SP_COPY_DELETESOURCE) && !Moved) {
  2047. DeleteFile(FullSourceFilename);
  2048. }
  2049. rc = NO_ERROR;
  2050. Ok = TRUE;
  2051. goto clean3;
  2052. clean4:
  2053. //
  2054. // Remove temporary target file.
  2055. // In case pSetupDecompressOrCopyFile MoveFile'd the source,
  2056. // we really need to try to move it back, so the source file isn't
  2057. // blown away when this routine fails.
  2058. //
  2059. if(Moved) {
  2060. MoveFile(TemporaryTargetFile,FullSourceFilename);
  2061. } else {
  2062. SetFileAttributes(TemporaryTargetFile,FILE_ATTRIBUTE_NORMAL);
  2063. DeleteFile(TemporaryTargetFile);
  2064. }
  2065. clean3:
  2066. MyFree(TemporaryTargetFile);
  2067. //
  2068. // If we didn't have a file queue, then we may have allocated a device
  2069. // description and validation platform structure when we called
  2070. // IsInfForDeviceInstall. Clean those up now.
  2071. //
  2072. if(!Queue) {
  2073. if(DeviceDesc) {
  2074. MyFree(DeviceDesc);
  2075. }
  2076. if(ValidationPlatform) {
  2077. MyFree(ValidationPlatform);
  2078. }
  2079. }
  2080. clean2:
  2081. if (BackupFileName) {
  2082. MyFree(BackupFileName);
  2083. }
  2084. MyFree(FullTargetFilename);
  2085. clean1:
  2086. MyFree(FullSourceFilename);
  2087. clean0:
  2088. if(SecurityInfo) {
  2089. MyFree(SecurityInfo);
  2090. }
  2091. //
  2092. // if there was an error of some sort, log it
  2093. //
  2094. if(rc != NO_ERROR) {
  2095. //
  2096. // maybe we ought to embelish this a bit.
  2097. //
  2098. WriteLogEntry(
  2099. lc,
  2100. SETUP_LOG_ERROR,
  2101. rc,
  2102. NULL);
  2103. }
  2104. if(slot_fileop) {
  2105. ReleaseLogInfoSlot(lc, slot_fileop);
  2106. }
  2107. if(LoadedInf) {
  2108. UnlockInf(LoadedInf);
  2109. }
  2110. SetLastError(rc);
  2111. return(Ok);
  2112. }
  2113. #ifdef UNICODE
  2114. //
  2115. // ANSI version
  2116. //
  2117. BOOL
  2118. SetupInstallFileExA(
  2119. IN HINF InfHandle, OPTIONAL
  2120. IN PINFCONTEXT InfContext, OPTIONAL
  2121. IN PCSTR SourceFile, OPTIONAL
  2122. IN PCSTR SourcePathRoot, OPTIONAL
  2123. IN PCSTR DestinationName, OPTIONAL
  2124. IN DWORD CopyStyle,
  2125. IN PSP_FILE_CALLBACK_A CopyMsgHandler, OPTIONAL
  2126. IN PVOID Context, OPTIONAL
  2127. OUT PBOOL FileWasInUse
  2128. )
  2129. {
  2130. PCWSTR sourceFile,sourcePathRoot,destinationName;
  2131. BOOL b, DontCare;
  2132. DWORD rc;
  2133. sourceFile = NULL;
  2134. sourcePathRoot = NULL;
  2135. destinationName = NULL;
  2136. rc = NO_ERROR;
  2137. if(SourceFile) {
  2138. rc = pSetupCaptureAndConvertAnsiArg(SourceFile,&sourceFile);
  2139. }
  2140. if((rc == NO_ERROR) && SourcePathRoot) {
  2141. rc = pSetupCaptureAndConvertAnsiArg(SourcePathRoot,&sourcePathRoot);
  2142. }
  2143. if((rc == NO_ERROR) && DestinationName) {
  2144. rc = pSetupCaptureAndConvertAnsiArg(DestinationName,&destinationName);
  2145. }
  2146. if(rc == NO_ERROR) {
  2147. b = _SetupInstallFileEx(
  2148. NULL,
  2149. NULL,
  2150. InfHandle,
  2151. InfContext,
  2152. sourceFile,
  2153. sourcePathRoot,
  2154. destinationName,
  2155. CopyStyle,
  2156. CopyMsgHandler,
  2157. Context,
  2158. FileWasInUse,
  2159. FALSE,
  2160. &DontCare
  2161. );
  2162. rc = b ? NO_ERROR : GetLastError();
  2163. } else {
  2164. b = FALSE;
  2165. }
  2166. if(sourceFile) {
  2167. MyFree(sourceFile);
  2168. }
  2169. if(sourcePathRoot) {
  2170. MyFree(sourcePathRoot);
  2171. }
  2172. if(destinationName) {
  2173. MyFree(destinationName);
  2174. }
  2175. SetLastError(rc);
  2176. return b;
  2177. }
  2178. #else
  2179. //
  2180. // Unicode stub
  2181. //
  2182. BOOL
  2183. SetupInstallFileExW(
  2184. IN HINF InfHandle, OPTIONAL
  2185. IN PINFCONTEXT InfContext, OPTIONAL
  2186. IN PCWSTR SourceFile, OPTIONAL
  2187. IN PCWSTR SourcePathRoot, OPTIONAL
  2188. IN PCWSTR DestinationName, OPTIONAL
  2189. IN DWORD CopyStyle,
  2190. IN PSP_FILE_CALLBACK_W CopyMsgHandler, OPTIONAL
  2191. IN PVOID Context, OPTIONAL
  2192. OUT PBOOL FileWasInUse
  2193. )
  2194. {
  2195. UNREFERENCED_PARAMETER(InfHandle);
  2196. UNREFERENCED_PARAMETER(InfContext);
  2197. UNREFERENCED_PARAMETER(SourceFile);
  2198. UNREFERENCED_PARAMETER(SourcePathRoot);
  2199. UNREFERENCED_PARAMETER(DestinationName);
  2200. UNREFERENCED_PARAMETER(CopyStyle);
  2201. UNREFERENCED_PARAMETER(CopyMsgHandler);
  2202. UNREFERENCED_PARAMETER(Context);
  2203. UNREFERENCED_PARAMETER(FileWasInUse);
  2204. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  2205. return(FALSE);
  2206. }
  2207. #endif
  2208. BOOL
  2209. SetupInstallFileEx(
  2210. IN HINF InfHandle, OPTIONAL
  2211. IN PINFCONTEXT InfContext, OPTIONAL
  2212. IN PCTSTR SourceFile, OPTIONAL
  2213. IN PCTSTR SourcePathRoot, OPTIONAL
  2214. IN PCTSTR DestinationName, OPTIONAL
  2215. IN DWORD CopyStyle,
  2216. IN PSP_FILE_CALLBACK CopyMsgHandler, OPTIONAL
  2217. IN PVOID Context, OPTIONAL
  2218. OUT PBOOL FileWasInUse
  2219. )
  2220. /*++
  2221. Routine Description:
  2222. Same as SetupInstallFile().
  2223. Arguments:
  2224. Same as SetupInstallFile().
  2225. FileWasInUse - receives flag indicating whether the file was in use.
  2226. Return Value:
  2227. Same as SetupInstallFile().
  2228. --*/
  2229. {
  2230. BOOL b, DontCare;
  2231. PCTSTR sourceFile,sourcePathRoot,destinationName;
  2232. PCTSTR p;
  2233. DWORD rc;
  2234. //
  2235. // Capture args.
  2236. //
  2237. if(SourceFile) {
  2238. rc = CaptureStringArg(SourceFile,&p);
  2239. if(rc != NO_ERROR) {
  2240. SetLastError(rc);
  2241. return FALSE;
  2242. }
  2243. sourceFile = p;
  2244. } else {
  2245. sourceFile = NULL;
  2246. }
  2247. if(SourcePathRoot) {
  2248. rc = CaptureStringArg(SourcePathRoot,&p);
  2249. if(rc != NO_ERROR) {
  2250. if(sourceFile) {
  2251. MyFree(sourceFile);
  2252. }
  2253. SetLastError(rc);
  2254. return FALSE;
  2255. }
  2256. sourcePathRoot = p;
  2257. } else {
  2258. sourcePathRoot = NULL;
  2259. }
  2260. if(DestinationName) {
  2261. rc = CaptureStringArg(DestinationName,&p);
  2262. if(rc != NO_ERROR) {
  2263. if(sourceFile) {
  2264. MyFree(sourceFile);
  2265. }
  2266. if(sourcePathRoot) {
  2267. MyFree(sourcePathRoot);
  2268. }
  2269. SetLastError(rc);
  2270. return FALSE;
  2271. }
  2272. destinationName = p;
  2273. } else {
  2274. destinationName = NULL;
  2275. }
  2276. b = _SetupInstallFileEx(
  2277. NULL,
  2278. NULL,
  2279. InfHandle,
  2280. InfContext,
  2281. sourceFile,
  2282. sourcePathRoot,
  2283. destinationName,
  2284. CopyStyle,
  2285. CopyMsgHandler,
  2286. Context,
  2287. FileWasInUse,
  2288. TRUE,
  2289. &DontCare
  2290. );
  2291. //
  2292. // We GetLastError and then set it back again before returning, so that
  2293. // the memory frees we do below can't blow away the error code.
  2294. //
  2295. rc = b ? NO_ERROR : GetLastError();
  2296. if(sourceFile) {
  2297. MyFree(sourceFile);
  2298. }
  2299. if(sourcePathRoot) {
  2300. MyFree(sourcePathRoot);
  2301. }
  2302. if(destinationName) {
  2303. MyFree(destinationName);
  2304. }
  2305. SetLastError(rc);
  2306. return b;
  2307. }
  2308. #ifdef UNICODE
  2309. //
  2310. // ANSI version
  2311. //
  2312. BOOL
  2313. SetupInstallFileA(
  2314. IN HINF InfHandle, OPTIONAL
  2315. IN PINFCONTEXT InfContext, OPTIONAL
  2316. IN PCSTR SourceFile, OPTIONAL
  2317. IN PCSTR SourcePathRoot, OPTIONAL
  2318. IN PCSTR DestinationName, OPTIONAL
  2319. IN DWORD CopyStyle,
  2320. IN PSP_FILE_CALLBACK_A CopyMsgHandler, OPTIONAL
  2321. IN PVOID Context OPTIONAL
  2322. )
  2323. {
  2324. BOOL b;
  2325. BOOL InUse;
  2326. b = SetupInstallFileExA(
  2327. InfHandle,
  2328. InfContext,
  2329. SourceFile,
  2330. SourcePathRoot,
  2331. DestinationName,
  2332. CopyStyle,
  2333. CopyMsgHandler,
  2334. Context,
  2335. &InUse
  2336. );
  2337. return(b);
  2338. }
  2339. #else
  2340. //
  2341. // Unicode stub
  2342. //
  2343. BOOL
  2344. SetupInstallFileW(
  2345. IN HINF InfHandle, OPTIONAL
  2346. IN PINFCONTEXT InfContext, OPTIONAL
  2347. IN PCWSTR SourceFile, OPTIONAL
  2348. IN PCWSTR SourcePathRoot, OPTIONAL
  2349. IN PCWSTR DestinationName, OPTIONAL
  2350. IN DWORD CopyStyle,
  2351. IN PSP_FILE_CALLBACK_W CopyMsgHandler, OPTIONAL
  2352. IN PVOID Context OPTIONAL
  2353. )
  2354. {
  2355. UNREFERENCED_PARAMETER(InfHandle);
  2356. UNREFERENCED_PARAMETER(InfContext);
  2357. UNREFERENCED_PARAMETER(SourceFile);
  2358. UNREFERENCED_PARAMETER(SourcePathRoot);
  2359. UNREFERENCED_PARAMETER(DestinationName);
  2360. UNREFERENCED_PARAMETER(CopyStyle);
  2361. UNREFERENCED_PARAMETER(CopyMsgHandler);
  2362. UNREFERENCED_PARAMETER(Context);
  2363. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  2364. return(FALSE);
  2365. }
  2366. #endif
  2367. BOOL
  2368. SetupInstallFile(
  2369. IN HINF InfHandle, OPTIONAL
  2370. IN PINFCONTEXT InfContext, OPTIONAL
  2371. IN PCTSTR SourceFile, OPTIONAL
  2372. IN PCTSTR SourcePathRoot, OPTIONAL
  2373. IN PCTSTR DestinationName, OPTIONAL
  2374. IN DWORD CopyStyle,
  2375. IN PSP_FILE_CALLBACK CopyMsgHandler, OPTIONAL
  2376. IN PVOID Context OPTIONAL
  2377. )
  2378. /*++
  2379. Routine Description:
  2380. Note: no disk prompting is performed by this routine. The caller must
  2381. ensure that the source specified in SourcePathRoot or SourceFile
  2382. (see below) is accessible.
  2383. Arguments:
  2384. InfHandle - handle of inf file containing [SourceDisksNames]
  2385. and [SourceDisksFiles] sections. If InfContext is not specified
  2386. and CopyFlags includes SP_COPY_SOURCE_ABSOLUTE or
  2387. SP_COPY_SOURCEPATH_ABSOLUTE, then InfHandle is ignored.
  2388. InfContext - if specified, supplies context for a line in a copy file
  2389. section in an inf file. The routine looks this file up in the
  2390. [SourceDisksFiles] section of InfHandle to get file copy info.
  2391. If not specified, SourceFile must be. If this parameter is specified,
  2392. then InfHandle must also be specified.
  2393. SourceFile - if specified, supplies the file name (no path) of the file
  2394. to be copied. The file is looked up in [SourceDisksFiles].
  2395. Must be specified if InfContext is not; ignored if InfContext
  2396. is specified.
  2397. SourcePathRoot - Supplies the root path for the source (for example,
  2398. a:\ or f:\). Paths in [SourceDisksNames] are appended to this path.
  2399. Ignored if CopyStyle includes SP_COPY_SOURCE_ABSOLUTE.
  2400. DestinationName - if InfContext is specified, supplies the filename only
  2401. (no path) of the target file. Can be NULL to indicate that the
  2402. target file is to have the same name as the source file. If InfContext is
  2403. not specified, supplies the full target path and filename for the target
  2404. file.
  2405. CopyStyle - supplies flags that control the behavior of the copy operation.
  2406. SP_COPY_DELETESOURCE - Delete the source file upon successful copy.
  2407. The caller receives no notification if the delete fails.
  2408. SP_COPY_REPLACEONLY - Copy the file only if doing so would overwrite
  2409. a file at the destination path.
  2410. SP_COPY_NEWER - Examine each file being copied to see if its version resources
  2411. (or timestamps for non-image files) indicate that it it is not newer than
  2412. an existing copy on the target. If so, and a CopyMsgHandler is specified,
  2413. the caller is notified and may veto the copy. If CopyMsgHandler is not
  2414. specified, the file is not copied.
  2415. SP_COPY_NOOVERWRITE - Check whether the target file exists, and, if so,
  2416. notify the caller who may veto the copy. If no CopyMsgHandler is specified,
  2417. the file is not overwritten.
  2418. SP_COPY_NODECOMP - Do not decompress the file. When this option is given,
  2419. the target file is not given the uncompressed form of the source name
  2420. (if appropriate). For example, copying f:\mips\cmd.ex_ to \\foo\bar
  2421. will result a target file \\foo\bar\cmd.ex_. (If this flag wasn't specified
  2422. the file would be decompressed and the target would be called
  2423. \\foo\bar\cmd.exe). The filename part of the target file name
  2424. is stripped and replaced with the filename of the soruce. When this option
  2425. is given, SP_COPY_LANGUAGEAWARE and SP_COPY_NEWER are ignored.
  2426. SP_COPY_ALREADYDECOMP - assume file to be decompressed but may have
  2427. compressed source name. In this case, rename the file on copy and
  2428. check SP_COPY_LANGUAGEAWARE/SP_COPY_NEWER, but don't attempt to
  2429. decompress the file any further.
  2430. SP_COPY_LANGUAGEAWARE - Examine each file being copied to see if its language
  2431. differs from the language of any existing file already on the target.
  2432. If so, and a CopyMsgHandler is specified, the caller is notified and
  2433. may veto the copy. If CopyMsgHandler is not specified, the file is not copied.
  2434. SP_COPY_SOURCE_ABSOLUTE - SourceFile is a full source path.
  2435. Do not attempt to look it up in [SourceDisksNames].
  2436. SP_COPY_SOURCEPATH_ABSOLUTE - SourcePathRoot is the full path part of the
  2437. source file. Ignore the relative source specified in the [SourceDisksNames]
  2438. section of the inf file for the source media where the file is located.
  2439. Ignored if SP_COPY_SOURCE_ABSOLUTE is specified.
  2440. SP_COPY_FORCE_IN_USE - if the target exists, behave as if it is in use and
  2441. queue the file for copy on next reboot.
  2442. CopyMsgHandler - if specified, supplies a callback function to be notified of
  2443. various conditions that may arise during the file copy.
  2444. Context - supplies a caller-defined value to be passed as the first
  2445. parameter to CopyMsgHandler.
  2446. Return Value:
  2447. TRUE if a file was copied. FALSE if not. Use GetLastError for extended
  2448. error information. If GetLastError returns NO_ERROR, then the file copy was
  2449. aborted because (a) it wasn't needed or (b) a callback function returned
  2450. FALSE.
  2451. --*/
  2452. {
  2453. BOOL b;
  2454. BOOL InUse;
  2455. b = SetupInstallFileEx(
  2456. InfHandle,
  2457. InfContext,
  2458. SourceFile,
  2459. SourcePathRoot,
  2460. DestinationName,
  2461. CopyStyle,
  2462. CopyMsgHandler,
  2463. Context,
  2464. &InUse
  2465. );
  2466. return(b);
  2467. }