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