/src/libfsxfs/libfsxfs/libfsxfs_block_directory.c
Line | Count | Source |
1 | | /* |
2 | | * Block directory functions |
3 | | * |
4 | | * Copyright (C) 2020-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 <byte_stream.h> |
24 | | #include <memory.h> |
25 | | #include <types.h> |
26 | | |
27 | | #include "libfsxfs_debug.h" |
28 | | #include "libfsxfs_definitions.h" |
29 | | #include "libfsxfs_directory_entry.h" |
30 | | #include "libfsxfs_block_directory.h" |
31 | | #include "libfsxfs_block_directory_footer.h" |
32 | | #include "libfsxfs_block_directory_header.h" |
33 | | #include "libfsxfs_io_handle.h" |
34 | | #include "libfsxfs_libbfio.h" |
35 | | #include "libfsxfs_libcdata.h" |
36 | | #include "libfsxfs_libcerror.h" |
37 | | #include "libfsxfs_libcnotify.h" |
38 | | |
39 | | #include "fsxfs_block_directory.h" |
40 | | |
41 | | /* Creates block directory |
42 | | * Make sure the value block_directory is referencing, is set to NULL |
43 | | * Returns 1 if successful or -1 on error |
44 | | */ |
45 | | int libfsxfs_block_directory_initialize( |
46 | | libfsxfs_block_directory_t **block_directory, |
47 | | size_t block_size, |
48 | | libcerror_error_t **error ) |
49 | 4.52k | { |
50 | 4.52k | static char *function = "libfsxfs_block_directory_initialize"; |
51 | | |
52 | 4.52k | if( block_directory == NULL ) |
53 | 0 | { |
54 | 0 | libcerror_error_set( |
55 | 0 | error, |
56 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
57 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
58 | 0 | "%s: invalid block directory.", |
59 | 0 | function ); |
60 | |
|
61 | 0 | return( -1 ); |
62 | 0 | } |
63 | 4.52k | if( *block_directory != NULL ) |
64 | 0 | { |
65 | 0 | libcerror_error_set( |
66 | 0 | error, |
67 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
68 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
69 | 0 | "%s: invalid block directory value already set.", |
70 | 0 | function ); |
71 | |
|
72 | 0 | return( -1 ); |
73 | 0 | } |
74 | 4.52k | if( ( block_size == 0 ) |
75 | 4.52k | || ( block_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) ) |
76 | 0 | { |
77 | 0 | libcerror_error_set( |
78 | 0 | error, |
79 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
80 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
81 | 0 | "%s: invalid block size value out of bounds.", |
82 | 0 | function ); |
83 | |
|
84 | 0 | return( -1 ); |
85 | 0 | } |
86 | 4.52k | *block_directory = memory_allocate_structure( |
87 | 4.52k | libfsxfs_block_directory_t ); |
88 | | |
89 | 4.52k | if( *block_directory == NULL ) |
90 | 0 | { |
91 | 0 | libcerror_error_set( |
92 | 0 | error, |
93 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
94 | 0 | LIBCERROR_MEMORY_ERROR_INSUFFICIENT, |
95 | 0 | "%s: unable to create block directory.", |
96 | 0 | function ); |
97 | |
|
98 | 0 | goto on_error; |
99 | 0 | } |
100 | 4.52k | if( memory_set( |
101 | 4.52k | *block_directory, |
102 | 4.52k | 0, |
103 | 4.52k | sizeof( libfsxfs_block_directory_t ) ) == NULL ) |
104 | 0 | { |
105 | 0 | libcerror_error_set( |
106 | 0 | error, |
107 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
108 | 0 | LIBCERROR_MEMORY_ERROR_SET_FAILED, |
109 | 0 | "%s: unable to clear block directory.", |
110 | 0 | function ); |
111 | |
|
112 | 0 | memory_free( |
113 | 0 | *block_directory ); |
114 | |
|
115 | 0 | *block_directory = NULL; |
116 | |
|
117 | 0 | return( -1 ); |
118 | 0 | } |
119 | 4.52k | ( *block_directory )->data = (uint8_t *) memory_allocate( |
120 | 4.52k | sizeof( uint8_t ) * block_size ); |
121 | | |
122 | 4.52k | if( ( *block_directory )->data == NULL ) |
123 | 0 | { |
124 | 0 | libcerror_error_set( |
125 | 0 | error, |
126 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
127 | 0 | LIBCERROR_MEMORY_ERROR_INSUFFICIENT, |
128 | 0 | "%s: unable to create block directory data.", |
129 | 0 | function ); |
130 | |
|
131 | 0 | goto on_error; |
132 | 0 | } |
133 | 4.52k | ( *block_directory )->data_size = block_size; |
134 | | |
135 | 4.52k | return( 1 ); |
136 | | |
137 | 0 | on_error: |
138 | 0 | if( *block_directory != NULL ) |
139 | 0 | { |
140 | 0 | memory_free( |
141 | 0 | *block_directory ); |
142 | |
|
143 | 0 | *block_directory = NULL; |
144 | 0 | } |
145 | 0 | return( -1 ); |
146 | 4.52k | } |
147 | | |
148 | | /* Frees block directory |
149 | | * Returns 1 if successful or -1 on error |
150 | | */ |
151 | | int libfsxfs_block_directory_free( |
152 | | libfsxfs_block_directory_t **block_directory, |
153 | | libcerror_error_t **error ) |
154 | 4.52k | { |
155 | 4.52k | static char *function = "libfsxfs_block_directory_free"; |
156 | 4.52k | int result = 1; |
157 | | |
158 | 4.52k | if( block_directory == NULL ) |
159 | 0 | { |
160 | 0 | libcerror_error_set( |
161 | 0 | error, |
162 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
163 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
164 | 0 | "%s: invalid block directory.", |
165 | 0 | function ); |
166 | |
|
167 | 0 | return( -1 ); |
168 | 0 | } |
169 | 4.52k | if( *block_directory != NULL ) |
170 | 4.52k | { |
171 | 4.52k | if( ( *block_directory )->footer != NULL ) |
172 | 2.06k | { |
173 | 2.06k | if( libfsxfs_block_directory_footer_free( |
174 | 2.06k | &( ( *block_directory )->footer ), |
175 | 2.06k | error ) != 1 ) |
176 | 0 | { |
177 | 0 | libcerror_error_set( |
178 | 0 | error, |
179 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
180 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
181 | 0 | "%s: unable to free footer.", |
182 | 0 | function ); |
183 | |
|
184 | 0 | result = -1; |
185 | 0 | } |
186 | 2.06k | } |
187 | 4.52k | if( ( *block_directory )->header != NULL ) |
188 | 4.10k | { |
189 | 4.10k | if( libfsxfs_block_directory_header_free( |
190 | 4.10k | &( ( *block_directory )->header ), |
191 | 4.10k | error ) != 1 ) |
192 | 0 | { |
193 | 0 | libcerror_error_set( |
194 | 0 | error, |
195 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
196 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
197 | 0 | "%s: unable to free header.", |
198 | 0 | function ); |
199 | |
|
200 | 0 | result = -1; |
201 | 0 | } |
202 | 4.10k | } |
203 | 4.52k | memory_free( |
204 | 4.52k | ( *block_directory )->data ); |
205 | | |
206 | 4.52k | memory_free( |
207 | 4.52k | *block_directory ); |
208 | | |
209 | 4.52k | *block_directory = NULL; |
210 | 4.52k | } |
211 | 4.52k | return( result ); |
212 | 4.52k | } |
213 | | |
214 | | /* Reads the block directory |
215 | | * Returns 1 if successful or -1 on error |
216 | | */ |
217 | | int libfsxfs_block_directory_read_data( |
218 | | libfsxfs_block_directory_t *block_directory, |
219 | | libfsxfs_io_handle_t *io_handle, |
220 | | const uint8_t *data, |
221 | | size_t data_size, |
222 | | libcdata_array_t *entries_array, |
223 | | libcerror_error_t **error ) |
224 | 4.26k | { |
225 | 4.26k | libfsxfs_directory_entry_t *directory_entry = NULL; |
226 | 4.26k | static char *function = "libfsxfs_block_directory_read_data"; |
227 | 4.26k | size_t alignment_padding_size = 0; |
228 | 4.26k | size_t data_offset = 0; |
229 | 4.26k | size_t entries_data_end_offset = 0; |
230 | 4.26k | size_t entry_data_size = 0; |
231 | 4.26k | size_t hash_values_data_size = 0; |
232 | 4.26k | uint64_t inode_number = 0; |
233 | 4.26k | uint32_t directory_entry_index = 0; |
234 | 4.26k | uint16_t free_tag = 0; |
235 | 4.26k | uint8_t name_size = 0; |
236 | 4.26k | int entry_index = 0; |
237 | | |
238 | | #if defined( HAVE_DEBUG_OUTPUT ) |
239 | | uint16_t value_16bit = 0; |
240 | | #endif |
241 | | |
242 | 4.26k | if( block_directory == NULL ) |
243 | 0 | { |
244 | 0 | libcerror_error_set( |
245 | 0 | error, |
246 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
247 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
248 | 0 | "%s: invalid block directory.", |
249 | 0 | function ); |
250 | |
|
251 | 0 | return( -1 ); |
252 | 0 | } |
253 | 4.26k | if( block_directory->header != NULL ) |
254 | 0 | { |
255 | 0 | libcerror_error_set( |
256 | 0 | error, |
257 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
258 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
259 | 0 | "%s: invalid block directory - header already set.", |
260 | 0 | function ); |
261 | |
|
262 | 0 | return( -1 ); |
263 | 0 | } |
264 | 4.26k | if( block_directory->footer != NULL ) |
265 | 0 | { |
266 | 0 | libcerror_error_set( |
267 | 0 | error, |
268 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
269 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
270 | 0 | "%s: invalid block directory - footer already set.", |
271 | 0 | function ); |
272 | |
|
273 | 0 | return( -1 ); |
274 | 0 | } |
275 | 4.26k | if( io_handle == NULL ) |
276 | 0 | { |
277 | 0 | libcerror_error_set( |
278 | 0 | error, |
279 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
280 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
281 | 0 | "%s: invalid IO handle.", |
282 | 0 | function ); |
283 | |
|
284 | 0 | return( -1 ); |
285 | 0 | } |
286 | 4.26k | if( data == NULL ) |
287 | 0 | { |
288 | 0 | libcerror_error_set( |
289 | 0 | error, |
290 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
291 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
292 | 0 | "%s: invalid data.", |
293 | 0 | function ); |
294 | |
|
295 | 0 | return( -1 ); |
296 | 0 | } |
297 | 4.26k | if( ( data_size < 8 ) |
298 | 4.26k | || ( data_size > (size_t) SSIZE_MAX ) ) |
299 | 0 | { |
300 | 0 | libcerror_error_set( |
301 | 0 | error, |
302 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
303 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
304 | 0 | "%s: invalid data size value out of bounds.", |
305 | 0 | function ); |
306 | |
|
307 | 0 | return( -1 ); |
308 | 0 | } |
309 | | #if defined( HAVE_DEBUG_OUTPUT ) |
310 | | if( libcnotify_verbose != 0 ) |
311 | | { |
312 | | libcnotify_printf( |
313 | | "%s: block directory data:\n", |
314 | | function ); |
315 | | libcnotify_print_data( |
316 | | data, |
317 | | data_size, |
318 | | LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); |
319 | | } |
320 | | #endif /* defined( HAVE_DEBUG_OUTPUT ) */ |
321 | | |
322 | 4.26k | if( libfsxfs_block_directory_header_initialize( |
323 | 4.26k | &( block_directory->header ), |
324 | 4.26k | error ) != 1 ) |
325 | 0 | { |
326 | 0 | libcerror_error_set( |
327 | 0 | error, |
328 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
329 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
330 | 0 | "%s: unable to create header.", |
331 | 0 | function ); |
332 | |
|
333 | 0 | goto on_error; |
334 | 0 | } |
335 | 4.26k | if( libfsxfs_block_directory_header_read_data( |
336 | 4.26k | block_directory->header, |
337 | 4.26k | data, |
338 | 4.26k | data_size, |
339 | 4.26k | error ) != 1 ) |
340 | 45 | { |
341 | 45 | libcerror_error_set( |
342 | 45 | error, |
343 | 45 | LIBCERROR_ERROR_DOMAIN_IO, |
344 | 45 | LIBCERROR_IO_ERROR_READ_FAILED, |
345 | 45 | "%s: unable to read block directory header.", |
346 | 45 | function ); |
347 | | |
348 | 45 | goto on_error; |
349 | 45 | } |
350 | 4.21k | if( block_directory->header->has_footer != 0 ) |
351 | 2.14k | { |
352 | 2.14k | if( libfsxfs_block_directory_footer_initialize( |
353 | 2.14k | &( block_directory->footer ), |
354 | 2.14k | error ) != 1 ) |
355 | 0 | { |
356 | 0 | libcerror_error_set( |
357 | 0 | error, |
358 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
359 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
360 | 0 | "%s: unable to create footer.", |
361 | 0 | function ); |
362 | |
|
363 | 0 | goto on_error; |
364 | 0 | } |
365 | 2.14k | if( libfsxfs_block_directory_footer_read_data( |
366 | 2.14k | block_directory->footer, |
367 | 2.14k | &( data[ data_size - 8 ] ), |
368 | 2.14k | 8, |
369 | 2.14k | error ) != 1 ) |
370 | 0 | { |
371 | 0 | libcerror_error_set( |
372 | 0 | error, |
373 | 0 | LIBCERROR_ERROR_DOMAIN_IO, |
374 | 0 | LIBCERROR_IO_ERROR_READ_FAILED, |
375 | 0 | "%s: unable to read block directory footer.", |
376 | 0 | function ); |
377 | |
|
378 | 0 | goto on_error; |
379 | 0 | } |
380 | 2.14k | if( (size_t) block_directory->footer->number_of_entries > ( ( data_size - data_offset - 8 ) / 8 ) ) |
381 | 55 | { |
382 | 55 | libcerror_error_set( |
383 | 55 | error, |
384 | 55 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
385 | 55 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
386 | 55 | "%s: invalid number of entries value out of bounds.", |
387 | 55 | function ); |
388 | | |
389 | 55 | goto on_error; |
390 | 55 | } |
391 | 2.08k | hash_values_data_size = (size_t) block_directory->footer->number_of_entries * 8; |
392 | | |
393 | 2.08k | entries_data_end_offset = data_size - ( 8 + hash_values_data_size ); |
394 | 2.08k | } |
395 | 2.07k | else |
396 | 2.07k | { |
397 | 2.07k | entries_data_end_offset = data_size; |
398 | 2.07k | } |
399 | 4.16k | if( block_directory->header->format_version == 3 ) |
400 | 2.18k | { |
401 | 2.18k | data_offset = sizeof( fsxfs_block_directory_header_v3_t ); |
402 | 2.18k | } |
403 | 1.97k | else |
404 | 1.97k | { |
405 | 1.97k | data_offset = sizeof( fsxfs_block_directory_header_v2_t ); |
406 | 1.97k | } |
407 | 121k | while( data_offset < entries_data_end_offset ) |
408 | 117k | { |
409 | 117k | if( ( entries_data_end_offset - data_offset ) < 4 ) |
410 | 6 | { |
411 | 6 | libcerror_error_set( |
412 | 6 | error, |
413 | 6 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
414 | 6 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
415 | 6 | "%s: invalid data size value out of bounds.", |
416 | 6 | function ); |
417 | | |
418 | 6 | goto on_error; |
419 | 6 | } |
420 | 117k | byte_stream_copy_to_uint16_big_endian( |
421 | 117k | &( data[ data_offset ] ), |
422 | 117k | free_tag ); |
423 | | |
424 | 117k | if( free_tag == 0xffff ) |
425 | 3.30k | { |
426 | 3.30k | byte_stream_copy_to_uint16_big_endian( |
427 | 3.30k | &( data[ data_offset + 2 ] ), |
428 | 3.30k | entry_data_size ); |
429 | | |
430 | | #if defined( HAVE_DEBUG_OUTPUT ) |
431 | | if( libcnotify_verbose != 0 ) |
432 | | { |
433 | | libcnotify_printf( |
434 | | "%s: unused block signature\t\t: 0x%04" PRIx16 "\n", |
435 | | function, |
436 | | free_tag ); |
437 | | |
438 | | libcnotify_printf( |
439 | | "%s: entry data size\t\t\t: %" PRIzd "\n", |
440 | | function, |
441 | | entry_data_size ); |
442 | | |
443 | | libcnotify_printf( |
444 | | "\n" ); |
445 | | } |
446 | | #endif /* defined( HAVE_DEBUG_OUTPUT ) */ |
447 | | |
448 | 3.30k | if( entry_data_size < 4 ) |
449 | 9 | { |
450 | 9 | libcerror_error_set( |
451 | 9 | error, |
452 | 9 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
453 | 9 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
454 | 9 | "%s: invalid data size value out of bounds.", |
455 | 9 | function ); |
456 | | |
457 | 9 | goto on_error; |
458 | 9 | } |
459 | 3.29k | data_offset += entry_data_size; |
460 | | |
461 | 3.29k | continue; |
462 | 3.30k | } |
463 | 114k | if( ( entries_data_end_offset - data_offset ) < 9 ) |
464 | 8 | { |
465 | 8 | libcerror_error_set( |
466 | 8 | error, |
467 | 8 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
468 | 8 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
469 | 8 | "%s: invalid data size value out of bounds.", |
470 | 8 | function ); |
471 | | |
472 | 8 | goto on_error; |
473 | 8 | } |
474 | 114k | name_size = data[ data_offset + 8 ]; |
475 | | |
476 | 114k | entry_data_size = 9 + name_size + 2; |
477 | | |
478 | 114k | if( ( io_handle->format_version == 5 ) |
479 | 20.0k | || ( ( io_handle->secondary_feature_flags & LIBFSXFS_SECONDARY_FEATURE_FLAG_FILE_TYPE ) != 0 ) ) |
480 | 103k | { |
481 | 103k | entry_data_size++; |
482 | 103k | } |
483 | 114k | alignment_padding_size = entry_data_size % 8; |
484 | | |
485 | 114k | if( alignment_padding_size != 0 ) |
486 | 110k | { |
487 | 110k | alignment_padding_size = 8 - alignment_padding_size; |
488 | 110k | entry_data_size += alignment_padding_size; |
489 | 110k | } |
490 | 114k | if( ( entry_data_size < 6 ) |
491 | 114k | || ( entry_data_size > ( entries_data_end_offset - data_offset ) ) ) |
492 | 32 | { |
493 | 32 | libcerror_error_set( |
494 | 32 | error, |
495 | 32 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
496 | 32 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
497 | 32 | "%s: invalid data size value out of bounds.", |
498 | 32 | function ); |
499 | | |
500 | 32 | goto on_error; |
501 | 32 | } |
502 | | #if defined( HAVE_DEBUG_OUTPUT ) |
503 | | if( libcnotify_verbose != 0 ) |
504 | | { |
505 | | libcnotify_printf( |
506 | | "%s: directory entry: %d data:\n", |
507 | | function, |
508 | | directory_entry_index ); |
509 | | libcnotify_print_data( |
510 | | &( data[ data_offset ] ), |
511 | | entry_data_size, |
512 | | LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); |
513 | | } |
514 | | #endif /* defined( HAVE_DEBUG_OUTPUT ) */ |
515 | | |
516 | 114k | byte_stream_copy_to_uint64_big_endian( |
517 | 114k | &( data[ data_offset ] ), |
518 | 114k | inode_number ); |
519 | | |
520 | 114k | data_offset += 9; |
521 | | |
522 | | #if defined( HAVE_DEBUG_OUTPUT ) |
523 | | if( libcnotify_verbose != 0 ) |
524 | | { |
525 | | libcnotify_printf( |
526 | | "%s: inode number\t\t\t: %" PRIu64 "\n", |
527 | | function, |
528 | | inode_number ); |
529 | | |
530 | | libcnotify_printf( |
531 | | "%s: name size\t\t\t\t: %" PRIu8 "\n", |
532 | | function, |
533 | | name_size ); |
534 | | |
535 | | if( libfsxfs_debug_print_utf8_string_value( |
536 | | function, |
537 | | "name\t\t\t\t", |
538 | | &( data[ data_offset ] ), |
539 | | name_size, |
540 | | error ) != 1 ) |
541 | | { |
542 | | libcerror_error_set( |
543 | | error, |
544 | | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
545 | | LIBCERROR_RUNTIME_ERROR_PRINT_FAILED, |
546 | | "%s: unable to print UTF-8 string value.", |
547 | | function ); |
548 | | |
549 | | goto on_error; |
550 | | } |
551 | | } |
552 | | #endif /* defined( HAVE_DEBUG_OUTPUT ) */ |
553 | | |
554 | 114k | if( ( name_size == 1 ) |
555 | 5.05k | && ( data[ data_offset ] == '.' ) ) |
556 | 924 | { |
557 | | /* Ignore self directory entry "." */ |
558 | 924 | } |
559 | 113k | else if( ( name_size == 2 ) |
560 | 7.80k | && ( data[ data_offset ] == '.' ) |
561 | 1.41k | && ( data[ data_offset + 1 ] == '.' ) ) |
562 | 556 | { |
563 | | /* Ignore parent directory entry ".." */ |
564 | 556 | } |
565 | 112k | else |
566 | 112k | { |
567 | 112k | if( libfsxfs_directory_entry_initialize( |
568 | 112k | &directory_entry, |
569 | 112k | error ) != 1 ) |
570 | 0 | { |
571 | 0 | libcerror_error_set( |
572 | 0 | error, |
573 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
574 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
575 | 0 | "%s: unable to create directory entry: %d.", |
576 | 0 | function, |
577 | 0 | directory_entry_index ); |
578 | |
|
579 | 0 | goto on_error; |
580 | 0 | } |
581 | 112k | directory_entry->inode_number = inode_number; |
582 | | |
583 | 112k | if( memory_copy( |
584 | 112k | directory_entry->name, |
585 | 112k | &( data[ data_offset ] ), |
586 | 112k | (size_t) name_size ) == NULL ) |
587 | 0 | { |
588 | 0 | libcerror_error_set( |
589 | 0 | error, |
590 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
591 | 0 | LIBCERROR_MEMORY_ERROR_COPY_FAILED, |
592 | 0 | "%s: unable to copy name.", |
593 | 0 | function ); |
594 | |
|
595 | 0 | goto on_error; |
596 | 0 | } |
597 | 112k | directory_entry->name_size = name_size; |
598 | 112k | } |
599 | 114k | data_offset += name_size; |
600 | | |
601 | 114k | if( ( io_handle->format_version == 5 ) |
602 | 20.0k | || ( ( io_handle->secondary_feature_flags & LIBFSXFS_SECONDARY_FEATURE_FLAG_FILE_TYPE ) != 0 ) ) |
603 | 103k | { |
604 | | #if defined( HAVE_DEBUG_OUTPUT ) |
605 | | if( libcnotify_verbose != 0 ) |
606 | | { |
607 | | libcnotify_printf( |
608 | | "%s: file type\t\t\t\t: %" PRIu8 "\n", |
609 | | function, |
610 | | data[ data_offset ] ); |
611 | | } |
612 | | #endif /* defined( HAVE_DEBUG_OUTPUT ) */ |
613 | | |
614 | 103k | data_offset++; |
615 | 103k | } |
616 | 114k | if( alignment_padding_size > 0 ) |
617 | 110k | { |
618 | | #if defined( HAVE_DEBUG_OUTPUT ) |
619 | | if( libcnotify_verbose != 0 ) |
620 | | { |
621 | | libcnotify_printf( |
622 | | "%s: alignment padding:\n", |
623 | | function, |
624 | | directory_entry_index ); |
625 | | libcnotify_print_data( |
626 | | &( data[ data_offset ] ), |
627 | | alignment_padding_size, |
628 | | 0 ); |
629 | | } |
630 | | #endif /* defined( HAVE_DEBUG_OUTPUT ) */ |
631 | | |
632 | 110k | data_offset += alignment_padding_size; |
633 | 110k | } |
634 | 114k | if( directory_entry != NULL ) |
635 | 112k | { |
636 | 112k | if( libcdata_array_append_entry( |
637 | 112k | entries_array, |
638 | 112k | &entry_index, |
639 | 112k | (intptr_t *) directory_entry, |
640 | 112k | error ) != 1 ) |
641 | 0 | { |
642 | 0 | libcerror_error_set( |
643 | 0 | error, |
644 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
645 | 0 | LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, |
646 | 0 | "%s: unable to append directory entry to entries array.", |
647 | 0 | function ); |
648 | |
|
649 | 0 | goto on_error; |
650 | 0 | } |
651 | 112k | directory_entry = NULL; |
652 | 112k | } |
653 | | #if defined( HAVE_DEBUG_OUTPUT ) |
654 | | if( libcnotify_verbose != 0 ) |
655 | | { |
656 | | byte_stream_copy_to_uint16_big_endian( |
657 | | &( data[ data_offset ] ), |
658 | | value_16bit ); |
659 | | libcnotify_printf( |
660 | | "%s: tag offset\t\t\t\t: %" PRIu16 "\n", |
661 | | function, |
662 | | value_16bit ); |
663 | | |
664 | | libcnotify_printf( |
665 | | "\n" ); |
666 | | } |
667 | | #endif /* defined( HAVE_DEBUG_OUTPUT ) */ |
668 | | |
669 | 114k | data_offset += 2; |
670 | | |
671 | 114k | directory_entry_index++; |
672 | 114k | } |
673 | 4.10k | if( hash_values_data_size > 0 ) |
674 | 527 | { |
675 | | #if defined( HAVE_DEBUG_OUTPUT ) |
676 | | if( libcnotify_verbose != 0 ) |
677 | | { |
678 | | libcnotify_printf( |
679 | | "%s: hash values data:\n", |
680 | | function ); |
681 | | libcnotify_print_data( |
682 | | &( data[ entries_data_end_offset ] ), |
683 | | hash_values_data_size, |
684 | | LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); |
685 | | } |
686 | | #endif /* defined( HAVE_DEBUG_OUTPUT ) */ |
687 | 527 | } |
688 | 4.10k | return( 1 ); |
689 | | |
690 | 155 | on_error: |
691 | 155 | if( directory_entry != NULL ) |
692 | 0 | { |
693 | 0 | libfsxfs_directory_entry_free( |
694 | 0 | &directory_entry, |
695 | 0 | NULL ); |
696 | 0 | } |
697 | 155 | if( block_directory->footer != NULL ) |
698 | 73 | { |
699 | 73 | libfsxfs_block_directory_footer_free( |
700 | 73 | &( block_directory->footer ), |
701 | 73 | NULL ); |
702 | 73 | } |
703 | 155 | if( block_directory->header != NULL ) |
704 | 155 | { |
705 | 155 | libfsxfs_block_directory_header_free( |
706 | 155 | &( block_directory->header ), |
707 | 155 | NULL ); |
708 | 155 | } |
709 | 155 | libcdata_array_empty( |
710 | 155 | entries_array, |
711 | 155 | (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_directory_entry_free, |
712 | 155 | NULL ); |
713 | | |
714 | 155 | return( -1 ); |
715 | 4.16k | } |
716 | | |
717 | | /* Reads the block directory from a Basic File IO (bfio) handle |
718 | | * Returns 1 if successful or -1 on error |
719 | | */ |
720 | | int libfsxfs_block_directory_read_file_io_handle( |
721 | | libfsxfs_block_directory_t *block_directory, |
722 | | libfsxfs_io_handle_t *io_handle, |
723 | | libbfio_handle_t *file_io_handle, |
724 | | off64_t file_offset, |
725 | | libcdata_array_t *entries_array, |
726 | | libcerror_error_t **error ) |
727 | 4.52k | { |
728 | 4.52k | static char *function = "libfsxfs_block_directory_read_file_io_handle"; |
729 | 4.52k | ssize_t read_count = 0; |
730 | | |
731 | 4.52k | if( block_directory == NULL ) |
732 | 0 | { |
733 | 0 | libcerror_error_set( |
734 | 0 | error, |
735 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
736 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
737 | 0 | "%s: invalid block directory.", |
738 | 0 | function ); |
739 | |
|
740 | 0 | return( -1 ); |
741 | 0 | } |
742 | 4.52k | if( block_directory->header != NULL ) |
743 | 0 | { |
744 | 0 | libcerror_error_set( |
745 | 0 | error, |
746 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
747 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
748 | 0 | "%s: invalid block directory - header value already set.", |
749 | 0 | function ); |
750 | |
|
751 | 0 | return( -1 ); |
752 | 0 | } |
753 | | #if defined( HAVE_DEBUG_OUTPUT ) |
754 | | if( libcnotify_verbose != 0 ) |
755 | | { |
756 | | libcnotify_printf( |
757 | | "%s: reading block directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n", |
758 | | function, |
759 | | file_offset, |
760 | | file_offset ); |
761 | | } |
762 | | #endif |
763 | 4.52k | read_count = libbfio_handle_read_buffer_at_offset( |
764 | 4.52k | file_io_handle, |
765 | 4.52k | block_directory->data, |
766 | 4.52k | block_directory->data_size, |
767 | 4.52k | file_offset, |
768 | 4.52k | error ); |
769 | | |
770 | 4.52k | if( read_count != (ssize_t) block_directory->data_size ) |
771 | 269 | { |
772 | 269 | libcerror_error_set( |
773 | 269 | error, |
774 | 269 | LIBCERROR_ERROR_DOMAIN_IO, |
775 | 269 | LIBCERROR_IO_ERROR_READ_FAILED, |
776 | 269 | "%s: unable to read block directory data at offset: %" PRIi64 " (0x%08" PRIx64 ").", |
777 | 269 | function, |
778 | 269 | file_offset, |
779 | 269 | file_offset ); |
780 | | |
781 | 269 | return( -1 ); |
782 | 269 | } |
783 | 4.26k | if( libfsxfs_block_directory_read_data( |
784 | 4.26k | block_directory, |
785 | 4.26k | io_handle, |
786 | 4.26k | block_directory->data, |
787 | 4.26k | block_directory->data_size, |
788 | 4.26k | entries_array, |
789 | 4.26k | error ) != 1 ) |
790 | 155 | { |
791 | 155 | libcerror_error_set( |
792 | 155 | error, |
793 | 155 | LIBCERROR_ERROR_DOMAIN_IO, |
794 | 155 | LIBCERROR_IO_ERROR_READ_FAILED, |
795 | 155 | "%s: unable to read block directory at offset: %" PRIi64 " (0x%08" PRIx64 ").", |
796 | 155 | function, |
797 | 155 | file_offset, |
798 | 155 | file_offset ); |
799 | | |
800 | 155 | return( -1 ); |
801 | 155 | } |
802 | 4.10k | return( 1 ); |
803 | 4.26k | } |
804 | | |