[PATCHES] MSZIP support for cabinet files

Jeremy Allison jra at samba.org
Wed Jun 28 00:36:12 UTC 2017


On Tue, Jun 27, 2017 at 05:59:49PM +0200, Günther Deschner via samba-technical wrote:
> Hi,
> 
> attached some patches (mostly from Aurelien) that add MSZIP compression
> support to our cabinet file marshalling code. This work is one of the
> prerequisites for the future MS-PAR protocol support.
> 
> Please review & push.

I'm a bit scared of integer wrap (see some below). Can you
convince me it's safe ?

:-) :-).

Cheers,

	Jeremy.

> +static enum ndr_err_code ndr_push_folder_cfdata(struct ndr_push *ndr,
> +						const struct CFDATA *r,
> +						enum cf_compress_type cab_ctype,
> +						size_t num_cfdata)
> +{
> +	size_t i;
> +	enum ndr_compression_alg ndr_ctype = 0;
> +
> +	ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
> +
> +	if (cab_ctype == CF_COMPRESS_MSZIP) {
> +		ndr_ctype = NDR_COMPRESSION_MSZIP_CAB;
> +		NDR_CHECK(ndr_push_compression_state_init(ndr, ndr_ctype, &ndr->cstate));
> +	}
> +
> +	for (i = 0; i < num_cfdata; i++, r++) {
> +		uint32_t compressed_offset, compressed_length = 0;
> +		uint32_t csum, csum_offset;
> +		uint32_t csumPartial;
> +
> +		/*
> +		 * checksum is a function of the size fields
> +		 * and the potentially compressed data bytes,
> +		 * which haven't been compressed yet so
> +		 * remember offset, write zeroes, fill out
> +		 * later
> +		 */
> +		csum_offset = ndr->offset;
> +		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
> +
> +		/*
> +		 * similarly, we don't know the compressed
> +		 * size yet, remember offset, write zeros,
> +		 * fill out later
> +		 */
> +		compressed_offset = ndr->offset;
> +		NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
> +		NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->cbUncomp));
> +
> +
> +		switch (cab_ctype) {
> +		case CF_COMPRESS_NONE:
> +			/* just copy the data */
> +			NDR_CHECK(ndr_push_bytes(ndr, r->ab.data, r->ab.length));
> +			compressed_length = r->cbUncomp;
> +
> +			break;
> +
> +		case CF_COMPRESS_LZX:
> +			/*
> +			 * we have not yet worked out the details of LZX
> +			 * compression
> +			 */
> +			return NDR_ERR_COMPRESSION;
> +
> +		case CF_COMPRESS_MSZIP: {
> +			struct ndr_push *push_sub, *push_compress;
> +
> +			/* compress via subcontext */
> +			NDR_CHECK(ndr_push_subcontext_start(ndr, &push_sub, 0, -1));
> +			push_sub->cstate = ndr->cstate;
> +			NDR_CHECK(ndr_push_compression_start(push_sub, &push_compress, ndr_ctype, -1));
> +			ndr_set_flags(&push_compress->flags, LIBNDR_FLAG_REMAINING);
> +			NDR_CHECK(ndr_push_DATA_BLOB(push_compress, NDR_SCALARS, r->ab));
> +			NDR_CHECK(ndr_push_compression_end(push_sub, push_compress, ndr_ctype, -1));
> +			NDR_CHECK(ndr_push_subcontext_end(ndr, push_sub, 0, -1));
> +			compressed_length = push_sub->offset;
> +
> +			break;
> +			}
> +		default:
> +			return NDR_ERR_BAD_SWITCH;
> +		}
> +
> +		/* we can now write the compressed size and the checksum */
> +		SSVAL(ndr->data, compressed_offset, compressed_length);
> +
> +		/*
> +		 * Checksum over compressed data.
> +		 *
> +		 * The 8 bytes are the header size.
> +		 */
> +
> +		csumPartial = ndr_cab_compute_checksum(&ndr->data[csum_offset + 8],

                                                                 ^^^^^^^^^^^^^^^^
                                                                 Integer wrap checks ?
Didn't cnum_offset come from the client ?

> +						       compressed_length, 0);
> +
> +		/*
> +		 * Checksum over header (compressed and uncompressed length).
> +		 *
> +		 * The first 4 bytes are the checksum size.
> +		 * The second 4 bytes are the size of the compressed and
> +		 * uncompressed length fields.
> +		 */
> +		csum = ndr_cab_compute_checksum(&ndr->data[csum_offset + 4],
                                                                 ^^^^^^^^^^^^^^^^
                                                                 Integer wrap checks ?
And here also ?

> +						4,
> +						csumPartial);
> +
> +		SIVAL(ndr->data, csum_offset, csum);
> +	}
> +
> +	ndr_push_compression_state_free(ndr->cstate);
> +	ndr->cstate = NULL;
> +
> +	return NDR_ERR_SUCCESS;
> +}
> +
>  _PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, int ndr_flags, const struct cab_file *r)
>  {
>  	uint32_t cntr_cffolders_0;
>  	uint32_t cntr_cffiles_0;
> -	uint32_t cntr_cfdata_0;
> +	uint32_t processed_cfdata = 0;
>  	{
>  		uint32_t _flags_save_STRUCT = ndr->flags;
>  		ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
>  		NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
> +
>  		if (ndr_flags & NDR_SCALARS) {
> -			uint32_t next_offset = 0;
> +			uint32_t i;
>  			NDR_CHECK(ndr_push_align(ndr, 4));
>  			NDR_CHECK(ndr_push_CFHEADER(ndr, NDR_SCALARS, &r->cfheader));
>  			for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (r->cfheader.cFolders); cntr_cffolders_0++) {
>  				NDR_CHECK(ndr_push_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0]));
>  			}
>  			for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (r->cfheader.cFiles); cntr_cffiles_0++) {
> -				uint32_t offset = ndr->offset + 4;
>  				NDR_CHECK(ndr_push_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0]));
> -				if (cntr_cffiles_0 > 0) {
> -					next_offset += r->cffiles[cntr_cffiles_0 - 1].cbFile;
> -				}
> -				SIVAL(ndr->data, offset, next_offset);
>  			}
>  #if 0
>  			NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_count_cfdata(r)));
>  #endif
> -			for (cntr_cfdata_0 = 0; cntr_cfdata_0 < (ndr_count_cfdata(r)); cntr_cfdata_0++) {
> -				NDR_CHECK(ndr_push_CFDATA(ndr, NDR_SCALARS, &r->cfdata[cntr_cfdata_0]));
> +
> +			/* write in the folder header the offset of its first data block */
> +			for (i = 0; i < r->cfheader.cFolders; i++) {
> +				SIVAL(ndr->data, OFFSET_OF_FOLDER_COFFCABSTART(i), ndr->offset);
> +				NDR_CHECK(ndr_push_folder_cfdata(ndr, r->cfdata + processed_cfdata, r->cffolders[i].typeCompress, r->cffolders[i].cCFData));
> +				processed_cfdata += r->cffolders[i].cCFData;
				^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
				Here also ?

>  			}
>  			NDR_CHECK(ndr_push_trailer_align(ndr, 4));
>  		}
> @@ -160,6 +278,79 @@ _PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, int ndr_flags
>  	return NDR_ERR_SUCCESS;
>  }
>  
> +
> +/* Pull all CFDATA of a folder.
> + *
> + * This works on a folder level because compression type is set per
> + * folder, and a compression state can be shared between CFDATA of the
> + * same folder.
> + *
> + * This is not a regular NDR func as we pass the compression type and
> + * the number of CFDATA as extra arguments
> + */
> +static enum ndr_err_code ndr_pull_folder_cfdata(struct ndr_pull *ndr,
> +						struct CFDATA *r,
> +						enum cf_compress_type cab_ctype,
> +						size_t num_cfdata)
> +{
> +	size_t i;
> +	enum ndr_compression_alg ndr_ctype = 0;
> +
> +	if (cab_ctype == CF_COMPRESS_MSZIP) {
> +		ndr_ctype = NDR_COMPRESSION_MSZIP_CAB;
> +		NDR_CHECK(ndr_pull_compression_state_init(ndr, NDR_COMPRESSION_MSZIP_CAB, &ndr->cstate));
> +	}
> +
> +	for (i = 0; i < num_cfdata; i++, r++) {
> +		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->csum));
> +		NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->cbData));
> +		NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->cbUncomp));
> +
> +		switch (cab_ctype) {
> +		case CF_COMPRESS_NONE:
> +			/* just copy the data */
> +			r->ab = data_blob_talloc(ndr->current_mem_ctx,
> +						 ndr->data+ndr->offset,
> +						 r->cbUncomp);
> +			ndr->offset += r->cbUncomp;
> +			break;
> +
> +		case CF_COMPRESS_LZX:
> +			/* just copy the data */
> +			r->ab = data_blob_talloc(ndr->current_mem_ctx,
> +						 ndr->data+ndr->offset,
> +						 r->cbData);
> +			ndr->offset += r->cbData;
> +
> +			break;
> +
> +		case CF_COMPRESS_MSZIP: {
> +			struct ndr_pull *pull_sub, *pull_compress;
> +
> +			/* decompress via subcontext */
> +			NDR_CHECK(ndr_pull_subcontext_start(ndr, &pull_sub, 0, r->cbData));
> +			pull_sub->cstate = ndr->cstate;
> +			NDR_CHECK(ndr_pull_compression_start(pull_sub, &pull_compress,
> +							     ndr_ctype, r->cbUncomp, r->cbData));
> +			ndr_set_flags(&pull_compress->flags, LIBNDR_FLAG_REMAINING);
> +			NDR_CHECK(ndr_pull_DATA_BLOB(pull_compress, NDR_SCALARS, &r->ab));
> +			NDR_CHECK(ndr_pull_compression_end(pull_sub, pull_compress, ndr_ctype, r->cbUncomp));
> +			NDR_CHECK(ndr_pull_subcontext_end(ndr, pull_sub, 0, r->cbData));
> +
> +			break;
> +		}
> +		default:
> +			return NDR_ERR_BAD_SWITCH;
> +		}
> +	}
> +
> +	ndr_pull_compression_state_free(ndr->cstate);
> +	ndr->cstate = NULL;
> +
> +	return NDR_ERR_SUCCESS;
> +}
> +
>  _PUBLIC_ enum ndr_err_code ndr_pull_cab_file(struct ndr_pull *ndr, int ndr_flags, struct cab_file *r)
>  {
>  	uint32_t size_cffolders_0 = 0;
> @@ -169,7 +360,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_cab_file(struct ndr_pull *ndr, int ndr_flags
>  	uint32_t cntr_cffiles_0;
>  	TALLOC_CTX *_mem_save_cffiles_0 = NULL;
>  	uint32_t size_cfdata_0 = 0;
> -	uint32_t cntr_cfdata_0;
> +	uint32_t processed_cfdata = 0;
>  	TALLOC_CTX *_mem_save_cfdata_0 = NULL;
>  	{
>  		uint32_t _flags_save_STRUCT = ndr->flags;
> @@ -203,8 +394,12 @@ _PUBLIC_ enum ndr_err_code ndr_pull_cab_file(struct ndr_pull *ndr, int ndr_flags
>  			NDR_PULL_ALLOC_N(ndr, r->cfdata, size_cfdata_0);
>  			_mem_save_cfdata_0 = NDR_PULL_GET_MEM_CTX(ndr);
>  			NDR_PULL_SET_MEM_CTX(ndr, r->cfdata, 0);
> -			for (cntr_cfdata_0 = 0; cntr_cfdata_0 < (size_cfdata_0); cntr_cfdata_0++) {
> -				NDR_CHECK(ndr_pull_CFDATA(ndr, NDR_SCALARS, &r->cfdata[cntr_cfdata_0]));
> +			for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (size_cffolders_0); cntr_cffolders_0++) {
> +				NDR_CHECK(ndr_pull_folder_cfdata(ndr,
> +								 r->cfdata + processed_cfdata,
> +								 r->cffolders[cntr_cffolders_0].typeCompress,
> +								 r->cffolders[cntr_cffolders_0].cCFData));
> +				processed_cfdata += r->cffolders[cntr_cffolders_0].cCFData;
>  			}
>  			NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cfdata_0, 0);
>  			NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
> diff --git a/librpc/ndr/ndr_compression.c b/librpc/ndr/ndr_compression.c
> index 5a821d5..54a6262 100644
> --- a/librpc/ndr/ndr_compression.c
> +++ b/librpc/ndr/ndr_compression.c
> @@ -47,6 +47,251 @@ static void  ndr_zlib_free(voidpf opaque, voidpf address)
>  	talloc_free(address);
>  }
>  
> +static enum ndr_err_code ndr_pull_compression_mszip_cab_chunk(struct ndr_pull *ndrpull,
> +							      struct ndr_push *ndrpush,
> +							      struct ndr_compression_state *state,
> +							      ssize_t decompressed_len,
> +							      ssize_t compressed_len)
> +{
> +	DATA_BLOB comp_chunk;
> +	uint32_t comp_chunk_offset;
> +	uint32_t comp_chunk_size;
> +	DATA_BLOB plain_chunk;
> +	uint32_t plain_chunk_offset;
> +	uint32_t plain_chunk_size;
> +	z_stream *z = state->mszip.z;
> +	int z_ret;
> +
> +	plain_chunk_size = decompressed_len;
> +
> +	if (plain_chunk_size > 0x00008000) {
> +		return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +				      "Bad MSZIP CAB plain chunk size %08X > 0x00008000 (PULL)",
> +				      plain_chunk_size);
> +	}
> +
> +
> +	comp_chunk_size = compressed_len;
> +
> +	DEBUG(9,("MSZIP CAB plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
> +		 plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
> +
> +	comp_chunk_offset = ndrpull->offset;
> +	NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
> +	comp_chunk.length = comp_chunk_size;
> +	comp_chunk.data = ndrpull->data + comp_chunk_offset;
> +
> +	plain_chunk_offset = ndrpush->offset;
> +	NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
> +	plain_chunk.length = plain_chunk_size;
> +	plain_chunk.data = ndrpush->data + plain_chunk_offset;
> +
> +	if (comp_chunk.length < 2) {
> +		return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +				      "Bad MSZIP CAB comp chunk size %u < 2 (PULL)",
> +				      (unsigned int)comp_chunk.length);
> +	}
> +	/* CK = Chris Kirmse, official Microsoft purloiner */
> +	if (comp_chunk.data[0] != 'C' ||
> +	    comp_chunk.data[1] != 'K') {
> +		return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +				      "Bad MSZIP CAB invalid prefix [%c%c] != [CK]",
> +				      comp_chunk.data[0], comp_chunk.data[1]);
> +	}
> +
> +	/*
> +	 * This is a MSZIP block. It is actually using the deflate
> +	 * algorithm which can be decompressed by zlib. zlib will try
> +	 * to decompress as much as it can in each run. If we provide
> +	 * all the input and enough room for the uncompressed output,
> +	 * one call is enough. It will loop over all the sub-blocks
> +	 * that make up a deflate block.
> +	 *
> +	 * See corresponding push function for more info.
> +	 */
> +
> +	z->next_in = comp_chunk.data + 2;
> +	z->avail_in = comp_chunk.length - 2;
> +	z->next_out = plain_chunk.data;
> +	z->avail_out = plain_chunk.length;
> +
> +	/*
> +	 * Each MSZIP CDATA contains a complete deflate stream
> +	 * i.e. the stream starts and ends in the CFDATA but the
> +	 * _dictionnary_ is shared between all CFDATA of a CFFOLDER.
> +	 *
> +	 * When decompressing, the initial dictionnary of the first
> +	 * CDATA is empty. All other CFDATA use the previous CFDATA
> +	 * uncompressed output as dictionnary.
> +	 */
> +
> +	if (state->mszip.dict_size) {
> +		z_ret = inflateSetDictionary(z, state->mszip.dict, state->mszip.dict_size);
> +		if (z_ret != Z_OK) {
> +			return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +					      "zlib inflateSetDictionary error %s (%d) %s (PULL)",
> +					      zError(z_ret), z_ret, z->msg);
> +		}
> +	}
> +
> +	z_ret = inflate(z, Z_FINISH);
> +	if (z_ret == Z_OK) {
> +		/*
> +		 * Z_OK here means there was no error but the stream
> +		 * hasn't been fully decompressed because there was
> +		 * not enough room for the output, which should not
> +		 * happen
> +		 */
> +		return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +				      "zlib inflate error not enough space for ouput (PULL)");
> +	}
> +	if (z_ret != Z_STREAM_END) {
> +		return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +				      "zlib inflate error %s (%d) %s (PULL)", zError(z_ret), z_ret, z->msg);
> +	}
> +
> +	if (z->total_out < plain_chunk.length) {
> +		return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +				      "zlib uncompressed output is smaller than expected (%lu < %zu) (PULL)",
> +				      z->total_out, plain_chunk.length);
> +	}
> +
> +	/*
> +	 * Keep a copy of the output to set as dictionnary for the
> +	 * next decompression call.
> +	 *
> +	 * The input pointer seems to be still valid between calls, so
> +	 * we can just store that instead of copying the memory over
> +	 * the dict temp buffer.
> +	 */
> +	state->mszip.dict = plain_chunk.data;
> +	state->mszip.dict_size = plain_chunk.length;
> +
> +	z_ret = inflateReset(z);
> +	if (z_ret != Z_OK) {
> +		return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +				      "zlib inflateReset error %s (%d) %s (PULL)",
> +				      zError(z_ret), z_ret, z->msg);
> +	}
> +
> +	return NDR_ERR_SUCCESS;
> +}
> +
> +static enum ndr_err_code ndr_push_compression_mszip_cab_chunk(struct ndr_push *ndrpush,
> +							      struct ndr_pull *ndrpull,
> +							      struct ndr_compression_state *state)
> +{
> +	DATA_BLOB comp_chunk;
> +	uint32_t comp_chunk_size;
> +	DATA_BLOB plain_chunk;
> +	uint32_t plain_chunk_size;
> +	uint32_t plain_chunk_offset;
> +	uint32_t max_plain_size = 0x00008000;
> +	/*
> +	 * The maximum compressed size of each MSZIP block is 32k + 12 bytes
> +	 * header size.
> +	 */
> +	uint32_t max_comp_size = 0x00008000 + 12;
> +	int z_ret;
> +	z_stream *z;
> +
> +	plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
> +	plain_chunk_offset = ndrpull->offset;
> +	NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
> +
> +	plain_chunk.data = ndrpull->data + plain_chunk_offset;
> +	plain_chunk.length = plain_chunk_size;
> +
> +	NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
> +
> +	comp_chunk.data = ndrpush->data + ndrpush->offset;
> +	comp_chunk.length = max_comp_size;
> +
> +	/* CK = Chris Kirmse, official Microsoft purloiner */
> +	comp_chunk.data[0] = 'C';
> +	comp_chunk.data[1] = 'K';
> +
> +	z = state->mszip.z;
> +	z->next_in	= plain_chunk.data;
> +	z->avail_in	= plain_chunk.length;
> +	z->total_in	= 0;
> +
> +	z->next_out	= comp_chunk.data + 2;
> +	z->avail_out	= comp_chunk.length;
> +	z->total_out	= 0;
> +
> +	/*
> +	 * See pull function for explanations of the MSZIP format.
> +	 *
> +	 * The CFDATA block contains a full deflate stream. Each stream
> +	 * uses the uncompressed input of the previous CFDATA in the
> +	 * same CFFOLDER as a dictionnary for the compression.
> +	 */
> +
> +	if (state->mszip.dict_size) {
> +		z_ret = deflateSetDictionary(z, state->mszip.dict, state->mszip.dict_size);
> +		if (z_ret != Z_OK) {
> +			return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +					      "zlib deflateSetDictionary error %s (%d) %s (PUSH)",
> +					      zError(z_ret), z_ret, z->msg);
> +		}
> +	}
> +
> +	/*
> +	 * Z_FINISH should make deflate process all of the input in
> +	 * one call. If the stream is not finished there was an error
> +	 * e.g. not enough room to store the compressed output.
> +	 */
> +	z_ret = deflate(z, Z_FINISH);
> +	if (z_ret != Z_STREAM_END) {
> +		return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
> +				      "zlib deflate error %s (%d) %s (PUSH)",
> +				      zError(z_ret), z_ret, z->msg);
> +	}
> +
> +	if (z->avail_in) {
> +		return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
> +				      "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
> +				      z->avail_in);
> +	}
> +
> +	comp_chunk_size = 2 + z->total_out;
> +
> +	z_ret = deflateReset(z);
> +	if (z_ret != Z_OK) {
> +		return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +				      "zlib deflateReset error %s (%d) %s (PUSH)",
> +				      zError(z_ret), z_ret, z->msg);
> +	}
> +
> +	if (plain_chunk.length > talloc_array_length(state->mszip.dict)) {
> +		return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
> +				      "zlib dict buffer is too big (PUSH)");
> +	}
> +
> +	/*
> +	 * Keep a copy of the input to set as dictionnary for the next
> +	 * compression call.
> +	 *
> +	 * Ideally we would just store the input pointer and length
> +	 * without copying but the memory gets invalidated between the
> +	 * calls, so we just copy to a dedicated buffer we now is
> +	 * still going to been valid for the lifetime of the
> +	 * compressions state object.
> +	 */
> +	memcpy(state->mszip.dict, plain_chunk.data, plain_chunk.length);
> +	state->mszip.dict_size = plain_chunk.length;
> +
> +	DEBUG(9,("MSZIP comp plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
> +		 (unsigned int)plain_chunk.length,
> +		 (unsigned int)plain_chunk.length,
> +		 comp_chunk_size, comp_chunk_size));
> +
> +	ndrpush->offset += comp_chunk_size;
> +	return NDR_ERR_SUCCESS;
> +}
> +
> +
>  static enum ndr_err_code ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull,
>  						 struct ndr_push *ndrpush,
>  						 z_stream *z,
> @@ -411,6 +656,12 @@ enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr,
>  	NDR_ERR_HAVE_NO_MEMORY(ndrpush);
>  
>  	switch (compression_alg) {
> +	case NDR_COMPRESSION_MSZIP_CAB:
> +		NDR_CHECK(ndr_pull_compression_mszip_cab_chunk(subndr, ndrpush,
> +							       subndr->cstate,
> +							       decompressed_len,
> +							       compressed_len));
> +		break;
>  	case NDR_COMPRESSION_MSZIP:
>  		ZERO_STRUCT(z);
>  		while (!last) {
> @@ -470,6 +721,7 @@ enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr,
>  	struct ndr_push *uncomndr;
>  
>  	switch (compression_alg) {
> +	case NDR_COMPRESSION_MSZIP_CAB:
>  	case NDR_COMPRESSION_MSZIP:
>  	case NDR_COMPRESSION_XPRESS:
>  		break;
> @@ -507,6 +759,10 @@ enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr,
>  	ndrpull->offset		= 0;
>  
>  	switch (compression_alg) {
> +	case NDR_COMPRESSION_MSZIP_CAB:
> +		NDR_CHECK(ndr_push_compression_mszip_cab_chunk(subndr, ndrpull, subndr->cstate));
> +		break;
> +
>  	case NDR_COMPRESSION_MSZIP:
>  		ZERO_STRUCT(z);
>  		while (!last) {
> diff --git a/source4/torture/ndr/cabinet.c b/source4/torture/ndr/cabinet.c
> index 790f7c3..f197534 100644
> --- a/source4/torture/ndr/cabinet.c
> +++ b/source4/torture/ndr/cabinet.c
> @@ -4233,10 +4233,9 @@ static bool cab_file_MSZIP_check(struct torture_context *tctx,
>  
>  	blob = data_blob(NULL, r->cfdata[0].cbUncomp);
>  	memset(blob.data, 'A', blob.length);
> -#if 0
> -	/* once we have MSZIP compression working we can enable this test */
> +
>  	torture_assert_data_blob_equal(tctx, r->cfdata[0].ab, blob, "ab");
> -#endif
> +
>  	return true;
>  }
>  
> -- 
> 2.9.4
> 
> 
> From 9784f4e411eed188d0c3daf91bde90843f2bc6b3 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd at samba.org>
> Date: Tue, 23 May 2017 15:50:55 +0200
> Subject: [PATCH 13/13] s4-torture: point out why we cannot validate MSZIP
>  compressed files
> 
> Guenther
> 
> Signed-off-by: Guenther Deschner <gd at samba.org>
> ---
>  source4/torture/ndr/cabinet.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/source4/torture/ndr/cabinet.c b/source4/torture/ndr/cabinet.c
> index f197534..8cdf4cb 100644
> --- a/source4/torture/ndr/cabinet.c
> +++ b/source4/torture/ndr/cabinet.c
> @@ -4318,5 +4318,12 @@ struct torture_suite *ndr_cabinet_suite(TALLOC_CTX *ctx)
>  
>  	torture_suite_add_ndr_pull_validate_test(suite, cab_file, cab_file_plain_data, cab_file_plain_check);
>  
> +	/*
> +	 * we cannot validate, as libz' compression routines currently create a
> +	 * slightly different result
> +	 */
> +
> +	/* torture_suite_add_ndr_pull_validate_test(suite, cab_file, cab_file_MSZIP_data, cab_file_MSZIP_check); */
> +
>  	return suite;
>  }
> -- 
> 2.9.4
> 







More information about the samba-technical mailing list