/src/libfsxfs/libfsxfs/libfsxfs_file_system.c
Line | Count | Source |
1 | | /* |
2 | | * File system 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 <memory.h> |
24 | | #include <types.h> |
25 | | |
26 | | #include "libfsxfs_definitions.h" |
27 | | #include "libfsxfs_directory.h" |
28 | | #include "libfsxfs_directory_entry.h" |
29 | | #include "libfsxfs_file_system.h" |
30 | | #include "libfsxfs_inode.h" |
31 | | #include "libfsxfs_inode_btree.h" |
32 | | #include "libfsxfs_inode_information.h" |
33 | | #include "libfsxfs_libbfio.h" |
34 | | #include "libfsxfs_libcerror.h" |
35 | | #include "libfsxfs_libcnotify.h" |
36 | | #include "libfsxfs_libcthreads.h" |
37 | | #include "libfsxfs_libuna.h" |
38 | | |
39 | | /* Creates a file system |
40 | | * Make sure the value file_system is referencing, is set to NULL |
41 | | * Returns 1 if successful or -1 on error |
42 | | */ |
43 | | int libfsxfs_file_system_initialize( |
44 | | libfsxfs_file_system_t **file_system, |
45 | | uint64_t root_directory_inode_number, |
46 | | libcerror_error_t **error ) |
47 | 4.24k | { |
48 | 4.24k | static char *function = "libfsxfs_file_system_initialize"; |
49 | | |
50 | 4.24k | if( file_system == NULL ) |
51 | 0 | { |
52 | 0 | libcerror_error_set( |
53 | 0 | error, |
54 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
55 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
56 | 0 | "%s: invalid file system.", |
57 | 0 | function ); |
58 | |
|
59 | 0 | return( -1 ); |
60 | 0 | } |
61 | 4.24k | if( *file_system != NULL ) |
62 | 0 | { |
63 | 0 | libcerror_error_set( |
64 | 0 | error, |
65 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
66 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
67 | 0 | "%s: invalid file system value already set.", |
68 | 0 | function ); |
69 | |
|
70 | 0 | return( -1 ); |
71 | 0 | } |
72 | 4.24k | *file_system = memory_allocate_structure( |
73 | 4.24k | libfsxfs_file_system_t ); |
74 | | |
75 | 4.24k | if( *file_system == NULL ) |
76 | 0 | { |
77 | 0 | libcerror_error_set( |
78 | 0 | error, |
79 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
80 | 0 | LIBCERROR_MEMORY_ERROR_INSUFFICIENT, |
81 | 0 | "%s: unable to create file system.", |
82 | 0 | function ); |
83 | |
|
84 | 0 | goto on_error; |
85 | 0 | } |
86 | 4.24k | if( memory_set( |
87 | 4.24k | *file_system, |
88 | 4.24k | 0, |
89 | 4.24k | sizeof( libfsxfs_file_system_t ) ) == NULL ) |
90 | 0 | { |
91 | 0 | libcerror_error_set( |
92 | 0 | error, |
93 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
94 | 0 | LIBCERROR_MEMORY_ERROR_SET_FAILED, |
95 | 0 | "%s: unable to clear file system.", |
96 | 0 | function ); |
97 | |
|
98 | 0 | memory_free( |
99 | 0 | *file_system ); |
100 | |
|
101 | 0 | *file_system = NULL; |
102 | |
|
103 | 0 | return( -1 ); |
104 | 0 | } |
105 | 4.24k | if( libfsxfs_inode_btree_initialize( |
106 | 4.24k | &( ( *file_system )->inode_btree ), |
107 | 4.24k | error ) != 1 ) |
108 | 0 | { |
109 | 0 | libcerror_error_set( |
110 | 0 | error, |
111 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
112 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
113 | 0 | "%s: unable to create inode B+ tree.", |
114 | 0 | function ); |
115 | |
|
116 | 0 | goto on_error; |
117 | 0 | } |
118 | 4.24k | #if defined( HAVE_LIBFSXFS_MULTI_THREAD_SUPPORT ) |
119 | 4.24k | if( libcthreads_read_write_lock_initialize( |
120 | 4.24k | &( ( *file_system )->read_write_lock ), |
121 | 4.24k | error ) != 1 ) |
122 | 0 | { |
123 | 0 | libcerror_error_set( |
124 | 0 | error, |
125 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
126 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
127 | 0 | "%s: unable to initialize read/write lock.", |
128 | 0 | function ); |
129 | |
|
130 | 0 | goto on_error; |
131 | 0 | } |
132 | 4.24k | #endif |
133 | 4.24k | ( *file_system )->root_directory_inode_number = root_directory_inode_number; |
134 | | |
135 | 4.24k | return( 1 ); |
136 | | |
137 | 0 | on_error: |
138 | 0 | if( *file_system != NULL ) |
139 | 0 | { |
140 | 0 | if( ( *file_system )->inode_btree != NULL ) |
141 | 0 | { |
142 | 0 | libfsxfs_inode_btree_free( |
143 | 0 | &( ( *file_system )->inode_btree ), |
144 | 0 | NULL ); |
145 | 0 | } |
146 | 0 | memory_free( |
147 | 0 | *file_system ); |
148 | |
|
149 | 0 | *file_system = NULL; |
150 | 0 | } |
151 | 0 | return( -1 ); |
152 | 4.24k | } |
153 | | |
154 | | /* Frees a file system |
155 | | * Returns 1 if successful or -1 on error |
156 | | */ |
157 | | int libfsxfs_file_system_free( |
158 | | libfsxfs_file_system_t **file_system, |
159 | | libcerror_error_t **error ) |
160 | 4.24k | { |
161 | 4.24k | static char *function = "libfsxfs_file_system_free"; |
162 | 4.24k | int result = 1; |
163 | | |
164 | 4.24k | if( file_system == NULL ) |
165 | 0 | { |
166 | 0 | libcerror_error_set( |
167 | 0 | error, |
168 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
169 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
170 | 0 | "%s: invalid file system.", |
171 | 0 | function ); |
172 | |
|
173 | 0 | return( -1 ); |
174 | 0 | } |
175 | 4.24k | if( *file_system != NULL ) |
176 | 4.24k | { |
177 | 4.24k | #if defined( HAVE_LIBFSXFS_MULTI_THREAD_SUPPORT ) |
178 | 4.24k | if( libcthreads_read_write_lock_free( |
179 | 4.24k | &( ( *file_system )->read_write_lock ), |
180 | 4.24k | error ) != 1 ) |
181 | 0 | { |
182 | 0 | libcerror_error_set( |
183 | 0 | error, |
184 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
185 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
186 | 0 | "%s: unable to free read/write lock.", |
187 | 0 | function ); |
188 | |
|
189 | 0 | result = -1; |
190 | 0 | } |
191 | 4.24k | #endif |
192 | 4.24k | if( libfsxfs_inode_btree_free( |
193 | 4.24k | &( ( *file_system )->inode_btree ), |
194 | 4.24k | error ) != 1 ) |
195 | 0 | { |
196 | 0 | libcerror_error_set( |
197 | 0 | error, |
198 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
199 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
200 | 0 | "%s: unable to free inode B+ tree.", |
201 | 0 | function ); |
202 | |
|
203 | 0 | result = -1; |
204 | 0 | } |
205 | 4.24k | memory_free( |
206 | 4.24k | *file_system ); |
207 | | |
208 | 4.24k | *file_system = NULL; |
209 | 4.24k | } |
210 | 4.24k | return( result ); |
211 | 4.24k | } |
212 | | |
213 | | /* Reads the inode information |
214 | | * Returns 1 if successful or -1 on error |
215 | | */ |
216 | | int libfsxfs_file_system_read_inode_information( |
217 | | libfsxfs_file_system_t *file_system, |
218 | | libfsxfs_io_handle_t *io_handle, |
219 | | libbfio_handle_t *file_io_handle, |
220 | | off64_t file_offset, |
221 | | libcerror_error_t **error ) |
222 | 15.6k | { |
223 | 15.6k | static char *function = "libfsxfs_file_system_read_inode_information"; |
224 | | |
225 | 15.6k | if( file_system == NULL ) |
226 | 0 | { |
227 | 0 | libcerror_error_set( |
228 | 0 | error, |
229 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
230 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
231 | 0 | "%s: invalid file system.", |
232 | 0 | function ); |
233 | |
|
234 | 0 | return( -1 ); |
235 | 0 | } |
236 | 15.6k | if( libfsxfs_inode_btree_read_inode_information( |
237 | 15.6k | file_system->inode_btree, |
238 | 15.6k | io_handle, |
239 | 15.6k | file_io_handle, |
240 | 15.6k | file_offset, |
241 | 15.6k | error ) != 1 ) |
242 | 9.03k | { |
243 | 9.03k | libcerror_error_set( |
244 | 9.03k | error, |
245 | 9.03k | LIBCERROR_ERROR_DOMAIN_IO, |
246 | 9.03k | LIBCERROR_IO_ERROR_READ_FAILED, |
247 | 9.03k | "%s: unable to read inode information at offset: %" PRIi64 " (0x%08" PRIx64 ").", |
248 | 9.03k | function, |
249 | 9.03k | file_offset, |
250 | 9.03k | file_offset ); |
251 | | |
252 | 9.03k | return( 1 ); |
253 | 9.03k | } |
254 | 6.61k | return( 1 ); |
255 | 15.6k | } |
256 | | |
257 | | /* Retrieves a specific inode |
258 | | * Returns 1 if successful, 0 if no such value or -1 on error |
259 | | */ |
260 | | int libfsxfs_file_system_get_inode_by_number( |
261 | | libfsxfs_file_system_t *file_system, |
262 | | libfsxfs_io_handle_t *io_handle, |
263 | | libbfio_handle_t *file_io_handle, |
264 | | uint64_t inode_number, |
265 | | libfsxfs_inode_t **inode, |
266 | | libcerror_error_t **error ) |
267 | 4.16k | { |
268 | 4.16k | libfsxfs_inode_t *safe_inode = NULL; |
269 | 4.16k | static char *function = "libfsxfs_file_system_get_inode_by_number"; |
270 | 4.16k | off64_t file_offset = 0; |
271 | 4.16k | int result = 0; |
272 | | |
273 | 4.16k | if( file_system == NULL ) |
274 | 0 | { |
275 | 0 | libcerror_error_set( |
276 | 0 | error, |
277 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
278 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
279 | 0 | "%s: invalid file system.", |
280 | 0 | function ); |
281 | |
|
282 | 0 | return( -1 ); |
283 | 0 | } |
284 | 4.16k | if( io_handle == NULL ) |
285 | 0 | { |
286 | 0 | libcerror_error_set( |
287 | 0 | error, |
288 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
289 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
290 | 0 | "%s: invalid IO handle.", |
291 | 0 | function ); |
292 | |
|
293 | 0 | return( -1 ); |
294 | 0 | } |
295 | 4.16k | if( io_handle->inode_size == 0 ) |
296 | 0 | { |
297 | 0 | libcerror_error_set( |
298 | 0 | error, |
299 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
300 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
301 | 0 | "%s: invalid IO handle - inode size value out of bounds.", |
302 | 0 | function ); |
303 | |
|
304 | 0 | return( -1 ); |
305 | 0 | } |
306 | 4.16k | if( ( inode_number == 0 ) |
307 | 4.16k | || ( inode_number > (uint64_t) UINT32_MAX ) ) |
308 | 198 | { |
309 | 198 | libcerror_error_set( |
310 | 198 | error, |
311 | 198 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
312 | 198 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
313 | 198 | "%s: invalid inode number value out of bounds.", |
314 | 198 | function ); |
315 | | |
316 | 198 | return( -1 ); |
317 | 198 | } |
318 | 3.97k | result = libfsxfs_inode_btree_get_inode_by_number( |
319 | 3.97k | file_system->inode_btree, |
320 | 3.97k | io_handle, |
321 | 3.97k | file_io_handle, |
322 | 3.97k | inode_number, |
323 | 3.97k | &file_offset, |
324 | 3.97k | error ); |
325 | | |
326 | 3.97k | if( result == -1 ) |
327 | 584 | { |
328 | 584 | libcerror_error_set( |
329 | 584 | error, |
330 | 584 | LIBCERROR_ERROR_DOMAIN_IO, |
331 | 584 | LIBCERROR_IO_ERROR_READ_FAILED, |
332 | 584 | "%s: unable to retrieve inode: %" PRIu64 "\n", |
333 | 584 | function, |
334 | 584 | inode_number ); |
335 | | |
336 | 584 | goto on_error; |
337 | 584 | } |
338 | 3.38k | else if( result != 0 ) |
339 | 3.27k | { |
340 | 3.27k | if( libfsxfs_inode_initialize( |
341 | 3.27k | &safe_inode, |
342 | 3.27k | io_handle->inode_size, |
343 | 3.27k | error ) != 1 ) |
344 | 61 | { |
345 | 61 | libcerror_error_set( |
346 | 61 | error, |
347 | 61 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
348 | 61 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
349 | 61 | "%s: unable to create inode.", |
350 | 61 | function ); |
351 | | |
352 | 61 | goto on_error; |
353 | 61 | } |
354 | | #if defined( HAVE_DEBUG_OUTPUT ) |
355 | | if( libcnotify_verbose != 0 ) |
356 | | { |
357 | | libcnotify_printf( |
358 | | "Reading inode: %" PRIu64 " at offset: %" PRIi64 " (0x%08" PRIx64 ").\n", |
359 | | inode_number, |
360 | | file_offset, |
361 | | file_offset ); |
362 | | } |
363 | | #endif |
364 | 3.21k | if( libfsxfs_inode_read_file_io_handle( |
365 | 3.21k | safe_inode, |
366 | 3.21k | io_handle, |
367 | 3.21k | file_io_handle, |
368 | 3.21k | file_offset, |
369 | 3.21k | error ) != 1 ) |
370 | 732 | { |
371 | 732 | libcerror_error_set( |
372 | 732 | error, |
373 | 732 | LIBCERROR_ERROR_DOMAIN_IO, |
374 | 732 | LIBCERROR_IO_ERROR_READ_FAILED, |
375 | 732 | "%s: unable to read inode: %" PRIu64 " at offset: %" PRIi64 " (0x%08" PRIx64 ").", |
376 | 732 | function, |
377 | 732 | inode_number, |
378 | 732 | file_offset, |
379 | 732 | file_offset ); |
380 | | |
381 | 732 | goto on_error; |
382 | 732 | } |
383 | 2.48k | *inode = safe_inode; |
384 | 2.48k | } |
385 | 2.59k | return( result ); |
386 | | |
387 | 1.37k | on_error: |
388 | 1.37k | if( safe_inode != NULL ) |
389 | 732 | { |
390 | 732 | libfsxfs_inode_free( |
391 | 732 | &safe_inode, |
392 | 732 | NULL ); |
393 | 732 | } |
394 | 1.37k | return( -1 ); |
395 | 3.97k | } |
396 | | |
397 | | /* Retrieves a directory entry for a specific UTF-8 formatted path |
398 | | * Returns 1 if successful, 0 if not found or -1 on error |
399 | | */ |
400 | | int libfsxfs_file_system_get_directory_entry_by_utf8_path( |
401 | | libfsxfs_file_system_t *file_system, |
402 | | libfsxfs_io_handle_t *io_handle, |
403 | | libbfio_handle_t *file_io_handle, |
404 | | const uint8_t *utf8_string, |
405 | | size_t utf8_string_length, |
406 | | uint64_t *inode_number, |
407 | | libfsxfs_inode_t **inode, |
408 | | libfsxfs_directory_entry_t **directory_entry, |
409 | | libcerror_error_t **error ) |
410 | 1.67k | { |
411 | 1.67k | libfsxfs_directory_t *directory = NULL; |
412 | 1.67k | libfsxfs_directory_entry_t *safe_directory_entry = NULL; |
413 | 1.67k | libfsxfs_inode_t *safe_inode = NULL; |
414 | 1.67k | const uint8_t *utf8_string_segment = NULL; |
415 | 1.67k | static char *function = "libfsxfs_file_system_get_directory_entry_by_utf8_path"; |
416 | 1.67k | libuna_unicode_character_t unicode_character = 0; |
417 | 1.67k | size_t utf8_string_index = 0; |
418 | 1.67k | size_t utf8_string_segment_length = 0; |
419 | 1.67k | uint64_t safe_inode_number = 0; |
420 | 1.67k | int result = 0; |
421 | | |
422 | 1.67k | if( file_system == NULL ) |
423 | 0 | { |
424 | 0 | libcerror_error_set( |
425 | 0 | error, |
426 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
427 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
428 | 0 | "%s: invalid file system.", |
429 | 0 | function ); |
430 | |
|
431 | 0 | return( -1 ); |
432 | 0 | } |
433 | 1.67k | if( utf8_string == NULL ) |
434 | 0 | { |
435 | 0 | libcerror_error_set( |
436 | 0 | error, |
437 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
438 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
439 | 0 | "%s: invalid UTF-8 string.", |
440 | 0 | function ); |
441 | |
|
442 | 0 | return( -1 ); |
443 | 0 | } |
444 | 1.67k | if( utf8_string_length > (size_t) SSIZE_MAX ) |
445 | 0 | { |
446 | 0 | libcerror_error_set( |
447 | 0 | error, |
448 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
449 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM, |
450 | 0 | "%s: invalid UTF-8 string length value exceeds maximum.", |
451 | 0 | function ); |
452 | |
|
453 | 0 | return( -1 ); |
454 | 0 | } |
455 | 1.67k | if( inode == NULL ) |
456 | 0 | { |
457 | 0 | libcerror_error_set( |
458 | 0 | error, |
459 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
460 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
461 | 0 | "%s: invalid inode.", |
462 | 0 | function ); |
463 | |
|
464 | 0 | return( -1 ); |
465 | 0 | } |
466 | 1.67k | if( directory_entry == NULL ) |
467 | 0 | { |
468 | 0 | libcerror_error_set( |
469 | 0 | error, |
470 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
471 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
472 | 0 | "%s: invalid directory entry.", |
473 | 0 | function ); |
474 | |
|
475 | 0 | return( -1 ); |
476 | 0 | } |
477 | 1.67k | if( utf8_string_length > 0 ) |
478 | 1.67k | { |
479 | | /* Ignore a leading separator |
480 | | */ |
481 | 1.67k | if( utf8_string[ utf8_string_index ] == (uint8_t) LIBFSXFS_SEPARATOR ) |
482 | 1.67k | { |
483 | 1.67k | utf8_string_index++; |
484 | 1.67k | } |
485 | 1.67k | } |
486 | 1.67k | safe_inode_number = file_system->root_directory_inode_number; |
487 | | |
488 | 1.67k | if( libfsxfs_file_system_get_inode_by_number( |
489 | 1.67k | file_system, |
490 | 1.67k | io_handle, |
491 | 1.67k | file_io_handle, |
492 | 1.67k | safe_inode_number, |
493 | 1.67k | &safe_inode, |
494 | 1.67k | error ) != 1 ) |
495 | 914 | { |
496 | 914 | libcerror_error_set( |
497 | 914 | error, |
498 | 914 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
499 | 914 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
500 | 914 | "%s: unable to retrieve inode: %" PRIu64 ".", |
501 | 914 | function, |
502 | 914 | safe_inode_number ); |
503 | | |
504 | 914 | goto on_error; |
505 | 914 | } |
506 | 756 | if( ( utf8_string_length == 0 ) |
507 | 756 | || ( utf8_string_length == 1 ) ) |
508 | 0 | { |
509 | 0 | result = 1; |
510 | 0 | } |
511 | 800 | else while( utf8_string_index < utf8_string_length ) |
512 | 800 | { |
513 | 800 | if( directory != NULL ) |
514 | 44 | { |
515 | 44 | if( libfsxfs_directory_free( |
516 | 44 | &directory, |
517 | 44 | error ) != 1 ) |
518 | 0 | { |
519 | 0 | libcerror_error_set( |
520 | 0 | error, |
521 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
522 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
523 | 0 | "%s: unable to free directory.", |
524 | 0 | function ); |
525 | |
|
526 | 0 | goto on_error; |
527 | 0 | } |
528 | 44 | } |
529 | 800 | if( libfsxfs_directory_initialize( |
530 | 800 | &directory, |
531 | 800 | error ) != 1 ) |
532 | 0 | { |
533 | 0 | libcerror_error_set( |
534 | 0 | error, |
535 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
536 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
537 | 0 | "%s: unable to create directory.", |
538 | 0 | function ); |
539 | |
|
540 | 0 | goto on_error; |
541 | 0 | } |
542 | 800 | if( libfsxfs_directory_read_file_io_handle( |
543 | 800 | directory, |
544 | 800 | io_handle, |
545 | 800 | file_io_handle, |
546 | 800 | safe_inode, |
547 | 800 | error ) != 1 ) |
548 | 419 | { |
549 | 419 | libcerror_error_set( |
550 | 419 | error, |
551 | 419 | LIBCERROR_ERROR_DOMAIN_IO, |
552 | 419 | LIBCERROR_IO_ERROR_READ_FAILED, |
553 | 419 | "%s: unable to read directory from inode: %" PRIu64 ".", |
554 | 419 | function, |
555 | 419 | safe_inode_number ); |
556 | | |
557 | 419 | goto on_error; |
558 | 419 | } |
559 | 381 | utf8_string_segment = &( utf8_string[ utf8_string_index ] ); |
560 | 381 | utf8_string_segment_length = utf8_string_index; |
561 | | |
562 | 4.35k | while( utf8_string_index < utf8_string_length ) |
563 | 4.31k | { |
564 | 4.31k | if( libuna_unicode_character_copy_from_utf8( |
565 | 4.31k | &unicode_character, |
566 | 4.31k | utf8_string, |
567 | 4.31k | utf8_string_length, |
568 | 4.31k | &utf8_string_index, |
569 | 4.31k | error ) != 1 ) |
570 | 0 | { |
571 | 0 | libcerror_error_set( |
572 | 0 | error, |
573 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
574 | 0 | LIBCERROR_RUNTIME_ERROR_COPY_FAILED, |
575 | 0 | "%s: unable to copy UTF-8 string to Unicode character.", |
576 | 0 | function ); |
577 | |
|
578 | 0 | goto on_error; |
579 | 0 | } |
580 | 4.31k | if( ( unicode_character == (libuna_unicode_character_t) LIBFSXFS_SEPARATOR ) |
581 | 3.97k | || ( unicode_character == 0 ) ) |
582 | 338 | { |
583 | 338 | utf8_string_segment_length += 1; |
584 | | |
585 | 338 | break; |
586 | 338 | } |
587 | 4.31k | } |
588 | 381 | utf8_string_segment_length = utf8_string_index - utf8_string_segment_length; |
589 | | |
590 | 381 | if( utf8_string_segment_length == 0 ) |
591 | 0 | { |
592 | 0 | result = 0; |
593 | 0 | } |
594 | 381 | else |
595 | 381 | { |
596 | 381 | result = libfsxfs_directory_get_entry_by_utf8_name( |
597 | 381 | directory, |
598 | 381 | utf8_string_segment, |
599 | 381 | utf8_string_segment_length, |
600 | 381 | &safe_directory_entry, |
601 | 381 | error ); |
602 | 381 | } |
603 | 381 | if( result == -1 ) |
604 | 146 | { |
605 | 146 | libcerror_error_set( |
606 | 146 | error, |
607 | 146 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
608 | 146 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
609 | 146 | "%s: unable to retrieve directory entry by UTF-8 name.", |
610 | 146 | function ); |
611 | | |
612 | 146 | goto on_error; |
613 | 146 | } |
614 | 235 | else if( result == 0 ) |
615 | 185 | { |
616 | 185 | break; |
617 | 185 | } |
618 | 50 | if( libfsxfs_directory_entry_get_inode_number( |
619 | 50 | safe_directory_entry, |
620 | 50 | &safe_inode_number, |
621 | 50 | error ) != 1 ) |
622 | 0 | { |
623 | 0 | libcerror_error_set( |
624 | 0 | error, |
625 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
626 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
627 | 0 | "%s: unable to retrieve inode number from directory entry.", |
628 | 0 | function ); |
629 | |
|
630 | 0 | goto on_error; |
631 | 0 | } |
632 | 50 | if( safe_inode != NULL ) |
633 | 50 | { |
634 | 50 | if( libfsxfs_inode_free( |
635 | 50 | &safe_inode, |
636 | 50 | error ) != 1 ) |
637 | 0 | { |
638 | 0 | libcerror_error_set( |
639 | 0 | error, |
640 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
641 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
642 | 0 | "%s: unable to free inode.", |
643 | 0 | function ); |
644 | |
|
645 | 0 | goto on_error; |
646 | 0 | } |
647 | 50 | } |
648 | 50 | if( libfsxfs_file_system_get_inode_by_number( |
649 | 50 | file_system, |
650 | 50 | io_handle, |
651 | 50 | file_io_handle, |
652 | 50 | safe_inode_number, |
653 | 50 | &safe_inode, |
654 | 50 | error ) != 1 ) |
655 | 6 | { |
656 | 6 | libcerror_error_set( |
657 | 6 | error, |
658 | 6 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
659 | 6 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
660 | 6 | "%s: unable to retrieve inode: %" PRIu32 ".", |
661 | 6 | function, |
662 | 6 | safe_inode_number ); |
663 | | |
664 | 6 | goto on_error; |
665 | 6 | } |
666 | 50 | } |
667 | 185 | if( result == 0 ) |
668 | 185 | { |
669 | 185 | if( safe_inode != NULL ) |
670 | 185 | { |
671 | 185 | if( libfsxfs_inode_free( |
672 | 185 | &safe_inode, |
673 | 185 | error ) != 1 ) |
674 | 0 | { |
675 | 0 | libcerror_error_set( |
676 | 0 | error, |
677 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
678 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
679 | 0 | "%s: unable to free inode.", |
680 | 0 | function ); |
681 | |
|
682 | 0 | goto on_error; |
683 | 0 | } |
684 | 185 | } |
685 | 185 | } |
686 | 0 | else |
687 | 0 | { |
688 | 0 | if( libfsxfs_directory_entry_clone( |
689 | 0 | directory_entry, |
690 | 0 | safe_directory_entry, |
691 | 0 | error ) != 1 ) |
692 | 0 | { |
693 | 0 | libcerror_error_set( |
694 | 0 | error, |
695 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
696 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
697 | 0 | "%s: unable to create directory entry.", |
698 | 0 | function ); |
699 | |
|
700 | 0 | goto on_error; |
701 | 0 | } |
702 | 0 | } |
703 | | /* Directory needs to be freed after making a clone of directory_entry |
704 | | */ |
705 | 185 | if( directory != NULL ) |
706 | 185 | { |
707 | 185 | if( libfsxfs_directory_free( |
708 | 185 | &directory, |
709 | 185 | error ) != 1 ) |
710 | 0 | { |
711 | 0 | libcerror_error_set( |
712 | 0 | error, |
713 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
714 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
715 | 0 | "%s: unable to free directory.", |
716 | 0 | function ); |
717 | |
|
718 | 0 | goto on_error; |
719 | 0 | } |
720 | 185 | } |
721 | 185 | *inode_number = safe_inode_number; |
722 | 185 | *inode = safe_inode; |
723 | | |
724 | 185 | return( result ); |
725 | | |
726 | 1.48k | on_error: |
727 | 1.48k | if( directory != NULL ) |
728 | 571 | { |
729 | 571 | libfsxfs_directory_free( |
730 | 571 | &directory, |
731 | 571 | NULL ); |
732 | 571 | } |
733 | 1.48k | if( safe_inode != NULL ) |
734 | 565 | { |
735 | 565 | libfsxfs_inode_free( |
736 | 565 | &safe_inode, |
737 | 565 | NULL ); |
738 | 565 | } |
739 | 1.48k | if( *directory_entry != NULL ) |
740 | 0 | { |
741 | 0 | libfsxfs_directory_entry_free( |
742 | 0 | directory_entry, |
743 | 0 | NULL ); |
744 | 0 | } |
745 | 1.48k | return( -1 ); |
746 | 185 | } |
747 | | |
748 | | /* Retrieves a directory entry for a specific UTF-16 formatted path |
749 | | * Returns 1 if successful, 0 if not found or -1 on error |
750 | | */ |
751 | | int libfsxfs_file_system_get_directory_entry_by_utf16_path( |
752 | | libfsxfs_file_system_t *file_system, |
753 | | libfsxfs_io_handle_t *io_handle, |
754 | | libbfio_handle_t *file_io_handle, |
755 | | const uint16_t *utf16_string, |
756 | | size_t utf16_string_length, |
757 | | uint64_t *inode_number, |
758 | | libfsxfs_inode_t **inode, |
759 | | libfsxfs_directory_entry_t **directory_entry, |
760 | | libcerror_error_t **error ) |
761 | 0 | { |
762 | 0 | libfsxfs_directory_t *directory = NULL; |
763 | 0 | libfsxfs_directory_entry_t *safe_directory_entry = NULL; |
764 | 0 | libfsxfs_inode_t *safe_inode = NULL; |
765 | 0 | const uint16_t *utf16_string_segment = NULL; |
766 | 0 | static char *function = "libfsxfs_file_system_get_directory_entry_by_utf16_path"; |
767 | 0 | libuna_unicode_character_t unicode_character = 0; |
768 | 0 | size_t utf16_string_index = 0; |
769 | 0 | size_t utf16_string_segment_length = 0; |
770 | 0 | uint64_t safe_inode_number = 0; |
771 | 0 | int result = 0; |
772 | |
|
773 | 0 | if( file_system == NULL ) |
774 | 0 | { |
775 | 0 | libcerror_error_set( |
776 | 0 | error, |
777 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
778 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
779 | 0 | "%s: invalid file system.", |
780 | 0 | function ); |
781 | |
|
782 | 0 | return( -1 ); |
783 | 0 | } |
784 | 0 | if( utf16_string == NULL ) |
785 | 0 | { |
786 | 0 | libcerror_error_set( |
787 | 0 | error, |
788 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
789 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
790 | 0 | "%s: invalid UTF-16 string.", |
791 | 0 | function ); |
792 | |
|
793 | 0 | return( -1 ); |
794 | 0 | } |
795 | 0 | if( utf16_string_length > (size_t) SSIZE_MAX ) |
796 | 0 | { |
797 | 0 | libcerror_error_set( |
798 | 0 | error, |
799 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
800 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM, |
801 | 0 | "%s: invalid UTF-16 string length value exceeds maximum.", |
802 | 0 | function ); |
803 | |
|
804 | 0 | return( -1 ); |
805 | 0 | } |
806 | 0 | if( inode == NULL ) |
807 | 0 | { |
808 | 0 | libcerror_error_set( |
809 | 0 | error, |
810 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
811 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
812 | 0 | "%s: invalid inode.", |
813 | 0 | function ); |
814 | |
|
815 | 0 | return( -1 ); |
816 | 0 | } |
817 | 0 | if( directory_entry == NULL ) |
818 | 0 | { |
819 | 0 | libcerror_error_set( |
820 | 0 | error, |
821 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
822 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
823 | 0 | "%s: invalid directory entry.", |
824 | 0 | function ); |
825 | |
|
826 | 0 | return( -1 ); |
827 | 0 | } |
828 | 0 | if( utf16_string_length > 0 ) |
829 | 0 | { |
830 | | /* Ignore a leading separator |
831 | | */ |
832 | 0 | if( utf16_string[ utf16_string_index ] == (uint16_t) LIBFSXFS_SEPARATOR ) |
833 | 0 | { |
834 | 0 | utf16_string_index++; |
835 | 0 | } |
836 | 0 | } |
837 | 0 | safe_inode_number = file_system->root_directory_inode_number; |
838 | |
|
839 | 0 | if( libfsxfs_file_system_get_inode_by_number( |
840 | 0 | file_system, |
841 | 0 | io_handle, |
842 | 0 | file_io_handle, |
843 | 0 | safe_inode_number, |
844 | 0 | &safe_inode, |
845 | 0 | error ) != 1 ) |
846 | 0 | { |
847 | 0 | libcerror_error_set( |
848 | 0 | error, |
849 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
850 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
851 | 0 | "%s: unable to retrieve inode: %" PRIu64 ".", |
852 | 0 | function, |
853 | 0 | safe_inode_number ); |
854 | |
|
855 | 0 | goto on_error; |
856 | 0 | } |
857 | 0 | if( ( utf16_string_length == 0 ) |
858 | 0 | || ( utf16_string_length == 1 ) ) |
859 | 0 | { |
860 | 0 | result = 1; |
861 | 0 | } |
862 | 0 | else while( utf16_string_index < utf16_string_length ) |
863 | 0 | { |
864 | 0 | if( directory != NULL ) |
865 | 0 | { |
866 | 0 | if( libfsxfs_directory_free( |
867 | 0 | &directory, |
868 | 0 | error ) != 1 ) |
869 | 0 | { |
870 | 0 | libcerror_error_set( |
871 | 0 | error, |
872 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
873 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
874 | 0 | "%s: unable to free directory.", |
875 | 0 | function ); |
876 | |
|
877 | 0 | goto on_error; |
878 | 0 | } |
879 | 0 | } |
880 | 0 | if( libfsxfs_directory_initialize( |
881 | 0 | &directory, |
882 | 0 | error ) != 1 ) |
883 | 0 | { |
884 | 0 | libcerror_error_set( |
885 | 0 | error, |
886 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
887 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
888 | 0 | "%s: unable to create directory.", |
889 | 0 | function ); |
890 | |
|
891 | 0 | goto on_error; |
892 | 0 | } |
893 | 0 | if( libfsxfs_directory_read_file_io_handle( |
894 | 0 | directory, |
895 | 0 | io_handle, |
896 | 0 | file_io_handle, |
897 | 0 | safe_inode, |
898 | 0 | error ) != 1 ) |
899 | 0 | { |
900 | 0 | libcerror_error_set( |
901 | 0 | error, |
902 | 0 | LIBCERROR_ERROR_DOMAIN_IO, |
903 | 0 | LIBCERROR_IO_ERROR_READ_FAILED, |
904 | 0 | "%s: unable to read directory from inode: %" PRIu64 ".", |
905 | 0 | function, |
906 | 0 | safe_inode_number ); |
907 | |
|
908 | 0 | goto on_error; |
909 | 0 | } |
910 | 0 | utf16_string_segment = &( utf16_string[ utf16_string_index ] ); |
911 | 0 | utf16_string_segment_length = utf16_string_index; |
912 | |
|
913 | 0 | while( utf16_string_index < utf16_string_length ) |
914 | 0 | { |
915 | 0 | if( libuna_unicode_character_copy_from_utf16( |
916 | 0 | &unicode_character, |
917 | 0 | utf16_string, |
918 | 0 | utf16_string_length, |
919 | 0 | &utf16_string_index, |
920 | 0 | error ) != 1 ) |
921 | 0 | { |
922 | 0 | libcerror_error_set( |
923 | 0 | error, |
924 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
925 | 0 | LIBCERROR_RUNTIME_ERROR_COPY_FAILED, |
926 | 0 | "%s: unable to copy UTF-16 string to Unicode character.", |
927 | 0 | function ); |
928 | |
|
929 | 0 | goto on_error; |
930 | 0 | } |
931 | 0 | if( ( unicode_character == (libuna_unicode_character_t) LIBFSXFS_SEPARATOR ) |
932 | 0 | || ( unicode_character == 0 ) ) |
933 | 0 | { |
934 | 0 | utf16_string_segment_length += 1; |
935 | |
|
936 | 0 | break; |
937 | 0 | } |
938 | 0 | } |
939 | 0 | utf16_string_segment_length = utf16_string_index - utf16_string_segment_length; |
940 | |
|
941 | 0 | if( utf16_string_segment_length == 0 ) |
942 | 0 | { |
943 | 0 | result = 0; |
944 | 0 | } |
945 | 0 | else |
946 | 0 | { |
947 | 0 | result = libfsxfs_directory_get_entry_by_utf16_name( |
948 | 0 | directory, |
949 | 0 | utf16_string_segment, |
950 | 0 | utf16_string_segment_length, |
951 | 0 | &safe_directory_entry, |
952 | 0 | error ); |
953 | 0 | } |
954 | 0 | if( result == -1 ) |
955 | 0 | { |
956 | 0 | libcerror_error_set( |
957 | 0 | error, |
958 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
959 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
960 | 0 | "%s: unable to retrieve directory entry by UTF-16 name.", |
961 | 0 | function ); |
962 | |
|
963 | 0 | goto on_error; |
964 | 0 | } |
965 | 0 | else if( result == 0 ) |
966 | 0 | { |
967 | 0 | break; |
968 | 0 | } |
969 | 0 | if( libfsxfs_directory_entry_get_inode_number( |
970 | 0 | safe_directory_entry, |
971 | 0 | &safe_inode_number, |
972 | 0 | error ) != 1 ) |
973 | 0 | { |
974 | 0 | libcerror_error_set( |
975 | 0 | error, |
976 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
977 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
978 | 0 | "%s: unable to retrieve inode number from directory entry.", |
979 | 0 | function ); |
980 | |
|
981 | 0 | goto on_error; |
982 | 0 | } |
983 | 0 | if( safe_inode != NULL ) |
984 | 0 | { |
985 | 0 | if( libfsxfs_inode_free( |
986 | 0 | &safe_inode, |
987 | 0 | error ) != 1 ) |
988 | 0 | { |
989 | 0 | libcerror_error_set( |
990 | 0 | error, |
991 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
992 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
993 | 0 | "%s: unable to free inode.", |
994 | 0 | function ); |
995 | |
|
996 | 0 | goto on_error; |
997 | 0 | } |
998 | 0 | } |
999 | 0 | if( libfsxfs_file_system_get_inode_by_number( |
1000 | 0 | file_system, |
1001 | 0 | io_handle, |
1002 | 0 | file_io_handle, |
1003 | 0 | safe_inode_number, |
1004 | 0 | &safe_inode, |
1005 | 0 | error ) != 1 ) |
1006 | 0 | { |
1007 | 0 | libcerror_error_set( |
1008 | 0 | error, |
1009 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1010 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
1011 | 0 | "%s: unable to retrieve inode: %" PRIu32 ".", |
1012 | 0 | function, |
1013 | 0 | safe_inode_number ); |
1014 | |
|
1015 | 0 | goto on_error; |
1016 | 0 | } |
1017 | 0 | } |
1018 | 0 | if( result == 0 ) |
1019 | 0 | { |
1020 | 0 | if( safe_inode != NULL ) |
1021 | 0 | { |
1022 | 0 | if( libfsxfs_inode_free( |
1023 | 0 | &safe_inode, |
1024 | 0 | error ) != 1 ) |
1025 | 0 | { |
1026 | 0 | libcerror_error_set( |
1027 | 0 | error, |
1028 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1029 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
1030 | 0 | "%s: unable to free inode.", |
1031 | 0 | function ); |
1032 | |
|
1033 | 0 | goto on_error; |
1034 | 0 | } |
1035 | 0 | } |
1036 | 0 | } |
1037 | 0 | else |
1038 | 0 | { |
1039 | 0 | if( libfsxfs_directory_entry_clone( |
1040 | 0 | directory_entry, |
1041 | 0 | safe_directory_entry, |
1042 | 0 | error ) != 1 ) |
1043 | 0 | { |
1044 | 0 | libcerror_error_set( |
1045 | 0 | error, |
1046 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1047 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
1048 | 0 | "%s: unable to create directory entry.", |
1049 | 0 | function ); |
1050 | |
|
1051 | 0 | goto on_error; |
1052 | 0 | } |
1053 | 0 | } |
1054 | | /* Directory needs to be freed after making a clone of directory_entry |
1055 | | */ |
1056 | 0 | if( directory != NULL ) |
1057 | 0 | { |
1058 | 0 | if( libfsxfs_directory_free( |
1059 | 0 | &directory, |
1060 | 0 | error ) != 1 ) |
1061 | 0 | { |
1062 | 0 | libcerror_error_set( |
1063 | 0 | error, |
1064 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1065 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
1066 | 0 | "%s: unable to free directory.", |
1067 | 0 | function ); |
1068 | |
|
1069 | 0 | goto on_error; |
1070 | 0 | } |
1071 | 0 | } |
1072 | 0 | *inode_number = safe_inode_number; |
1073 | 0 | *inode = safe_inode; |
1074 | |
|
1075 | 0 | return( result ); |
1076 | | |
1077 | 0 | on_error: |
1078 | 0 | if( directory != NULL ) |
1079 | 0 | { |
1080 | 0 | libfsxfs_directory_free( |
1081 | 0 | &directory, |
1082 | 0 | NULL ); |
1083 | 0 | } |
1084 | 0 | if( safe_inode != NULL ) |
1085 | 0 | { |
1086 | 0 | libfsxfs_inode_free( |
1087 | 0 | &safe_inode, |
1088 | 0 | NULL ); |
1089 | 0 | } |
1090 | 0 | if( *directory_entry != NULL ) |
1091 | 0 | { |
1092 | 0 | libfsxfs_directory_entry_free( |
1093 | 0 | directory_entry, |
1094 | | NULL ); |
1095 | 0 | } |
1096 | 0 | return( -1 ); |
1097 | 0 | } |
1098 | | |