1 /*
2  * Debug functions
3  *
4  * Copyright (C) 2020-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 <memory.h>
24 #include <narrow_string.h>
25 #include <system_string.h>
26 #include <types.h>
27 #include <wide_string.h>
28 
29 #include "libfsxfs_debug.h"
30 #include "libfsxfs_definitions.h"
31 #include "libfsxfs_libbfio.h"
32 #include "libfsxfs_libcerror.h"
33 #include "libfsxfs_libcnotify.h"
34 #include "libfsxfs_libfdatetime.h"
35 #include "libfsxfs_libfguid.h"
36 #include "libfsxfs_libuna.h"
37 
38 #if defined( HAVE_DEBUG_OUTPUT )
39 
40 /* Prints the feature flags
41  */
libfsxfs_debug_print_feature_flags(uint16_t feature_flags)42 void libfsxfs_debug_print_feature_flags(
43       uint16_t feature_flags )
44 {
45 	if( ( feature_flags & 0x0010 ) != 0 )
46 	{
47 		libcnotify_printf(
48 		 "\t(XFS_SB_VERSION_ATTRBIT)\n" );
49 	}
50 	if( ( feature_flags & 0x0020 ) != 0 )
51 	{
52 		libcnotify_printf(
53 		 "\t(XFS_SB_VERSION_NLINKBIT)\n" );
54 	}
55 	if( ( feature_flags & 0x0040 ) != 0 )
56 	{
57 		libcnotify_printf(
58 		 "\t(XFS_SB_VERSION_QUOTABIT)\n" );
59 	}
60 	if( ( feature_flags & 0x0080 ) != 0 )
61 	{
62 		libcnotify_printf(
63 		 "\t(XFS_SB_VERSION_ALIGNBIT)\n" );
64 	}
65 	if( ( feature_flags & 0x0100 ) != 0 )
66 	{
67 		libcnotify_printf(
68 		 "\t(XFS_SB_VERSION_DALIGNBIT)\n" );
69 	}
70 	if( ( feature_flags & 0x0200 ) != 0 )
71 	{
72 		libcnotify_printf(
73 		 "\t(XFS_SB_VERSION_SHAREDBIT)\n" );
74 	}
75 	if( ( feature_flags & 0x0400 ) != 0 )
76 	{
77 		libcnotify_printf(
78 		 "\t(XFS_SB_VERSION_LOGV2BIT)\n" );
79 	}
80 	if( ( feature_flags & 0x0800 ) != 0 )
81 	{
82 		libcnotify_printf(
83 		 "\t(XFS_SB_VERSION_SECTORBIT)\n" );
84 	}
85 	if( ( feature_flags & 0x1000 ) != 0 )
86 	{
87 		libcnotify_printf(
88 		 "\t(XFS_SB_VERSION_EXTFLGBIT)\n" );
89 	}
90 	if( ( feature_flags & 0x2000 ) != 0 )
91 	{
92 		libcnotify_printf(
93 		 "\t(XFS_SB_VERSION_DIRV2BIT)\n" );
94 	}
95 	if( ( feature_flags & 0x4000 ) != 0 )
96 	{
97 		libcnotify_printf(
98 		 "\t(XFS_SB_VERSION_BORGBIT)\n" );
99 	}
100 	if( ( feature_flags & 0x8000 ) != 0 )
101 	{
102 		libcnotify_printf(
103 		 "\t(XFS_SB_VERSION_MOREBITSBIT)\n" );
104 	}
105 }
106 
107 /* Prints the secondary feature flags
108  */
libfsxfs_debug_print_secondary_feature_flags(uint32_t secondary_feature_flags)109 void libfsxfs_debug_print_secondary_feature_flags(
110       uint32_t secondary_feature_flags )
111 {
112 	if( ( secondary_feature_flags & 0x00000001UL ) != 0 )
113 	{
114 		libcnotify_printf(
115 		 "\t(XFS_SB_VERSION2_RESERVED1BIT)\n" );
116 	}
117 	if( ( secondary_feature_flags & 0x00000002UL ) != 0 )
118 	{
119 		libcnotify_printf(
120 		 "\t(XFS_SB_VERSION2_LAZYSBCOUNTBIT)\n" );
121 	}
122 	if( ( secondary_feature_flags & 0x00000004UL ) != 0 )
123 	{
124 		libcnotify_printf(
125 		 "\t(XFS_SB_VERSION2_RESERVED4BIT)\n" );
126 	}
127 	if( ( secondary_feature_flags & 0x00000008UL ) != 0 )
128 	{
129 		libcnotify_printf(
130 		 "\t(XFS_SB_VERSION2_ATTR2BIT)\n" );
131 	}
132 	if( ( secondary_feature_flags & 0x00000010UL ) != 0 )
133 	{
134 		libcnotify_printf(
135 		 "\t(XFS_SB_VERSION2_PARENTBIT)\n" );
136 	}
137 
138 	if( ( secondary_feature_flags & 0x00000080UL ) != 0 )
139 	{
140 		libcnotify_printf(
141 		 "\t(XFS_SB_VERSION2_PROJID32BIT)\n" );
142 	}
143 	if( ( secondary_feature_flags & 0x00000100UL ) != 0 )
144 	{
145 		libcnotify_printf(
146 		 "\t(XFS_SB_VERSION2_CRCBIT)\n" );
147 	}
148 	if( ( secondary_feature_flags & 0x00000200UL ) != 0 )
149 	{
150 		libcnotify_printf(
151 		 "\t(XFS_SB_VERSION2_FTYPE)\n" );
152 	}
153 }
154 
155 /* Prints the file mode
156  */
libfsxfs_debug_print_file_mode(uint16_t file_mode)157 void libfsxfs_debug_print_file_mode(
158       uint16_t file_mode )
159 {
160 	if( ( file_mode & 0x0007 ) != 0 )
161 	{
162 		libcnotify_printf(
163 		 "\tAccess other: " );
164 
165 		if( ( file_mode & 0x0004 ) != 0 )
166 		{
167 			libcnotify_printf(
168 			 "R" );
169 		}
170 		if( ( file_mode & 0x0002 ) != 0 )
171 		{
172 			libcnotify_printf(
173 			 "W" );
174 		}
175 		if( ( file_mode & 0x0001 ) != 0 )
176 		{
177 			libcnotify_printf(
178 			 "X" );
179 		}
180 		libcnotify_printf(
181 		 "\n" );
182 	}
183 	if( ( file_mode & 0x0038 ) != 0 )
184 	{
185 		libcnotify_printf(
186 		 "\tAccess group: " );
187 
188 		if( ( file_mode & 0x0020 ) != 0 )
189 		{
190 			libcnotify_printf(
191 			 "R" );
192 		}
193 		if( ( file_mode & 0x0010 ) != 0 )
194 		{
195 			libcnotify_printf(
196 			 "W" );
197 		}
198 		if( ( file_mode & 0x0008 ) != 0 )
199 		{
200 			libcnotify_printf(
201 			 "X" );
202 		}
203 		libcnotify_printf(
204 		 "\n" );
205 	}
206 	if( ( file_mode & 0x01c0 ) != 0 )
207 	{
208 		libcnotify_printf(
209 		 "\tAccess user: " );
210 
211 		if( ( file_mode & 0x0100 ) != 0 )
212 		{
213 			libcnotify_printf(
214 			 "R" );
215 		}
216 		if( ( file_mode & 0x0080 ) != 0 )
217 		{
218 			libcnotify_printf(
219 			 "W" );
220 		}
221 		if( ( file_mode & 0x0040 ) != 0 )
222 		{
223 			libcnotify_printf(
224 			 "X" );
225 		}
226 		libcnotify_printf(
227 		 "\n" );
228 	}
229 	if( ( file_mode & 0x0200 ) != 0 )
230 	{
231 		libcnotify_printf(
232 		 "\tSticky bit (S_ISTXT)" );
233 	}
234 	if( ( file_mode & 0x0400 ) != 0 )
235 	{
236 		libcnotify_printf(
237 		 "\tSet group identifer (GID) on execution (S_ISGID)\n" );
238 	}
239 	if( ( file_mode & 0x0800 ) != 0 )
240 	{
241 		libcnotify_printf(
242 		 "\tSet user identifer (UID) on execution (S_ISUID)\n" );
243 	}
244 	switch( file_mode & 0xf000 )
245 	{
246 		case 0x1000:
247 			libcnotify_printf(
248 			 "\tNamed pipe (FIFO) (S_IFIFO)\n" );
249 			break;
250 
251 		case 0x2000:
252 			libcnotify_printf(
253 			 "\tCharacter device (S_IFCHR)\n" );
254 			break;
255 
256 		case 0x4000:
257 			libcnotify_printf(
258 			 "\tDirectory (S_IFDIR)\n" );
259 			break;
260 
261 		case 0x6000:
262 			libcnotify_printf(
263 			 "\tBlock device (S_IFBLK)\n" );
264 			break;
265 
266 		case 0x8000:
267 			libcnotify_printf(
268 			 "\tRegular file (S_IFREG)\n" );
269 			break;
270 
271 		case 0xa000:
272 			libcnotify_printf(
273 			 "\tSymbolic link (S_IFLNK)\n" );
274 			break;
275 
276 		case 0xc000:
277 			libcnotify_printf(
278 			 "\tSocket (S_IFSOCK)\n" );
279 			break;
280 
281 		default:
282 			break;
283 	}
284 	libcnotify_printf(
285 	 "\n" );
286 }
287 
288 /* Prints the fork type
289  */
libfsxfs_debug_print_fork_type(uint8_t fork_type)290 const char *libfsxfs_debug_print_fork_type(
291              uint8_t fork_type )
292 {
293 	switch( fork_type )
294 	{
295 		case 0:
296 			return( "XFS_DINODE_FMT_DEV" );
297 
298 		case 1:
299 			return( "XFS_DINODE_FMT_LOCAL" );
300 
301 		case 2:
302 			return( "XFS_DINODE_FMT_EXTENTS" );
303 
304 		case 3:
305 			return( "XFS_DINODE_FMT_BTREE" );
306 
307 		case 4:
308 			return( "XFS_DINODE_FMT_UUID" );
309 
310 		case 5:
311 			return( "XFS_DINODE_FMT_RMAP" );
312 	}
313 	return( "Unknown" );
314 }
315 
316 /* Prints a POSIX value
317  * Returns 1 if successful or -1 on error
318  */
libfsxfs_debug_print_posix_time_value(const char * function_name,const char * value_name,const uint8_t * byte_stream,size_t byte_stream_size,int byte_order,uint8_t value_type,uint32_t string_format_flags,libcerror_error_t ** error)319 int libfsxfs_debug_print_posix_time_value(
320      const char *function_name,
321      const char *value_name,
322      const uint8_t *byte_stream,
323      size_t byte_stream_size,
324      int byte_order,
325      uint8_t value_type,
326      uint32_t string_format_flags,
327      libcerror_error_t **error )
328 {
329 	char date_time_string[ 32 ];
330 
331 	libfdatetime_posix_time_t *posix_time = NULL;
332 	static char *function                 = "libfsxfs_debug_print_posix_time_value";
333 
334 	if( libfdatetime_posix_time_initialize(
335 	     &posix_time,
336 	     error ) != 1 )
337 	{
338 		libcerror_error_set(
339 		 error,
340 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
341 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
342 		 "%s: unable to create posix time.",
343 		 function );
344 
345 		goto on_error;
346 	}
347 	if( libfdatetime_posix_time_copy_from_byte_stream(
348 	     posix_time,
349 	     byte_stream,
350 	     byte_stream_size,
351 	     byte_order,
352 	     value_type,
353 	     error ) != 1 )
354 	{
355 		libcerror_error_set(
356 		 error,
357 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
358 		 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
359 		 "%s: unable to copy byte stream to posix time.",
360 		 function );
361 
362 		goto on_error;
363 	}
364 	if( libfdatetime_posix_time_copy_to_utf8_string(
365 	     posix_time,
366 	     (uint8_t *) date_time_string,
367 	     32,
368 	     string_format_flags,
369 	     error ) != 1 )
370 	{
371 		libcerror_error_set(
372 		 error,
373 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
374 		 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
375 		 "%s: unable to copy posix_time to string.",
376 		 function );
377 
378 		goto on_error;
379 	}
380 	libcnotify_printf(
381 	 "%s: %s: %s UTC\n",
382 	 function_name,
383 	 value_name,
384 	 date_time_string );
385 
386 	if( libfdatetime_posix_time_free(
387 	     &posix_time,
388 	     error ) != 1 )
389 	{
390 		libcerror_error_set(
391 		 error,
392 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
393 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
394 		 "%s: unable to free posix time.",
395 		 function );
396 
397 		goto on_error;
398 	}
399 	return( 1 );
400 
401 on_error:
402 	if( posix_time != NULL )
403 	{
404 		libfdatetime_posix_time_free(
405 		 &posix_time,
406 		 NULL );
407 	}
408 	return( -1 );
409 }
410 
411 /* Prints a GUID/UUID value
412  * Returns 1 if successful or -1 on error
413  */
libfsxfs_debug_print_guid_value(const char * function_name,const char * value_name,const uint8_t * byte_stream,size_t byte_stream_size,int byte_order,uint32_t string_format_flags,libcerror_error_t ** error)414 int libfsxfs_debug_print_guid_value(
415      const char *function_name,
416      const char *value_name,
417      const uint8_t *byte_stream,
418      size_t byte_stream_size,
419      int byte_order,
420      uint32_t string_format_flags,
421      libcerror_error_t **error )
422 {
423         system_character_t guid_string[ 48 ];
424 
425         libfguid_identifier_t *guid = NULL;
426 	static char *function       = "libfsxfs_debug_print_guid_value";
427 
428 	if( libfguid_identifier_initialize(
429 	     &guid,
430 	     error ) != 1 )
431 	{
432 		libcerror_error_set(
433 		 error,
434 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
435 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
436 		 "%s: unable to create GUID.",
437 		 function );
438 
439 		goto on_error;
440 	}
441 	if( libfguid_identifier_copy_from_byte_stream(
442 	     guid,
443 	     byte_stream,
444 	     byte_stream_size,
445 	     byte_order,
446 	     error ) != 1 )
447 	{
448 		libcerror_error_set(
449 		 error,
450 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
451 		 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
452 		 "%s: unable to copy byte stream to GUID.",
453 		 function );
454 
455 		goto on_error;
456 	}
457 	if( libfguid_identifier_copy_to_utf8_string(
458 	     guid,
459 	     (uint8_t *) guid_string,
460 	     48,
461 	     string_format_flags,
462 	     error ) != 1 )
463 	{
464 		libcerror_error_set(
465 		 error,
466 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
467 		 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
468 		 "%s: unable to copy GUID to string.",
469 		 function );
470 
471 		goto on_error;
472 	}
473 	libcnotify_printf(
474 	 "%s: %s: %s\n",
475 	 function_name,
476 	 value_name,
477 	 guid_string );
478 
479 	if( libfguid_identifier_free(
480 	     &guid,
481 	     error ) != 1 )
482 	{
483 		libcerror_error_set(
484 		 error,
485 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
486 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
487 		 "%s: unable to free GUID.",
488 		 function );
489 
490 		goto on_error;
491 	}
492 	return( 1 );
493 
494 on_error:
495 	if( guid != NULL )
496 	{
497 		libfguid_identifier_free(
498 		 &guid,
499 		 NULL );
500 	}
501 	return( -1 );
502 }
503 
504 /* Prints an UTF-8 string value
505  * Returns 1 if successful or -1 on error
506  */
libfsxfs_debug_print_utf8_string_value(const char * function_name,const char * value_name,const uint8_t * byte_stream,size_t byte_stream_size,libcerror_error_t ** error)507 int libfsxfs_debug_print_utf8_string_value(
508      const char *function_name,
509      const char *value_name,
510      const uint8_t *byte_stream,
511      size_t byte_stream_size,
512      libcerror_error_t **error )
513 {
514 	system_character_t *string = NULL;
515 	static char *function      = "libfsxfs_debug_print_utf8_string_value";
516 	size_t string_size         = 0;
517 	int result                 = 0;
518 
519 	if( ( byte_stream == NULL )
520 	 || ( byte_stream_size == 0 ) )
521 	{
522 		libcnotify_printf(
523 		 "%s: %s: \n",
524 		 function_name,
525 		 value_name );
526 
527 		return( 1 );
528 	}
529 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
530 	result = libuna_utf16_string_size_from_utf8_stream(
531 		  byte_stream,
532 		  byte_stream_size,
533 		  &string_size,
534 		  error );
535 #else
536 	result = libuna_utf8_string_size_from_utf8_stream(
537 		  byte_stream,
538 		  byte_stream_size,
539 		  &string_size,
540 		  error );
541 #endif
542 	if( result != 1 )
543 	{
544 		libcerror_error_set(
545 		 error,
546 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
547 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
548 		 "%s: unable to determine size of string.",
549 		 function );
550 
551 		goto on_error;
552 	}
553 	if( string_size > (size_t) ( SSIZE_MAX / sizeof( system_character_t ) ) )
554 	{
555 		libcerror_error_set(
556 		 error,
557 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
558 		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
559 		 "%s: invalid string size value exceeds maximum.",
560 		 function );
561 
562 		goto on_error;
563 	}
564 	string = system_string_allocate(
565 	          string_size );
566 
567 	if( string == NULL )
568 	{
569 		libcerror_error_set(
570 		 error,
571 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
572 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
573 		 "%s: unable to create string.",
574 		 function );
575 
576 		goto on_error;
577 	}
578 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
579 	result = libuna_utf16_string_copy_from_utf8_stream(
580 		  (libuna_utf16_character_t *) string,
581 		  string_size,
582 		  byte_stream,
583 		  byte_stream_size,
584 		  error );
585 #else
586 	result = libuna_utf8_string_copy_from_utf8_stream(
587 		  (libuna_utf8_character_t *) string,
588 		  string_size,
589 		  byte_stream,
590 		  byte_stream_size,
591 		  error );
592 #endif
593 	if( result != 1 )
594 	{
595 		libcerror_error_set(
596 		 error,
597 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
598 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
599 		 "%s: unable to set string.",
600 		 function );
601 
602 		goto on_error;
603 	}
604 	libcnotify_printf(
605 	 "%s: %s: %" PRIs_SYSTEM "\n",
606 	 function_name,
607 	 value_name,
608 	 string );
609 
610 	memory_free(
611 	 string );
612 
613 	return( 1 );
614 
615 on_error:
616 	if( string != NULL )
617 	{
618 		memory_free(
619 		 string );
620 	}
621 	return( -1 );
622 }
623 
624 /* Prints the read offsets
625  * Returns 1 if successful or -1 on error
626  */
libfsxfs_debug_print_read_offsets(libbfio_handle_t * file_io_handle,libcerror_error_t ** error)627 int libfsxfs_debug_print_read_offsets(
628      libbfio_handle_t *file_io_handle,
629      libcerror_error_t **error )
630 {
631 	static char *function = "libfsxfs_debug_print_read_offsets";
632 	off64_t offset        = 0;
633 	size64_t size         = 0;
634 	int number_of_offsets = 0;
635 	int offset_iterator   = 0;
636 
637 	if( file_io_handle == NULL )
638 	{
639 		libcerror_error_set(
640 		 error,
641 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
642 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
643 		 "%s: invalid file IO handle.",
644 		 function );
645 
646 		return( -1 );
647 	}
648 	if( libbfio_handle_get_number_of_offsets_read(
649 	     file_io_handle,
650 	     &number_of_offsets,
651 	     error ) != 1 )
652 	{
653 		libcerror_error_set(
654 		 error,
655 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
656 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
657 		 "%s: unable to retrieve number of offsets read.",
658 		 function );
659 
660 		return( -1 );
661 	}
662 	libcnotify_printf(
663 	 "Offsets read:\n" );
664 
665 	for( offset_iterator = 0;
666 	     offset_iterator < number_of_offsets;
667 	     offset_iterator++ )
668 	{
669 		if( libbfio_handle_get_offset_read(
670 		     file_io_handle,
671 		     offset_iterator,
672 		     &offset,
673 		     &size,
674 		     error ) != 1 )
675 		{
676 			libcerror_error_set(
677 			 error,
678 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
679 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
680 			 "%s: unable to retrieve offset: %d.",
681 			 function,
682 			 ( offset_iterator + 1 ) );
683 
684 			return( -1 );
685 		}
686 		libcnotify_printf(
687 		 "%08" PRIi64 " ( 0x%08" PRIx64 " ) - %08" PRIi64 " ( 0x%08" PRIx64 " ) size: %" PRIu64 "\n",
688 		 offset,
689 		 offset,
690 		 offset + (off64_t) size,
691 		 offset + (off64_t) size,
692 		 size );
693 	}
694 	libcnotify_printf(
695 	 "\n" );
696 
697 	return( 1 );
698 }
699 
700 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
701 
702