1 /*
2  * Grain table 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_extent_table.h"
29 #include "libvmdk_grain_data.h"
30 #include "libvmdk_grain_table.h"
31 #include "libvmdk_io_handle.h"
32 #include "libvmdk_libbfio.h"
33 #include "libvmdk_libcerror.h"
34 #include "libvmdk_libcnotify.h"
35 #include "libvmdk_libfcache.h"
36 #include "libvmdk_libfdata.h"
37 #include "libvmdk_unused.h"
38 
39 /* Creates a grain table
40  * Make sure the value grain_table is referencing, is set to NULL
41  * Returns 1 if successful or -1 on error
42  */
libvmdk_grain_table_initialize(libvmdk_grain_table_t ** grain_table,libvmdk_io_handle_t * io_handle,libcerror_error_t ** error)43 int libvmdk_grain_table_initialize(
44      libvmdk_grain_table_t **grain_table,
45      libvmdk_io_handle_t *io_handle,
46      libcerror_error_t **error )
47 {
48 	static char *function = "libvmdk_grain_table_initialize";
49 
50 	if( grain_table == NULL )
51 	{
52 		libcerror_error_set(
53 		 error,
54 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
55 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
56 		 "%s: invalid grain table.",
57 		 function );
58 
59 		return( -1 );
60 	}
61 	if( *grain_table != NULL )
62 	{
63 		libcerror_error_set(
64 		 error,
65 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
66 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
67 		 "%s: invalid grain table value already set.",
68 		 function );
69 
70 		return( -1 );
71 	}
72 	if( io_handle == NULL )
73 	{
74 		libcerror_error_set(
75 		 error,
76 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
77 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
78 		 "%s: invalid IO handle.",
79 		 function );
80 
81 		return( -1 );
82 	}
83 	*grain_table = memory_allocate_structure(
84 	                libvmdk_grain_table_t );
85 
86 	if( *grain_table == NULL )
87 	{
88 		libcerror_error_set(
89 		 error,
90 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
91 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
92 		 "%s: unable to create grain table.",
93 		 function );
94 
95 		goto on_error;
96 	}
97 	if( memory_set(
98 	     *grain_table,
99 	     0,
100 	     sizeof( libvmdk_grain_table_t ) ) == NULL )
101 	{
102 		libcerror_error_set(
103 		 error,
104 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
105 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
106 		 "%s: unable to clear grain table.",
107 		 function );
108 
109 		goto on_error;
110 	}
111 	( *grain_table )->io_handle = io_handle;
112 
113 	return( 1 );
114 
115 on_error:
116 	if( *grain_table != NULL )
117 	{
118 		memory_free(
119 		 *grain_table );
120 
121 		*grain_table = NULL;
122 	}
123 	return( -1 );
124 }
125 
126 /* Frees a grain table
127  * Returns 1 if successful or -1 on error
128  */
libvmdk_grain_table_free(libvmdk_grain_table_t ** grain_table,libcerror_error_t ** error)129 int libvmdk_grain_table_free(
130      libvmdk_grain_table_t **grain_table,
131      libcerror_error_t **error )
132 {
133 	static char *function = "libvmdk_grain_table_free";
134 
135 	if( grain_table == NULL )
136 	{
137 		libcerror_error_set(
138 		 error,
139 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
140 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
141 		 "%s: invalid grain table.",
142 		 function );
143 
144 		return( -1 );
145 	}
146 	if( *grain_table != NULL )
147 	{
148 		/* The IO handle reference is freed elsewhere
149 		 */
150 		memory_free(
151 		 *grain_table );
152 
153 		*grain_table = NULL;
154 	}
155 	return( 1 );
156 }
157 
158 /* Clones the grain table
159  * Returns 1 if successful or -1 on error
160  */
libvmdk_grain_table_clone(libvmdk_grain_table_t ** destination_grain_table,libvmdk_grain_table_t * source_grain_table,libcerror_error_t ** error)161 int libvmdk_grain_table_clone(
162      libvmdk_grain_table_t **destination_grain_table,
163      libvmdk_grain_table_t *source_grain_table,
164      libcerror_error_t **error )
165 {
166 	static char *function = "libvmdk_grain_table_clone";
167 
168 	if( destination_grain_table == NULL )
169 	{
170 		libcerror_error_set(
171 		 error,
172 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
173 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
174 		 "%s: invalid destination grain table.",
175 		 function );
176 
177 		return( -1 );
178 	}
179 	if( *destination_grain_table != NULL )
180 	{
181 		libcerror_error_set(
182 		 error,
183 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
184 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
185 		 "%s: invalid destination grain table value already set.",
186 		 function );
187 
188 		return( -1 );
189 	}
190 	if( source_grain_table == NULL )
191 	{
192 		*destination_grain_table = NULL;
193 
194 		return( 1 );
195 	}
196 	*destination_grain_table = memory_allocate_structure(
197 	                            libvmdk_grain_table_t );
198 
199 	if( *destination_grain_table == NULL )
200 	{
201 		libcerror_error_set(
202 		 error,
203 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
204 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
205 		 "%s: unable to create destination grain table.",
206 		 function );
207 
208 		goto on_error;
209 	}
210 	if( memory_copy(
211 	     *destination_grain_table,
212 	     source_grain_table,
213 	     sizeof( libvmdk_grain_table_t ) ) == NULL )
214 	{
215 		libcerror_error_set(
216 		 error,
217 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
218 		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
219 		 "%s: unable to copy source to destination grain table.",
220 		 function );
221 
222 		goto on_error;
223 	}
224 	return( 1 );
225 
226 on_error:
227 	if( *destination_grain_table != NULL )
228 	{
229 		memory_free(
230 		 *destination_grain_table );
231 
232 		*destination_grain_table = NULL;
233 	}
234 	return( -1 );
235 }
236 
237 /* Determines if the grain at a specific offset is sparse
238  * Returns 1 if the grain is sparse, 0 if not or -1 on error
239  */
libvmdk_grain_table_grain_is_sparse_at_offset(libvmdk_grain_table_t * grain_table,uint64_t grain_index,libbfio_pool_t * file_io_pool,libvmdk_extent_table_t * extent_table,off64_t offset,libcerror_error_t ** error)240 int libvmdk_grain_table_grain_is_sparse_at_offset(
241      libvmdk_grain_table_t *grain_table,
242      uint64_t grain_index,
243      libbfio_pool_t *file_io_pool,
244      libvmdk_extent_table_t *extent_table,
245      off64_t offset,
246      libcerror_error_t **error )
247 {
248 	libvmdk_extent_file_t *extent_file = NULL;
249 	libfdata_list_t *grains_list       = NULL;
250 	static char *function              = "libvmdk_grain_table_grain_is_sparse_at_offset";
251 	off64_t extent_file_data_offset    = 0;
252 	off64_t grain_data_offset          = 0;
253 	off64_t grain_group_data_offset    = 0;
254 	off64_t grain_offset               = 0;
255 	size64_t grain_size                = 0;
256 	uint32_t grain_flags               = 0;
257 	int extent_number                  = 0;
258 	int grain_file_index               = 0;
259 	int grain_groups_list_index        = 0;
260 	int grains_list_index              = 0;
261 	int result                         = 0;
262 
263 	if( grain_table == NULL )
264 	{
265 		libcerror_error_set(
266 		 error,
267 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
268 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
269 		 "%s: invalid grain table.",
270 		 function );
271 
272 		return( -1 );
273 	}
274 	result = libvmdk_extent_table_get_extent_file_at_offset(
275 	          extent_table,
276 	          offset,
277 	          file_io_pool,
278 	          &extent_number,
279 	          &extent_file_data_offset,
280 	          &extent_file,
281 	          error );
282 
283 	if( result != 1 )
284 	{
285 		libcerror_error_set(
286 		 error,
287 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
288 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
289 		 "%s: unable to retrieve extent file at offset: %" PRIi64 " from extent table.",
290 		 function,
291 		 offset );
292 
293 		return( -1 );
294 	}
295 	if( extent_file == NULL )
296 	{
297 		libcerror_error_set(
298 		 error,
299 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
300 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
301 		 "%s: missing extent file.",
302 		 function );
303 
304 		return( -1 );
305 	}
306 	result = libvmdk_extent_file_grain_group_is_sparse_at_offset(
307 	          extent_file,
308 	          extent_file_data_offset,
309 	          &grain_groups_list_index,
310 	          &grain_group_data_offset,
311 	          error );
312 
313 	if( result == -1 )
314 	{
315 		libcerror_error_set(
316 		 error,
317 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
318 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
319 		 "%s: unable to retrieve grain group from extent file: %d at offset: %" PRIi64 ".",
320 		 function,
321 		 extent_number,
322 		 extent_file_data_offset );
323 
324 		return( -1 );
325 	}
326 	else if( result != 0 )
327 	{
328 		return( 1 );
329 	}
330 	result = libvmdk_extent_file_get_grain_group_at_offset(
331 		  extent_file,
332 		  file_io_pool,
333 		  extent_file_data_offset,
334 		  &grain_groups_list_index,
335 		  &grain_group_data_offset,
336 		  &grains_list,
337 		  error );
338 
339 	if( result != 1 )
340 	{
341 		libcerror_error_set(
342 		 error,
343 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
344 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
345 		 "%s: unable to retrieve grain group from extent file: %d at offset: %" PRIi64 ".",
346 		 function,
347 		 extent_number,
348 		 extent_file_data_offset );
349 
350 		return( -1 );
351 	}
352 	result = libfdata_list_get_element_at_offset(
353 		  grains_list,
354 		  grain_group_data_offset,
355 		  &grains_list_index,
356 		  &grain_data_offset,
357 		  &grain_file_index,
358 		  &grain_offset,
359 		  &grain_size,
360 		  &grain_flags,
361 		  error );
362 
363 	if( result != 1 )
364 	{
365 		libcerror_error_set(
366 		 error,
367 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
368 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
369 		 "%s: unable to retrieve grain: %" PRIu64 " from grain group: %d in extent file: %d at offset: %" PRIi64 ".",
370 		 function,
371 		 grain_index,
372 		 grain_groups_list_index,
373 		 extent_number,
374 		 extent_file_data_offset );
375 
376 		return( -1 );
377 	}
378 	if( ( grain_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
379 	{
380 		return( 1 );
381 	}
382 	return( 0 );
383 }
384 
385 /* Retrieves the grain data of a grain at a specific offset
386  * Returns 1 if successful or -1 on error
387  */
libvmdk_grain_table_get_grain_data_at_offset(libvmdk_grain_table_t * grain_table,uint64_t grain_index,libbfio_pool_t * file_io_pool,libvmdk_extent_table_t * extent_table,libfcache_cache_t * grains_cache,off64_t offset,libvmdk_grain_data_t ** grain_data,off64_t * grain_data_offset,libcerror_error_t ** error)388 int libvmdk_grain_table_get_grain_data_at_offset(
389      libvmdk_grain_table_t *grain_table,
390      uint64_t grain_index,
391      libbfio_pool_t *file_io_pool,
392      libvmdk_extent_table_t *extent_table,
393      libfcache_cache_t *grains_cache,
394      off64_t offset,
395      libvmdk_grain_data_t **grain_data,
396      off64_t *grain_data_offset,
397      libcerror_error_t **error )
398 {
399 	libvmdk_extent_file_t *extent_file = NULL;
400 	libfdata_list_t *grains_list       = NULL;
401 	static char *function              = "libvmdk_grain_table_get_grain_data_at_offset";
402 	off64_t grain_group_data_offset    = 0;
403 	off64_t extent_file_data_offset    = 0;
404 	int extent_number                  = 0;
405 	int grain_groups_list_index        = 0;
406 	int grains_list_index              = 0;
407 	int result                         = 0;
408 
409 	if( grain_table == NULL )
410 	{
411 		libcerror_error_set(
412 		 error,
413 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
414 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
415 		 "%s: invalid grain table.",
416 		 function );
417 
418 		return( -1 );
419 	}
420 	result = libvmdk_extent_table_get_extent_file_at_offset(
421 	          extent_table,
422 	          offset,
423 	          file_io_pool,
424 	          &extent_number,
425 	          &extent_file_data_offset,
426 	          &extent_file,
427 	          error );
428 
429 	if( result != 1 )
430 	{
431 		libcerror_error_set(
432 		 error,
433 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
434 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
435 		 "%s: unable to retrieve extent file at offset: %" PRIi64 " from extent table.",
436 		 function,
437 		 offset );
438 
439 		return( -1 );
440 	}
441 	if( extent_file == NULL )
442 	{
443 		libcerror_error_set(
444 		 error,
445 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
446 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
447 		 "%s: missing extent file.",
448 		 function );
449 
450 		return( -1 );
451 	}
452 	result = libvmdk_extent_file_get_grain_group_at_offset(
453 		  extent_file,
454 		  file_io_pool,
455 		  extent_file_data_offset,
456 		  &grain_groups_list_index,
457 		  &grain_group_data_offset,
458 		  &grains_list,
459 		  error );
460 
461 	if( result != 1 )
462 	{
463 		libcerror_error_set(
464 		 error,
465 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
466 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
467 		 "%s: unable to retrieve grain group from extent file: %d at offset: %" PRIi64 ".",
468 		 function,
469 		 extent_number,
470 		 extent_file_data_offset );
471 
472 		return( -1 );
473 	}
474 	result = libfdata_list_get_element_value_at_offset(
475 		  grains_list,
476 		  (intptr_t *) file_io_pool,
477 		  (libfdata_cache_t *) grains_cache,
478 		  grain_group_data_offset,
479 		  &grains_list_index,
480 		  grain_data_offset,
481 		  (intptr_t **) grain_data,
482 		  0,
483 		  error );
484 
485 	if( result != 1 )
486 	{
487 		libcerror_error_set(
488 		 error,
489 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
490 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
491 		 "%s: unable to retrieve grain: %" PRIu64 " data from grain group: %d in extent file: %d at offset: %" PRIi64 ".",
492 		 function,
493 		 grain_index,
494 		 grain_groups_list_index,
495 		 extent_number,
496 		 extent_file_data_offset );
497 
498 		return( -1 );
499 	}
500 	return( 1 );
501 }
502 
503