Coverage Report

Created: 2025-06-24 07:14

/src/libqcow/libqcow/libqcow_cluster_table.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Cluster table functions
3
 *
4
 * Copyright (C) 2010-2024, 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_table.h"
28
#include "libqcow_libbfio.h"
29
#include "libqcow_libcerror.h"
30
#include "libqcow_libcnotify.h"
31
32
/* Creates a cluster table
33
 * Make sure the value cluste_table is referencing, is set to NULL
34
 * Returns 1 if successful or -1 on error
35
 */
36
int libqcow_cluster_table_initialize(
37
     libqcow_cluster_table_t **cluster_table,
38
     libcerror_error_t **error )
39
161
{
40
161
  static char *function = "libqcow_cluster_table_initialize";
41
42
161
  if( cluster_table == NULL )
43
0
  {
44
0
    libcerror_error_set(
45
0
     error,
46
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
47
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
48
0
     "%s: invalid cluster table.",
49
0
     function );
50
51
0
    return( -1 );
52
0
  }
53
161
  if( *cluster_table != NULL )
54
0
  {
55
0
    libcerror_error_set(
56
0
     error,
57
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
58
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
59
0
     "%s: invalid cluster table value already set.",
60
0
     function );
61
62
0
    return( -1 );
63
0
  }
64
161
  *cluster_table = memory_allocate_structure(
65
161
                    libqcow_cluster_table_t );
66
67
161
  if( *cluster_table == NULL )
68
0
  {
69
0
    libcerror_error_set(
70
0
     error,
71
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
72
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
73
0
     "%s: unable to create cluster table.",
74
0
     function );
75
76
0
    goto on_error;
77
0
  }
78
161
  if( memory_set(
79
161
       *cluster_table,
80
161
       0,
81
161
       sizeof( libqcow_cluster_table_t ) ) == NULL )
82
0
  {
83
0
    libcerror_error_set(
84
0
     error,
85
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
86
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
87
0
     "%s: unable to clear cluster table.",
88
0
     function );
89
90
0
    goto on_error;
91
0
  }
92
161
  return( 1 );
93
94
0
on_error:
95
0
  if( *cluster_table != NULL )
96
0
  {
97
0
    memory_free(
98
0
     *cluster_table );
99
100
0
    *cluster_table = NULL;
101
0
  }
102
0
  return( -1 );
103
161
}
104
105
/* Frees a cluster table
106
 * Returns 1 if successful or -1 on error
107
 */
108
int libqcow_cluster_table_free(
109
     libqcow_cluster_table_t **cluster_table,
110
     libcerror_error_t **error )
111
161
{
112
161
  static char *function = "libqcow_cluster_table_free";
113
114
161
  if( cluster_table == NULL )
115
0
  {
116
0
    libcerror_error_set(
117
0
     error,
118
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
119
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
120
0
     "%s: invalid cluster table.",
121
0
     function );
122
123
0
    return( -1 );
124
0
  }
125
161
  if( *cluster_table != NULL )
126
161
  {
127
161
    if( ( *cluster_table )->references != NULL )
128
47
    {
129
47
      memory_free(
130
47
       ( *cluster_table )->references );
131
47
    }
132
161
    memory_free(
133
161
     *cluster_table );
134
135
161
    *cluster_table = NULL;
136
161
  }
137
161
  return( 1 );
138
161
}
139
140
/* Retrieves the number of references in the cluster table
141
 * Returns 1 if successful or -1 on error
142
 */
143
int libqcow_cluster_table_get_number_of_references(
144
     libqcow_cluster_table_t *cluster_table,
145
     int *number_of_references,
146
     libcerror_error_t **error )
147
0
{
148
0
  static char *function = "libqcow_cluster_table_get_number_of_references";
149
150
0
  if( cluster_table == NULL )
151
0
  {
152
0
    libcerror_error_set(
153
0
     error,
154
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
155
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
156
0
     "%s: invalid cluster table.",
157
0
     function );
158
159
0
    return( -1 );
160
0
  }
161
0
  if( number_of_references == NULL )
162
0
  {
163
0
    libcerror_error_set(
164
0
     error,
165
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
166
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
167
0
     "%s: invalid number of references.",
168
0
     function );
169
170
0
    return( -1 );
171
0
  }
172
0
  *number_of_references = cluster_table->number_of_references;
173
174
0
  return( 1 );
175
0
}
176
177
/* Retrieves a specific reference from the cluster table
178
 * Returns 1 if successful or -1 on error
179
 */
180
int libqcow_cluster_table_get_reference_by_index(
181
     libqcow_cluster_table_t *cluster_table,
182
     int reference_index,
183
     uint64_t *reference,
184
     libcerror_error_t **error )
185
0
{
186
0
  static char *function = "libqcow_cluster_table_get_reference_by_index";
187
188
0
  if( cluster_table == NULL )
189
0
  {
190
0
    libcerror_error_set(
191
0
     error,
192
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
193
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
194
0
     "%s: invalid cluster table.",
195
0
     function );
196
197
0
    return( -1 );
198
0
  }
199
0
  if( cluster_table->references == NULL )
200
0
  {
201
0
    libcerror_error_set(
202
0
     error,
203
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
204
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
205
0
     "%s: invalid cluster table - missing references.",
206
0
     function );
207
208
0
    return( -1 );
209
0
  }
210
0
  if( ( reference_index < 0 )
211
0
   || ( reference_index >= cluster_table->number_of_references ) )
212
0
  {
213
0
    libcerror_error_set(
214
0
     error,
215
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
216
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
217
0
     "%s: invalid reference index value out of bounds.",
218
0
     function );
219
220
0
    return( -1 );
221
0
  }
222
0
  if( reference == NULL )
223
0
  {
224
0
    libcerror_error_set(
225
0
     error,
226
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
227
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
228
0
     "%s: invalid reference.",
229
0
     function );
230
231
0
    return( -1 );
232
0
  }
233
0
  *reference = cluster_table->references[ reference_index ];
234
235
0
  return( 1 );
236
0
}
237
238
/* Reads the cluster table
239
 * Returns 1 if successful or -1 on error
240
 */
241
int libqcow_cluster_table_read(
242
     libqcow_cluster_table_t *cluster_table,
243
     libbfio_handle_t *file_io_handle,
244
     off64_t file_offset,
245
     size_t cluster_table_size,
246
     libcerror_error_t **error )
247
161
{
248
161
  uint8_t *cluster_table_data      = NULL;
249
161
  static char *function            = "libqcow_cluster_table_read";
250
161
  size_t cluster_table_data_offset = 0;
251
161
  ssize_t read_count               = 0;
252
161
  int cluster_table_index          = 0;
253
254
161
  if( cluster_table == NULL )
255
0
  {
256
0
    libcerror_error_set(
257
0
     error,
258
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
259
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
260
0
     "%s: invalid cluster table.",
261
0
     function );
262
263
0
    return( -1 );
264
0
  }
265
161
  if( cluster_table->references != NULL )
266
0
  {
267
0
    libcerror_error_set(
268
0
     error,
269
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
270
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
271
0
     "%s: invalid cluster table - references already set.",
272
0
     function );
273
274
0
    return( -1 );
275
0
  }
276
161
  if( ( cluster_table_size == 0 )
277
161
   || ( cluster_table_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE )
278
161
   || ( ( cluster_table_size % 8 ) != 0 ) )
279
0
  {
280
0
    libcerror_error_set(
281
0
     error,
282
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
283
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
284
0
     "%s: invalid cluster table size value out of bounds.",
285
0
     function );
286
287
0
    return( -1 );
288
0
  }
289
161
  if( ( cluster_table_size / 8 ) > (size_t) INT_MAX )
290
0
  {
291
0
    libcerror_error_set(
292
0
     error,
293
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
294
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
295
0
     "%s: invalid number of references value exceeds maximum.",
296
0
     function );
297
298
0
    return( -1 );
299
0
  }
300
161
  cluster_table->references = (uint64_t *) memory_allocate(
301
161
                                            cluster_table_size );
302
303
161
  if( cluster_table->references == NULL )
304
0
  {
305
0
    libcerror_error_set(
306
0
     error,
307
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
308
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
309
0
     "%s: unable to create references.",
310
0
     function );
311
312
0
    goto on_error;
313
0
  }
314
161
  cluster_table->number_of_references = (int) ( cluster_table_size / 8 );
315
316
161
  cluster_table_data = (uint8_t *) memory_allocate(
317
161
                                    cluster_table_size );
318
319
161
  if( cluster_table_data == NULL )
320
0
  {
321
0
    libcerror_error_set(
322
0
     error,
323
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
324
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
325
0
     "%s: unable to create cluster table data.",
326
0
     function );
327
328
0
    goto on_error;
329
0
  }
330
#if defined( HAVE_DEBUG_OUTPUT )
331
  if( libcnotify_verbose != 0 )
332
  {
333
    libcnotify_printf(
334
     "%s: reading cluster table at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
335
     function,
336
     file_offset,
337
     file_offset );
338
  }
339
#endif
340
161
  read_count = libbfio_handle_read_buffer_at_offset(
341
161
                file_io_handle,
342
161
                cluster_table_data,
343
161
                cluster_table_size,
344
161
                file_offset,
345
161
                error );
346
347
161
  if( read_count != (ssize_t) cluster_table_size )
348
114
  {
349
114
    libcerror_error_set(
350
114
     error,
351
114
     LIBCERROR_ERROR_DOMAIN_IO,
352
114
     LIBCERROR_IO_ERROR_READ_FAILED,
353
114
     "%s: unable to read cluster table at offset: %" PRIi64 " (0x%08" PRIx64 ").",
354
114
     function,
355
114
     file_offset,
356
114
     file_offset );
357
358
114
    goto on_error;
359
114
  }
360
#if defined( HAVE_DEBUG_OUTPUT )
361
  if( libcnotify_verbose != 0 )
362
  {
363
    libcnotify_printf(
364
     "%s: cluster table data:\n",
365
     function );
366
    libcnotify_print_data(
367
     cluster_table_data,
368
     cluster_table_size,
369
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
370
  }
371
#endif
372
47
  for( cluster_table_index = 0;
373
481k
       cluster_table_index < cluster_table->number_of_references;
374
481k
       cluster_table_index++ )
375
481k
  {
376
481k
    byte_stream_copy_to_uint64_big_endian(
377
481k
     &( cluster_table_data[ cluster_table_data_offset ] ),
378
481k
     ( cluster_table->references )[ cluster_table_index ] );
379
380
481k
    cluster_table_data_offset += 8;
381
382
#if defined( HAVE_DEBUG_OUTPUT )
383
    if( libcnotify_verbose != 0 )
384
    {
385
      libcnotify_printf(
386
       "%s: cluster table reference: %03d\t\t: 0x%08" PRIx64 "\n",
387
       function,
388
       cluster_table_index,
389
       ( cluster_table->references )[ cluster_table_index ] );
390
    }
391
#endif
392
481k
  }
393
#if defined( HAVE_DEBUG_OUTPUT )
394
  if( libcnotify_verbose != 0 )
395
  {
396
    libcnotify_printf(
397
     "\n" );
398
  }
399
#endif
400
47
  memory_free(
401
47
   cluster_table_data );
402
403
47
  cluster_table_data = NULL;
404
405
47
  return( 1 );
406
407
114
on_error:
408
114
  if( cluster_table_data != NULL )
409
114
  {
410
114
    memory_free(
411
114
     cluster_table_data );
412
114
  }
413
114
  if( cluster_table->references != NULL )
414
114
  {
415
114
    memory_free(
416
114
     cluster_table->references );
417
418
114
    cluster_table->references = NULL;
419
114
  }
420
114
  return( -1 );
421
161
}
422