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