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.

405 lines
12 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. compress.c
  5. Abstract:
  6. This module implements staging support routines for FRS
  7. Author:
  8. Sudarshan Chitre 26-Apr-2000
  9. Revision History:
  10. --*/
  11. #include <ntreppch.h>
  12. #pragma hdrstop
  13. #include <frs.h>
  14. //
  15. // Guids for compression formats that are supported by the service.
  16. //
  17. extern GUID FrsGuidCompressionFormatNone;
  18. extern GUID FrsGuidCompressionFormatLZNT1;
  19. extern BOOL DisableCompressionStageFiles;
  20. DWORD
  21. FrsLZNT1CompressBuffer(
  22. IN PUCHAR UnCompressedBuf,
  23. IN DWORD UnCompressedBufLen,
  24. OUT PUCHAR CompressedBuf,
  25. IN DWORD CompressedBufLen,
  26. OUT DWORD *pCompressedSize
  27. )
  28. /*++
  29. Routine Description:
  30. Compression routine for default compression format.
  31. COMPRESSION_FORMAT_LZNT1
  32. Arguments:
  33. UnCompressedBuf : Source buffer.
  34. UnCompressedBufLen : Length of source buffer.
  35. CompressedBuf : Resultant compressed buffer.
  36. CompressedBufLen : Length of compressed buffer supplied.
  37. CompressedSize : Actual size of the compressed data.
  38. Return Value:
  39. Win Status
  40. --*/
  41. {
  42. #undef DEBSUB
  43. #define DEBSUB "FrsLZNT1CompressBuffer:"
  44. DWORD WStatus = ERROR_SUCCESS;
  45. DWORD NtStatus;
  46. PVOID WorkSpace = NULL;
  47. DWORD WorkSpaceSize = 0;
  48. DWORD FragmentWorkSpaceSize = 0;
  49. *pCompressedSize = 0;
  50. if (UnCompressedBuf == NULL ||
  51. UnCompressedBufLen == 0) {
  52. WStatus = ERROR_INVALID_PARAMETER;
  53. goto out;
  54. }
  55. if (CompressedBuf == NULL ||
  56. CompressedBufLen == 0) {
  57. WStatus = ERROR_MORE_DATA;
  58. goto out;
  59. }
  60. *pCompressedSize = 0;
  61. NtStatus = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1,
  62. &WorkSpaceSize,
  63. &FragmentWorkSpaceSize);
  64. WStatus = FrsSetLastNTError(NtStatus);
  65. if (!WIN_SUCCESS(WStatus)) {
  66. goto out;
  67. }
  68. WorkSpace = FrsAlloc(WorkSpaceSize);
  69. NtStatus = RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, // compression engine
  70. UnCompressedBuf, // input
  71. UnCompressedBufLen, // length of input
  72. CompressedBuf, // output
  73. CompressedBufLen, // length of output
  74. FRS_UNCOMPRESSED_CHUNK_SIZE, // chunking that occurs in buffer
  75. pCompressedSize, // result size
  76. WorkSpace); // used by rtl routines
  77. if (NtStatus == STATUS_BUFFER_TOO_SMALL) {
  78. WStatus = ERROR_MORE_DATA;
  79. goto out;
  80. } else if (NtStatus == STATUS_BUFFER_ALL_ZEROS) {
  81. //
  82. // STATUS_BUFFER_ALL_ZEROS means the compression worked without a hitch
  83. // and in addition the input buffer was all zeros.
  84. //
  85. NtStatus = STATUS_SUCCESS;
  86. }
  87. WStatus = FrsSetLastNTError(NtStatus);
  88. if (!WIN_SUCCESS(WStatus)) {
  89. *pCompressedSize = 0;
  90. DPRINT1(0,"ERROR compressing data. NtStatus = 0x%x\n", NtStatus);
  91. goto out;
  92. }
  93. WStatus = ERROR_SUCCESS;
  94. out:
  95. FrsFree(WorkSpace);
  96. return WStatus;
  97. }
  98. DWORD
  99. FrsLZNT1DecompressBuffer(
  100. OUT PUCHAR DecompressedBuf,
  101. IN DWORD DecompressedBufLen,
  102. IN PUCHAR CompressedBuf,
  103. IN DWORD CompressedBufLen,
  104. OUT DWORD *pDecompressedSize,
  105. OUT DWORD *pBytesProcessed,
  106. OUT PVOID *pDecompressContext
  107. )
  108. /*++
  109. Routine Description:
  110. Decompression routine for default compression format.
  111. COMPRESSION_FORMAT_LZNT1
  112. Arguments:
  113. DecompressedBuf : Resultant decompressed buffer.
  114. DecompressedBufLen : Max size of decompressed buffer.
  115. CompressedBuf : Input buffer.
  116. CompressedBufLen : Input buffer length.
  117. pDecompressedSize : Size of decompressed buffer.
  118. pBytesProcessed : Total bytes processed (could be over multiple calls to this function)
  119. pDecompressContext : Decompress context returned if multiple calls are needed to
  120. decompress this buffer. Valid context is returned when ERROR_MORE_DATA
  121. is returned.
  122. Return Value:
  123. Win Status
  124. --*/
  125. {
  126. #undef DEBSUB
  127. #define DEBSUB "FrsLZNT1DecompressBuffer:"
  128. DWORD WStatus = ERROR_SUCCESS;
  129. DWORD NtStatus;
  130. DWORD CompressedBufIndex = 0;
  131. DWORD CompressedBufStart = 0;
  132. DWORD CompressedBufEnd = 0;
  133. DWORD NoOfChunks = 0;
  134. FRS_COMPRESSED_CHUNK_HEADER ChunkHeader;
  135. *pDecompressedSize = 0;
  136. if (CompressedBuf == NULL ||
  137. CompressedBufLen == 0) {
  138. WStatus = ERROR_INVALID_PARAMETER;
  139. goto out;
  140. }
  141. if (DecompressedBuf == NULL ||
  142. DecompressedBufLen < FRS_MAX_CHUNKS_TO_DECOMPRESS * FRS_UNCOMPRESSED_CHUNK_SIZE) {
  143. //
  144. // At this point we don't know how much the data will grow when it is
  145. // decompressed. We don't have to return it all at once. Ask the
  146. // caller to allocate 64k and then he can make multiple calls
  147. // if the decompressed data does not fit in 64K buffer.
  148. //
  149. *pDecompressedSize = FRS_MAX_CHUNKS_TO_DECOMPRESS * FRS_UNCOMPRESSED_CHUNK_SIZE;
  150. *pBytesProcessed = 0;
  151. *pDecompressContext = FrsAlloc(sizeof(FRS_DECOMPRESS_CONTEXT));
  152. ((PFRS_DECOMPRESS_CONTEXT)(*pDecompressContext))->BytesProcessed;
  153. WStatus = ERROR_MORE_DATA;
  154. goto out;
  155. }
  156. if (*pDecompressContext != NULL) {
  157. CompressedBufIndex = ((PFRS_DECOMPRESS_CONTEXT)(*pDecompressContext))->BytesProcessed;
  158. if (CompressedBufIndex>= CompressedBufLen) {
  159. WStatus = ERROR_INVALID_PARAMETER;
  160. goto out;
  161. }
  162. }
  163. //
  164. // We start deoompressing the buffer from the start if either no context is passed
  165. // or the index in the context is zero. If this is not the case then we want to
  166. // start processing the buffer where we left off last time.
  167. //
  168. CompressedBufStart = CompressedBufIndex;
  169. while ((CompressedBufIndex <= CompressedBufLen) &&
  170. (NoOfChunks < FRS_MAX_CHUNKS_TO_DECOMPRESS)){
  171. if (CompressedBufIndex + sizeof(FRS_COMPRESSED_CHUNK_HEADER) > CompressedBufLen) {
  172. CompressedBufEnd = CompressedBufIndex;
  173. break;
  174. }
  175. CopyMemory(&ChunkHeader, CompressedBuf + CompressedBufIndex,sizeof(FRS_COMPRESSED_CHUNK_HEADER));
  176. ++NoOfChunks;
  177. CompressedBufEnd = CompressedBufIndex;
  178. CompressedBufIndex+=ChunkHeader.Chunk.CompressedChunkSizeMinus3+3;
  179. }
  180. if (CompressedBufStart == CompressedBufEnd) {
  181. //
  182. // The data left to process in the input buffer is less than 1 chunk.
  183. //
  184. *pBytesProcessed = CompressedBufEnd;
  185. WStatus = ERROR_SUCCESS;
  186. goto out;
  187. }
  188. NtStatus = RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, // decompression engine
  189. DecompressedBuf, // output
  190. DecompressedBufLen, // length of output
  191. CompressedBuf + CompressedBufStart, // input
  192. CompressedBufEnd - CompressedBufStart, // length of input
  193. pDecompressedSize); // result size
  194. WStatus = FrsSetLastNTError(NtStatus);
  195. if (!WIN_SUCCESS(WStatus)) {
  196. DPRINT2(0,"Error decompressing. NtStatus = 0x%x. DeCompressedSize = 0x%x\n", NtStatus, *pDecompressedSize);
  197. goto out;
  198. }
  199. //
  200. // If we maxed out the number of chunks that can be decompressed at 1 time then
  201. // we have some more compressed data in this buffer left to decompress. Pass the
  202. // conext back to caller and return ERROR_MORE_DATA. The caller will make this call
  203. // again to get the next set of decompressed data.
  204. //
  205. *pBytesProcessed = CompressedBufEnd;
  206. if (NoOfChunks >= FRS_MAX_CHUNKS_TO_DECOMPRESS) {
  207. if (*pDecompressContext == NULL) {
  208. *pDecompressContext = FrsAlloc(sizeof(FRS_DECOMPRESS_CONTEXT));
  209. }
  210. ((PFRS_DECOMPRESS_CONTEXT)(*pDecompressContext))->BytesProcessed = CompressedBufEnd;
  211. WStatus = ERROR_MORE_DATA;
  212. goto out;
  213. }
  214. WStatus = ERROR_SUCCESS;
  215. out:
  216. return WStatus;
  217. }
  218. PVOID
  219. FrsLZNT1FreeDecompressContext(
  220. IN PVOID *pDecompressContext
  221. )
  222. /*++
  223. Routine Description:
  224. Frees the decompresscontext.
  225. Arguments:
  226. pDecompressContext : Decompress context to free.
  227. Return Value:
  228. Win Status
  229. --*/
  230. {
  231. #undef DEBSUB
  232. #define DEBSUB "FrsLZNT1FreeDecompressContext:"
  233. if (pDecompressContext == NULL) {
  234. return NULL;
  235. }
  236. return FrsFree(*pDecompressContext);
  237. }
  238. DWORD
  239. FrsGetCompressionRoutine(
  240. IN PWCHAR FileName,
  241. IN HANDLE FileHandle,
  242. OUT DWORD (**ppFrsCompressBuffer)(IN UnCompressedBuf, IN UnCompressedBufLen,
  243. OUT CompressedBuf, IN CompressedBufLen, OUT pCompressedSize),
  244. OUT GUID *pCompressionFormatGuid
  245. )
  246. /*++
  247. Routine Description:
  248. Find the appropriate routine to compress the file.
  249. Arguments:
  250. FileName : Name of the file to compress.
  251. pFrsCompressBuf : Address of Function pointer to the selected compression routine,
  252. Return Value:
  253. Win Status
  254. --*/
  255. {
  256. #undef DEBSUB
  257. #define DEBSUB "FrsGetCompressionRoutine:"
  258. if (DisableCompressionStageFiles) {
  259. *ppFrsCompressBuffer = NULL;
  260. ZeroMemory(pCompressionFormatGuid, sizeof(GUID));
  261. return ERROR_SUCCESS;
  262. }
  263. *ppFrsCompressBuffer = FrsLZNT1CompressBuffer;
  264. COPY_GUID(pCompressionFormatGuid, &FrsGuidCompressionFormatLZNT1);
  265. return ERROR_SUCCESS;
  266. }
  267. DWORD
  268. FrsGetDecompressionRoutine(
  269. IN PCHANGE_ORDER_COMMAND Coc,
  270. IN PSTAGE_HEADER Header,
  271. OUT DWORD (**ppFrsDecompressBuffer)(OUT DecompressedBuf, IN DecompressedBufLen, IN CompressedBuf, IN CompressedBufLen, OUT DecompressedSize, OUT BytesProcessed),
  272. OUT PVOID (**ppFrsFreeDecompressContext)(IN pDecompressContext)
  273. )
  274. /*++
  275. Routine Description:
  276. Find the appropriate routine to decompress the file.
  277. Arguments:
  278. Coc : Change order command.
  279. StageHeader : Stage header read from the compressed staging file.
  280. ppFrsDecompressBuffer : Function pointer to the decompression api.
  281. ppFrsFreeDecompressContext : Function pointer to the api used to free
  282. the decompress context.
  283. Return Value:
  284. Win Status
  285. --*/
  286. {
  287. #undef DEBSUB
  288. #define DEBSUB "FrsGetDecompressionRoutine:"
  289. if (IS_GUID_ZERO(&Header->CompressionGuid)) {
  290. *ppFrsDecompressBuffer = NULL;
  291. *ppFrsFreeDecompressContext = NULL;
  292. return ERROR_SUCCESS;
  293. }
  294. *ppFrsDecompressBuffer = FrsLZNT1DecompressBuffer;
  295. *ppFrsFreeDecompressContext = FrsLZNT1FreeDecompressContext;
  296. return ERROR_SUCCESS;
  297. }
  298. DWORD
  299. FrsGetDecompressionRoutineByGuid(
  300. IN GUID *CompressionFormatGuid,
  301. OUT DWORD (**ppFrsDecompressBuffer)(OUT DecompressedBuf, IN DecompressedBufLen, IN CompressedBuf, IN CompressedBufLen, OUT DecompressedSize, OUT BytesProcessed),
  302. OUT PVOID (**ppFrsFreeDecompressContext)(IN pDecompressContext)
  303. )
  304. /*++
  305. Routine Description:
  306. Find the appropriate routine to decompress the file using the guid.
  307. Arguments:
  308. CompressionFormatGuid : Guid for the compression format.
  309. ppFrsDecompressBuffer : Function pointer to the decompression api.
  310. ppFrsFreeDecompressContext : Function pointer to the api used to free
  311. the decompress context.
  312. Return Value:
  313. Win Status
  314. --*/
  315. {
  316. #undef DEBSUB
  317. #define DEBSUB "FrsGetDecompressionRoutineByGuid:"
  318. if (IS_GUID_ZERO(CompressionFormatGuid)) {
  319. *ppFrsDecompressBuffer = NULL;
  320. *ppFrsFreeDecompressContext = NULL;
  321. return ERROR_SUCCESS;
  322. }
  323. *ppFrsDecompressBuffer = FrsLZNT1DecompressBuffer;
  324. *ppFrsFreeDecompressContext = FrsLZNT1FreeDecompressContext;
  325. return ERROR_SUCCESS;
  326. }