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.

1251 lines
30 KiB

  1. #include "spprecmp.h"
  2. #pragma hdrstop
  3. #include <diamondd.h>
  4. #define SETUP_FDI_POOL_TAG 0x44465053 // 'SPFD'
  5. #ifdef DeleteFile
  6. #undef DeleteFile // we mean "DeleteFile", not "DeleteFileA"
  7. #endif
  8. HFDI FdiContext;
  9. ERF FdiError;
  10. //
  11. // Gloabls used when copying a file.
  12. // Setup opens the source and target files and maps the source.
  13. // To avoid opening and closing the source and target multiple times
  14. // and to maintain a mapped file inplementation, we'll fake the i/o calls.
  15. // These globals remember state about the source (cabinet) and target
  16. // files currently in use.
  17. //
  18. PUCHAR SpdSourceAddress;
  19. ULONG SpdSourceFileSize;
  20. typedef struct {
  21. PEXPAND_CALLBACK Callback;
  22. PVOID CallbackContext;
  23. LPWSTR DestinationPath;
  24. } EXPAND_CAB_CONTEXT;
  25. typedef struct _DRIVER_CAB_CONTEXT {
  26. PCWSTR FileName;
  27. PCSTR FileNameA;
  28. USHORT FileDate;
  29. USHORT FileTime;
  30. } DRIVER_CAB_CONTEXT, *PDRIVER_CAB_CONTEXT;
  31. DRIVER_CAB_CONTEXT DriverContext;
  32. typedef struct _MY_FILE_STATE {
  33. ULONG Signature;
  34. union {
  35. LONG FileOffset;
  36. HANDLE Handle;
  37. } u;
  38. } MY_FILE_STATE, *PMY_FILE_STATE;
  39. #define SOURCE_FILE_SIGNATURE 0x45f3ec83
  40. #define TARGET_FILE_SIGNATURE 0x46f3ec83
  41. MY_FILE_STATE CurrentTargetFile;
  42. INT_PTR
  43. DIAMONDAPI
  44. SpdNotifyFunction(
  45. IN FDINOTIFICATIONTYPE Operation,
  46. IN PFDINOTIFICATION Perameters
  47. );
  48. INT_PTR
  49. DIAMONDAPI
  50. SpdNotifyFunctionCabinet(
  51. IN FDINOTIFICATIONTYPE Operation,
  52. IN PFDINOTIFICATION Parameters
  53. );
  54. INT_PTR
  55. DIAMONDAPI
  56. SpdNotifyFunctionDriverCab(
  57. IN FDINOTIFICATIONTYPE Operation,
  58. IN PFDINOTIFICATION Perameters
  59. );
  60. INT_PTR
  61. DIAMONDAPI
  62. SpdFdiOpen(
  63. IN PSTR FileName,
  64. IN int oflag,
  65. IN int pmode
  66. );
  67. int
  68. DIAMONDAPI
  69. SpdFdiClose(
  70. IN INT_PTR Handle
  71. );
  72. VOID
  73. pSpdInitGlobals(
  74. IN PVOID SourceBaseAddress,
  75. IN ULONG SourceFileSize
  76. )
  77. {
  78. SpdSourceAddress = SourceBaseAddress;
  79. SpdSourceFileSize = SourceFileSize;
  80. }
  81. BOOLEAN
  82. SpdIsCabinet(
  83. IN PVOID SourceBaseAddress,
  84. IN ULONG SourceFileSize,
  85. OUT PBOOLEAN ContainsMultipleFiles
  86. )
  87. {
  88. FDICABINETINFO CabinetInfo;
  89. INT_PTR h;
  90. BOOLEAN b;
  91. *ContainsMultipleFiles = FALSE;
  92. ASSERT(FdiContext);
  93. if(!FdiContext) {
  94. return(FALSE);
  95. }
  96. //
  97. // Save away globals for later use.
  98. //
  99. pSpdInitGlobals(SourceBaseAddress,SourceFileSize);
  100. //
  101. // 'Open' the file so we can pass a handle that will work
  102. // with SpdFdiRead and SpdFdiWrite.
  103. //
  104. h = SpdFdiOpen("",0,0);
  105. if(h == -1) {
  106. return(FALSE);
  107. }
  108. //
  109. // We don't trust diamond to be robust.
  110. //
  111. memset(&CabinetInfo, 0, sizeof(CabinetInfo));
  112. try {
  113. b = FDIIsCabinet(FdiContext,h,&CabinetInfo) ? TRUE : FALSE;
  114. } except(EXCEPTION_EXECUTE_HANDLER) {
  115. b = FALSE;
  116. }
  117. //
  118. // If spanned or more than one file inside, report it as multiple
  119. //
  120. if (b) {
  121. if ((CabinetInfo.cFolders > 1) || (CabinetInfo.cFiles > 1)) {
  122. *ContainsMultipleFiles = TRUE;
  123. }
  124. }
  125. //
  126. // 'Close' the file.
  127. //
  128. SpdFdiClose(h);
  129. return(b);
  130. }
  131. BOOLEAN
  132. SpdIsCompressed(
  133. IN PVOID SourceBaseAddress,
  134. IN ULONG SourceFileSize
  135. )
  136. {
  137. INT_PTR h;
  138. BOOLEAN b;
  139. BOOLEAN bMultiple;
  140. b = SpdIsCabinet(SourceBaseAddress,SourceFileSize,&bMultiple);
  141. //
  142. // Compressed files with more than one contained file s/b treated as
  143. // an uncompressed file and copied as is. We're not prepared to uncompress
  144. // multiple files from one file.
  145. //
  146. if (bMultiple) {
  147. b = FALSE;
  148. }
  149. return(b);
  150. }
  151. NTSTATUS
  152. SpdDecompressFile(
  153. IN PVOID SourceBaseAddress,
  154. IN ULONG SourceFileSize,
  155. IN HANDLE DestinationHandle
  156. )
  157. {
  158. BOOL b;
  159. ASSERT(FdiContext);
  160. //
  161. // Save away globals for later use.
  162. //
  163. pSpdInitGlobals(SourceBaseAddress,SourceFileSize);
  164. CurrentTargetFile.Signature = TARGET_FILE_SIGNATURE;
  165. CurrentTargetFile.u.Handle = DestinationHandle;
  166. //
  167. // Get the copy going. Note that we pass empty cabinet filenames
  168. // because we've already opened the files.
  169. //
  170. b = FDICopy(FdiContext,"","",0,SpdNotifyFunction,NULL,NULL);
  171. return(b ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
  172. }
  173. NTSTATUS
  174. SpdDecompressCabinet(
  175. IN PVOID SourceBaseAddress,
  176. IN ULONG SourceFileSize,
  177. IN PWSTR DestinationPath,
  178. IN PEXPAND_CALLBACK Callback,
  179. IN PVOID CallbackContext
  180. )
  181. {
  182. BOOL b;
  183. EXPAND_CAB_CONTEXT NotifyContext;
  184. ASSERT(FdiContext);
  185. //
  186. // Save away globals for later use.
  187. //
  188. pSpdInitGlobals(SourceBaseAddress,SourceFileSize);
  189. CurrentTargetFile.Signature = TARGET_FILE_SIGNATURE;
  190. CurrentTargetFile.u.Handle = INVALID_HANDLE_VALUE;
  191. //
  192. // Tunnel expand context info into SpdNotifyFunctionCabinet
  193. //
  194. NotifyContext.Callback = Callback;
  195. NotifyContext.CallbackContext = CallbackContext;
  196. NotifyContext.DestinationPath = DestinationPath;
  197. //
  198. // Get the copy going. Note that we pass empty cabinet filenames
  199. // because we've already opened the files.
  200. //
  201. b = FDICopy(FdiContext,"","",0,SpdNotifyFunctionCabinet,NULL,&NotifyContext);
  202. if ( CurrentTargetFile.u.Handle != INVALID_HANDLE_VALUE ) {
  203. //
  204. // FDI had some error, so we need to close & destroy the target
  205. // file-in-progress. Note that FDI calls it's FDIClose callback
  206. // but in our implementation, that has no effect on the target
  207. // file.
  208. //
  209. FILE_DISPOSITION_INFORMATION FileDispositionDetails;
  210. IO_STATUS_BLOCK IoStatusBlock;
  211. FileDispositionDetails.DeleteFile = TRUE;
  212. ZwSetInformationFile( CurrentTargetFile.u.Handle,
  213. &IoStatusBlock,
  214. &FileDispositionDetails,
  215. sizeof(FileDispositionDetails),
  216. FileDispositionInformation );
  217. ZwClose( CurrentTargetFile.u.Handle );
  218. b = FALSE; // make sure we report failure
  219. }
  220. return(b ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
  221. }
  222. NTSTATUS
  223. SpdDecompressFileFromDriverCab(
  224. IN PWSTR SourceFileName,
  225. IN PVOID SourceBaseAddress,
  226. IN ULONG SourceFileSize,
  227. IN HANDLE DestinationHandle,
  228. OUT PUSHORT pDate,
  229. OUT PUSHORT pTime
  230. )
  231. {
  232. BOOL b;
  233. ASSERT(FdiContext);
  234. ASSERT(DriverContext.FileName == NULL);
  235. ASSERT(DriverContext.FileNameA == NULL);
  236. //
  237. // Save away globals for later use.
  238. //
  239. pSpdInitGlobals(SourceBaseAddress,SourceFileSize);
  240. CurrentTargetFile.Signature = TARGET_FILE_SIGNATURE;
  241. CurrentTargetFile.u.Handle = DestinationHandle;
  242. DriverContext.FileName = SpDupStringW(SourceFileName);
  243. if (!DriverContext.FileName) {
  244. return(STATUS_NO_MEMORY);
  245. }
  246. DriverContext.FileNameA = SpToOem((PWSTR)DriverContext.FileName);
  247. //
  248. // Get the copy going. Note that we pass empty cabinet filenames
  249. // because we've already opened the files.
  250. //
  251. b = FDICopy(FdiContext,"","",0,SpdNotifyFunctionDriverCab,NULL,NULL);
  252. ASSERT(DriverContext.FileName != NULL);
  253. SpMemFree( (PWSTR)DriverContext.FileName );
  254. DriverContext.FileName = NULL;
  255. if (DriverContext.FileNameA) {
  256. SpMemFree( (PSTR)DriverContext.FileNameA );
  257. DriverContext.FileNameA = NULL;
  258. }
  259. *pDate = DriverContext.FileDate;
  260. *pTime = DriverContext.FileTime;
  261. return(b ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
  262. }
  263. INT_PTR
  264. DIAMONDAPI
  265. SpdNotifyFunction(
  266. IN FDINOTIFICATIONTYPE Operation,
  267. IN PFDINOTIFICATION Parameters
  268. )
  269. {
  270. switch(Operation) {
  271. case fdintCABINET_INFO:
  272. case fdintNEXT_CABINET:
  273. case fdintPARTIAL_FILE:
  274. //
  275. // Cabinet management functions which we don't use.
  276. // Return success.
  277. //
  278. return(0);
  279. case fdintCOPY_FILE:
  280. //
  281. // Diamond is asking us whether we want to copy the file.
  282. // We need to return a file handle to indicate that we do.
  283. //
  284. return((INT_PTR)&CurrentTargetFile);
  285. case fdintCLOSE_FILE_INFO:
  286. //
  287. // Diamond is done with the target file and wants us to close it.
  288. // (ie, this is the counterpart to fdint_COPY_FILE).
  289. // We manage our own file i/o so ignore this.
  290. //
  291. return(TRUE);
  292. }
  293. return 0;
  294. }
  295. INT_PTR
  296. DIAMONDAPI
  297. SpdNotifyFunctionCabinet(
  298. IN FDINOTIFICATIONTYPE Operation,
  299. IN PFDINOTIFICATION Parameters
  300. )
  301. {
  302. EXPAND_CAB_CONTEXT * Context = (EXPAND_CAB_CONTEXT *) Parameters->pv;
  303. NTSTATUS Status;
  304. ULONG FileNameLength;
  305. ULONG Disposition;
  306. OBJECT_ATTRIBUTES Obja;
  307. UNICODE_STRING UnicodeString;
  308. IO_STATUS_BLOCK IoStatusBlock;
  309. union {
  310. FILE_BASIC_INFORMATION FileBasicDetails;
  311. FILE_RENAME_INFORMATION FileRenameDetails;
  312. FILE_DISPOSITION_INFORMATION FileDispositionDetails;
  313. WCHAR PathName[CB_MAX_FILENAME * 2];
  314. } U;
  315. HANDLE TempHandle;
  316. //
  317. // These values are retained between fdintCOPY_FILE and fdintCLOSE_FILE_INFO
  318. //
  319. static WCHAR FileName[CB_MAX_FILENAME];
  320. static LARGE_INTEGER FileSize;
  321. static LARGE_INTEGER FileTime;
  322. static ULONG FileAttributes;
  323. switch ( Operation ) {
  324. case fdintCOPY_FILE:
  325. //
  326. // Diamond is asking us whether we want to copy the file.
  327. // Convert everything we're given to the form needed to
  328. // call the client back to ask it about this file.
  329. // We need to return a file handle to indicate that we do.
  330. //
  331. Status = RtlMultiByteToUnicodeN (
  332. FileName,
  333. sizeof(FileName),
  334. &FileNameLength,
  335. Parameters->psz1,
  336. strlen(Parameters->psz1)
  337. );
  338. if (!NT_SUCCESS(Status)) {
  339. //
  340. // failed to translate, ignore file
  341. //
  342. return(-1);
  343. }
  344. FileName[ FileNameLength / sizeof(WCHAR) ] = L'\0';
  345. FileSize.LowPart = Parameters->cb;
  346. FileSize.HighPart = 0;
  347. SpTimeFromDosTime( Parameters->date,
  348. Parameters->time,
  349. &FileTime );
  350. FileAttributes = Parameters->attribs &
  351. (FILE_ATTRIBUTE_ARCHIVE |
  352. FILE_ATTRIBUTE_READONLY |
  353. FILE_ATTRIBUTE_HIDDEN |
  354. FILE_ATTRIBUTE_SYSTEM);
  355. Disposition = Context->Callback( EXPAND_COPY_FILE,
  356. FileName,
  357. &FileSize,
  358. &FileTime,
  359. FileAttributes,
  360. Context->CallbackContext);
  361. if ( Disposition == EXPAND_ABORT ) {
  362. return(-1); // tell FDI to abort
  363. } else if ( Disposition != EXPAND_COPY_THIS_FILE ) {
  364. return(0); // tell FDI to skip this file
  365. }
  366. //
  367. // see if target file already exists
  368. //
  369. wcscpy( U.PathName, Context->DestinationPath );
  370. SpConcatenatePaths( U.PathName, FileName );
  371. INIT_OBJA( &Obja, &UnicodeString, U.PathName );
  372. Status = ZwCreateFile( &TempHandle,
  373. FILE_GENERIC_READ,
  374. &Obja,
  375. &IoStatusBlock,
  376. NULL,
  377. FILE_ATTRIBUTE_NORMAL,
  378. 0, // no sharing
  379. FILE_OPEN, // fail if not existing
  380. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  381. NULL,
  382. 0
  383. );
  384. if ( NT_SUCCESS(Status) ) {
  385. //
  386. // Target file already exists. Check for over-write.
  387. //
  388. Status = ZwQueryInformationFile( TempHandle,
  389. &IoStatusBlock,
  390. &U.FileBasicDetails,
  391. sizeof(FILE_BASIC_INFORMATION),
  392. FileBasicInformation );
  393. ZwClose( TempHandle );
  394. if ( NT_SUCCESS(Status) &&
  395. ( U.FileBasicDetails.FileAttributes & FILE_ATTRIBUTE_READONLY )) {
  396. //
  397. // target file is read-only: report error
  398. //
  399. Disposition = Context->Callback( EXPAND_NOTIFY_CREATE_FAILED,
  400. FileName,
  401. &FileSize,
  402. &FileTime,
  403. FileAttributes,
  404. Context->CallbackContext);
  405. if ( Disposition != EXPAND_CONTINUE ) {
  406. return(-1); // tell FDI to abort
  407. }
  408. return (0); // tell FDI to just skip this target file
  409. }
  410. //
  411. // ask client about overwrite
  412. //
  413. Disposition = Context->Callback( EXPAND_QUERY_OVERWRITE,
  414. FileName,
  415. &FileSize,
  416. &FileTime,
  417. FileAttributes,
  418. Context->CallbackContext);
  419. if ( Disposition == EXPAND_ABORT ) {
  420. return(-1); // tell FDI to abort
  421. } else if ( Disposition != EXPAND_COPY_THIS_FILE ) {
  422. return(0); // tell FDI to skip this file
  423. }
  424. } // end if target file already exists
  425. //
  426. // create temporary target file
  427. //
  428. wcscpy( U.PathName, Context->DestinationPath );
  429. SpConcatenatePaths( U.PathName, L"$$TEMP$$.~~~" );
  430. //
  431. // see if target file exists
  432. //
  433. INIT_OBJA( &Obja, &UnicodeString, U.PathName );
  434. Status = ZwCreateFile( &CurrentTargetFile.u.Handle,
  435. FILE_GENERIC_WRITE,
  436. &Obja,
  437. &IoStatusBlock,
  438. NULL,
  439. FILE_ATTRIBUTE_NORMAL,
  440. 0, // no sharing
  441. FILE_OVERWRITE_IF, // allow overwrite
  442. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  443. NULL,
  444. 0
  445. );
  446. if ( !NT_SUCCESS(Status) ) {
  447. //
  448. // advise client we can't create this file
  449. //
  450. Disposition = Context->Callback( EXPAND_NOTIFY_CREATE_FAILED,
  451. FileName,
  452. &FileSize,
  453. &FileTime,
  454. FileAttributes,
  455. Context->CallbackContext);
  456. if ( Disposition != EXPAND_CONTINUE ) {
  457. return(-1); // tell FDI to abort
  458. }
  459. return (0); // tell FDI to just skip this target file
  460. }
  461. //
  462. // target file created: give the handle to FDI to expand
  463. //
  464. return( (INT_PTR) &CurrentTargetFile ); // target "handle"
  465. case fdintCLOSE_FILE_INFO:
  466. //
  467. // Diamond is done with the target file and wants us to close it.
  468. //
  469. ASSERT( CurrentTargetFile.Signature == TARGET_FILE_SIGNATURE );
  470. ASSERT( CurrentTargetFile.u.Handle != INVALID_HANDLE_VALUE );
  471. if (( CurrentTargetFile.Signature == TARGET_FILE_SIGNATURE ) &&
  472. ( CurrentTargetFile.u.Handle != INVALID_HANDLE_VALUE )) {
  473. //
  474. // set target file's true name (overwriting old file)
  475. //
  476. U.FileRenameDetails.ReplaceIfExists = TRUE;
  477. U.FileRenameDetails.RootDirectory = NULL;
  478. U.FileRenameDetails.FileNameLength = wcslen( FileName ) * sizeof(WCHAR);
  479. wcscpy( U.FileRenameDetails.FileName, FileName );
  480. Status = ZwSetInformationFile( CurrentTargetFile.u.Handle,
  481. &IoStatusBlock,
  482. &U.FileRenameDetails,
  483. sizeof(U.FileRenameDetails) +
  484. U.FileRenameDetails.FileNameLength,
  485. FileRenameInformation );
  486. if ( !NT_SUCCESS(Status) ) {
  487. //
  488. // Unable to change temp name to true name. Change to delete
  489. // on close, close it, and tell the user it didn't work.
  490. //
  491. U.FileDispositionDetails.DeleteFile = TRUE;
  492. ZwSetInformationFile( CurrentTargetFile.u.Handle,
  493. &IoStatusBlock,
  494. &U.FileDispositionDetails,
  495. sizeof(U.FileDispositionDetails),
  496. FileDispositionInformation );
  497. ZwClose( CurrentTargetFile.u.Handle );
  498. CurrentTargetFile.u.Handle = INVALID_HANDLE_VALUE;
  499. Disposition = Context->Callback( EXPAND_NOTIFY_CREATE_FAILED,
  500. FileName,
  501. &FileSize,
  502. &FileTime,
  503. FileAttributes,
  504. Context->CallbackContext);
  505. if ( Disposition != EXPAND_CONTINUE ) {
  506. return(-1); // tell FDI to abort
  507. }
  508. return (TRUE); // keep FDI going
  509. }
  510. //
  511. // try to set file's last-modifed time
  512. //
  513. Status = ZwQueryInformationFile( CurrentTargetFile.u.Handle,
  514. &IoStatusBlock,
  515. &U.FileBasicDetails,
  516. sizeof(U.FileBasicDetails),
  517. FileBasicInformation );
  518. if (NT_SUCCESS(Status) ) {
  519. U.FileBasicDetails.LastWriteTime = FileTime;
  520. ZwSetInformationFile( CurrentTargetFile.u.Handle,
  521. &IoStatusBlock,
  522. &U.FileBasicDetails,
  523. sizeof(U.FileBasicDetails),
  524. FileBasicInformation );
  525. }
  526. //
  527. // Note that we did not put any attributes on this file.
  528. // The client callback code may do that if it so desires.
  529. //
  530. ZwClose( CurrentTargetFile.u.Handle );
  531. CurrentTargetFile.u.Handle = INVALID_HANDLE_VALUE;
  532. //
  533. // Tell client it has been done
  534. //
  535. Disposition = Context->Callback( EXPAND_COPIED_FILE,
  536. FileName,
  537. &FileSize,
  538. &FileTime,
  539. FileAttributes,
  540. Context->CallbackContext);
  541. if ( Disposition == EXPAND_ABORT ) {
  542. return(-1); // tell FDI to abort now
  543. }
  544. }
  545. return(TRUE);
  546. break;
  547. default:
  548. //
  549. // Cabinet management functions which we don't use.
  550. // Return success.
  551. //
  552. return 0;
  553. }
  554. }
  555. INT_PTR
  556. DIAMONDAPI
  557. SpdNotifyFunctionDriverCab(
  558. IN FDINOTIFICATIONTYPE Operation,
  559. IN PFDINOTIFICATION Parameters
  560. )
  561. {
  562. BOOLEAN extract;
  563. PWSTR CabNameW;
  564. ULONG Size;
  565. ULONG StringSize;
  566. NTSTATUS Status;
  567. switch(Operation) {
  568. case fdintCABINET_INFO:
  569. case fdintNEXT_CABINET:
  570. case fdintPARTIAL_FILE:
  571. //
  572. // Cabinet management functions which we don't use.
  573. // Return success.
  574. //
  575. return(0);
  576. case fdintCOPY_FILE:
  577. //
  578. // Diamond is asking us whether we want to copy the file.
  579. // We need to return a file handle to indicate that we do.
  580. //
  581. //
  582. // diamond is an ansi API -- we need to convert to unicode string
  583. //
  584. extract = FALSE;
  585. if (DriverContext.FileNameA) {
  586. if (_stricmp(DriverContext.FileNameA, Parameters->psz1) == 0) {
  587. extract = TRUE;
  588. }
  589. } else {
  590. StringSize = strlen(Parameters->psz1);
  591. CabNameW = SpMemAlloc ((StringSize+1) * sizeof(WCHAR));
  592. if (!CabNameW) {
  593. //
  594. // we're out of memory, abort
  595. //
  596. return(-1);
  597. }
  598. Status = RtlMultiByteToUnicodeN (
  599. CabNameW,
  600. StringSize * sizeof(WCHAR),
  601. &Size,
  602. Parameters->psz1,
  603. StringSize
  604. );
  605. if (!NT_SUCCESS(Status)) {
  606. //
  607. // failed to translate, abort
  608. //
  609. SpMemFree(CabNameW);
  610. return(-1);
  611. }
  612. extract = FALSE;
  613. //
  614. // null terminate
  615. //
  616. CabNameW[StringSize] = 0;
  617. if (_wcsicmp(DriverContext.FileName, CabNameW) == 0) {
  618. extract = TRUE;
  619. }
  620. SpMemFree( CabNameW );
  621. }
  622. if (extract) {
  623. return((INT_PTR)&CurrentTargetFile);
  624. } else {
  625. return (INT_PTR)NULL;
  626. }
  627. case fdintCLOSE_FILE_INFO:
  628. //
  629. // Diamond is done with the target file and wants us to close it.
  630. // (ie, this is the counterpart to fdint_COPY_FILE).
  631. // We manage our own file i/o so ignore this
  632. // (first we grab the file date and time)
  633. //
  634. DriverContext.FileDate = Parameters->date;
  635. DriverContext.FileTime = Parameters->time;
  636. return(TRUE);
  637. }
  638. return 0;
  639. }
  640. PVOID
  641. DIAMONDAPI
  642. SpdFdiAlloc(
  643. IN ULONG NumberOfBytes
  644. )
  645. /*++
  646. Routine Description:
  647. Callback used by FDICopy to allocate memory.
  648. Arguments:
  649. NumberOfBytes - supplies desired size of block.
  650. Return Value:
  651. Returns pointer to a block of cache-aligned memory.
  652. Does not return if memory cannot be allocated.
  653. --*/
  654. {
  655. PVOID p;
  656. p = ExAllocatePoolWithTag(PagedPoolCacheAligned,NumberOfBytes,SETUP_FDI_POOL_TAG);
  657. if(!p) {
  658. SpOutOfMemory();
  659. }
  660. return(p);
  661. }
  662. VOID
  663. DIAMONDAPI
  664. SpdFdiFree(
  665. IN PVOID Block
  666. )
  667. /*++
  668. Routine Description:
  669. Callback used by FDICopy to free a memory block.
  670. The block must have been allocated with SpdFdiAlloc().
  671. Arguments:
  672. Block - supplies pointer to block of memory to be freed.
  673. Return Value:
  674. None.
  675. --*/
  676. {
  677. ExFreePool(Block);
  678. }
  679. INT_PTR
  680. DIAMONDAPI
  681. SpdFdiOpen(
  682. IN PSTR FileName,
  683. IN int oflag,
  684. IN int pmode
  685. )
  686. /*++
  687. Routine Description:
  688. Callback used by FDICopy to open files.
  689. In our implementation, the source and target files are already opened
  690. by the time we can get to this point so we don'tt ever actually open
  691. anything here.
  692. However diamond may 'open' the source file more than once because it
  693. wants 2 different states. We support that here by using our own
  694. 'handles' with special meaning to us.
  695. Arguments:
  696. FileName - supplies name of file to be opened. Ignored.
  697. oflag - supplies flags for open. Ignored.
  698. pmode - supplies additional flags for open. Ignored.
  699. Return Value:
  700. --*/
  701. {
  702. PMY_FILE_STATE State;
  703. UNREFERENCED_PARAMETER(FileName);
  704. UNREFERENCED_PARAMETER(oflag);
  705. UNREFERENCED_PARAMETER(pmode);
  706. //
  707. // Note: we only support opening the source (cabinet) file, which we
  708. // carefully pass in to FDICopy() as the empty string.
  709. //
  710. ASSERT(*FileName == 0);
  711. if(*FileName) {
  712. return(-1);
  713. }
  714. State = SpMemAlloc(sizeof(MY_FILE_STATE));
  715. State->u.FileOffset = 0;
  716. State->Signature = SOURCE_FILE_SIGNATURE;
  717. return((INT_PTR)State);
  718. }
  719. UINT
  720. DIAMONDAPI
  721. SpdFdiRead(
  722. IN INT_PTR Handle,
  723. OUT PVOID pv,
  724. IN UINT ByteCount
  725. )
  726. /*++
  727. Routine Description:
  728. Callback used by FDICopy to read from a file.
  729. We assume that diamond is going to read only from the cabinet file.
  730. Arguments:
  731. Handle - supplies handle to open file to be read from.
  732. pv - supplies pointer to buffer to receive bytes we read.
  733. ByteCount - supplies number of bytes to read.
  734. Return Value:
  735. Number of bytes read or -1 if an error occurs.
  736. --*/
  737. {
  738. UINT rc;
  739. PMY_FILE_STATE State;
  740. LONG RealByteCount;
  741. State = (PMY_FILE_STATE)Handle;
  742. //
  743. // Assume failure.
  744. //
  745. rc = (UINT)(-1);
  746. //
  747. // Only read the source with this routine.
  748. //
  749. ASSERT(State->Signature == SOURCE_FILE_SIGNATURE);
  750. if(State->Signature == SOURCE_FILE_SIGNATURE) {
  751. RealByteCount = (LONG)ByteCount;
  752. if(State->u.FileOffset + RealByteCount > (LONG)SpdSourceFileSize) {
  753. RealByteCount = (LONG)SpdSourceFileSize - State->u.FileOffset;
  754. }
  755. if(RealByteCount < 0) {
  756. RealByteCount = 0;
  757. }
  758. try {
  759. RtlCopyMemory(
  760. pv,
  761. SpdSourceAddress + State->u.FileOffset,
  762. (ULONG)RealByteCount
  763. );
  764. State->u.FileOffset += RealByteCount;
  765. rc = RealByteCount;
  766. } except(EXCEPTION_EXECUTE_HANDLER) {
  767. ;
  768. }
  769. }
  770. return(rc);
  771. }
  772. UINT
  773. DIAMONDAPI
  774. SpdFdiWrite(
  775. IN INT_PTR Handle,
  776. IN PVOID pv,
  777. IN UINT ByteCount
  778. )
  779. /*++
  780. Routine Description:
  781. Callback used by FDICopy to write to a file.
  782. We assume that diamond is going to write only to the target file.
  783. Arguments:
  784. Handle - supplies handle to open file to be written to.
  785. pv - supplies pointer to buffer containing bytes to write.
  786. ByteCount - supplies number of bytes to write.
  787. Return Value:
  788. Number of bytes written (ByteCount) or -1 if an error occurs.
  789. --*/
  790. {
  791. UINT rc;
  792. IO_STATUS_BLOCK IoStatusBlock;
  793. NTSTATUS Status;
  794. PMY_FILE_STATE State;
  795. State = (PMY_FILE_STATE)Handle;
  796. //
  797. // Assume failure.
  798. //
  799. rc = (UINT)(-1);
  800. //
  801. // Only write the target with this routine.
  802. //
  803. ASSERT(State->Signature == TARGET_FILE_SIGNATURE);
  804. if(State->Signature == TARGET_FILE_SIGNATURE) {
  805. Status = ZwWriteFile(
  806. (HANDLE)State->u.Handle,
  807. NULL,
  808. NULL,
  809. NULL,
  810. &IoStatusBlock,
  811. pv,
  812. ByteCount,
  813. NULL,
  814. NULL
  815. );
  816. if(NT_SUCCESS(Status)) {
  817. rc = ByteCount;
  818. } else {
  819. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpdFdiWrite: Status %lx writing to target file\n",Status));
  820. }
  821. }
  822. return(rc);
  823. }
  824. int
  825. DIAMONDAPI
  826. SpdFdiClose(
  827. IN INT_PTR Handle
  828. )
  829. /*++
  830. Routine Description:
  831. Callback used by FDICopy to close files.
  832. In our implementation, the source and target files are managed
  833. elsewhere so we don't actually need to close any files.
  834. However we may need to free some state information.
  835. Arguments:
  836. Handle - handle of file to close.
  837. Return Value:
  838. 0 (success).
  839. --*/
  840. {
  841. PMY_FILE_STATE State = (PMY_FILE_STATE)Handle;
  842. //
  843. // Only 'close' the source file.
  844. //
  845. if(State->Signature == SOURCE_FILE_SIGNATURE) {
  846. SpMemFree(State);
  847. }
  848. return(0);
  849. }
  850. LONG
  851. DIAMONDAPI
  852. SpdFdiSeek(
  853. IN INT_PTR Handle,
  854. IN long Distance,
  855. IN int SeekType
  856. )
  857. /*++
  858. Routine Description:
  859. Callback used by FDICopy to seek files.
  860. We assume that we can seek only in the source file.
  861. Arguments:
  862. Handle - handle of file to close.
  863. Distance - supplies distance to seek. Interpretation of this
  864. parameter depends on the value of SeekType.
  865. SeekType - supplies a value indicating how Distance is to be
  866. interpreted; one of SEEK_SET, SEEK_CUR, SEEK_END.
  867. Return Value:
  868. New file offset.
  869. --*/
  870. {
  871. PMY_FILE_STATE State = (PMY_FILE_STATE)Handle;
  872. LONG rc;
  873. //
  874. // Assume failure.
  875. //
  876. rc = -1L;
  877. //
  878. // Only allow seeking in the source.
  879. //
  880. ASSERT(State->Signature == SOURCE_FILE_SIGNATURE);
  881. if(State->Signature == SOURCE_FILE_SIGNATURE) {
  882. switch(SeekType) {
  883. case SEEK_CUR:
  884. //
  885. // Distance is an offset from the current file position.
  886. //
  887. State->u.FileOffset += Distance;
  888. break;
  889. case SEEK_END:
  890. //
  891. // Distance is an offset from the end of file.
  892. //
  893. State->u.FileOffset = SpdSourceFileSize - Distance;
  894. break;
  895. case SEEK_SET:
  896. //
  897. // Distance is the new absolute offset.
  898. //
  899. State->u.FileOffset = (ULONG)Distance;
  900. break;
  901. }
  902. if(State->u.FileOffset < 0) {
  903. State->u.FileOffset = 0;
  904. }
  905. if(State->u.FileOffset > (LONG)SpdSourceFileSize) {
  906. State->u.FileOffset = SpdSourceFileSize;
  907. }
  908. //
  909. // Return successful status.
  910. //
  911. rc = State->u.FileOffset;
  912. }
  913. return(rc);
  914. }
  915. VOID
  916. SpdInitialize(
  917. VOID
  918. )
  919. {
  920. FdiContext = FDICreate(
  921. SpdFdiAlloc,
  922. SpdFdiFree,
  923. SpdFdiOpen,
  924. SpdFdiRead,
  925. SpdFdiWrite,
  926. SpdFdiClose,
  927. SpdFdiSeek,
  928. cpuUNKNOWN,
  929. &FdiError
  930. );
  931. if(FdiContext == NULL) {
  932. SpOutOfMemory();
  933. }
  934. RtlZeroMemory(&DriverContext, sizeof(DriverContext) );
  935. }
  936. VOID
  937. SpdTerminate(
  938. VOID
  939. )
  940. {
  941. FDIDestroy(FdiContext);
  942. FdiContext = NULL;
  943. }