Coverage Report

Created: 2026-01-20 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libscca/libscca/libscca_compressed_blocks_stream.c
Line
Count
Source
1
/*
2
 * The compressed blocks stream functions
3
 *
4
 * Copyright (C) 2011-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 <memory.h>
24
#include <types.h>
25
26
#include "libscca_compressed_block.h"
27
#include "libscca_compressed_blocks_stream.h"
28
#include "libscca_definitions.h"
29
#include "libscca_libcerror.h"
30
#include "libscca_libfcache.h"
31
#include "libscca_libfdata.h"
32
#include "libscca_unused.h"
33
34
/* Creates a data handle
35
 * Make sure the value data_handle is referencing, is set to NULL
36
 * Returns 1 if successful or -1 on error
37
 */
38
int libscca_compressed_blocks_stream_data_handle_initialize(
39
     libscca_compressed_blocks_stream_data_handle_t **data_handle,
40
     libcerror_error_t **error )
41
141
{
42
141
  static char *function = "libscca_compressed_blocks_stream_data_handle_initialize";
43
44
141
  if( data_handle == NULL )
45
0
  {
46
0
    libcerror_error_set(
47
0
     error,
48
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
49
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
50
0
     "%s: invalid data handle.",
51
0
     function );
52
53
0
    return( -1 );
54
0
  }
55
141
  if( *data_handle != NULL )
56
0
  {
57
0
    libcerror_error_set(
58
0
     error,
59
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
60
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
61
0
     "%s: invalid data handle value already set.",
62
0
     function );
63
64
0
    return( -1 );
65
0
  }
66
141
  *data_handle = memory_allocate_structure(
67
141
                  libscca_compressed_blocks_stream_data_handle_t );
68
69
141
  if( *data_handle == NULL )
70
0
  {
71
0
    libcerror_error_set(
72
0
     error,
73
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
74
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
75
0
     "%s: unable to create data handle.",
76
0
     function );
77
78
0
    goto on_error;
79
0
  }
80
141
  if( memory_set(
81
141
       *data_handle,
82
141
       0,
83
141
       sizeof( libscca_compressed_blocks_stream_data_handle_t ) ) == NULL )
84
0
  {
85
0
    libcerror_error_set(
86
0
     error,
87
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
88
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
89
0
     "%s: unable to clear data handle.",
90
0
     function );
91
92
0
    memory_free(
93
0
     *data_handle );
94
95
0
    *data_handle = NULL;
96
97
0
    return( -1 );
98
0
  }
99
141
  return( 1 );
100
101
0
on_error:
102
0
  if( *data_handle != NULL )
103
0
  {
104
0
    memory_free(
105
0
     *data_handle );
106
107
0
    *data_handle = NULL;
108
0
  }
109
0
  return( -1 );
110
141
}
111
112
/* Frees a data handle
113
 * Returns 1 if successful or -1 on error
114
 */
115
int libscca_compressed_blocks_stream_data_handle_free(
116
     libscca_compressed_blocks_stream_data_handle_t **data_handle,
117
     libcerror_error_t **error )
118
141
{
119
141
  static char *function = "libscca_compressed_blocks_stream_data_handle_free";
120
141
  int result            = 1;
121
122
141
  if( data_handle == NULL )
123
0
  {
124
0
    libcerror_error_set(
125
0
     error,
126
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
127
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
128
0
     "%s: invalid data handle.",
129
0
     function );
130
131
0
    return( -1 );
132
0
  }
133
141
  if( *data_handle != NULL )
134
141
  {
135
    /* The compressed_blocks_list and compressed_blocks_cache values are referenced and freed elsewhere
136
     */
137
141
    memory_free(
138
141
     *data_handle );
139
140
141
    *data_handle = NULL;
141
141
  }
142
141
  return( result );
143
141
}
144
145
/* Reads data from the current offset into a buffer
146
 * Callback for the compressed block stream
147
 * Returns the number of bytes read or -1 on error
148
 */
149
ssize_t libscca_compressed_blocks_stream_data_handle_read_segment_data(
150
         libscca_compressed_blocks_stream_data_handle_t *data_handle,
151
         intptr_t *file_io_handle,
152
         int segment_index,
153
         int segment_file_index LIBSCCA_ATTRIBUTE_UNUSED,
154
         uint8_t *segment_data,
155
         size_t segment_data_size,
156
         uint32_t segment_flags LIBSCCA_ATTRIBUTE_UNUSED,
157
         uint8_t read_flags,
158
         libcerror_error_t **error )
159
138
{
160
138
  libscca_compressed_block_t *compressed_block = NULL;
161
138
  static char *function                        = "libscca_compressed_blocks_stream_data_handle_read_segment_data";
162
138
  off64_t segment_data_offset                  = 0;
163
138
  ssize_t read_count                           = 0;
164
165
138
  LIBSCCA_UNREFERENCED_PARAMETER( segment_file_index )
166
138
  LIBSCCA_UNREFERENCED_PARAMETER( segment_flags )
167
168
138
  if( data_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 data handle.",
175
0
     function );
176
177
0
    return( -1 );
178
0
  }
179
138
  if( segment_data == NULL )
180
0
  {
181
0
    libcerror_error_set(
182
0
     error,
183
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
184
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
185
0
     "%s: invalid segment data.",
186
0
     function );
187
188
0
    return( -1 );
189
0
  }
190
138
  if( segment_data_size > (size_t) SSIZE_MAX )
191
0
  {
192
0
    libcerror_error_set(
193
0
     error,
194
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
195
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
196
0
     "%s: invalid segment data size value exceeds maximum.",
197
0
     function );
198
199
0
    return( -1 );
200
0
  }
201
138
  if( libfdata_list_get_element_value_at_offset(
202
138
       data_handle->compressed_blocks_list,
203
138
       (intptr_t *) file_io_handle,
204
138
       (libfdata_cache_t *) data_handle->compressed_blocks_cache,
205
138
       data_handle->current_offset,
206
138
       &segment_index,
207
138
       &segment_data_offset,
208
138
       (intptr_t **) &compressed_block,
209
138
       read_flags,
210
138
       error ) != 1 )
211
0
  {
212
0
    libcerror_error_set(
213
0
     error,
214
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
215
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
216
0
     "%s: unable to retrieve compressed block: %d from list.",
217
0
     function,
218
0
     segment_index );
219
220
0
    return( -1 );
221
0
  }
222
138
  if( compressed_block == NULL )
223
0
  {
224
0
    libcerror_error_set(
225
0
     error,
226
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
227
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
228
0
     "%s: missing compressed block: %d.",
229
0
     function,
230
0
     segment_index );
231
232
0
    return( -1 );
233
0
  }
234
138
  if( ( segment_data_offset < 0 )
235
138
   || ( segment_data_offset >= (off64_t) compressed_block->data_size ) )
236
0
  {
237
0
    libcerror_error_set(
238
0
     error,
239
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
240
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
241
0
     "%s: invalid segment data offset value out of bounds.",
242
0
     function );
243
244
0
    return( -1 );
245
0
  }
246
138
  if( (off64_t) ( segment_data_offset + segment_data_size ) > (off64_t) compressed_block->data_size )
247
0
  {
248
0
    read_count = (ssize_t) ( compressed_block->data_size - segment_data_offset );
249
0
  }
250
138
  else
251
138
  {
252
138
    read_count = (ssize_t) segment_data_size;
253
138
  }
254
138
  if( memory_copy(
255
138
       segment_data,
256
138
       &( compressed_block->data[ segment_data_offset ] ),
257
138
       (size_t) read_count ) == NULL )
258
0
  {
259
0
    libcerror_error_set(
260
0
     error,
261
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
262
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
263
0
     "%s: unable to copy compressed block data.",
264
0
     function );
265
266
0
    return( -1 );
267
0
  }
268
138
  data_handle->current_offset += read_count;
269
270
138
  return( read_count );
271
138
}
272
273
/* Seeks a certain offset of the data
274
 * Callback for the compressed block stream
275
 * Returns the offset if seek is successful or -1 on error
276
 */
277
off64_t libscca_compressed_blocks_stream_data_handle_seek_segment_offset(
278
         libscca_compressed_blocks_stream_data_handle_t *data_handle,
279
         intptr_t *file_io_handle LIBSCCA_ATTRIBUTE_UNUSED,
280
         int segment_index LIBSCCA_ATTRIBUTE_UNUSED,
281
         int segment_file_index LIBSCCA_ATTRIBUTE_UNUSED,
282
         off64_t segment_offset,
283
         libcerror_error_t **error )
284
138
{
285
138
  static char *function = "libscca_compressed_blocks_stream_data_handle_seek_segment_offset";
286
287
138
  LIBSCCA_UNREFERENCED_PARAMETER( file_io_handle )
288
138
  LIBSCCA_UNREFERENCED_PARAMETER( segment_index )
289
138
  LIBSCCA_UNREFERENCED_PARAMETER( segment_file_index )
290
291
138
  if( data_handle == NULL )
292
0
  {
293
0
    libcerror_error_set(
294
0
     error,
295
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
296
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
297
0
     "%s: invalid data handle.",
298
0
     function );
299
300
0
    return( -1 );
301
0
  }
302
138
  if( segment_offset < 0 )
303
0
  {
304
0
    libcerror_error_set(
305
0
     error,
306
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
307
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
308
0
     "%s: invalid segment offset value out of bounds.",
309
0
     function );
310
311
0
    return( -1 );
312
0
  }
313
138
  data_handle->current_offset = segment_offset;
314
315
138
  return( segment_offset );
316
138
}
317
318
/* Creates a compressed block stream
319
 * Make sure the value compressed_blocks_stream is referencing, is set to NULL
320
 * Returns 1 if successful or -1 on error
321
 */
322
int libscca_compressed_blocks_stream_initialize(
323
     libfdata_stream_t **compressed_blocks_stream,
324
     libfdata_list_t *compressed_blocks_list,
325
     libfcache_cache_t *compressed_blocks_cache,
326
     libcerror_error_t **error )
327
141
{
328
141
  libscca_compressed_blocks_stream_data_handle_t *data_handle = NULL;
329
141
  static char *function                                       = "libscca_compressed_blocks_stream_initialize";
330
141
  off64_t segment_offset                                      = 0;
331
141
  size64_t segment_size                                       = 0;
332
141
  int element_index                                           = 0;
333
141
  int number_of_elements                                      = 0;
334
141
  int segment_index                                           = 0;
335
336
141
  if( compressed_blocks_stream == NULL )
337
0
  {
338
0
    libcerror_error_set(
339
0
     error,
340
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
341
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
342
0
     "%s: invalid compressed block stream.",
343
0
     function );
344
345
0
    return( -1 );
346
0
  }
347
141
  if( compressed_blocks_list == NULL )
348
0
  {
349
0
    libcerror_error_set(
350
0
     error,
351
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
352
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
353
0
     "%s: invalid compressed blocks list.",
354
0
     function );
355
356
0
    return( -1 );
357
0
  }
358
141
  if( libscca_compressed_blocks_stream_data_handle_initialize(
359
141
       &data_handle,
360
141
       error ) != 1 )
361
0
  {
362
0
    libcerror_error_set(
363
0
     error,
364
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
365
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
366
0
     "%s: unable to create data handle.",
367
0
     function );
368
369
0
    goto on_error;
370
0
  }
371
141
  if( data_handle == NULL )
372
0
  {
373
0
    libcerror_error_set(
374
0
     error,
375
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
376
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
377
0
     "%s: missing data handle.",
378
0
     function );
379
380
0
    goto on_error;
381
0
  }
382
141
  data_handle->compressed_blocks_list  = compressed_blocks_list;
383
141
  data_handle->compressed_blocks_cache = compressed_blocks_cache;
384
385
141
  if( libfdata_stream_initialize(
386
141
       compressed_blocks_stream,
387
141
       (intptr_t *) data_handle,
388
141
       (int (*)(intptr_t **, libcerror_error_t **)) &libscca_compressed_blocks_stream_data_handle_free,
389
141
       NULL,
390
141
       NULL,
391
141
       (ssize_t (*)(intptr_t *, intptr_t *, int, int, uint8_t *, size_t, uint32_t, uint8_t, libcerror_error_t **)) &libscca_compressed_blocks_stream_data_handle_read_segment_data,
392
141
       NULL,
393
141
       (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libscca_compressed_blocks_stream_data_handle_seek_segment_offset,
394
141
       LIBFDATA_DATA_HANDLE_FLAG_MANAGED,
395
141
       error ) != 1 )
396
0
  {
397
0
    libcerror_error_set(
398
0
     error,
399
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
400
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
401
0
     "%s: unable to create stream.",
402
0
     function );
403
404
0
    goto on_error;
405
0
  }
406
141
  if( libfdata_list_get_number_of_elements(
407
141
       compressed_blocks_list,
408
141
       &number_of_elements,
409
141
       error ) != 1 )
410
0
  {
411
0
    libcerror_error_set(
412
0
     error,
413
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
414
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
415
0
     "%s: unable to retrieve number of compressed blocks list elements.",
416
0
     function );
417
418
0
    data_handle = NULL;
419
420
0
    goto on_error;
421
0
  }
422
141
  for( element_index = 0;
423
279
       element_index < number_of_elements;
424
141
       element_index++ )
425
138
  {
426
138
    if( libfdata_list_get_mapped_size_by_index(
427
138
         compressed_blocks_list,
428
138
         element_index,
429
138
         &segment_size,
430
138
         error ) != 1 )
431
0
    {
432
0
      libcerror_error_set(
433
0
       error,
434
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
435
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
436
0
       "%s: unable to retrieve compressed blocks list element: %d mapped size.",
437
0
       function,
438
0
       element_index );
439
440
0
      data_handle = NULL;
441
442
0
      goto on_error;
443
0
    }
444
138
    if( libfdata_stream_append_segment(
445
138
         *compressed_blocks_stream,
446
138
         &segment_index,
447
138
         0,
448
138
         segment_offset,
449
138
         segment_size,
450
138
         0,
451
138
         error ) != 1 )
452
0
    {
453
0
      libcerror_error_set(
454
0
       error,
455
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
456
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
457
0
       "%s: unable to append compressed blocks stream segment: %d.",
458
0
       function,
459
0
       element_index );
460
461
0
      data_handle = NULL;
462
463
0
      goto on_error;
464
0
    }
465
138
    segment_offset += segment_size;
466
138
  }
467
141
  return( 1 );
468
469
0
on_error:
470
0
  if( *compressed_blocks_stream != NULL )
471
0
  {
472
0
    libfdata_stream_free(
473
0
     compressed_blocks_stream,
474
0
     NULL );
475
0
  }
476
0
  if( data_handle != NULL )
477
0
  {
478
0
    libscca_compressed_blocks_stream_data_handle_free(
479
0
     &data_handle,
480
     NULL );
481
0
  }
482
0
  return( -1 );
483
141
}
484