/src/libfsntfs/libfsntfs/libfsntfs_cluster_block_vector.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Cluster block vector 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 <types.h> |
24 | | |
25 | | #include "libfsntfs_cluster_block.h" |
26 | | #include "libfsntfs_cluster_block_vector.h" |
27 | | #include "libfsntfs_data_run.h" |
28 | | #include "libfsntfs_definitions.h" |
29 | | #include "libfsntfs_io_handle.h" |
30 | | #include "libfsntfs_libbfio.h" |
31 | | #include "libfsntfs_libcerror.h" |
32 | | #include "libfsntfs_libfdata.h" |
33 | | #include "libfsntfs_mft_attribute.h" |
34 | | #include "libfsntfs_unused.h" |
35 | | |
36 | | /* Creates a cluster block vector |
37 | | * Make sure the value cluster_block_vector is referencing, is set to NULL |
38 | | * Returns 1 if successful or -1 on error |
39 | | */ |
40 | | int libfsntfs_cluster_block_vector_initialize( |
41 | | libfdata_vector_t **cluster_block_vector, |
42 | | libfsntfs_io_handle_t *io_handle, |
43 | | libfsntfs_mft_attribute_t *mft_attribute, |
44 | | libcerror_error_t **error ) |
45 | 685 | { |
46 | 685 | libfdata_vector_t *safe_cluster_block_vector = NULL; |
47 | 685 | libfsntfs_data_run_t *data_run = NULL; |
48 | 685 | static char *function = "libfsntfs_cluster_block_vector_initialize"; |
49 | 685 | size64_t attribute_data_vcn_size = 0; |
50 | 685 | size64_t calculated_allocated_data_size = 0; |
51 | 685 | size64_t stored_allocated_data_size = 0; |
52 | 685 | off64_t attribute_data_vcn_offset = 0; |
53 | 685 | off64_t calculated_attribute_data_vcn_offset = 0; |
54 | 685 | uint16_t attribute_data_flags = 0; |
55 | 685 | int attribute_index = 0; |
56 | 685 | int data_run_index = 0; |
57 | 685 | int number_of_data_runs = 0; |
58 | 685 | int segment_index = 0; |
59 | | |
60 | 685 | if( cluster_block_vector == 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 cluster block vector.", |
67 | 0 | function ); |
68 | |
|
69 | 0 | return( -1 ); |
70 | 0 | } |
71 | 685 | if( *cluster_block_vector != NULL ) |
72 | 0 | { |
73 | 0 | libcerror_error_set( |
74 | 0 | error, |
75 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
76 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
77 | 0 | "%s: invalid cluster block vector value already set.", |
78 | 0 | function ); |
79 | |
|
80 | 0 | return( -1 ); |
81 | 0 | } |
82 | 685 | if( io_handle == NULL ) |
83 | 0 | { |
84 | 0 | libcerror_error_set( |
85 | 0 | error, |
86 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
87 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
88 | 0 | "%s: invalid IO handle.", |
89 | 0 | function ); |
90 | |
|
91 | 0 | return( -1 ); |
92 | 0 | } |
93 | 685 | if( io_handle->cluster_block_size == 0 ) |
94 | 0 | { |
95 | 0 | libcerror_error_set( |
96 | 0 | error, |
97 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
98 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
99 | 0 | "%s: invalid IO handle - cluster block size value out of bounds.", |
100 | 0 | function ); |
101 | |
|
102 | 0 | return( -1 ); |
103 | 0 | } |
104 | 685 | if( libfsntfs_mft_attribute_get_data_flags( |
105 | 685 | mft_attribute, |
106 | 685 | &attribute_data_flags, |
107 | 685 | error ) != 1 ) |
108 | 0 | { |
109 | 0 | libcerror_error_set( |
110 | 0 | error, |
111 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
112 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
113 | 0 | "%s: unable to retrieve attribute data flags.", |
114 | 0 | function ); |
115 | |
|
116 | 0 | goto on_error; |
117 | 0 | } |
118 | 685 | if( ( attribute_data_flags & LIBFSNTFS_ATTRIBUTE_FLAG_COMPRESSION_MASK ) != 0 ) |
119 | 1 | { |
120 | 1 | libcerror_error_set( |
121 | 1 | error, |
122 | 1 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
123 | 1 | LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, |
124 | 1 | "%s: unsupported compressed attribute data.", |
125 | 1 | function ); |
126 | | |
127 | 1 | goto on_error; |
128 | 1 | } |
129 | 684 | if( libfsntfs_mft_attribute_get_allocated_data_size( |
130 | 684 | mft_attribute, |
131 | 684 | &stored_allocated_data_size, |
132 | 684 | error ) != 1 ) |
133 | 0 | { |
134 | 0 | libcerror_error_set( |
135 | 0 | error, |
136 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
137 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
138 | 0 | "%s: unable to retrieve attribute allocated data size.", |
139 | 0 | function ); |
140 | |
|
141 | 0 | goto on_error; |
142 | 0 | } |
143 | 684 | if( libfdata_vector_initialize( |
144 | 684 | &safe_cluster_block_vector, |
145 | 684 | (size64_t) io_handle->cluster_block_size, |
146 | 684 | (intptr_t *) io_handle, |
147 | 684 | NULL, |
148 | 684 | NULL, |
149 | 684 | (int (*)(intptr_t *, intptr_t *, libfdata_vector_t *, libfdata_cache_t *, int, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsntfs_cluster_block_vector_read_element_data, |
150 | 684 | NULL, |
151 | 684 | LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED, |
152 | 684 | error ) != 1 ) |
153 | 0 | { |
154 | 0 | libcerror_error_set( |
155 | 0 | error, |
156 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
157 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
158 | 0 | "%s: unable to create cluster block vector.", |
159 | 0 | function ); |
160 | |
|
161 | 0 | goto on_error; |
162 | 0 | } |
163 | 1.15k | while( mft_attribute != NULL ) |
164 | 789 | { |
165 | 789 | if( libfsntfs_mft_attribute_get_data_vcn_range( |
166 | 789 | mft_attribute, |
167 | 789 | (uint64_t *) &attribute_data_vcn_offset, |
168 | 789 | (uint64_t *) &attribute_data_vcn_size, |
169 | 789 | error ) != 1 ) |
170 | 1 | { |
171 | 1 | libcerror_error_set( |
172 | 1 | error, |
173 | 1 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
174 | 1 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
175 | 1 | "%s: unable to retrieve attribute data VCN range.", |
176 | 1 | function ); |
177 | | |
178 | 1 | goto on_error; |
179 | 1 | } |
180 | 788 | if( attribute_data_vcn_size != 0xffffffffffffffffULL ) |
181 | 769 | { |
182 | 769 | if( (uint64_t) attribute_data_vcn_offset > (uint64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) ) |
183 | 86 | { |
184 | 86 | libcerror_error_set( |
185 | 86 | error, |
186 | 86 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
187 | 86 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
188 | 86 | "%s: invalid attribute data first VCN value out of bounds.", |
189 | 86 | function ); |
190 | | |
191 | 86 | goto on_error; |
192 | 86 | } |
193 | 683 | if( attribute_data_vcn_size > (size64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) ) |
194 | 82 | { |
195 | 82 | libcerror_error_set( |
196 | 82 | error, |
197 | 82 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
198 | 82 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
199 | 82 | "%s: invalid attribute data last VCN value out of bounds.", |
200 | 82 | function ); |
201 | | |
202 | 82 | goto on_error; |
203 | 82 | } |
204 | 601 | if( attribute_data_vcn_offset > (off64_t) attribute_data_vcn_size ) |
205 | 54 | { |
206 | 54 | libcerror_error_set( |
207 | 54 | error, |
208 | 54 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
209 | 54 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
210 | 54 | "%s: invalid attribute data first VCN value exceeds last VCN value.", |
211 | 54 | function ); |
212 | | |
213 | 54 | goto on_error; |
214 | 54 | } |
215 | 547 | attribute_data_vcn_size += 1; |
216 | 547 | attribute_data_vcn_size -= attribute_data_vcn_offset; |
217 | 547 | attribute_data_vcn_offset *= io_handle->cluster_block_size; |
218 | 547 | attribute_data_vcn_size *= io_handle->cluster_block_size; |
219 | | |
220 | 547 | if( ( calculated_attribute_data_vcn_offset != 0 ) |
221 | 547 | && ( calculated_attribute_data_vcn_offset != attribute_data_vcn_offset ) ) |
222 | 99 | { |
223 | 99 | libcerror_error_set( |
224 | 99 | error, |
225 | 99 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
226 | 99 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
227 | 99 | "%s: invalid attribute data VCN offset value out of bounds.", |
228 | 99 | function ); |
229 | | |
230 | 99 | goto on_error; |
231 | 99 | } |
232 | 448 | calculated_attribute_data_vcn_offset = attribute_data_vcn_offset + (off64_t) attribute_data_vcn_size; |
233 | 448 | } |
234 | 467 | if( libfsntfs_mft_attribute_get_number_of_data_runs( |
235 | 467 | mft_attribute, |
236 | 467 | &number_of_data_runs, |
237 | 467 | error ) != 1 ) |
238 | 0 | { |
239 | 0 | libcerror_error_set( |
240 | 0 | error, |
241 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
242 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
243 | 0 | "%s: unable to retrieve attribute: %d number of data runs.", |
244 | 0 | function, |
245 | 0 | attribute_index ); |
246 | |
|
247 | 0 | goto on_error; |
248 | 0 | } |
249 | 467 | for( data_run_index = 0; |
250 | 1.63k | data_run_index < number_of_data_runs; |
251 | 1.17k | data_run_index++ ) |
252 | 1.17k | { |
253 | 1.17k | if( libfsntfs_mft_attribute_get_data_run_by_index( |
254 | 1.17k | mft_attribute, |
255 | 1.17k | data_run_index, |
256 | 1.17k | &data_run, |
257 | 1.17k | error ) != 1 ) |
258 | 0 | { |
259 | 0 | libcerror_error_set( |
260 | 0 | error, |
261 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
262 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
263 | 0 | "%s: unable to retrieve attribute: %d data run: %d.", |
264 | 0 | function, |
265 | 0 | attribute_index, |
266 | 0 | data_run_index ); |
267 | |
|
268 | 0 | goto on_error; |
269 | 0 | } |
270 | 1.17k | if( data_run == NULL ) |
271 | 0 | { |
272 | 0 | libcerror_error_set( |
273 | 0 | error, |
274 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
275 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, |
276 | 0 | "%s: missing attribute: %d data run: %d.", |
277 | 0 | function, |
278 | 0 | attribute_index, |
279 | 0 | data_run_index ); |
280 | |
|
281 | 0 | goto on_error; |
282 | 0 | } |
283 | 1.17k | if( libfdata_vector_append_segment( |
284 | 1.17k | safe_cluster_block_vector, |
285 | 1.17k | &segment_index, |
286 | 1.17k | 0, |
287 | 1.17k | data_run->start_offset, |
288 | 1.17k | data_run->size, |
289 | 1.17k | data_run->range_flags, |
290 | 1.17k | error ) != 1 ) |
291 | 1 | { |
292 | 1 | libcerror_error_set( |
293 | 1 | error, |
294 | 1 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
295 | 1 | LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, |
296 | 1 | "%s: unable to append attribute: %d data run: %d vector segment.", |
297 | 1 | function, |
298 | 1 | attribute_index, |
299 | 1 | data_run_index ); |
300 | | |
301 | 1 | goto on_error; |
302 | 1 | } |
303 | 1.17k | calculated_allocated_data_size += data_run->size; |
304 | 1.17k | } |
305 | 466 | attribute_index++; |
306 | | |
307 | 466 | if( libfsntfs_mft_attribute_get_next_attribute( |
308 | 466 | mft_attribute, |
309 | 466 | &mft_attribute, |
310 | 466 | error ) != 1 ) |
311 | 0 | { |
312 | 0 | libcerror_error_set( |
313 | 0 | error, |
314 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
315 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
316 | 0 | "%s: unable to retrieve next MFT attribute: %d.", |
317 | 0 | function, |
318 | 0 | attribute_index ); |
319 | |
|
320 | 0 | goto on_error; |
321 | 0 | } |
322 | 466 | } |
323 | 361 | if( calculated_allocated_data_size != stored_allocated_data_size ) |
324 | 79 | { |
325 | 79 | libcerror_error_set( |
326 | 79 | error, |
327 | 79 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
328 | 79 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
329 | 79 | "%s: size of data runs: %" PRIu64 " does not match allocated data size: %" PRIu64 ".", |
330 | 79 | function, |
331 | 79 | calculated_allocated_data_size, |
332 | 79 | stored_allocated_data_size ); |
333 | | |
334 | 79 | goto on_error; |
335 | 79 | } |
336 | 282 | *cluster_block_vector = safe_cluster_block_vector; |
337 | | |
338 | 282 | return( 1 ); |
339 | | |
340 | 403 | on_error: |
341 | 403 | if( safe_cluster_block_vector != NULL ) |
342 | 402 | { |
343 | 402 | libfdata_vector_free( |
344 | 402 | &safe_cluster_block_vector, |
345 | 402 | NULL ); |
346 | 402 | } |
347 | 403 | return( -1 ); |
348 | 361 | } |
349 | | |
350 | | /* Reads a cluster block |
351 | | * Callback function for the cluster block vector |
352 | | * Returns 1 if successful or -1 on error |
353 | | */ |
354 | | int libfsntfs_cluster_block_vector_read_element_data( |
355 | | intptr_t *data_handle LIBFSNTFS_ATTRIBUTE_UNUSED, |
356 | | libbfio_handle_t *file_io_handle, |
357 | | libfdata_vector_t *vector, |
358 | | libfdata_cache_t *cache, |
359 | | int element_index LIBFSNTFS_ATTRIBUTE_UNUSED, |
360 | | int element_data_file_index LIBFSNTFS_ATTRIBUTE_UNUSED, |
361 | | off64_t cluster_block_offset, |
362 | | size64_t cluster_block_size, |
363 | | uint32_t range_flags, |
364 | | uint8_t read_flags LIBFSNTFS_ATTRIBUTE_UNUSED, |
365 | | libcerror_error_t **error ) |
366 | 45.7k | { |
367 | 45.7k | libfsntfs_cluster_block_t *cluster_block = NULL; |
368 | 45.7k | static char *function = "libfsntfs_cluster_block_vector_read_element_data"; |
369 | | |
370 | 45.7k | LIBFSNTFS_UNREFERENCED_PARAMETER( data_handle ) |
371 | 45.7k | LIBFSNTFS_UNREFERENCED_PARAMETER( element_index ) |
372 | 45.7k | LIBFSNTFS_UNREFERENCED_PARAMETER( element_data_file_index ) |
373 | 45.7k | LIBFSNTFS_UNREFERENCED_PARAMETER( read_flags ) |
374 | | |
375 | 45.7k | if( ( cluster_block_size == 0 ) |
376 | 45.7k | || ( cluster_block_size > (size64_t) SSIZE_MAX ) ) |
377 | 0 | { |
378 | 0 | libcerror_error_set( |
379 | 0 | error, |
380 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
381 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
382 | 0 | "%s: invalid cluster block size value out of bounds.", |
383 | 0 | function ); |
384 | |
|
385 | 0 | return( -1 ); |
386 | 0 | } |
387 | 45.7k | if( libfsntfs_cluster_block_initialize( |
388 | 45.7k | &cluster_block, |
389 | 45.7k | (size_t) cluster_block_size, |
390 | 45.7k | error ) != 1 ) |
391 | 0 | { |
392 | 0 | libcerror_error_set( |
393 | 0 | error, |
394 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
395 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
396 | 0 | "%s: unable to create cluster block.", |
397 | 0 | function ); |
398 | |
|
399 | 0 | goto on_error; |
400 | 0 | } |
401 | 45.7k | if( ( range_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 ) |
402 | 0 | { |
403 | 0 | if( libfsntfs_cluster_block_clear( |
404 | 0 | cluster_block, |
405 | 0 | error ) != 1 ) |
406 | 0 | { |
407 | 0 | libcerror_error_set( |
408 | 0 | error, |
409 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
410 | 0 | LIBCERROR_RUNTIME_ERROR_SET_FAILED, |
411 | 0 | "%s: unable to clear cluster block.", |
412 | 0 | function ); |
413 | |
|
414 | 0 | goto on_error; |
415 | 0 | } |
416 | 0 | } |
417 | 45.7k | else |
418 | 45.7k | { |
419 | 45.7k | if( libfsntfs_cluster_block_read_file_io_handle( |
420 | 45.7k | cluster_block, |
421 | 45.7k | file_io_handle, |
422 | 45.7k | cluster_block_offset, |
423 | 45.7k | error ) != 1 ) |
424 | 183 | { |
425 | 183 | libcerror_error_set( |
426 | 183 | error, |
427 | 183 | LIBCERROR_ERROR_DOMAIN_IO, |
428 | 183 | LIBCERROR_IO_ERROR_READ_FAILED, |
429 | 183 | "%s: unable to read cluster block at offset: %" PRIi64 " (0x%08" PRIx64 ").", |
430 | 183 | function, |
431 | 183 | cluster_block_offset, |
432 | 183 | cluster_block_offset ); |
433 | | |
434 | 183 | goto on_error; |
435 | 183 | } |
436 | 45.7k | } |
437 | 45.6k | if( libfdata_vector_set_element_value_by_index( |
438 | 45.6k | vector, |
439 | 45.6k | (intptr_t *) file_io_handle, |
440 | 45.6k | cache, |
441 | 45.6k | element_index, |
442 | 45.6k | (intptr_t *) cluster_block, |
443 | 45.6k | (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_cluster_block_free, |
444 | 45.6k | LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED, |
445 | 45.6k | error ) != 1 ) |
446 | 0 | { |
447 | 0 | libcerror_error_set( |
448 | 0 | error, |
449 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
450 | 0 | LIBCERROR_RUNTIME_ERROR_SET_FAILED, |
451 | 0 | "%s: unable to set cluster block as element value.", |
452 | 0 | function ); |
453 | |
|
454 | 0 | goto on_error; |
455 | 0 | } |
456 | 45.6k | return( 1 ); |
457 | | |
458 | 183 | on_error: |
459 | 183 | if( cluster_block != NULL ) |
460 | 183 | { |
461 | 183 | libfsntfs_cluster_block_free( |
462 | 183 | &cluster_block, |
463 | 183 | NULL ); |
464 | 183 | } |
465 | 183 | return( -1 ); |
466 | 45.6k | } |
467 | | |