/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 | | |