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.

420 lines
13 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 > CompressedBufLen - sizeof(FRS_COMPRESSED_CHUNK_HEADER)) {
  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. //
  198. // We don't want to abort this CO just because the was a decompression
  199. // error. That error could have been caused by a corruption of the
  200. // staging file, which we can recover. Unfortunately the NTStatus
  201. // STATUS_BAD_COMPRESSION_BUFFER gets mapped to the more generic Win32
  202. // error ERROR_MR_MID_NOT_FOUND. We can't make that a retriable error
  203. // so let's just return ERROR_RETRY here.
  204. //
  205. WStatus = ERROR_RETRY;
  206. goto out;
  207. }
  208. //
  209. // If we maxed out the number of chunks that can be decompressed at 1 time then
  210. // we have some more compressed data in this buffer left to decompress. Pass the
  211. // conext back to caller and return ERROR_MORE_DATA. The caller will make this call
  212. // again to get the next set of decompressed data.
  213. //
  214. *pBytesProcessed = CompressedBufEnd;
  215. if (NoOfChunks >= FRS_MAX_CHUNKS_TO_DECOMPRESS) {
  216. if (*pDecompressContext == NULL) {
  217. *pDecompressContext = FrsAlloc(sizeof(FRS_DECOMPRESS_CONTEXT));
  218. }
  219. ((PFRS_DECOMPRESS_CONTEXT)(*pDecompressContext))->BytesProcessed = CompressedBufEnd;
  220. WStatus = ERROR_MORE_DATA;
  221. goto out;
  222. }
  223. WStatus = ERROR_SUCCESS;
  224. out:
  225. return WStatus;
  226. }
  227. PVOID
  228. FrsLZNT1FreeDecompressContext(
  229. IN PVOID *pDecompressContext
  230. )
  231. /*++
  232. Routine Description:
  233. Frees the decompresscontext.
  234. Arguments:
  235. pDecompressContext : Decompress context to free.
  236. Return Value:
  237. NULL ptr
  238. --*/
  239. {
  240. #undef DEBSUB
  241. #define DEBSUB "FrsLZNT1FreeDecompressContext:"
  242. if (pDecompressContext == NULL) {
  243. return NULL;
  244. }
  245. return FrsFree(*pDecompressContext);
  246. }
  247. DWORD
  248. FrsGetCompressionRoutine(
  249. IN PWCHAR FileName,
  250. IN HANDLE FileHandle,
  251. OUT PFRS_COMPRESS_BUFFER *ppFrsCompressBuffer,
  252. //OUT DWORD (**ppFrsCompressBuffer)(IN UnCompressedBuf, IN UnCompressedBufLen,
  253. // OUT CompressedBuf, IN CompressedBufLen, OUT pCompressedSize),
  254. OUT GUID *pCompressionFormatGuid
  255. )
  256. /*++
  257. Routine Description:
  258. Find the appropriate routine to compress the file.
  259. Arguments:
  260. FileName : Name of the file to compress.
  261. pFrsCompressBuf : Address of Function pointer to the selected compression routine,
  262. Return Value:
  263. Win Status
  264. --*/
  265. {
  266. #undef DEBSUB
  267. #define DEBSUB "FrsGetCompressionRoutine:"
  268. if (DisableCompressionStageFiles) {
  269. *ppFrsCompressBuffer = NULL;
  270. ZeroMemory(pCompressionFormatGuid, sizeof(GUID));
  271. return ERROR_SUCCESS;
  272. }
  273. *ppFrsCompressBuffer = FrsLZNT1CompressBuffer;
  274. COPY_GUID(pCompressionFormatGuid, &FrsGuidCompressionFormatLZNT1);
  275. return ERROR_SUCCESS;
  276. }
  277. DWORD
  278. FrsGetDecompressionRoutine(
  279. IN PCHANGE_ORDER_COMMAND Coc,
  280. IN PSTAGE_HEADER Header,
  281. OUT PFRS_DECOMPRESS_BUFFER *ppFrsDecompressBuffer,
  282. OUT PFRS_FREE_DECOMPRESS_BUFFER *ppFrsFreeDecompressContext
  283. //OUT DWORD (**ppFrsDecompressBuffer)(OUT DecompressedBuf, IN DecompressedBufLen, IN CompressedBuf, IN CompressedBufLen, OUT DecompressedSize, OUT BytesProcessed),
  284. //OUT PVOID (**ppFrsFreeDecompressContext)(IN pDecompressContext)
  285. )
  286. /*++
  287. Routine Description:
  288. Find the appropriate routine to decompress the file.
  289. Arguments:
  290. Coc : Change order command.
  291. StageHeader : Stage header read from the compressed staging file.
  292. ppFrsDecompressBuffer : Function pointer to the decompression api.
  293. ppFrsFreeDecompressContext : Function pointer to the api used to free
  294. the decompress context.
  295. Return Value:
  296. Win Status
  297. --*/
  298. {
  299. #undef DEBSUB
  300. #define DEBSUB "FrsGetDecompressionRoutine:"
  301. if (IS_GUID_ZERO(&Header->CompressionGuid)) {
  302. *ppFrsDecompressBuffer = NULL;
  303. *ppFrsFreeDecompressContext = NULL;
  304. return ERROR_SUCCESS;
  305. }
  306. *ppFrsDecompressBuffer = FrsLZNT1DecompressBuffer;
  307. *ppFrsFreeDecompressContext = FrsLZNT1FreeDecompressContext;
  308. return ERROR_SUCCESS;
  309. }
  310. DWORD
  311. FrsGetDecompressionRoutineByGuid(
  312. IN GUID *CompressionFormatGuid,
  313. OUT PFRS_DECOMPRESS_BUFFER *ppFrsDecompressBuffer,
  314. OUT PFRS_FREE_DECOMPRESS_BUFFER *ppFrsFreeDecompressContext
  315. //OUT DWORD (**ppFrsDecompressBuffer)(OUT DecompressedBuf, IN DecompressedBufLen, IN CompressedBuf, IN CompressedBufLen, OUT DecompressedSize, OUT BytesProcessed),
  316. //OUT PVOID (**ppFrsFreeDecompressContext)(IN pDecompressContext)
  317. )
  318. /*++
  319. Routine Description:
  320. Find the appropriate routine to decompress the file using the guid.
  321. Arguments:
  322. CompressionFormatGuid : Guid for the compression format.
  323. ppFrsDecompressBuffer : Function pointer to the decompression api.
  324. ppFrsFreeDecompressContext : Function pointer to the api used to free
  325. the decompress context.
  326. Return Value:
  327. Win Status
  328. --*/
  329. {
  330. #undef DEBSUB
  331. #define DEBSUB "FrsGetDecompressionRoutineByGuid:"
  332. if (IS_GUID_ZERO(CompressionFormatGuid)) {
  333. *ppFrsDecompressBuffer = NULL;
  334. *ppFrsFreeDecompressContext = NULL;
  335. return ERROR_SUCCESS;
  336. }
  337. *ppFrsDecompressBuffer = FrsLZNT1DecompressBuffer;
  338. *ppFrsFreeDecompressContext = FrsLZNT1FreeDecompressContext;
  339. return ERROR_SUCCESS;
  340. }