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.

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