1 /*
2  * Input/Output (IO) handle 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 <byte_stream.h>
24 #include <memory.h>
25 #include <types.h>
26 
27 #include "libqcow_cluster_block.h"
28 #include "libqcow_cluster_table.h"
29 #include "libqcow_encryption.h"
30 #include "libqcow_file_header.h"
31 #include "libqcow_io_handle.h"
32 #include "libqcow_libbfio.h"
33 #include "libqcow_libcerror.h"
34 #include "libqcow_libcnotify.h"
35 #include "libqcow_libfdata.h"
36 #include "libqcow_unused.h"
37 
38 #include "qcow_file_header.h"
39 
40 const uint8_t qcow_file_signature[ 4 ] = { 0x51, 0x46, 0x49, 0xfb };
41 
42 /* Creates an IO handle
43  * Make sure the value io_handle is referencing, is set to NULL
44  * Returns 1 if successful or -1 on error
45  */
libqcow_io_handle_initialize(libqcow_io_handle_t ** io_handle,libcerror_error_t ** error)46 int libqcow_io_handle_initialize(
47      libqcow_io_handle_t **io_handle,
48      libcerror_error_t **error )
49 {
50 	static char *function = "libqcow_io_handle_initialize";
51 
52 	if( io_handle == NULL )
53 	{
54 		libcerror_error_set(
55 		 error,
56 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
57 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
58 		 "%s: invalid IO handle.",
59 		 function );
60 
61 		return( -1 );
62 	}
63 	if( *io_handle != NULL )
64 	{
65 		libcerror_error_set(
66 		 error,
67 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
68 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
69 		 "%s: invalid IO handle value already set.",
70 		 function );
71 
72 		return( -1 );
73 	}
74 	*io_handle = memory_allocate_structure(
75 	              libqcow_io_handle_t );
76 
77 	if( *io_handle == NULL )
78 	{
79 		libcerror_error_set(
80 		 error,
81 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
82 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
83 		 "%s: unable to create IO handle.",
84 		 function );
85 
86 		goto on_error;
87 	}
88 	if( memory_set(
89 	     *io_handle,
90 	     0,
91 	     sizeof( libqcow_io_handle_t ) ) == NULL )
92 	{
93 		libcerror_error_set(
94 		 error,
95 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
96 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
97 		 "%s: unable to clear IO handle.",
98 		 function );
99 
100 		goto on_error;
101 	}
102 	return( 1 );
103 
104 on_error:
105 	if( *io_handle != NULL )
106 	{
107 		memory_free(
108 		 *io_handle );
109 
110 		*io_handle = NULL;
111 	}
112 	return( -1 );
113 }
114 
115 /* Frees an IO handle
116  * Returns 1 if successful or -1 on error
117  */
libqcow_io_handle_free(libqcow_io_handle_t ** io_handle,libcerror_error_t ** error)118 int libqcow_io_handle_free(
119      libqcow_io_handle_t **io_handle,
120      libcerror_error_t **error )
121 {
122 	static char *function = "libqcow_io_handle_free";
123 	int result            = 1;
124 
125 	if( io_handle == NULL )
126 	{
127 		libcerror_error_set(
128 		 error,
129 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
130 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
131 		 "%s: invalid IO handle.",
132 		 function );
133 
134 		return( -1 );
135 	}
136 	if( *io_handle != NULL )
137 	{
138 		if( libqcow_io_handle_clear(
139 		     *io_handle,
140 		     error ) != 1 )
141 		{
142 			libcerror_error_set(
143 			 error,
144 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
145 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
146 			 "%s: unable to clear IO handle.",
147 			 function );
148 
149 			result = -1;
150 		}
151 		memory_free(
152 		 *io_handle );
153 
154 		*io_handle = NULL;
155 	}
156 	return( result );
157 }
158 
159 /* Clears the IO handle
160  * Returns 1 if successful or -1 on error
161  */
libqcow_io_handle_clear(libqcow_io_handle_t * io_handle,libcerror_error_t ** error)162 int libqcow_io_handle_clear(
163      libqcow_io_handle_t *io_handle,
164      libcerror_error_t **error )
165 {
166 	static char *function = "libqcow_io_handle_clear";
167 
168 	if( io_handle == NULL )
169 	{
170 		libcerror_error_set(
171 		 error,
172 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
173 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
174 		 "%s: invalid IO handle.",
175 		 function );
176 
177 		return( -1 );
178 	}
179 	if( memory_set(
180 	     io_handle,
181 	     0,
182 	     sizeof( libqcow_io_handle_t ) ) == NULL )
183 	{
184 		libcerror_error_set(
185 		 error,
186 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
187 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
188 		 "%s: unable to clear IO handle.",
189 		 function );
190 
191 		return( -1 );
192 	}
193 	return( 1 );
194 }
195 
196 /* Reads a level 2 table
197  * Callback function for the level 2 table vector
198  * Returns 1 if successful or -1 on error
199  */
libqcow_io_handle_read_level2_table(intptr_t * data_handle LIBQCOW_ATTRIBUTE_UNUSED,libbfio_handle_t * file_io_handle,libfdata_vector_t * vector,libfdata_cache_t * cache,int element_index,int element_data_file_index LIBQCOW_ATTRIBUTE_UNUSED,off64_t element_data_offset,size64_t element_data_size,uint32_t element_data_flags LIBQCOW_ATTRIBUTE_UNUSED,uint8_t read_flags LIBQCOW_ATTRIBUTE_UNUSED,libcerror_error_t ** error)200 int libqcow_io_handle_read_level2_table(
201      intptr_t *data_handle LIBQCOW_ATTRIBUTE_UNUSED,
202      libbfio_handle_t *file_io_handle,
203      libfdata_vector_t *vector,
204      libfdata_cache_t *cache,
205      int element_index,
206      int element_data_file_index LIBQCOW_ATTRIBUTE_UNUSED,
207      off64_t element_data_offset,
208      size64_t element_data_size,
209      uint32_t element_data_flags LIBQCOW_ATTRIBUTE_UNUSED,
210      uint8_t read_flags LIBQCOW_ATTRIBUTE_UNUSED,
211      libcerror_error_t **error )
212 {
213 	libqcow_cluster_table_t *level2_table = NULL;
214 	static char *function                 = "libqcow_io_handle_read_level2_table";
215 
216 	LIBQCOW_UNREFERENCED_PARAMETER( data_handle );
217 	LIBQCOW_UNREFERENCED_PARAMETER( element_data_file_index );
218 	LIBQCOW_UNREFERENCED_PARAMETER( element_data_flags );
219 	LIBQCOW_UNREFERENCED_PARAMETER( read_flags );
220 
221 	if( element_data_size > (size64_t) SSIZE_MAX )
222 	{
223 		libcerror_error_set(
224 		 error,
225 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
226 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
227 		 "%s: invalid element data size value exceeds maximum.",
228 		 function );
229 
230 		return( -1 );
231 	}
232 	if( libqcow_cluster_table_initialize(
233 	     &level2_table,
234 	     error ) != 1 )
235 	{
236 		libcerror_error_set(
237 		 error,
238 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
239 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
240 		 "%s: unable to create level 2 table.",
241 		 function );
242 
243 		goto on_error;
244 	}
245 	if( libqcow_cluster_table_read(
246 	     level2_table,
247 	     file_io_handle,
248 	     element_data_offset,
249 	     (size_t) element_data_size,
250 	     error ) != 1 )
251 	{
252 		libcerror_error_set(
253 		 error,
254 		 LIBCERROR_ERROR_DOMAIN_IO,
255 		 LIBCERROR_IO_ERROR_READ_FAILED,
256 		 "%s: unable to read level 2 table.",
257 		 function );
258 
259 		goto on_error;
260 	}
261 	if( libfdata_vector_set_element_value_by_index(
262 	     vector,
263 	     (intptr_t *) file_io_handle,
264 	     cache,
265 	     element_index,
266 	     (intptr_t *) level2_table,
267 	     (int (*)(intptr_t **, libcerror_error_t **)) &libqcow_cluster_table_free,
268 	     LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
269 	     error ) != 1 )
270 	{
271 		libcerror_error_set(
272 		 error,
273 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
274 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
275 		 "%s: unable to set level 2 table as element value.",
276 		 function );
277 
278 		goto on_error;
279 	}
280 	return( 1 );
281 
282 on_error:
283 	if( level2_table != NULL )
284 	{
285 		libqcow_cluster_table_free(
286 		 &level2_table,
287 		 NULL );
288 	}
289 	return( -1 );
290 }
291 
292 /* Reads a cluster block
293  * Callback function for the cluster block vector
294  * Returns 1 if successful or -1 on error
295  */
libqcow_io_handle_read_cluster_block(intptr_t * data_handle LIBQCOW_ATTRIBUTE_UNUSED,libbfio_handle_t * file_io_handle,libfdata_vector_t * vector,libfdata_cache_t * cache,int element_index,int element_data_file_index LIBQCOW_ATTRIBUTE_UNUSED,off64_t element_data_offset,size64_t element_data_size,uint32_t element_data_flags LIBQCOW_ATTRIBUTE_UNUSED,uint8_t read_flags LIBQCOW_ATTRIBUTE_UNUSED,libcerror_error_t ** error)296 int libqcow_io_handle_read_cluster_block(
297      intptr_t *data_handle LIBQCOW_ATTRIBUTE_UNUSED,
298      libbfio_handle_t *file_io_handle,
299      libfdata_vector_t *vector,
300      libfdata_cache_t *cache,
301      int element_index,
302      int element_data_file_index LIBQCOW_ATTRIBUTE_UNUSED,
303      off64_t element_data_offset,
304      size64_t element_data_size,
305      uint32_t element_data_flags LIBQCOW_ATTRIBUTE_UNUSED,
306      uint8_t read_flags LIBQCOW_ATTRIBUTE_UNUSED,
307      libcerror_error_t **error )
308 {
309 	libqcow_cluster_block_t *cluster_block = NULL;
310 	static char *function                  = "libqcow_io_handle_read_cluster_block";
311 
312 	LIBQCOW_UNREFERENCED_PARAMETER( data_handle );
313 	LIBQCOW_UNREFERENCED_PARAMETER( element_data_file_index );
314 	LIBQCOW_UNREFERENCED_PARAMETER( element_data_flags );
315 	LIBQCOW_UNREFERENCED_PARAMETER( read_flags );
316 
317 	if( element_data_size > (size64_t) SSIZE_MAX )
318 	{
319 		libcerror_error_set(
320 		 error,
321 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
322 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
323 		 "%s: invalid element data size value exceeds maximum.",
324 		 function );
325 
326 		goto on_error;
327 	}
328 	if( libqcow_cluster_block_initialize(
329 	     &cluster_block,
330 	     (size_t) element_data_size,
331 	     error ) != 1 )
332 	{
333 		libcerror_error_set(
334 		 error,
335 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
336 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
337 		 "%s: unable to create cluster block.",
338 		 function );
339 
340 		goto on_error;
341 	}
342 	if( libqcow_cluster_block_read(
343 	     cluster_block,
344 	     file_io_handle,
345              element_data_offset,
346 	     error ) != 1 )
347 	{
348 		libcerror_error_set(
349 		 error,
350 		 LIBCERROR_ERROR_DOMAIN_IO,
351 		 LIBCERROR_IO_ERROR_READ_FAILED,
352 		 "%s: unable to read cluster block.",
353 		 function );
354 
355 		goto on_error;
356 	}
357 	if( libfdata_vector_set_element_value_by_index(
358 	     vector,
359 	     (intptr_t *) file_io_handle,
360 	     cache,
361 	     element_index,
362 	     (intptr_t *) cluster_block,
363 	     (int (*)(intptr_t **, libcerror_error_t **)) &libqcow_cluster_block_free,
364 	     LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
365 	     error ) != 1 )
366 	{
367 		libcerror_error_set(
368 		 error,
369 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
370 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
371 		 "%s: unable to set cluster block as element value.",
372 		 function );
373 
374 		goto on_error;
375 	}
376 	return( 1 );
377 
378 on_error:
379 	if( cluster_block != NULL )
380 	{
381 		libqcow_cluster_block_free(
382 		 &cluster_block,
383 		 NULL );
384 	}
385 	return( -1 );
386 }
387 
388