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
420 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
compress.c
|
|
|
|
Abstract:
|
|
|
|
This module implements staging support routines for FRS
|
|
|
|
Author:
|
|
|
|
Sudarshan Chitre 26-Apr-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <ntreppch.h>
|
|
#pragma hdrstop
|
|
|
|
|
|
#include <frs.h>
|
|
|
|
//
|
|
// Guids for compression formats that are supported by the service.
|
|
//
|
|
|
|
extern GUID FrsGuidCompressionFormatNone;
|
|
extern GUID FrsGuidCompressionFormatLZNT1;
|
|
extern BOOL DisableCompressionStageFiles;
|
|
|
|
DWORD
|
|
FrsLZNT1CompressBuffer(
|
|
IN PUCHAR UnCompressedBuf,
|
|
IN DWORD UnCompressedBufLen,
|
|
OUT PUCHAR CompressedBuf,
|
|
IN DWORD CompressedBufLen,
|
|
OUT DWORD *pCompressedSize
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Compression routine for default compression format.
|
|
COMPRESSION_FORMAT_LZNT1
|
|
|
|
Arguments:
|
|
UnCompressedBuf : Source buffer.
|
|
UnCompressedBufLen : Length of source buffer.
|
|
CompressedBuf : Resultant compressed buffer.
|
|
CompressedBufLen : Length of compressed buffer supplied.
|
|
CompressedSize : Actual size of the compressed data.
|
|
|
|
Return Value:
|
|
Win Status
|
|
--*/
|
|
{
|
|
#undef DEBSUB
|
|
#define DEBSUB "FrsLZNT1CompressBuffer:"
|
|
|
|
DWORD WStatus = ERROR_SUCCESS;
|
|
DWORD NtStatus;
|
|
PVOID WorkSpace = NULL;
|
|
DWORD WorkSpaceSize = 0;
|
|
DWORD FragmentWorkSpaceSize = 0;
|
|
|
|
*pCompressedSize = 0;
|
|
|
|
if (UnCompressedBuf == NULL ||
|
|
UnCompressedBufLen == 0) {
|
|
|
|
WStatus = ERROR_INVALID_PARAMETER;
|
|
goto out;
|
|
}
|
|
|
|
if (CompressedBuf == NULL ||
|
|
CompressedBufLen == 0) {
|
|
|
|
WStatus = ERROR_MORE_DATA;
|
|
goto out;
|
|
}
|
|
|
|
*pCompressedSize = 0;
|
|
|
|
NtStatus = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1,
|
|
&WorkSpaceSize,
|
|
&FragmentWorkSpaceSize);
|
|
|
|
WStatus = FrsSetLastNTError(NtStatus);
|
|
|
|
if (!WIN_SUCCESS(WStatus)) {
|
|
goto out;
|
|
}
|
|
|
|
WorkSpace = FrsAlloc(WorkSpaceSize);
|
|
|
|
NtStatus = RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, // compression engine
|
|
UnCompressedBuf, // input
|
|
UnCompressedBufLen, // length of input
|
|
CompressedBuf, // output
|
|
CompressedBufLen, // length of output
|
|
FRS_UNCOMPRESSED_CHUNK_SIZE, // chunking that occurs in buffer
|
|
pCompressedSize, // result size
|
|
WorkSpace); // used by rtl routines
|
|
|
|
if (NtStatus == STATUS_BUFFER_TOO_SMALL) {
|
|
|
|
WStatus = ERROR_MORE_DATA;
|
|
goto out;
|
|
} else if (NtStatus == STATUS_BUFFER_ALL_ZEROS) {
|
|
//
|
|
// STATUS_BUFFER_ALL_ZEROS means the compression worked without a hitch
|
|
// and in addition the input buffer was all zeros.
|
|
//
|
|
NtStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
WStatus = FrsSetLastNTError(NtStatus);
|
|
|
|
if (!WIN_SUCCESS(WStatus)) {
|
|
*pCompressedSize = 0;
|
|
DPRINT1(0,"ERROR compressing data. NtStatus = 0x%x\n", NtStatus);
|
|
goto out;
|
|
}
|
|
|
|
WStatus = ERROR_SUCCESS;
|
|
|
|
out:
|
|
FrsFree(WorkSpace);
|
|
return WStatus;
|
|
}
|
|
|
|
DWORD
|
|
FrsLZNT1DecompressBuffer(
|
|
OUT PUCHAR DecompressedBuf,
|
|
IN DWORD DecompressedBufLen,
|
|
IN PUCHAR CompressedBuf,
|
|
IN DWORD CompressedBufLen,
|
|
OUT DWORD *pDecompressedSize,
|
|
OUT DWORD *pBytesProcessed,
|
|
OUT PVOID *pDecompressContext
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Decompression routine for default compression format.
|
|
COMPRESSION_FORMAT_LZNT1
|
|
|
|
Arguments:
|
|
DecompressedBuf : Resultant decompressed buffer.
|
|
DecompressedBufLen : Max size of decompressed buffer.
|
|
CompressedBuf : Input buffer.
|
|
CompressedBufLen : Input buffer length.
|
|
pDecompressedSize : Size of decompressed buffer.
|
|
pBytesProcessed : Total bytes processed (could be over multiple calls to this function)
|
|
pDecompressContext : Decompress context returned if multiple calls are needed to
|
|
decompress this buffer. Valid context is returned when ERROR_MORE_DATA
|
|
is returned.
|
|
|
|
Return Value:
|
|
Win Status
|
|
--*/
|
|
{
|
|
#undef DEBSUB
|
|
#define DEBSUB "FrsLZNT1DecompressBuffer:"
|
|
|
|
DWORD WStatus = ERROR_SUCCESS;
|
|
DWORD NtStatus;
|
|
DWORD CompressedBufIndex = 0;
|
|
DWORD CompressedBufStart = 0;
|
|
DWORD CompressedBufEnd = 0;
|
|
DWORD NoOfChunks = 0;
|
|
FRS_COMPRESSED_CHUNK_HEADER ChunkHeader;
|
|
|
|
*pDecompressedSize = 0;
|
|
|
|
if (CompressedBuf == NULL ||
|
|
CompressedBufLen == 0) {
|
|
WStatus = ERROR_INVALID_PARAMETER;
|
|
goto out;
|
|
}
|
|
|
|
if (DecompressedBuf == NULL ||
|
|
DecompressedBufLen < FRS_MAX_CHUNKS_TO_DECOMPRESS * FRS_UNCOMPRESSED_CHUNK_SIZE) {
|
|
//
|
|
// At this point we don't know how much the data will grow when it is
|
|
// decompressed. We don't have to return it all at once. Ask the
|
|
// caller to allocate 64k and then he can make multiple calls
|
|
// if the decompressed data does not fit in 64K buffer.
|
|
//
|
|
*pDecompressedSize = FRS_MAX_CHUNKS_TO_DECOMPRESS * FRS_UNCOMPRESSED_CHUNK_SIZE;
|
|
*pBytesProcessed = 0;
|
|
*pDecompressContext = FrsAlloc(sizeof(FRS_DECOMPRESS_CONTEXT));
|
|
((PFRS_DECOMPRESS_CONTEXT)(*pDecompressContext))->BytesProcessed;
|
|
WStatus = ERROR_MORE_DATA;
|
|
goto out;
|
|
}
|
|
|
|
if (*pDecompressContext != NULL) {
|
|
CompressedBufIndex = ((PFRS_DECOMPRESS_CONTEXT)(*pDecompressContext))->BytesProcessed;
|
|
if (CompressedBufIndex>= CompressedBufLen) {
|
|
WStatus = ERROR_INVALID_PARAMETER;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We start deoompressing the buffer from the start if either no context is passed
|
|
// or the index in the context is zero. If this is not the case then we want to
|
|
// start processing the buffer where we left off last time.
|
|
//
|
|
CompressedBufStart = CompressedBufIndex;
|
|
|
|
while ((CompressedBufIndex <= CompressedBufLen) &&
|
|
(NoOfChunks < FRS_MAX_CHUNKS_TO_DECOMPRESS)){
|
|
|
|
if (CompressedBufIndex > CompressedBufLen - sizeof(FRS_COMPRESSED_CHUNK_HEADER)) {
|
|
CompressedBufEnd = CompressedBufIndex;
|
|
break;
|
|
}
|
|
|
|
CopyMemory(&ChunkHeader, CompressedBuf + CompressedBufIndex,sizeof(FRS_COMPRESSED_CHUNK_HEADER));
|
|
++NoOfChunks;
|
|
CompressedBufEnd = CompressedBufIndex;
|
|
CompressedBufIndex+=ChunkHeader.Chunk.CompressedChunkSizeMinus3+3;
|
|
}
|
|
|
|
if (CompressedBufStart == CompressedBufEnd) {
|
|
//
|
|
// The data left to process in the input buffer is less than 1 chunk.
|
|
//
|
|
*pBytesProcessed = CompressedBufEnd;
|
|
WStatus = ERROR_SUCCESS;
|
|
goto out;
|
|
}
|
|
|
|
NtStatus = RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, // decompression engine
|
|
DecompressedBuf, // output
|
|
DecompressedBufLen, // length of output
|
|
CompressedBuf + CompressedBufStart, // input
|
|
CompressedBufEnd - CompressedBufStart, // length of input
|
|
pDecompressedSize); // result size
|
|
|
|
WStatus = FrsSetLastNTError(NtStatus);
|
|
|
|
if (!WIN_SUCCESS(WStatus)) {
|
|
DPRINT2(0,"Error decompressing. NtStatus = 0x%x. DeCompressedSize = 0x%x\n", NtStatus, *pDecompressedSize);
|
|
|
|
//
|
|
// We don't want to abort this CO just because the was a decompression
|
|
// error. That error could have been caused by a corruption of the
|
|
// staging file, which we can recover. Unfortunately the NTStatus
|
|
// STATUS_BAD_COMPRESSION_BUFFER gets mapped to the more generic Win32
|
|
// error ERROR_MR_MID_NOT_FOUND. We can't make that a retriable error
|
|
// so let's just return ERROR_RETRY here.
|
|
//
|
|
WStatus = ERROR_RETRY;
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// If we maxed out the number of chunks that can be decompressed at 1 time then
|
|
// we have some more compressed data in this buffer left to decompress. Pass the
|
|
// conext back to caller and return ERROR_MORE_DATA. The caller will make this call
|
|
// again to get the next set of decompressed data.
|
|
//
|
|
*pBytesProcessed = CompressedBufEnd;
|
|
|
|
if (NoOfChunks >= FRS_MAX_CHUNKS_TO_DECOMPRESS) {
|
|
if (*pDecompressContext == NULL) {
|
|
*pDecompressContext = FrsAlloc(sizeof(FRS_DECOMPRESS_CONTEXT));
|
|
}
|
|
|
|
((PFRS_DECOMPRESS_CONTEXT)(*pDecompressContext))->BytesProcessed = CompressedBufEnd;
|
|
|
|
WStatus = ERROR_MORE_DATA;
|
|
goto out;
|
|
}
|
|
|
|
|
|
WStatus = ERROR_SUCCESS;
|
|
out:
|
|
return WStatus;
|
|
|
|
}
|
|
|
|
PVOID
|
|
FrsLZNT1FreeDecompressContext(
|
|
IN PVOID *pDecompressContext
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Frees the decompresscontext.
|
|
|
|
Arguments:
|
|
pDecompressContext : Decompress context to free.
|
|
|
|
Return Value:
|
|
NULL ptr
|
|
--*/
|
|
{
|
|
#undef DEBSUB
|
|
#define DEBSUB "FrsLZNT1FreeDecompressContext:"
|
|
|
|
if (pDecompressContext == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
return FrsFree(*pDecompressContext);
|
|
}
|
|
|
|
DWORD
|
|
FrsGetCompressionRoutine(
|
|
IN PWCHAR FileName,
|
|
IN HANDLE FileHandle,
|
|
OUT PFRS_COMPRESS_BUFFER *ppFrsCompressBuffer,
|
|
//OUT DWORD (**ppFrsCompressBuffer)(IN UnCompressedBuf, IN UnCompressedBufLen,
|
|
// OUT CompressedBuf, IN CompressedBufLen, OUT pCompressedSize),
|
|
OUT GUID *pCompressionFormatGuid
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Find the appropriate routine to compress the file.
|
|
|
|
Arguments:
|
|
FileName : Name of the file to compress.
|
|
pFrsCompressBuf : Address of Function pointer to the selected compression routine,
|
|
|
|
Return Value:
|
|
Win Status
|
|
--*/
|
|
{
|
|
#undef DEBSUB
|
|
#define DEBSUB "FrsGetCompressionRoutine:"
|
|
|
|
if (DisableCompressionStageFiles) {
|
|
*ppFrsCompressBuffer = NULL;
|
|
ZeroMemory(pCompressionFormatGuid, sizeof(GUID));
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
*ppFrsCompressBuffer = FrsLZNT1CompressBuffer;
|
|
COPY_GUID(pCompressionFormatGuid, &FrsGuidCompressionFormatLZNT1);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
FrsGetDecompressionRoutine(
|
|
IN PCHANGE_ORDER_COMMAND Coc,
|
|
IN PSTAGE_HEADER Header,
|
|
OUT PFRS_DECOMPRESS_BUFFER *ppFrsDecompressBuffer,
|
|
OUT PFRS_FREE_DECOMPRESS_BUFFER *ppFrsFreeDecompressContext
|
|
//OUT DWORD (**ppFrsDecompressBuffer)(OUT DecompressedBuf, IN DecompressedBufLen, IN CompressedBuf, IN CompressedBufLen, OUT DecompressedSize, OUT BytesProcessed),
|
|
//OUT PVOID (**ppFrsFreeDecompressContext)(IN pDecompressContext)
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Find the appropriate routine to decompress the file.
|
|
|
|
Arguments:
|
|
Coc : Change order command.
|
|
StageHeader : Stage header read from the compressed staging file.
|
|
ppFrsDecompressBuffer : Function pointer to the decompression api.
|
|
ppFrsFreeDecompressContext : Function pointer to the api used to free
|
|
the decompress context.
|
|
|
|
Return Value:
|
|
Win Status
|
|
--*/
|
|
{
|
|
#undef DEBSUB
|
|
#define DEBSUB "FrsGetDecompressionRoutine:"
|
|
|
|
if (IS_GUID_ZERO(&Header->CompressionGuid)) {
|
|
*ppFrsDecompressBuffer = NULL;
|
|
*ppFrsFreeDecompressContext = NULL;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
*ppFrsDecompressBuffer = FrsLZNT1DecompressBuffer;
|
|
*ppFrsFreeDecompressContext = FrsLZNT1FreeDecompressContext;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
FrsGetDecompressionRoutineByGuid(
|
|
IN GUID *CompressionFormatGuid,
|
|
OUT PFRS_DECOMPRESS_BUFFER *ppFrsDecompressBuffer,
|
|
OUT PFRS_FREE_DECOMPRESS_BUFFER *ppFrsFreeDecompressContext
|
|
//OUT DWORD (**ppFrsDecompressBuffer)(OUT DecompressedBuf, IN DecompressedBufLen, IN CompressedBuf, IN CompressedBufLen, OUT DecompressedSize, OUT BytesProcessed),
|
|
//OUT PVOID (**ppFrsFreeDecompressContext)(IN pDecompressContext)
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Find the appropriate routine to decompress the file using the guid.
|
|
|
|
Arguments:
|
|
CompressionFormatGuid : Guid for the compression format.
|
|
ppFrsDecompressBuffer : Function pointer to the decompression api.
|
|
ppFrsFreeDecompressContext : Function pointer to the api used to free
|
|
the decompress context.
|
|
|
|
Return Value:
|
|
Win Status
|
|
--*/
|
|
{
|
|
#undef DEBSUB
|
|
#define DEBSUB "FrsGetDecompressionRoutineByGuid:"
|
|
|
|
if (IS_GUID_ZERO(CompressionFormatGuid)) {
|
|
*ppFrsDecompressBuffer = NULL;
|
|
*ppFrsFreeDecompressContext = NULL;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
*ppFrsDecompressBuffer = FrsLZNT1DecompressBuffer;
|
|
*ppFrsFreeDecompressContext = FrsLZNT1FreeDecompressContext;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|