1 /*
2 * Directory entry functions
3 *
4 * Copyright (C) 2010-2021, 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 "libfsntfs_directory_entry.h"
28 #include "libfsntfs_file_name_values.h"
29 #include "libfsntfs_index_value.h"
30 #include "libfsntfs_libcdata.h"
31 #include "libfsntfs_libcerror.h"
32 #include "libfsntfs_libcnotify.h"
33
34 /* Creates a directory entry
35 * Make sure the value directory_entry is referencing, is set to NULL
36 * Returns 1 if successful or -1 on error
37 */
libfsntfs_directory_entry_initialize(libfsntfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)38 int libfsntfs_directory_entry_initialize(
39 libfsntfs_directory_entry_t **directory_entry,
40 libcerror_error_t **error )
41 {
42 static char *function = "libfsntfs_directory_entry_initialize";
43
44 if( directory_entry == NULL )
45 {
46 libcerror_error_set(
47 error,
48 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
49 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
50 "%s: invalid directory entry.",
51 function );
52
53 return( -1 );
54 }
55 if( *directory_entry != NULL )
56 {
57 libcerror_error_set(
58 error,
59 LIBCERROR_ERROR_DOMAIN_RUNTIME,
60 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
61 "%s: invalid directory entry value already set.",
62 function );
63
64 return( -1 );
65 }
66 *directory_entry = memory_allocate_structure(
67 libfsntfs_directory_entry_t );
68
69 if( *directory_entry == NULL )
70 {
71 libcerror_error_set(
72 error,
73 LIBCERROR_ERROR_DOMAIN_MEMORY,
74 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
75 "%s: unable to create directory entry.",
76 function );
77
78 goto on_error;
79 }
80 if( memory_set(
81 *directory_entry,
82 0,
83 sizeof( libfsntfs_directory_entry_t ) ) == NULL )
84 {
85 libcerror_error_set(
86 error,
87 LIBCERROR_ERROR_DOMAIN_MEMORY,
88 LIBCERROR_MEMORY_ERROR_SET_FAILED,
89 "%s: unable to clear directory entry.",
90 function );
91
92 memory_free(
93 *directory_entry );
94
95 *directory_entry = NULL;
96
97 return( -1 );
98 }
99 return( 1 );
100
101 on_error:
102 if( *directory_entry != NULL )
103 {
104 memory_free(
105 *directory_entry );
106
107 *directory_entry = NULL;
108 }
109 return( -1 );
110 }
111
112 /* Frees a directory entry
113 * Returns 1 if successful or -1 on error
114 */
libfsntfs_directory_entry_free(libfsntfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)115 int libfsntfs_directory_entry_free(
116 libfsntfs_directory_entry_t **directory_entry,
117 libcerror_error_t **error )
118 {
119 static char *function = "libfsntfs_directory_entry_free";
120 int result = 1;
121
122 if( directory_entry == NULL )
123 {
124 libcerror_error_set(
125 error,
126 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
127 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
128 "%s: invalid directory entry.",
129 function );
130
131 return( -1 );
132 }
133 if( *directory_entry != NULL )
134 {
135 if( ( *directory_entry )->file_name_values != NULL )
136 {
137 if( libfsntfs_file_name_values_free(
138 &( ( *directory_entry )->file_name_values ),
139 error ) != 1 )
140 {
141 libcerror_error_set(
142 error,
143 LIBCERROR_ERROR_DOMAIN_RUNTIME,
144 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
145 "%s: unable to free file name values.",
146 function );
147
148 result = -1;
149 }
150 }
151 if( ( *directory_entry )->short_file_name_values != NULL )
152 {
153 if( libfsntfs_file_name_values_free(
154 &( ( *directory_entry )->short_file_name_values ),
155 error ) != 1 )
156 {
157 libcerror_error_set(
158 error,
159 LIBCERROR_ERROR_DOMAIN_RUNTIME,
160 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
161 "%s: unable to free short file name values.",
162 function );
163
164 result = -1;
165 }
166 }
167 memory_free(
168 *directory_entry );
169
170 *directory_entry = NULL;
171 }
172 return( result );
173 }
174
175 /* Clones a directory entry
176 * Returns 1 if successful or -1 on error
177 */
libfsntfs_directory_entry_clone(libfsntfs_directory_entry_t ** destination_directory_entry,libfsntfs_directory_entry_t * source_directory_entry,libcerror_error_t ** error)178 int libfsntfs_directory_entry_clone(
179 libfsntfs_directory_entry_t **destination_directory_entry,
180 libfsntfs_directory_entry_t *source_directory_entry,
181 libcerror_error_t **error )
182 {
183 static char *function = "libfsntfs_directory_entry_clone";
184
185 if( destination_directory_entry == NULL )
186 {
187 libcerror_error_set(
188 error,
189 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
190 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
191 "%s: invalid directory entry.",
192 function );
193
194 return( -1 );
195 }
196 if( *destination_directory_entry != NULL )
197 {
198 libcerror_error_set(
199 error,
200 LIBCERROR_ERROR_DOMAIN_RUNTIME,
201 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
202 "%s: invalid destination directory entry value already set.",
203 function );
204
205 return( -1 );
206 }
207 if( source_directory_entry == NULL )
208 {
209 *destination_directory_entry = source_directory_entry;
210
211 return( 1 );
212 }
213 if( libfsntfs_directory_entry_initialize(
214 destination_directory_entry,
215 error ) != 1 )
216 {
217 libcerror_error_set(
218 error,
219 LIBCERROR_ERROR_DOMAIN_RUNTIME,
220 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
221 "%s: unable to create destination directory entry.",
222 function );
223
224 goto on_error;
225 }
226 if( libfsntfs_file_name_values_clone(
227 &( ( *destination_directory_entry )->file_name_values ),
228 source_directory_entry->file_name_values,
229 error ) != 1 )
230 {
231 libcerror_error_set(
232 error,
233 LIBCERROR_ERROR_DOMAIN_RUNTIME,
234 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
235 "%s: unable to create destination file name values.",
236 function );
237
238 goto on_error;
239 }
240 if( libfsntfs_file_name_values_clone(
241 &( ( *destination_directory_entry )->short_file_name_values ),
242 source_directory_entry->short_file_name_values,
243 error ) != 1 )
244 {
245 libcerror_error_set(
246 error,
247 LIBCERROR_ERROR_DOMAIN_RUNTIME,
248 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
249 "%s: unable to create destination short file name values.",
250 function );
251
252 goto on_error;
253 }
254 ( *destination_directory_entry )->file_reference = source_directory_entry->file_reference;
255
256 return( 1 );
257
258 on_error:
259 if( *destination_directory_entry != NULL )
260 {
261 libfsntfs_directory_entry_free(
262 destination_directory_entry,
263 NULL );
264 }
265 return( -1 );
266 }
267
268 /* Compares 2 directory entries by file reference
269 * Returns LIBCDATA_COMPARE_LESS, LIBCDATA_COMPARE_EQUAL, LIBCDATA_COMPARE_GREATER if successful or -1 on error
270 */
libfsntfs_directory_entry_compare_by_file_reference(libfsntfs_directory_entry_t * first_directory_entry,libfsntfs_directory_entry_t * second_directory_entry,libcerror_error_t ** error)271 int libfsntfs_directory_entry_compare_by_file_reference(
272 libfsntfs_directory_entry_t *first_directory_entry,
273 libfsntfs_directory_entry_t *second_directory_entry,
274 libcerror_error_t **error )
275 {
276 static char *function = "libfsntfs_directory_entry_compare_by_file_reference";
277 uint64_t first_mft_entry_index = 0;
278 uint64_t second_mft_entry_index = 0;
279 uint16_t first_sequence_number = 0;
280 uint16_t second_sequence_number = 0;
281
282 if( first_directory_entry == NULL )
283 {
284 libcerror_error_set(
285 error,
286 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
287 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
288 "%s: invalid first directory entry.",
289 function );
290
291 return( -1 );
292 }
293 if( second_directory_entry == NULL )
294 {
295 libcerror_error_set(
296 error,
297 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
298 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
299 "%s: invalid second directory entry.",
300 function );
301
302 return( -1 );
303 }
304 first_mft_entry_index = first_directory_entry->file_reference & 0xffffffffffffUL;
305 second_mft_entry_index = second_directory_entry->file_reference & 0xffffffffffffUL;
306
307 if( first_mft_entry_index < second_mft_entry_index )
308 {
309 return( LIBCDATA_COMPARE_LESS );
310 }
311 else if( first_mft_entry_index > second_mft_entry_index )
312 {
313 return( LIBCDATA_COMPARE_GREATER );
314 }
315 first_sequence_number = (uint16_t) ( first_directory_entry->file_reference >> 48 );
316 second_sequence_number = (uint16_t) ( second_directory_entry->file_reference >> 48 );
317
318 if( first_sequence_number < second_sequence_number )
319 {
320 return( LIBCDATA_COMPARE_LESS );
321 }
322 else if( first_sequence_number > second_sequence_number )
323 {
324 return( LIBCDATA_COMPARE_GREATER );
325 }
326 return( LIBCDATA_COMPARE_EQUAL );
327 }
328
329 /* Retrieves the MFT entry index
330 * Returns 1 if successful or -1 on error
331 */
libfsntfs_directory_entry_get_mft_entry_index(libfsntfs_directory_entry_t * directory_entry,uint64_t * mft_entry_index,libcerror_error_t ** error)332 int libfsntfs_directory_entry_get_mft_entry_index(
333 libfsntfs_directory_entry_t *directory_entry,
334 uint64_t *mft_entry_index,
335 libcerror_error_t **error )
336 {
337 static char *function = "libfsntfs_directory_entry_get_mft_entry_index";
338
339 if( directory_entry == NULL )
340 {
341 libcerror_error_set(
342 error,
343 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
344 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
345 "%s: invalid directory entry.",
346 function );
347
348 return( -1 );
349 }
350 if( mft_entry_index == NULL )
351 {
352 libcerror_error_set(
353 error,
354 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
355 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
356 "%s: invalid MFT entry index.",
357 function );
358
359 return( -1 );
360 }
361 if( ( directory_entry->file_reference & 0xffffffffffffUL ) > (uint64_t) INT_MAX )
362 {
363 libcerror_error_set(
364 error,
365 LIBCERROR_ERROR_DOMAIN_RUNTIME,
366 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
367 "%s: invalid MFT entry index value out of bounds.",
368 function );
369
370 return( -1 );
371 }
372 *mft_entry_index = (int) ( directory_entry->file_reference & 0xffffffffffffUL );
373
374 return( 1 );
375 }
376
377 /* Retrieves the file reference
378 * Returns 1 if successful or -1 on error
379 */
libfsntfs_directory_entry_get_file_reference(libfsntfs_directory_entry_t * directory_entry,uint64_t * file_reference,libcerror_error_t ** error)380 int libfsntfs_directory_entry_get_file_reference(
381 libfsntfs_directory_entry_t *directory_entry,
382 uint64_t *file_reference,
383 libcerror_error_t **error )
384 {
385 static char *function = "libfsntfs_directory_entry_get_file_reference";
386
387 if( directory_entry == NULL )
388 {
389 libcerror_error_set(
390 error,
391 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
392 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
393 "%s: invalid directory entry.",
394 function );
395
396 return( -1 );
397 }
398 if( file_reference == NULL )
399 {
400 libcerror_error_set(
401 error,
402 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
403 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
404 "%s: invalid file reference.",
405 function );
406
407 return( -1 );
408 }
409 *file_reference = directory_entry->file_reference;
410
411 return( 1 );
412 }
413
414 /* Retrieves the parent file reference
415 * Returns 1 if successful or -1 on error
416 */
libfsntfs_directory_entry_get_parent_file_reference(libfsntfs_directory_entry_t * directory_entry,uint64_t * parent_file_reference,libcerror_error_t ** error)417 int libfsntfs_directory_entry_get_parent_file_reference(
418 libfsntfs_directory_entry_t *directory_entry,
419 uint64_t *parent_file_reference,
420 libcerror_error_t **error )
421 {
422 static char *function = "libfsntfs_directory_entry_get_parent_file_reference";
423
424 if( directory_entry == NULL )
425 {
426 libcerror_error_set(
427 error,
428 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
429 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
430 "%s: invalid directory entry.",
431 function );
432
433 return( -1 );
434 }
435 if( libfsntfs_file_name_values_get_parent_file_reference(
436 directory_entry->file_name_values,
437 parent_file_reference,
438 error ) != 1 )
439 {
440 libcerror_error_set(
441 error,
442 LIBCERROR_ERROR_DOMAIN_RUNTIME,
443 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
444 "%s: unable to retrieve parent reference from file name values.",
445 function );
446
447 return( -1 );
448 }
449 return( 1 );
450 }
451
452 /* Retrieves the size of the UTF-8 encoded name
453 * The returned size includes the end of string character
454 * Returns 1 if successful or -1 on error
455 */
libfsntfs_directory_entry_get_utf8_name_size(libfsntfs_directory_entry_t * directory_entry,size_t * utf8_string_size,libcerror_error_t ** error)456 int libfsntfs_directory_entry_get_utf8_name_size(
457 libfsntfs_directory_entry_t *directory_entry,
458 size_t *utf8_string_size,
459 libcerror_error_t **error )
460 {
461 static char *function = "libfsntfs_directory_entry_get_utf8_name_size";
462
463 if( directory_entry == NULL )
464 {
465 libcerror_error_set(
466 error,
467 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
468 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
469 "%s: invalid directory entry.",
470 function );
471
472 return( -1 );
473 }
474 if( libfsntfs_file_name_values_get_utf8_name_size(
475 directory_entry->file_name_values,
476 utf8_string_size,
477 error ) != 1 )
478 {
479 libcerror_error_set(
480 error,
481 LIBCERROR_ERROR_DOMAIN_RUNTIME,
482 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
483 "%s: unable to retrieve size of UTF-8 name from file name values.",
484 function );
485
486 return( -1 );
487 }
488 return( 1 );
489 }
490
491 /* Retrieves the UTF-8 encoded name
492 * The size should include the end of string character
493 * Returns 1 if successful or -1 on error
494 */
libfsntfs_directory_entry_get_utf8_name(libfsntfs_directory_entry_t * directory_entry,uint8_t * utf8_string,size_t utf8_string_size,libcerror_error_t ** error)495 int libfsntfs_directory_entry_get_utf8_name(
496 libfsntfs_directory_entry_t *directory_entry,
497 uint8_t *utf8_string,
498 size_t utf8_string_size,
499 libcerror_error_t **error )
500 {
501 static char *function = "libfsntfs_directory_entry_get_utf8_name";
502
503 if( directory_entry == NULL )
504 {
505 libcerror_error_set(
506 error,
507 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
508 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
509 "%s: invalid directory entry.",
510 function );
511
512 return( -1 );
513 }
514 if( libfsntfs_file_name_values_get_utf8_name(
515 directory_entry->file_name_values,
516 utf8_string,
517 utf8_string_size,
518 error ) != 1 )
519 {
520 libcerror_error_set(
521 error,
522 LIBCERROR_ERROR_DOMAIN_RUNTIME,
523 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
524 "%s: unable to retrieve UTF-8 name from file name values.",
525 function );
526
527 return( -1 );
528 }
529 return( 1 );
530 }
531
532 /* Retrieves the size of the UTF-16 encoded name
533 * The returned size includes the end of string character
534 * Returns 1 if successful or -1 on error
535 */
libfsntfs_directory_entry_get_utf16_name_size(libfsntfs_directory_entry_t * directory_entry,size_t * utf16_string_size,libcerror_error_t ** error)536 int libfsntfs_directory_entry_get_utf16_name_size(
537 libfsntfs_directory_entry_t *directory_entry,
538 size_t *utf16_string_size,
539 libcerror_error_t **error )
540 {
541 static char *function = "libfsntfs_directory_entry_get_utf16_name_size";
542
543 if( directory_entry == NULL )
544 {
545 libcerror_error_set(
546 error,
547 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
548 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
549 "%s: invalid directory entry.",
550 function );
551
552 return( -1 );
553 }
554 if( libfsntfs_file_name_values_get_utf16_name_size(
555 directory_entry->file_name_values,
556 utf16_string_size,
557 error ) != 1 )
558 {
559 libcerror_error_set(
560 error,
561 LIBCERROR_ERROR_DOMAIN_RUNTIME,
562 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
563 "%s: unable to retrieve size of UTF-16 name from file name values.",
564 function );
565
566 return( -1 );
567 }
568 return( 1 );
569 }
570
571 /* Retrieves the UTF-16 encoded name
572 * The size should include the end of string character
573 * Returns 1 if successful or -1 on error
574 */
libfsntfs_directory_entry_get_utf16_name(libfsntfs_directory_entry_t * directory_entry,uint16_t * utf16_string,size_t utf16_string_size,libcerror_error_t ** error)575 int libfsntfs_directory_entry_get_utf16_name(
576 libfsntfs_directory_entry_t *directory_entry,
577 uint16_t *utf16_string,
578 size_t utf16_string_size,
579 libcerror_error_t **error )
580 {
581 static char *function = "libfsntfs_directory_entry_get_utf16_name";
582
583 if( directory_entry == NULL )
584 {
585 libcerror_error_set(
586 error,
587 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
588 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
589 "%s: invalid directory entry.",
590 function );
591
592 return( -1 );
593 }
594 if( libfsntfs_file_name_values_get_utf16_name(
595 directory_entry->file_name_values,
596 utf16_string,
597 utf16_string_size,
598 error ) != 1 )
599 {
600 libcerror_error_set(
601 error,
602 LIBCERROR_ERROR_DOMAIN_RUNTIME,
603 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
604 "%s: unable to retrieve UTF-16 name from file name values.",
605 function );
606
607 return( -1 );
608 }
609 return( 1 );
610 }
611
612