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.

1133 lines
26 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. decomp.c
  5. Abstract:
  6. Routines to handle reading of files compressed into single-file
  7. cabinet format.
  8. Author:
  9. Ted Miller (tedm) 16 May 1997
  10. Revision History:
  11. --*/
  12. #include "..\lib\bootlib.h"
  13. #include "diamondd.h"
  14. #include <stdio.h>
  15. #include <fcntl.h>
  16. #include <basetsd.h>
  17. #ifdef i386
  18. #include "bldrx86.h"
  19. #endif
  20. #if defined(_IA64_)
  21. #include "bldria64.h"
  22. #endif
  23. #if 0
  24. #define TmErrOut(x) DbgPrint x
  25. #define TmDbgOut(x) DbgPrint x
  26. #define TmDbgPause() DbgBreakPoint()
  27. #else
  28. #define TmErrOut(x)
  29. #define TmDbgOut(x)
  30. #define TmDbgPause()
  31. #endif
  32. BOOLEAN Decompress;
  33. //
  34. // Global variable that points to a buffer used for decompressing the file
  35. // being opened. After that, reads are satisfied from this buffer. The buffer
  36. // holds exactly one file at a time. We rely on the ordering of stuff in the loader
  37. // to ensure that only one file that needs to be decompressed is open at a time!
  38. //
  39. ULONG_PTR DecompressBufferBasePage;
  40. PVOID DecompressBuffer;
  41. ULONG DecompressBufferSize;
  42. BOOLEAN DecompressBufferInUse;
  43. ULONG SizeOfFileInDecompressBuffer;
  44. ULONG DecompExpectedSize;
  45. HFDI FdiContext;
  46. ERF DecompErf;
  47. //
  48. // The diamond stuff allocates and frees blocks of memory
  49. // for each file. There's no memory allocator in the boot loader that allows
  50. // for memory frees. So we have to fake it.
  51. //
  52. PVOID DecompressHeap;
  53. ULONG_PTR DecompressHeapPage;
  54. #define DECOMP_HEAP_SIZE ((128+2048)*1024) // 128K work + 2MB window
  55. typedef struct _DECOMP_HEAP_BLOCK {
  56. struct _DECOMP_HEAP_BLOCK *Next;
  57. ULONG BlockSize;
  58. BOOL Free;
  59. } DECOMP_HEAP_BLOCK, *PDECOMP_HEAP_BLOCK;
  60. VOID
  61. ReinitializeDiamondMiniHeap(
  62. VOID
  63. );
  64. //
  65. // Bogus global variable used to track the device id for the device that
  66. // the file we are currently decompressing lives on.
  67. //
  68. ULONG DecompDeviceId;
  69. ARC_STATUS DecompLastIoError;
  70. //
  71. // This is the value we return to diamond when it asks us to create
  72. // the target file.
  73. //
  74. #define DECOMP_MAGIC_HANDLE 0x87654
  75. //
  76. // Misc forward references.
  77. //
  78. ARC_STATUS
  79. DecompAllocateDecompressBuffer (
  80. IN ULONG BufferSize
  81. );
  82. VOID
  83. DecompFreeDecompressBuffer (
  84. VOID
  85. );
  86. ARC_STATUS
  87. DecompClose(
  88. IN ULONG FileId
  89. );
  90. ARC_STATUS
  91. DecompRead(
  92. IN ULONG FileId,
  93. OUT VOID * FIRMWARE_PTR Buffer,
  94. IN ULONG Length,
  95. OUT ULONG * FIRMWARE_PTR Transfer
  96. );
  97. ARC_STATUS
  98. DecompSeek(
  99. IN ULONG FileId,
  100. IN LARGE_INTEGER * FIRMWARE_PTR Offset,
  101. IN SEEK_MODE SeekMode
  102. );
  103. ARC_STATUS
  104. DecompGetFileInfo(
  105. IN ULONG FileId,
  106. OUT FILE_INFORMATION * FIRMWARE_PTR FileInfo
  107. );
  108. PVOID
  109. DIAMONDAPI
  110. DiamondAlloc(
  111. IN ULONG Size
  112. );
  113. VOID
  114. DIAMONDAPI
  115. DiamondFree(
  116. IN PVOID Block
  117. );
  118. INT_PTR
  119. DIAMONDAPI
  120. DiamondOpen(
  121. IN LPSTR FileName,
  122. IN int oflag,
  123. IN int pmode
  124. );
  125. UINT
  126. DIAMONDAPI
  127. DiamondRead(
  128. IN INT_PTR Handle,
  129. OUT PVOID pv,
  130. IN UINT ByteCount
  131. );
  132. UINT
  133. DIAMONDAPI
  134. DiamondWrite(
  135. IN INT_PTR Handle,
  136. IN PVOID pv,
  137. IN UINT ByteCount
  138. );
  139. int
  140. DIAMONDAPI
  141. DiamondClose(
  142. IN INT_PTR Handle
  143. );
  144. long
  145. DIAMONDAPI
  146. DiamondSeek(
  147. IN INT_PTR Handle,
  148. IN long Distance,
  149. IN int SeekType
  150. );
  151. INT_PTR
  152. DIAMONDAPI
  153. DiamondNotifyFunction(
  154. IN FDINOTIFICATIONTYPE Operation,
  155. IN PFDINOTIFICATION Parameters
  156. );
  157. //
  158. // Device dispatch table for our pseudo-filesystem.
  159. //
  160. BL_DEVICE_ENTRY_TABLE DecompDeviceEntryTable = { DecompClose, // close
  161. NULL, // mount
  162. NULL, // open
  163. DecompRead, // read
  164. NULL, // read status
  165. DecompSeek, // seek
  166. NULL, // write
  167. DecompGetFileInfo, // get file info
  168. NULL, // set file info
  169. NULL, // rename
  170. NULL, // get dirent
  171. NULL // PBOOTFS_INFO, unused
  172. };
  173. VOID
  174. DecompEnableDecompression(
  175. IN BOOLEAN Enable
  176. )
  177. {
  178. #if defined(_X86_) || defined(_IA64_)
  179. //
  180. // Disable on alpha, since it doesn't seem to work.
  181. //
  182. Decompress = Enable;
  183. #endif
  184. }
  185. BOOLEAN
  186. DecompGenerateCompressedName(
  187. IN LPCSTR Filename,
  188. OUT LPSTR CompressedName
  189. )
  190. /*++
  191. Routine Description:
  192. This routine generates the "compressed-form" name of a file.
  193. The compressed form substitutes the last character of the extension
  194. with a _. If there is no extension then ._ is appended to the name.
  195. Only the final component is relevent; others are preserved in the
  196. compressed form name.
  197. Arguments:
  198. Filename - supplies full pathname of file whose compressed form name
  199. is desired.
  200. CompressedName - receives compressed form of the full path. The caller must
  201. ensure that the buffer is large enough.
  202. Return Value:
  203. TRUE - the caller should try to locate the compressed filename first.
  204. FALSE - the caller should not attempt to locate the compressed filename
  205. at all.
  206. This value depends on the state of the Decompress global.
  207. --*/
  208. {
  209. PCHAR p,q;
  210. if(!Decompress) {
  211. return(FALSE);
  212. }
  213. strcpy(CompressedName,Filename);
  214. p = strrchr(CompressedName,'.');
  215. q = strrchr(CompressedName,'\\');
  216. if(q < p) {
  217. //
  218. // If there are 0, 1, or 2 characters after the dot, just append
  219. // the underscore. p points to the dot so include that in the length.
  220. //
  221. if(strlen(p) < 4) {
  222. strcat(CompressedName,"_");
  223. } else {
  224. //
  225. // Assume there are 3 characters in the extension and replace
  226. // the final one with an underscore.
  227. //
  228. p[3] = '_';
  229. }
  230. } else {
  231. //
  232. // No dot, just add ._.
  233. //
  234. strcat(CompressedName,"._");
  235. }
  236. return(TRUE);
  237. }
  238. DECOMP_STRUCTURE_CONTEXT DecompStructureContext = {0};
  239. ULONG
  240. DecompPrepareToReadCompressedFile(
  241. IN LPCSTR Filename,
  242. IN ULONG FileId
  243. )
  244. {
  245. ULONG Status;
  246. BOOL b;
  247. int err;
  248. ULONGLONG x;
  249. FDICABINETINFO CabinetInfo;
  250. ULONG OldUsableBase, OldUsableLimit;
  251. //
  252. // On both x86 and alpha the allocation of our large decompress buffer
  253. // has an unfortunate tendency to place the block right where the
  254. // (non-relocatable) kernel wants to go. By allocating from the top
  255. // of memory we make this problem go away.
  256. //
  257. if(!Decompress) {
  258. return((ULONG)(-1));
  259. }
  260. //
  261. // If we're in the middle of FDICopy or FDIIsCabinet then
  262. // we don't want to do our special processing. Special return code
  263. // of -1 tells the caller that we didn't process it.
  264. //
  265. if(FdiContext) {
  266. return((ULONG)(-1));
  267. }
  268. //
  269. // If there's no decompression heap yet, allocate one.
  270. //
  271. if(!DecompressHeap) {
  272. //
  273. // Set allocatable range to the decompression-specific range
  274. //
  275. OldUsableBase = BlUsableBase;
  276. OldUsableLimit = BlUsableLimit;
  277. BlUsableBase = BL_DECOMPRESS_RANGE_LOW;
  278. BlUsableLimit = BL_DECOMPRESS_RANGE_HIGH;
  279. Status = BlAllocateDescriptor(
  280. LoaderOsloaderHeap,
  281. 0,
  282. ROUND_TO_PAGES(DECOMP_HEAP_SIZE) >> PAGE_SHIFT,
  283. (PULONG)&DecompressHeapPage
  284. );
  285. //
  286. // Restore the previous alloc range.
  287. //
  288. BlUsableBase = OldUsableBase;
  289. BlUsableLimit = OldUsableLimit;
  290. if(Status != ESUCCESS) {
  291. TmErrOut(("Setup: couldn't allocate decompression heap (%u)\r\n",Status));
  292. DecompressHeap = NULL;
  293. return(Status);
  294. }
  295. DecompressHeap = (PVOID)(KSEG0_BASE | (DecompressHeapPage << PAGE_SHIFT));
  296. }
  297. //
  298. // We reinitialize diamond each time because of the way we deal with
  299. // the heap for alloc and free requests from diamond -- doing this
  300. // allows us to wipe our heap clean for each file.
  301. //
  302. ReinitializeDiamondMiniHeap();
  303. FdiContext = FDICreate(
  304. DiamondAlloc,
  305. DiamondFree,
  306. DiamondOpen,
  307. DiamondRead,
  308. DiamondWrite,
  309. DiamondClose,
  310. DiamondSeek,
  311. 0, // cpu type flag is ignored
  312. &DecompErf
  313. );
  314. if(!FdiContext) {
  315. TmErrOut(("Setup: FDICreate failed\r\n"));
  316. return(ENOMEM);
  317. }
  318. //
  319. // Check if file is a cabinet and reset file pointer.
  320. //
  321. b = FDIIsCabinet(FdiContext,FileId,&CabinetInfo);
  322. x = 0;
  323. BlSeek(FileId,(PLARGE_INTEGER)&x,SeekAbsolute);
  324. if(!b) {
  325. //
  326. // Not a cabinet, we're done. Bail with return code of -1
  327. // which tells the caller that everything's OK.
  328. //
  329. TmDbgOut(("Setup: file %s is not a cabinet\r\n",Filename));
  330. FDIDestroy(FdiContext);
  331. FdiContext = NULL;
  332. return((ULONG)(-1));
  333. }
  334. TmDbgOut(("Setup: file %s is compressed, prearing it for read\r\n",Filename));
  335. DecompDeviceId = BlFileTable[FileId].DeviceId;
  336. DecompLastIoError = ESUCCESS;
  337. b = FDICopy(
  338. FdiContext,
  339. "", // filename part only
  340. (LPSTR)Filename, // full path
  341. 0, // no flags relevent
  342. DiamondNotifyFunction, // routine to process control messages
  343. NULL, // no decryption
  344. NULL // no user-specified data
  345. );
  346. err = DecompErf.erfOper;
  347. FDIDestroy(FdiContext);
  348. FdiContext = NULL;
  349. if(b) {
  350. //
  351. // Everything worked.
  352. //
  353. // Get file information from the original file system so we can
  354. // return it later if someone wants it.
  355. //
  356. // Close the original file and switch context
  357. // structures so that read, seek, close, etc. requests come to us
  358. // instead of the original filesystem.
  359. //
  360. if(SizeOfFileInDecompressBuffer != DecompExpectedSize) {
  361. TmErrOut(("Setup: warning: expected size %lx, actual size = %lx\r\n",DecompExpectedSize,SizeOfFileInDecompressBuffer));
  362. }
  363. Status = BlGetFileInformation(FileId,&DecompStructureContext.FileInfo);
  364. if(Status != ESUCCESS) {
  365. TmErrOut(("DecompPrepareToReadCompressedFile: BlGetFileInfo returned %u\r\n",Status));
  366. DecompFreeDecompressBuffer();
  367. return(Status);
  368. }
  369. DecompStructureContext.FileInfo.EndingAddress.LowPart = SizeOfFileInDecompressBuffer;
  370. DecompStructureContext.FileInfo.EndingAddress.HighPart = 0;
  371. //
  372. // We don't handle files whose size doesn't fit in a DWORD.
  373. //
  374. if(DecompStructureContext.FileInfo.EndingAddress.HighPart) {
  375. TmErrOut(("DecompPrepareToReadCompressedFile: file too big\r\n"));
  376. DecompFreeDecompressBuffer();
  377. return(E2BIG);
  378. }
  379. BlClose(FileId);
  380. BlFileTable[FileId].Flags.Open = 1;
  381. BlFileTable[FileId].Position.QuadPart = 0;
  382. BlFileTable[FileId].DeviceEntryTable = &DecompDeviceEntryTable;
  383. #ifdef CACHE_DEVINFO
  384. BlFileTable[FileId].StructureContext = &DecompStructureContext;
  385. #else
  386. RtlCopyMemory(
  387. BlFileTable[FileId].StructureContext,
  388. &DecompStructureContext,
  389. sizeof(DECOMP_STRUCTURE_CONTEXT)
  390. );
  391. #endif
  392. return(ESUCCESS);
  393. } else {
  394. //
  395. // Failure.
  396. //
  397. TmErrOut(("Setupldr: FDICopy failed (FDIERROR = %u, last io err = %u)\r\n",err,DecompLastIoError));
  398. TmDbgPause();
  399. return(EINVAL);
  400. }
  401. }
  402. ARC_STATUS
  403. DecompAllocateDecompressBuffer (
  404. IN ULONG BufferSize
  405. )
  406. {
  407. ARC_STATUS Status;
  408. ULONG OldUsableBase, OldUsableLimit;
  409. //
  410. // On both x86 and alpha the allocation of our large decompress buffer
  411. // has an unfortunate tendency to place the block right where the
  412. // (non-relocatable) kernel wants to go. By allocating from the top
  413. // of memory we make this problem go away.
  414. //
  415. DecompressBufferSize = BufferSize;
  416. //
  417. // Set allocatable range to the decompression-specific range
  418. //
  419. OldUsableBase = BlUsableBase;
  420. OldUsableLimit = BlUsableLimit;
  421. BlUsableBase = BL_DECOMPRESS_RANGE_LOW;
  422. BlUsableLimit = BL_DECOMPRESS_RANGE_HIGH;
  423. Status = BlAllocateDescriptor(
  424. LoaderOsloaderHeap,
  425. 0,
  426. (ULONG)(ROUND_TO_PAGES(DecompressBufferSize) >> PAGE_SHIFT),
  427. (PULONG)&DecompressBufferBasePage
  428. );
  429. //
  430. // Restore the previous alloc range.
  431. //
  432. BlUsableBase = OldUsableBase;
  433. BlUsableLimit = OldUsableLimit;
  434. if ( Status != ESUCCESS ) {
  435. TmErrOut(("Setup: couldn't allocate decompression buffer (%u)\r\n",Status));
  436. DecompressBuffer = NULL;
  437. return(Status);
  438. }
  439. DecompressBuffer = (PVOID)(KSEG0_BASE | (DecompressBufferBasePage << PAGE_SHIFT));
  440. DecompressBufferInUse = TRUE;
  441. return ESUCCESS;
  442. }
  443. VOID
  444. DecompFreeDecompressBuffer (
  445. VOID
  446. )
  447. {
  448. if ( DecompressBufferInUse ) {
  449. DecompressBufferInUse = FALSE;
  450. BlFreeDescriptor( (ULONG)DecompressBufferBasePage );
  451. }
  452. if(DecompressHeap) {
  453. BlFreeDescriptor( (ULONG)DecompressHeapPage );
  454. DecompressHeap = NULL;
  455. }
  456. return;
  457. }
  458. ARC_STATUS
  459. DecompClose(
  460. IN ULONG FileId
  461. )
  462. /*++
  463. Routine Description:
  464. Close routine for decompression pseudo-filesystem.
  465. We mark the decompression buffer free and return success.
  466. Arguments:
  467. FileId - supplies open file id to be closed.
  468. Return Value:
  469. --*/
  470. {
  471. TmDbgOut(("DecompClose\r\n"));
  472. if(DecompressBufferInUse) {
  473. DecompFreeDecompressBuffer();
  474. } else {
  475. TmErrOut(("DecompClose: warning: no file buffered!\r\n"));
  476. TmDbgPause();
  477. }
  478. BlFileTable[FileId].Flags.Open = 0;
  479. return(ESUCCESS);
  480. }
  481. ARC_STATUS
  482. DecompRead(
  483. IN ULONG FileId,
  484. OUT VOID * FIRMWARE_PTR Buffer,
  485. IN ULONG Length,
  486. OUT ULONG * FIRMWARE_PTR Transfer
  487. )
  488. /*++
  489. Routine Description:
  490. Read routine for the decompression pseudo-filesystem.
  491. Reads are satisfied out of the decompression buffer.
  492. Arguments:
  493. FileId - supplies id for open file as returned by BlOpen().
  494. Buffer - receives data read from file.
  495. Length - supplies amount of data to be read, in bytes.
  496. Transfer - recieves number of bytes actually transferred
  497. into caller's buffer.
  498. Return Value:
  499. ARC status indicating outcome.
  500. --*/
  501. {
  502. ARC_STATUS Status;
  503. ULONG length;
  504. if(DecompressBufferInUse) {
  505. //
  506. // Make sure we don't try to read past EOF.
  507. //
  508. if((Length + BlFileTable[FileId].Position.LowPart) > SizeOfFileInDecompressBuffer) {
  509. TmErrOut(("DecompRead: warning: attempt to read past eof; read trucated\r\n"));
  510. TmDbgPause();
  511. Length = SizeOfFileInDecompressBuffer - BlFileTable[FileId].Position.LowPart;
  512. }
  513. //
  514. // Transfer data into caller's buffer.
  515. //
  516. TmDbgOut(("DecompRead: %lx bytes at filepos %lx\r\n",Length,BlFileTable[FileId].Position.LowPart));
  517. RtlCopyMemory(
  518. Buffer,
  519. (PCHAR)DecompressBuffer + BlFileTable[FileId].Position.LowPart,
  520. Length
  521. );
  522. *Transfer = Length;
  523. BlFileTable[FileId].Position.QuadPart += Length;
  524. Status = ESUCCESS;
  525. } else {
  526. //
  527. // Should never get here.
  528. //
  529. TmErrOut(("DecompRead: no file buffered!\r\n"));
  530. TmDbgPause();
  531. Status = EACCES;
  532. }
  533. return(Status);
  534. }
  535. ARC_STATUS
  536. DecompSeek(
  537. IN ULONG FileId,
  538. IN LARGE_INTEGER * FIRMWARE_PTR Offset,
  539. IN SEEK_MODE SeekMode
  540. )
  541. /*++
  542. Routine Description:
  543. Seek routine for the decompression pseudo-filesystem.
  544. Sets pseudo-file pointer to given offset.
  545. Arguments:
  546. FileId - supplies id for open file as returned by BlOpen().
  547. Offset - supplies new offset, whose interpretation depends on
  548. the SeekMode parameter.
  549. SeekMode - supplies type of seek. One of SeekAbsolute or SeekRelative.
  550. Return Value:
  551. ARC status indicating outcome.
  552. --*/
  553. {
  554. LONGLONG NewPosition;
  555. TmDbgOut(("DecompSeek: mode %u, pos = %lx\r\n",SeekMode,Offset->LowPart));
  556. if(DecompressBufferInUse) {
  557. switch(SeekMode) {
  558. case SeekAbsolute:
  559. NewPosition = Offset->QuadPart;
  560. break;
  561. case SeekRelative:
  562. NewPosition = BlFileTable[FileId].Position.QuadPart + Offset->QuadPart;
  563. break;
  564. default:
  565. TmErrOut(("DecompSeek: invalid seek mode\r\n"));
  566. TmDbgPause();
  567. return(EINVAL);
  568. }
  569. //
  570. // Make sure we don't try to seek to a negative offset or past EOF.
  571. //
  572. if(NewPosition < 0) {
  573. TmErrOut(("DecompSeek: warning: attempt to seek to negative offset\r\n"));
  574. TmDbgPause();
  575. NewPosition = 0;
  576. } else {
  577. if((ULONGLONG)NewPosition > (ULONGLONG)SizeOfFileInDecompressBuffer) {
  578. TmErrOut(("DecompSeek: attempt to seek past eof\r\n"));
  579. TmDbgPause();
  580. return(EINVAL);
  581. }
  582. }
  583. //
  584. // Remember new position.
  585. //
  586. TmDbgOut(("DecompSeek: new position is %lx\r\n",NewPosition));
  587. BlFileTable[FileId].Position.QuadPart = NewPosition;
  588. } else {
  589. //
  590. // Should never get here.
  591. //
  592. TmErrOut(("DecompSeek: no file buffered!\r\n"));
  593. TmDbgPause();
  594. return(EACCES);
  595. }
  596. return(ESUCCESS);
  597. }
  598. ARC_STATUS
  599. DecompGetFileInfo(
  600. IN ULONG FileId,
  601. OUT FILE_INFORMATION * FIRMWARE_PTR FileInfo
  602. )
  603. {
  604. RtlCopyMemory(
  605. FileInfo,
  606. &((PDECOMP_STRUCTURE_CONTEXT)BlFileTable[FileId].StructureContext)->FileInfo,
  607. sizeof(FILE_INFORMATION)
  608. );
  609. TmDbgOut(("DecompGetFileInfo: size = %lx\r\n",FileInfo->EndingAddress.LowPart));
  610. return(ESUCCESS);
  611. }
  612. VOID
  613. ReinitializeDiamondMiniHeap(
  614. VOID
  615. )
  616. {
  617. PDECOMP_HEAP_BLOCK p;
  618. p = DecompressHeap;
  619. p->BlockSize = DECOMP_HEAP_SIZE - sizeof(DECOMP_HEAP_BLOCK);
  620. p->Next = NULL;
  621. p->Free = TRUE;
  622. }
  623. PVOID
  624. DIAMONDAPI
  625. DiamondAlloc(
  626. IN ULONG Size
  627. )
  628. {
  629. PDECOMP_HEAP_BLOCK p,q;
  630. ULONG LeftOver;
  631. TmDbgOut(("DiamondAlloc: request %lx bytes\r\n",Size));
  632. //
  633. // Round size up to dword boundary.
  634. //
  635. if(Size % sizeof(ULONG_PTR)) {
  636. Size += sizeof(ULONG_PTR) - (Size % sizeof(ULONG_PTR));
  637. }
  638. //
  639. // Nothing fancy. First-fit algorithm, traversing all blocks
  640. // in the heap every time.
  641. //
  642. for(p=DecompressHeap; p; p=p->Next) {
  643. if(p->Free && (p->BlockSize >= Size)) {
  644. p->Free = FALSE;
  645. LeftOver = p->BlockSize - Size;
  646. if(LeftOver > sizeof(DECOMP_HEAP_BLOCK)) {
  647. //
  648. // Split the block.
  649. //
  650. p->BlockSize = Size;
  651. q = (PDECOMP_HEAP_BLOCK)((PUCHAR)(p+1) + Size);
  652. q->Next = p->Next;
  653. p->Next = q;
  654. q->Free = TRUE;
  655. q->BlockSize = LeftOver - sizeof(DECOMP_HEAP_BLOCK);
  656. }
  657. //
  658. // Return pointer to data area of the block.
  659. //
  660. TmDbgOut(("DiamondAlloc(%lx): %lx\r\n",Size,p+1));
  661. return(p+1);
  662. }
  663. }
  664. TmErrOut(("DiamondAlloc: out of heap space!\r\n"));
  665. TmDbgPause();
  666. return(NULL);
  667. }
  668. VOID
  669. DIAMONDAPI
  670. DiamondFree(
  671. IN PVOID Block
  672. )
  673. {
  674. PDECOMP_HEAP_BLOCK p;
  675. TmDbgOut(("DiamondFree(%lx)\r\n",Block));
  676. //
  677. // Get pointer to header for block.
  678. //
  679. Block = (PUCHAR)Block - sizeof(DECOMP_HEAP_BLOCK);
  680. //
  681. // Nothing fancy, no coalescing free blocks.
  682. //
  683. for(p=DecompressHeap; p; p=p->Next) {
  684. if(p == Block) {
  685. if(p->Free) {
  686. TmErrOut(("DiamondFree: warning: freeing free block\r\n"));
  687. TmDbgPause();
  688. return;
  689. }
  690. p->Free = TRUE;
  691. return;
  692. }
  693. }
  694. TmErrOut(("DiamondFree: warning: freeing invalid block\r\n"));
  695. TmDbgPause();
  696. }
  697. INT_PTR
  698. DIAMONDAPI
  699. DiamondOpen(
  700. IN LPSTR FileName,
  701. IN int oflag,
  702. IN int pmode
  703. )
  704. {
  705. ARC_STATUS Status;
  706. ULONG FileId;
  707. UNREFERENCED_PARAMETER(pmode);
  708. TmDbgOut(("DiamondOpen: %s\r\n",FileName));
  709. if(oflag & (_O_WRONLY | _O_RDWR | _O_APPEND | _O_CREAT | _O_TRUNC | _O_EXCL)) {
  710. TmErrOut(("DiamondOpen: invalid oflag %lx for %s\r\n",oflag,FileName));
  711. TmDbgPause();
  712. DecompLastIoError = EINVAL;
  713. return(-1);
  714. }
  715. Status = BlOpen(DecompDeviceId,FileName,ArcOpenReadOnly,&FileId);
  716. if(Status != ESUCCESS) {
  717. TmErrOut(("DiamondOpen: BlOpen %s returned %u\r\n",FileName,Status));
  718. TmDbgPause();
  719. DecompLastIoError = Status;
  720. return(-1);
  721. } else {
  722. TmDbgOut(("DiamondOpen: handle to %s is %lx\r\n",FileName,FileId));
  723. }
  724. return((INT_PTR)FileId);
  725. }
  726. UINT
  727. DIAMONDAPI
  728. DiamondRead(
  729. IN INT_PTR Handle,
  730. OUT PVOID pv,
  731. IN UINT ByteCount
  732. )
  733. {
  734. ARC_STATUS Status;
  735. ULONG n;
  736. TmDbgOut(("DiamondRead: %lx bytes, handle %lx\r\n",ByteCount,Handle));
  737. //
  738. // We should never be asked to read from the target file.
  739. //
  740. if(Handle == DECOMP_MAGIC_HANDLE) {
  741. TmErrOut(("DiamondRead: called for unexpected file!\r\n"));
  742. TmDbgPause();
  743. DecompLastIoError = EACCES;
  744. return((UINT)(-1));
  745. }
  746. Status = BlRead((ULONG)Handle,pv,ByteCount,&n);
  747. if(Status != ESUCCESS) {
  748. TmErrOut(("DiamondRead: BlRead failed %u\r\n",Status));
  749. TmDbgPause();
  750. DecompLastIoError = Status;
  751. n = (UINT)(-1);
  752. }
  753. return(n);
  754. }
  755. UINT
  756. DIAMONDAPI
  757. DiamondWrite(
  758. IN INT_PTR Handle,
  759. IN PVOID pv,
  760. IN UINT ByteCount
  761. )
  762. {
  763. TmDbgOut(("DiamondWrite: %lx bytes\r\n",ByteCount));
  764. //
  765. // This guy should be called ONLY to write decompressed data
  766. // into the decompress buffer.
  767. //
  768. if(Handle != DECOMP_MAGIC_HANDLE) {
  769. TmErrOut(("DiamondWrite: called for unexpected file!\r\n"));
  770. TmDbgPause();
  771. DecompLastIoError = EACCES;
  772. return((UINT)(-1));
  773. }
  774. //
  775. // Check for overflow.
  776. //
  777. if(SizeOfFileInDecompressBuffer+ByteCount > DecompressBufferSize) {
  778. TmErrOut(("DiamondWrite: decompressed file too big!\r\n"));
  779. TmDbgPause();
  780. DecompLastIoError = E2BIG;
  781. return((UINT)(-1));
  782. }
  783. RtlCopyMemory(
  784. (PCHAR)DecompressBuffer + SizeOfFileInDecompressBuffer,
  785. pv,
  786. ByteCount
  787. );
  788. SizeOfFileInDecompressBuffer += ByteCount;
  789. return(ByteCount);
  790. }
  791. int
  792. DIAMONDAPI
  793. DiamondClose(
  794. IN INT_PTR Handle
  795. )
  796. {
  797. TmDbgOut(("DiamondClose, handle=%lx\r\n",Handle));
  798. if(Handle != DECOMP_MAGIC_HANDLE) {
  799. BlClose((ULONG)Handle);
  800. }
  801. return(0);
  802. }
  803. long
  804. DIAMONDAPI
  805. DiamondSeek(
  806. IN INT_PTR Handle,
  807. IN long Distance,
  808. IN int SeekType
  809. )
  810. {
  811. ARC_STATUS Status;
  812. LARGE_INTEGER Offset;
  813. TmDbgOut(("DiamondSeek: type=%u, dist=%lx, handle=%lx\r\n",SeekType,Distance,Handle));
  814. //
  815. // We should never be asked to seek in the output file.
  816. //
  817. if(Handle == DECOMP_MAGIC_HANDLE) {
  818. TmErrOut(("DiamondSeek: asked to seek target file!\r\n"));
  819. TmDbgPause();
  820. DecompLastIoError = EACCES;
  821. return(-1);
  822. }
  823. //
  824. // We can't handle seek from end of file.
  825. //
  826. if(SeekType == SEEK_END) {
  827. TmErrOut(("DiamondSeek: asked to seek relative to end of file!\r\n"));
  828. TmDbgPause();
  829. DecompLastIoError = EACCES;
  830. return(-1);
  831. }
  832. Offset.QuadPart = Distance;
  833. Status = BlSeek((ULONG)Handle,&Offset,SeekType);
  834. if(Status != ESUCCESS) {
  835. TmErrOut(("DiamondSeek: BlSeek(%lx,%x) returned %u\r\n",Distance,SeekType,Status));
  836. TmDbgPause();
  837. DecompLastIoError = Status;
  838. return(-1);
  839. }
  840. TmDbgOut(("DiamondSeek: BlSeek(%lx,%x) new file position is %lx\r\n",Distance,SeekType,BlFileTable[Handle].Position.LowPart));
  841. return((long)BlFileTable[Handle].Position.LowPart);
  842. }
  843. INT_PTR
  844. DIAMONDAPI
  845. DiamondNotifyFunction(
  846. IN FDINOTIFICATIONTYPE Operation,
  847. IN PFDINOTIFICATION Parameters
  848. )
  849. {
  850. ARC_STATUS Status;
  851. switch(Operation) {
  852. case fdintCABINET_INFO:
  853. //
  854. // Nothing interesting here. Return 0 to continue.
  855. //
  856. return(0);
  857. case fdintCOPY_FILE:
  858. //
  859. // The file was obviously a cabinet so we're going to extract
  860. // the file out of it. Rememember that the decompression buffer
  861. // is in use. If it's already in use, then a fundamental
  862. // principle of our implementation has been violated and we
  863. // must bail now.
  864. //
  865. if(DecompressBufferInUse) {
  866. TmErrOut(("DiamondNotifyFunction: opens overlap (%s)!\r\n",Parameters->psz1));
  867. DecompLastIoError = EACCES;
  868. return(-1);
  869. }
  870. DecompExpectedSize = Parameters->cb;
  871. Status = DecompAllocateDecompressBuffer( DecompExpectedSize );
  872. if (Status != ESUCCESS) {
  873. TmErrOut(("DiamondNotifyFunction: unable to allocate decompress buffer!\r\n"));
  874. return(-1);
  875. }
  876. SizeOfFileInDecompressBuffer = 0;
  877. return(DECOMP_MAGIC_HANDLE);
  878. case fdintCLOSE_FILE_INFO:
  879. //
  880. // Diamond is asking to close the target handle. There's nothing we really
  881. // care about here, just return success as long as we recognize the handle.
  882. //
  883. if(Parameters->hf == DECOMP_MAGIC_HANDLE) {
  884. return(TRUE);
  885. } else {
  886. TmErrOut(("DiamondNotifyFunction: asked to close unexpected file!\r\n"));
  887. TmDbgPause();
  888. DecompLastIoError = EINVAL;
  889. return(FALSE);
  890. }
  891. default:
  892. //
  893. // Disregard any other messages
  894. //
  895. return(0);
  896. }
  897. }