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