Coverage Report

Created: 2025-10-14 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmsiecf/libmsiecf/libmsiecf_allocation_table.c
Line
Count
Source
1
/*
2
 * Allocation table functions
3
 *
4
 * Copyright (C) 2009-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 <memory.h>
24
#include <types.h>
25
26
#include "libmsiecf_allocation_table.h"
27
#include "libmsiecf_definitions.h"
28
#include "libmsiecf_libbfio.h"
29
#include "libmsiecf_libcdata.h"
30
#include "libmsiecf_libcerror.h"
31
#include "libmsiecf_libcnotify.h"
32
33
/* Reads an allocation table
34
 * Returns 1 if successful or -1 on error
35
 */
36
int libmsiecf_allocation_table_read_file_io_handle(
37
     libcdata_range_list_t *unallocated_block_list,
38
     libbfio_handle_t *file_io_handle,
39
     off64_t allocation_table_offset,
40
     size64_t file_size,
41
     off64_t base_offset,
42
     uint16_t block_size,
43
     uint32_t number_of_blocks,
44
     uint32_t number_of_allocated_blocks,
45
     libcerror_error_t **error )
46
2.72k
{
47
2.72k
  uint8_t *allocation_table_data                 = NULL;
48
2.72k
  static char *function                          = "libmsiecf_allocation_table_read_file_io_handle";
49
2.72k
  size_t read_size                               = 0;
50
2.72k
  size_t table_iterator                          = 0;
51
2.72k
  size_t unallocated_size                        = 0;
52
2.72k
  ssize_t read_count                             = 0;
53
2.72k
  off64_t offset                                 = 0;
54
2.72k
  off64_t unallocated_offset                     = 0;
55
2.72k
  uint32_t calculated_number_of_allocated_blocks = 0;
56
2.72k
  uint8_t allocation_table_entry                 = 0;
57
2.72k
  uint8_t bit_iterator                           = 0;
58
2.72k
  int result                                     = 0;
59
60
2.72k
  if( unallocated_block_list == NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
65
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
66
0
     "%s: invalid unallocated block list.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
2.72k
  if( file_io_handle == NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
76
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
77
0
     "%s: invalid file IO handle.",
78
0
     function );
79
80
0
    return( -1 );
81
0
  }
82
2.72k
  if( file_size > (size64_t) INT32_MAX )
83
3
  {
84
3
    libcerror_error_set(
85
3
     error,
86
3
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
87
3
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
88
3
     "%s: invalid file size value exceeds maximum.",
89
3
     function );
90
91
3
    return( -1 );
92
3
  }
93
2.71k
  if( base_offset < 0 )
94
0
  {
95
0
    libcerror_error_set(
96
0
     error,
97
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
98
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_LESS_THAN_ZERO,
99
0
     "%s: invalid base offset value less than zero.",
100
0
     function );
101
102
0
    return( -1 );
103
0
  }
104
2.71k
  if( base_offset > (off64_t) file_size )
105
29
  {
106
29
    libcerror_error_set(
107
29
     error,
108
29
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
109
29
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
110
29
     "%s: invalid base offset value exceeds file size.",
111
29
     function );
112
113
29
    return( -1 );
114
29
  }
115
2.69k
  if( block_size == 0 )
116
0
  {
117
0
    libcerror_error_set(
118
0
     error,
119
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
120
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
121
0
     "%s: invalid block size value zero or less.",
122
0
     function );
123
124
0
    return( -1 );
125
0
  }
126
  /* Every bit in the allocation table represents one block
127
   */
128
2.69k
  read_size = number_of_blocks / 8;
129
130
2.69k
  if( read_size == 0 )
131
1.55k
  {
132
1.55k
    return( 1 );
133
1.55k
  }
134
1.13k
  if( read_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE )
135
81
  {
136
81
    libcerror_error_set(
137
81
     error,
138
81
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
139
81
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
140
81
     "%s: invalid allocation table data size value exceeds maximum allocation size.",
141
81
     function );
142
143
81
    goto on_error;
144
81
  }
145
1.05k
  if( (off64_t) read_size > ( base_offset - allocation_table_offset ) )
146
78
  {
147
78
    libcerror_error_set(
148
78
     error,
149
78
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
150
78
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
151
78
     "%s: invalid allocation table size value exceeds base offset.",
152
78
     function );
153
154
78
    goto on_error;
155
78
  }
156
980
  allocation_table_data = (uint8_t *) memory_allocate(
157
980
                                       read_size );
158
159
980
  if( allocation_table_data == NULL )
160
0
  {
161
0
    libcerror_error_set(
162
0
     error,
163
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
164
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
165
0
     "%s: unable to create alloction table data.",
166
0
     function );
167
168
0
    goto on_error;
169
0
  }
170
980
  read_count = libbfio_handle_read_buffer_at_offset(
171
980
                file_io_handle,
172
980
                allocation_table_data,
173
980
                read_size,
174
980
                allocation_table_offset,
175
980
                error );
176
177
980
  if( read_count != (ssize_t) read_size )
178
75
  {
179
75
    libcerror_error_set(
180
75
     error,
181
75
     LIBCERROR_ERROR_DOMAIN_IO,
182
75
     LIBCERROR_IO_ERROR_READ_FAILED,
183
75
     "%s: unable to read allocation table at offset: %" PRIi64 " (0x%08" PRIx64 ").",
184
75
     function,
185
75
     allocation_table_offset,
186
75
     allocation_table_offset );
187
188
75
    goto on_error;
189
75
  }
190
#if defined( HAVE_DEBUG_OUTPUT )
191
  if( libcnotify_verbose != 0 )
192
  {
193
    libcnotify_printf(
194
     "%s: allocation table:\n",
195
     function );
196
    libcnotify_print_data(
197
     allocation_table_data,
198
     read_size,
199
     0 );
200
  }
201
#endif
202
905
  for( table_iterator = 0;
203
1.99M
       table_iterator < read_size;
204
1.99M
       table_iterator++ )
205
1.99M
  {
206
1.99M
    allocation_table_entry = allocation_table_data[ table_iterator ];
207
208
1.99M
    for( bit_iterator = 0;
209
17.9M
         bit_iterator < 8;
210
15.9M
         bit_iterator++ )
211
15.9M
    {
212
15.9M
      if( ( allocation_table_entry & 0x01 ) == 0 )
213
12.7M
      {
214
12.7M
        if( unallocated_size == 0 )
215
1.47M
        {
216
1.47M
          unallocated_offset = offset;
217
1.47M
        }
218
12.7M
        unallocated_size += block_size;
219
12.7M
      }
220
3.19M
      else if( unallocated_size > 0 )
221
1.47M
      {
222
1.47M
        result = libcdata_range_list_insert_range(
223
1.47M
                  unallocated_block_list,
224
1.47M
                  (uint64_t) ( base_offset + unallocated_offset ),
225
1.47M
                  (uint64_t) unallocated_size,
226
1.47M
                  NULL,
227
1.47M
                  NULL,
228
1.47M
                  NULL,
229
1.47M
                  error );
230
231
1.47M
        if( result == -1 )
232
0
        {
233
0
          libcerror_error_set(
234
0
           error,
235
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
236
0
           LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
237
0
           "%s: unable to insert unallocated block in offset list.",
238
0
           function );
239
240
0
          goto on_error;
241
0
        }
242
1.47M
        unallocated_size = 0;
243
1.47M
      }
244
15.9M
      if( ( allocation_table_entry & 0x01 ) != 0 )
245
3.19M
      {
246
3.19M
        calculated_number_of_allocated_blocks++;
247
3.19M
      }
248
15.9M
      allocation_table_entry >>= 1;
249
250
15.9M
      offset += block_size;
251
252
15.9M
      if( offset >= (off64_t) file_size )
253
86
      {
254
86
        break;
255
86
      }
256
15.9M
    }
257
1.99M
    if( offset >= (off64_t) file_size )
258
86
    {
259
86
      break;
260
86
    }
261
1.99M
  }
262
905
  if( unallocated_size > 0 )
263
764
  {
264
764
    result = libcdata_range_list_insert_range(
265
764
              unallocated_block_list,
266
764
              (uint64_t) ( base_offset + unallocated_offset ),
267
764
              (uint64_t) unallocated_size,
268
764
              NULL,
269
764
              NULL,
270
764
              NULL,
271
764
              error );
272
273
764
    if( result == -1 )
274
0
    {
275
0
      libcerror_error_set(
276
0
       error,
277
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
278
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
279
0
       "%s: unable to insert unallocated block in offset list.",
280
0
       function );
281
282
0
      goto on_error;
283
0
    }
284
764
    unallocated_size = 0;
285
764
  }
286
905
  memory_free(
287
905
   allocation_table_data );
288
289
905
  allocation_table_data = NULL;
290
291
#if defined( HAVE_VERBOSE_OUTPUT )
292
  if( libcnotify_verbose != 0 )
293
  {
294
    if( number_of_allocated_blocks != calculated_number_of_allocated_blocks )
295
    {
296
      libcnotify_printf(
297
       "%s: mismatch in number of allocated blocks (stored: %" PRIu32 ", calculated: %" PRIu32 ")\n",
298
       function,
299
       number_of_allocated_blocks,
300
       calculated_number_of_allocated_blocks );
301
    }
302
  }
303
#endif
304
905
  return( 1 );
305
306
234
on_error:
307
234
  if( allocation_table_data != NULL )
308
75
  {
309
75
    memory_free(
310
75
     allocation_table_data );
311
75
  }
312
234
  return( -1 );
313
905
}
314