1 /*
2 * Compressed block vector functions
3 *
4 * Copyright (C) 2010-2021, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <memory.h>
24 #include <types.h>
25
26 #include "libfsntfs_compressed_block.h"
27 #include "libfsntfs_compressed_block_vector.h"
28 #include "libfsntfs_compression_unit_data_handle.h"
29 #include "libfsntfs_compression_unit_descriptor.h"
30 #include "libfsntfs_compression.h"
31 #include "libfsntfs_definitions.h"
32 #include "libfsntfs_io_handle.h"
33 #include "libfsntfs_libcerror.h"
34 #include "libfsntfs_libfdata.h"
35 #include "libfsntfs_mft_attribute.h"
36 #include "libfsntfs_unused.h"
37
38 /* Creates a compressed block vector
39 * Make sure the value compressed_block_vector is referencing, is set to NULL
40 * Returns 1 if successful or -1 on error
41 */
libfsntfs_compressed_block_vector_initialize(libfdata_vector_t ** compressed_block_vector,libfsntfs_io_handle_t * io_handle,libfsntfs_mft_attribute_t * mft_attribute,libcerror_error_t ** error)42 int libfsntfs_compressed_block_vector_initialize(
43 libfdata_vector_t **compressed_block_vector,
44 libfsntfs_io_handle_t *io_handle,
45 libfsntfs_mft_attribute_t *mft_attribute,
46 libcerror_error_t **error )
47 {
48 libfdata_vector_t *safe_compressed_block_vector = NULL;
49 libfsntfs_compression_unit_data_handle_t *data_handle = NULL;
50 libfsntfs_compression_unit_descriptor_t *descriptor = NULL;
51 static char *function = "libfsntfs_compressed_block_vector_initialize";
52 int descriptor_index = 0;
53 int number_of_descriptors = 0;
54 int segment_index = 0;
55
56 if( compressed_block_vector == NULL )
57 {
58 libcerror_error_set(
59 error,
60 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
61 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
62 "%s: invalid compressed block vector.",
63 function );
64
65 return( -1 );
66 }
67 if( *compressed_block_vector != NULL )
68 {
69 libcerror_error_set(
70 error,
71 LIBCERROR_ERROR_DOMAIN_RUNTIME,
72 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
73 "%s: invalid compressed block vector value already set.",
74 function );
75
76 return( -1 );
77 }
78 if( io_handle == NULL )
79 {
80 libcerror_error_set(
81 error,
82 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
83 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
84 "%s: invalid IO handle.",
85 function );
86
87 return( -1 );
88 }
89 if( libfsntfs_compression_unit_data_handle_initialize(
90 &data_handle,
91 io_handle,
92 mft_attribute,
93 error ) != 1 )
94 {
95 libcerror_error_set(
96 error,
97 LIBCERROR_ERROR_DOMAIN_RUNTIME,
98 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
99 "%s: unable to create compression unit data handle.",
100 function );
101
102 goto on_error;
103 }
104 if( libfdata_vector_initialize(
105 &safe_compressed_block_vector,
106 (size64_t) data_handle->compression_unit_size,
107 (intptr_t *) data_handle,
108 (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_compression_unit_data_handle_free,
109 NULL,
110 (int (*)(intptr_t *, intptr_t *, libfdata_vector_t *, libfdata_cache_t *, int, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsntfs_compressed_block_vector_read_element_data,
111 NULL,
112 LIBFDATA_DATA_HANDLE_FLAG_MANAGED,
113 error ) != 1 )
114 {
115 libcerror_error_set(
116 error,
117 LIBCERROR_ERROR_DOMAIN_RUNTIME,
118 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
119 "%s: unable to create compressed block vector.",
120 function );
121
122 goto on_error;
123 }
124 if( libfsntfs_compression_unit_data_handle_get_number_of_descriptors(
125 data_handle,
126 &number_of_descriptors,
127 error ) != 1 )
128 {
129 libcerror_error_set(
130 error,
131 LIBCERROR_ERROR_DOMAIN_RUNTIME,
132 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
133 "%s: unable to retrieve number of descriptors.",
134 function );
135
136 data_handle = NULL;
137
138 goto on_error;
139 }
140 for( descriptor_index = 0;
141 descriptor_index < number_of_descriptors;
142 descriptor_index++ )
143 {
144 if( libfsntfs_compression_unit_data_handle_get_descriptor_by_index(
145 data_handle,
146 descriptor_index,
147 &descriptor,
148 error ) != 1 )
149 {
150 libcerror_error_set(
151 error,
152 LIBCERROR_ERROR_DOMAIN_RUNTIME,
153 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
154 "%s: unable to retrieve descriptor: %d.",
155 function,
156 descriptor_index );
157
158 data_handle = NULL;
159
160 goto on_error;
161 }
162 if( descriptor == NULL )
163 {
164 libcerror_error_set(
165 error,
166 LIBCERROR_ERROR_DOMAIN_RUNTIME,
167 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
168 "%s: missing descriptor: %d.",
169 function,
170 descriptor_index );
171
172 data_handle = NULL;
173
174 goto on_error;
175 }
176 if( libfdata_vector_append_segment(
177 safe_compressed_block_vector,
178 &segment_index,
179 descriptor_index,
180 descriptor->data_offset,
181 descriptor->compression_unit_size,
182 descriptor->data_range_flags,
183 error ) != 1 )
184 {
185 libcerror_error_set(
186 error,
187 LIBCERROR_ERROR_DOMAIN_RUNTIME,
188 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
189 "%s: unable to append compression unit: %d segment to compressed block vector.",
190 function,
191 descriptor_index );
192
193 data_handle = NULL;
194
195 goto on_error;
196 }
197 }
198 *compressed_block_vector = safe_compressed_block_vector;
199
200 return( 1 );
201
202 on_error:
203 if( safe_compressed_block_vector != NULL )
204 {
205 libfdata_vector_free(
206 &safe_compressed_block_vector,
207 NULL );
208 }
209 if( data_handle != NULL )
210 {
211 libfsntfs_compression_unit_data_handle_free(
212 &data_handle,
213 NULL );
214 }
215 return( -1 );
216 }
217
218 /* Reads a compressed block
219 * Callback function for the compressed block vector
220 * Returns 1 if successful or -1 on error
221 */
libfsntfs_compressed_block_vector_read_element_data(libfsntfs_compression_unit_data_handle_t * data_handle,libbfio_handle_t * file_io_handle,libfdata_vector_t * vector,libfdata_cache_t * cache,int element_index,int element_data_file_index,off64_t element_data_offset,size64_t compressed_block_size,uint32_t range_flags,uint8_t read_flags LIBFSNTFS_ATTRIBUTE_UNUSED,libcerror_error_t ** error)222 int libfsntfs_compressed_block_vector_read_element_data(
223 libfsntfs_compression_unit_data_handle_t *data_handle,
224 libbfio_handle_t *file_io_handle,
225 libfdata_vector_t *vector,
226 libfdata_cache_t *cache,
227 int element_index,
228 int element_data_file_index,
229 off64_t element_data_offset,
230 size64_t compressed_block_size,
231 uint32_t range_flags,
232 uint8_t read_flags LIBFSNTFS_ATTRIBUTE_UNUSED,
233 libcerror_error_t **error )
234 {
235 libfsntfs_compressed_block_t *compressed_block = NULL;
236 libfsntfs_compression_unit_descriptor_t *compression_unit_descriptor = NULL;
237 uint8_t *compressed_block_data = NULL;
238 uint8_t *compressed_data = NULL;
239 const char *block_type = NULL;
240 static char *function = "libfsntfs_compressed_block_vector_read_element_data";
241 ssize_t read_count = 0;
242 off64_t data_stream_offset = 0;
243 int result = 0;
244
245 LIBFSNTFS_UNREFERENCED_PARAMETER( read_flags )
246
247 if( ( compressed_block_size == 0 )
248 || ( compressed_block_size > (size64_t) SSIZE_MAX ) )
249 {
250 libcerror_error_set(
251 error,
252 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
253 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
254 "%s: invalid compressed block size value out of bounds.",
255 function );
256
257 return( -1 );
258 }
259 if( libfsntfs_compression_unit_data_handle_get_descriptor_by_index(
260 data_handle,
261 element_data_file_index,
262 &compression_unit_descriptor,
263 error ) != 1 )
264 {
265 libcerror_error_set(
266 error,
267 LIBCERROR_ERROR_DOMAIN_RUNTIME,
268 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
269 "%s: unable to retrieve compression unit descriptor: %d.",
270 function,
271 element_data_file_index );
272
273 goto on_error;
274 }
275 if( compression_unit_descriptor == NULL )
276 {
277 libcerror_error_set(
278 error,
279 LIBCERROR_ERROR_DOMAIN_RUNTIME,
280 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
281 "%s: missing compression unit descriptor: %d.",
282 function,
283 element_data_file_index );
284
285 goto on_error;
286 }
287 if( libfsntfs_compressed_block_initialize(
288 &compressed_block,
289 compressed_block_size,
290 error ) != 1 )
291 {
292 libcerror_error_set(
293 error,
294 LIBCERROR_ERROR_DOMAIN_RUNTIME,
295 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
296 "%s: unable to create compressed block.",
297 function );
298
299 goto on_error;
300 }
301 if( compressed_block == NULL )
302 {
303 libcerror_error_set(
304 error,
305 LIBCERROR_ERROR_DOMAIN_RUNTIME,
306 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
307 "%s: missing compressed block.",
308 function );
309
310 goto on_error;
311 }
312 if( ( range_flags & LIBFDATA_RANGE_FLAG_IS_COMPRESSED ) != 0 )
313 {
314 compressed_data = (uint8_t *) memory_allocate(
315 sizeof( uint8_t ) * (size_t) compressed_block_size );
316
317 if( compressed_data == NULL )
318 {
319 libcerror_error_set(
320 error,
321 LIBCERROR_ERROR_DOMAIN_MEMORY,
322 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
323 "%s: unable to create compressed data.",
324 function );
325
326 goto on_error;
327 }
328 compressed_block_data = compressed_data;
329
330 /* Make sure to read from the start of the data stream
331 * otherwise successive reads will fail
332 */
333 data_stream_offset = 0;
334
335 block_type = "compressed";
336 }
337 else
338 {
339 compressed_block_data = compressed_block->data;
340 data_stream_offset = element_data_offset - compression_unit_descriptor->data_offset;
341
342 block_type = "uncompressed";
343 }
344 read_count = libfdata_stream_read_buffer_at_offset(
345 compression_unit_descriptor->data_stream,
346 (intptr_t *) file_io_handle,
347 compressed_block_data,
348 compressed_block_size,
349 data_stream_offset,
350 0,
351 error );
352
353 if( read_count != (ssize_t) compressed_block_size )
354 {
355 libcerror_error_set(
356 error,
357 LIBCERROR_ERROR_DOMAIN_IO,
358 LIBCERROR_IO_ERROR_READ_FAILED,
359 "%s: unable to read %s block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
360 function,
361 block_type,
362 data_stream_offset,
363 data_stream_offset );
364
365 goto on_error;
366 }
367 if( ( range_flags & LIBFDATA_RANGE_FLAG_IS_COMPRESSED ) != 0 )
368 {
369 result = libfsntfs_decompress_data(
370 compressed_data,
371 (size_t) compressed_block_size,
372 LIBFSNTFS_COMPRESSION_METHOD_LZNT1,
373 compressed_block->data,
374 &( compressed_block->data_size ),
375 error );
376
377 if( result != 1 )
378 {
379 libcerror_error_set(
380 error,
381 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
382 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
383 "%s: unable to decompress compressed data.",
384 function );
385
386 goto on_error;
387 }
388 memory_free(
389 compressed_data );
390
391 compressed_data = NULL;
392
393 /* If the compressed block data size is 0 or the compressed block was truncated
394 * fill the remainder of the compressed block with 0-byte values
395 */
396 if( compressed_block->data_size < compressed_block_size )
397 {
398 if( memory_set(
399 &( compressed_block->data[ compressed_block->data_size ] ),
400 0,
401 compressed_block_size - compressed_block->data_size ) == NULL )
402 {
403 libcerror_error_set(
404 error,
405 LIBCERROR_ERROR_DOMAIN_MEMORY,
406 LIBCERROR_MEMORY_ERROR_SET_FAILED,
407 "%s: unable to clear remainder of compressed block.",
408 function );
409
410 goto on_error;
411 }
412 compressed_block->data_size = compressed_block_size;
413 }
414 }
415 if( libfdata_vector_set_element_value_by_index(
416 vector,
417 (intptr_t *) file_io_handle,
418 cache,
419 element_index,
420 (intptr_t *) compressed_block,
421 (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_compressed_block_free,
422 LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
423 error ) != 1 )
424 {
425 libcerror_error_set(
426 error,
427 LIBCERROR_ERROR_DOMAIN_RUNTIME,
428 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
429 "%s: unable to set cluster block as element value.",
430 function );
431
432 goto on_error;
433 }
434 return( 1 );
435
436 on_error:
437 if( compressed_data != NULL )
438 {
439 memory_free(
440 compressed_data );
441 }
442 if( compressed_block != NULL )
443 {
444 libfsntfs_compressed_block_free(
445 &compressed_block,
446 NULL );
447 }
448 return( -1 );
449 }
450
451