Coverage Report

Created: 2026-01-20 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libqcow/libqcow/libqcow_io_handle.c
Line
Count
Source
1
/*
2
 * Input/Output (IO) handle functions
3
 *
4
 * Copyright (C) 2010-2025, 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
 */
46
int libqcow_io_handle_initialize(
47
     libqcow_io_handle_t **io_handle,
48
     libcerror_error_t **error )
49
925
{
50
925
  static char *function = "libqcow_io_handle_initialize";
51
52
925
  if( io_handle == NULL )
53
0
  {
54
0
    libcerror_error_set(
55
0
     error,
56
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
57
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
58
0
     "%s: invalid IO handle.",
59
0
     function );
60
61
0
    return( -1 );
62
0
  }
63
925
  if( *io_handle != NULL )
64
0
  {
65
0
    libcerror_error_set(
66
0
     error,
67
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
68
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
69
0
     "%s: invalid IO handle value already set.",
70
0
     function );
71
72
0
    return( -1 );
73
0
  }
74
925
  *io_handle = memory_allocate_structure(
75
925
                libqcow_io_handle_t );
76
77
925
  if( *io_handle == NULL )
78
0
  {
79
0
    libcerror_error_set(
80
0
     error,
81
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
82
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
83
0
     "%s: unable to create IO handle.",
84
0
     function );
85
86
0
    goto on_error;
87
0
  }
88
925
  if( memory_set(
89
925
       *io_handle,
90
925
       0,
91
925
       sizeof( libqcow_io_handle_t ) ) == NULL )
92
0
  {
93
0
    libcerror_error_set(
94
0
     error,
95
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
96
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
97
0
     "%s: unable to clear IO handle.",
98
0
     function );
99
100
0
    goto on_error;
101
0
  }
102
925
  return( 1 );
103
104
0
on_error:
105
0
  if( *io_handle != NULL )
106
0
  {
107
0
    memory_free(
108
0
     *io_handle );
109
110
0
    *io_handle = NULL;
111
0
  }
112
0
  return( -1 );
113
925
}
114
115
/* Frees an IO handle
116
 * Returns 1 if successful or -1 on error
117
 */
118
int libqcow_io_handle_free(
119
     libqcow_io_handle_t **io_handle,
120
     libcerror_error_t **error )
121
925
{
122
925
  static char *function = "libqcow_io_handle_free";
123
925
  int result            = 1;
124
125
925
  if( io_handle == NULL )
126
0
  {
127
0
    libcerror_error_set(
128
0
     error,
129
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
130
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
131
0
     "%s: invalid IO handle.",
132
0
     function );
133
134
0
    return( -1 );
135
0
  }
136
925
  if( *io_handle != NULL )
137
925
  {
138
925
    if( libqcow_io_handle_clear(
139
925
         *io_handle,
140
925
         error ) != 1 )
141
0
    {
142
0
      libcerror_error_set(
143
0
       error,
144
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
145
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
146
0
       "%s: unable to clear IO handle.",
147
0
       function );
148
149
0
      result = -1;
150
0
    }
151
925
    memory_free(
152
925
     *io_handle );
153
154
925
    *io_handle = NULL;
155
925
  }
156
925
  return( result );
157
925
}
158
159
/* Clears the IO handle
160
 * Returns 1 if successful or -1 on error
161
 */
162
int libqcow_io_handle_clear(
163
     libqcow_io_handle_t *io_handle,
164
     libcerror_error_t **error )
165
969
{
166
969
  static char *function = "libqcow_io_handle_clear";
167
168
969
  if( io_handle == NULL )
169
0
  {
170
0
    libcerror_error_set(
171
0
     error,
172
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
173
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
174
0
     "%s: invalid IO handle.",
175
0
     function );
176
177
0
    return( -1 );
178
0
  }
179
969
  if( memory_set(
180
969
       io_handle,
181
969
       0,
182
969
       sizeof( libqcow_io_handle_t ) ) == NULL )
183
0
  {
184
0
    libcerror_error_set(
185
0
     error,
186
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
187
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
188
0
     "%s: unable to clear IO handle.",
189
0
     function );
190
191
0
    return( -1 );
192
0
  }
193
969
  return( 1 );
194
969
}
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
 */
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
0
{
213
0
  libqcow_cluster_table_t *level2_table = NULL;
214
0
  static char *function                 = "libqcow_io_handle_read_level2_table";
215
216
0
  LIBQCOW_UNREFERENCED_PARAMETER( data_handle );
217
0
  LIBQCOW_UNREFERENCED_PARAMETER( element_data_file_index );
218
0
  LIBQCOW_UNREFERENCED_PARAMETER( element_data_flags );
219
0
  LIBQCOW_UNREFERENCED_PARAMETER( read_flags );
220
221
0
  if( element_data_size > (size64_t) SSIZE_MAX )
222
0
  {
223
0
    libcerror_error_set(
224
0
     error,
225
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
226
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
227
0
     "%s: invalid element data size value exceeds maximum.",
228
0
     function );
229
230
0
    return( -1 );
231
0
  }
232
0
  if( libqcow_cluster_table_initialize(
233
0
       &level2_table,
234
0
       error ) != 1 )
235
0
  {
236
0
    libcerror_error_set(
237
0
     error,
238
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
239
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
240
0
     "%s: unable to create level 2 table.",
241
0
     function );
242
243
0
    goto on_error;
244
0
  }
245
0
  if( libqcow_cluster_table_read(
246
0
       level2_table,
247
0
       file_io_handle,
248
0
       element_data_offset,
249
0
       (size_t) element_data_size,
250
0
       error ) != 1 )
251
0
  {
252
0
    libcerror_error_set(
253
0
     error,
254
0
     LIBCERROR_ERROR_DOMAIN_IO,
255
0
     LIBCERROR_IO_ERROR_READ_FAILED,
256
0
     "%s: unable to read level 2 table.",
257
0
     function );
258
259
0
    goto on_error;
260
0
  }
261
0
  if( libfdata_vector_set_element_value_by_index(
262
0
       vector,
263
0
       (intptr_t *) file_io_handle,
264
0
       cache,
265
0
       element_index,
266
0
       (intptr_t *) level2_table,
267
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libqcow_cluster_table_free,
268
0
       LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
269
0
       error ) != 1 )
270
0
  {
271
0
    libcerror_error_set(
272
0
     error,
273
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
274
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
275
0
     "%s: unable to set level 2 table as element value.",
276
0
     function );
277
278
0
    goto on_error;
279
0
  }
280
0
  return( 1 );
281
282
0
on_error:
283
0
  if( level2_table != NULL )
284
0
  {
285
0
    libqcow_cluster_table_free(
286
0
     &level2_table,
287
0
     NULL );
288
0
  }
289
0
  return( -1 );
290
0
}
291
292
/* Reads a cluster block
293
 * Callback function for the cluster block vector
294
 * Returns 1 if successful or -1 on error
295
 */
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
0
{
309
0
  libqcow_cluster_block_t *cluster_block = NULL;
310
0
  static char *function                  = "libqcow_io_handle_read_cluster_block";
311
312
0
  LIBQCOW_UNREFERENCED_PARAMETER( data_handle );
313
0
  LIBQCOW_UNREFERENCED_PARAMETER( element_data_file_index );
314
0
  LIBQCOW_UNREFERENCED_PARAMETER( element_data_flags );
315
0
  LIBQCOW_UNREFERENCED_PARAMETER( read_flags );
316
317
0
  if( element_data_size > (size64_t) SSIZE_MAX )
318
0
  {
319
0
    libcerror_error_set(
320
0
     error,
321
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
322
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
323
0
     "%s: invalid element data size value exceeds maximum.",
324
0
     function );
325
326
0
    goto on_error;
327
0
  }
328
0
  if( libqcow_cluster_block_initialize(
329
0
       &cluster_block,
330
0
       (size_t) element_data_size,
331
0
       error ) != 1 )
332
0
  {
333
0
    libcerror_error_set(
334
0
     error,
335
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
336
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
337
0
     "%s: unable to create cluster block.",
338
0
     function );
339
340
0
    goto on_error;
341
0
  }
342
0
  if( libqcow_cluster_block_read(
343
0
       cluster_block,
344
0
       file_io_handle,
345
0
             element_data_offset,
346
0
       error ) != 1 )
347
0
  {
348
0
    libcerror_error_set(
349
0
     error,
350
0
     LIBCERROR_ERROR_DOMAIN_IO,
351
0
     LIBCERROR_IO_ERROR_READ_FAILED,
352
0
     "%s: unable to read cluster block.",
353
0
     function );
354
355
0
    goto on_error;
356
0
  }
357
0
  if( libfdata_vector_set_element_value_by_index(
358
0
       vector,
359
0
       (intptr_t *) file_io_handle,
360
0
       cache,
361
0
       element_index,
362
0
       (intptr_t *) cluster_block,
363
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libqcow_cluster_block_free,
364
0
       LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
365
0
       error ) != 1 )
366
0
  {
367
0
    libcerror_error_set(
368
0
     error,
369
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
370
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
371
0
     "%s: unable to set cluster block as element value.",
372
0
     function );
373
374
0
    goto on_error;
375
0
  }
376
0
  return( 1 );
377
378
0
on_error:
379
0
  if( cluster_block != NULL )
380
0
  {
381
0
    libqcow_cluster_block_free(
382
0
     &cluster_block,
383
     NULL );
384
0
  }
385
0
  return( -1 );
386
0
}
387