1 /*
2 * Grain group functions
3 *
4 * Copyright (C) 2009-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 <byte_stream.h>
24 #include <memory.h>
25 #include <types.h>
26
27 #include "libvmdk_definitions.h"
28 #include "libvmdk_grain_group.h"
29 #include "libvmdk_libcerror.h"
30 #include "libvmdk_libcnotify.h"
31 #include "libvmdk_libfdata.h"
32
33 /* Creates a grain group
34 * Make sure the value grain_group is referencing, is set to NULL
35 * Returns 1 if successful or -1 on error
36 */
libvmdk_grain_group_initialize(libvmdk_grain_group_t ** grain_group,libcerror_error_t ** error)37 int libvmdk_grain_group_initialize(
38 libvmdk_grain_group_t **grain_group,
39 libcerror_error_t **error )
40 {
41 static char *function = "libvmdk_grain_group_initialize";
42
43 if( grain_group == NULL )
44 {
45 libcerror_error_set(
46 error,
47 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
48 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
49 "%s: invalid grain group.",
50 function );
51
52 return( -1 );
53 }
54 if( *grain_group != NULL )
55 {
56 libcerror_error_set(
57 error,
58 LIBCERROR_ERROR_DOMAIN_RUNTIME,
59 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
60 "%s: invalid grain group value already set.",
61 function );
62
63 return( -1 );
64 }
65 *grain_group = memory_allocate_structure(
66 libvmdk_grain_group_t );
67
68 if( *grain_group == NULL )
69 {
70 libcerror_error_set(
71 error,
72 LIBCERROR_ERROR_DOMAIN_MEMORY,
73 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
74 "%s: unable to create grain group.",
75 function );
76
77 goto on_error;
78 }
79 if( memory_set(
80 *grain_group,
81 0,
82 sizeof( libvmdk_grain_group_t ) ) == NULL )
83 {
84 libcerror_error_set(
85 error,
86 LIBCERROR_ERROR_DOMAIN_MEMORY,
87 LIBCERROR_MEMORY_ERROR_SET_FAILED,
88 "%s: unable to clear grain group.",
89 function );
90
91 goto on_error;
92 }
93 return( 1 );
94
95 on_error:
96 if( *grain_group != NULL )
97 {
98 memory_free(
99 *grain_group );
100
101 *grain_group = NULL;
102 }
103 return( -1 );
104 }
105
106 /* Frees a grain group
107 * Returns 1 if successful or -1 on error
108 */
libvmdk_grain_group_free(libvmdk_grain_group_t ** grain_group,libcerror_error_t ** error)109 int libvmdk_grain_group_free(
110 libvmdk_grain_group_t **grain_group,
111 libcerror_error_t **error )
112 {
113 static char *function = "libvmdk_grain_group_free";
114
115 if( grain_group == NULL )
116 {
117 libcerror_error_set(
118 error,
119 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
120 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
121 "%s: invalid grain group.",
122 function );
123
124 return( -1 );
125 }
126 if( *grain_group != NULL )
127 {
128 memory_free(
129 *grain_group );
130
131 *grain_group = NULL;
132 }
133 return( 1 );
134 }
135
136 /* Clones the grain group
137 * Returns 1 if successful or -1 on error
138 */
libvmdk_grain_group_clone(libvmdk_grain_group_t ** destination_grain_group,libvmdk_grain_group_t * source_grain_group,libcerror_error_t ** error)139 int libvmdk_grain_group_clone(
140 libvmdk_grain_group_t **destination_grain_group,
141 libvmdk_grain_group_t *source_grain_group,
142 libcerror_error_t **error )
143 {
144 static char *function = "libvmdk_grain_group_clone";
145
146 if( destination_grain_group == NULL )
147 {
148 libcerror_error_set(
149 error,
150 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
151 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
152 "%s: invalid destination grain group.",
153 function );
154
155 return( -1 );
156 }
157 if( *destination_grain_group != NULL )
158 {
159 libcerror_error_set(
160 error,
161 LIBCERROR_ERROR_DOMAIN_RUNTIME,
162 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
163 "%s: invalid destination grain group value already set.",
164 function );
165
166 return( -1 );
167 }
168 if( source_grain_group == NULL )
169 {
170 *destination_grain_group = NULL;
171
172 return( 1 );
173 }
174 *destination_grain_group = memory_allocate_structure(
175 libvmdk_grain_group_t );
176
177 if( *destination_grain_group == NULL )
178 {
179 libcerror_error_set(
180 error,
181 LIBCERROR_ERROR_DOMAIN_MEMORY,
182 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
183 "%s: unable to create destination grain group.",
184 function );
185
186 goto on_error;
187 }
188 if( memory_copy(
189 *destination_grain_group,
190 source_grain_group,
191 sizeof( libvmdk_grain_group_t ) ) == NULL )
192 {
193 libcerror_error_set(
194 error,
195 LIBCERROR_ERROR_DOMAIN_MEMORY,
196 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
197 "%s: unable to copy source to destination grain group.",
198 function );
199
200 goto on_error;
201 }
202 return( 1 );
203
204 on_error:
205 if( *destination_grain_group != NULL )
206 {
207 memory_free(
208 *destination_grain_group );
209
210 *destination_grain_group = NULL;
211 }
212 return( -1 );
213 }
214
215 /* Fills the grain offset from the grain group
216 * Returns 1 if successful or -1 on error
217 */
libvmdk_grain_group_fill(libfdata_list_t * grains_list,int grain_index,size64_t grain_size,libbfio_pool_t * file_io_pool,int file_io_pool_entry,const uint8_t * grain_group_data,size_t grain_group_data_size,int number_of_grain_group_entries,uint32_t extent_file_flags,libcerror_error_t ** error)218 int libvmdk_grain_group_fill(
219 libfdata_list_t *grains_list,
220 int grain_index,
221 size64_t grain_size,
222 libbfio_pool_t *file_io_pool,
223 int file_io_pool_entry,
224 const uint8_t *grain_group_data,
225 size_t grain_group_data_size,
226 int number_of_grain_group_entries,
227 uint32_t extent_file_flags,
228 libcerror_error_t **error )
229 {
230 uint8_t compressed_data_header[ 12 ];
231
232 const uint8_t *grain_group_entry = NULL;
233 static char *function = "libvmdk_grain_group_fill";
234 off64_t grain_data_offset = 0;
235 size64_t grain_data_size = 0;
236 ssize_t read_count = 0;
237 uint32_t range_flags = 0;
238 int element_index = 0;
239 int grain_group_entry_index = 0;
240
241 if( grains_list == NULL )
242 {
243 libcerror_error_set(
244 error,
245 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
246 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
247 "%s: invalid grains list.",
248 function );
249
250 return( -1 );
251 }
252 if( grain_size == 0 )
253 {
254 libcerror_error_set(
255 error,
256 LIBCERROR_ERROR_DOMAIN_RUNTIME,
257 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
258 "%s: invalid grain size.",
259 function );
260
261 return( -1 );
262 }
263 if( grain_group_data == NULL )
264 {
265 libcerror_error_set(
266 error,
267 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
268 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
269 "%s: invalid grain group data.",
270 function );
271
272 return( -1 );
273 }
274 if( grain_group_data_size > (size_t) SSIZE_MAX )
275 {
276 libcerror_error_set(
277 error,
278 LIBCERROR_ERROR_DOMAIN_RUNTIME,
279 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
280 "%s: invalid grain group size value exceeds maximum.",
281 function );
282
283 return( -1 );
284 }
285 if( ( (size_t) number_of_grain_group_entries * 4 ) > grain_group_data_size )
286 {
287 libcerror_error_set(
288 error,
289 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
290 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
291 "%s: invalid number of grain group entries value out of bounds.",
292 function );
293
294 return( -1 );
295 }
296 grain_group_entry = grain_group_data;
297
298 for( grain_group_entry_index = 0;
299 grain_group_entry_index < number_of_grain_group_entries;
300 grain_group_entry_index++ )
301 {
302 byte_stream_copy_to_uint32_little_endian(
303 grain_group_entry,
304 grain_data_offset );
305
306 #if defined( HAVE_DEBUG_OUTPUT )
307 if( libcnotify_verbose != 0 )
308 {
309 libcnotify_printf(
310 "%s: grain table entry: %03" PRIu32 " sector number\t\t: %" PRIi64 "\n",
311 function,
312 grain_group_entry_index,
313 grain_data_offset );
314 }
315 #endif
316 if( grain_data_offset != 0 )
317 {
318 if( ( extent_file_flags & LIBVMDK_FLAG_HAS_GRAIN_COMPRESSION ) != 0 )
319 {
320 range_flags = LIBVMDK_RANGE_FLAG_IS_COMPRESSED;
321 }
322 else
323 {
324 range_flags = 0;
325 }
326 grain_data_offset *= 512;
327 }
328 else
329 {
330 range_flags = LIBVMDK_RANGE_FLAG_IS_SPARSE;
331 }
332 if( ( extent_file_flags & LIBVMDK_FLAG_HAS_GRAIN_COMPRESSION ) != 0 )
333 {
334 if( libbfio_pool_seek_offset(
335 file_io_pool,
336 file_io_pool_entry,
337 grain_data_offset,
338 SEEK_SET,
339 error ) == -1 )
340 {
341 libcerror_error_set(
342 error,
343 LIBCERROR_ERROR_DOMAIN_IO,
344 LIBCERROR_IO_ERROR_SEEK_FAILED,
345 "%s: unable to seek grain offset: %" PRIi64 " in file IO pool entry: %d.",
346 function,
347 grain_data_offset,
348 file_io_pool_entry );
349
350 return( -1 );
351 }
352 read_count = libbfio_pool_read_buffer(
353 file_io_pool,
354 file_io_pool_entry,
355 compressed_data_header,
356 12,
357 error );
358
359 if( read_count != (ssize_t) 12 )
360 {
361 libcerror_error_set(
362 error,
363 LIBCERROR_ERROR_DOMAIN_IO,
364 LIBCERROR_IO_ERROR_READ_FAILED,
365 "%s: unable to read compressed grain data header.",
366 function );
367
368 return( -1 );
369 }
370 byte_stream_copy_to_uint32_little_endian(
371 &( compressed_data_header[ 8 ] ),
372 grain_data_size );
373 }
374 else
375 {
376 grain_data_size = grain_size;
377 }
378 #if defined( HAVE_DEBUG_OUTPUT )
379 if( libcnotify_verbose != 0 )
380 {
381 libcnotify_printf(
382 "%s: grain table entry: %03" PRIu32 " offset\t\t\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
383 function,
384 grain_group_entry_index,
385 grain_data_offset * 512,
386 grain_data_offset * 512 );
387
388 libcnotify_printf(
389 "%s: grain table entry: %03" PRIu32 " size\t\t\t: %" PRIu64 "\n",
390 function,
391 grain_group_entry_index,
392 grain_data_size );
393
394 libcnotify_printf(
395 "%s: grain table entry: %03" PRIu32 " file IO pool entry\t: %d\n",
396 function,
397 grain_group_entry_index,
398 file_io_pool_entry );
399
400 libcnotify_printf(
401 "%s: grain table entry: %03" PRIu32 " range flags\t\t: 0x%08" PRIx64 "\n",
402 function,
403 grain_group_entry_index,
404 range_flags );
405
406 if( ( range_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
407 {
408 libcnotify_printf(
409 "\tIs sparse.\n" );
410 }
411 if( ( range_flags & LIBVMDK_RANGE_FLAG_IS_COMPRESSED ) != 0 )
412 {
413 libcnotify_printf(
414 "\tIs compressed.\n" );
415 }
416 libcnotify_printf(
417 "\n" );
418 }
419 #endif
420 if( libfdata_list_append_element_with_mapped_size(
421 grains_list,
422 &element_index,
423 file_io_pool_entry,
424 grain_data_offset,
425 grain_data_size,
426 range_flags,
427 grain_size,
428 error ) != 1 )
429 {
430 libcerror_error_set(
431 error,
432 LIBCERROR_ERROR_DOMAIN_RUNTIME,
433 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
434 "%s: unable to append grain: %d to grains list.",
435 function,
436 grain_index );
437
438 return( -1 );
439 }
440 grain_group_entry += sizeof( uint32_t );
441
442 grain_index++;
443 }
444 return( 1 );
445 }
446
447