1 /*
2  * Path functions
3  *
4  * Copyright (C) 2008-2020, 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 <types.h>
26 #include <wide_string.h>
27 
28 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
29 #include <system_string.h>
30 #endif
31 
32 #if defined( HAVE_ERRNO_H )
33 #include <errno.h>
34 #endif
35 
36 #if defined( HAVE_SYS_STAT_H )
37 #include <sys/stat.h>
38 #endif
39 
40 #if defined( HAVE_LIMITS_H ) || defined( WINAPI )
41 /* Include for PATH_MAX */
42 #include <limits.h>
43 #endif
44 
45 #if defined( HAVE_UNISTD_H )
46 #include <unistd.h>
47 #endif
48 
49 #include "libcpath_definitions.h"
50 #include "libcpath_libcerror.h"
51 #include "libcpath_libcsplit.h"
52 #include "libcpath_path.h"
53 #include "libcpath_system_string.h"
54 
55 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
56 
57 /* Cross Windows safe version of CloseHandle
58  * Returns TRUE if successful or FALSE on error
59  */
libcpath_CloseHandle(HANDLE file_handle)60 BOOL libcpath_CloseHandle(
61       HANDLE file_handle )
62 {
63 	FARPROC function       = NULL;
64 	HMODULE library_handle = NULL;
65 	BOOL result            = FALSE;
66 
67 	if( file_handle == NULL )
68 	{
69 		return( FALSE );
70 	}
71 	library_handle = LoadLibrary(
72 	                  _SYSTEM_STRING( "kernel32.dll" ) );
73 
74 	if( library_handle == NULL )
75 	{
76 		return( FALSE );
77 	}
78 	function = GetProcAddress(
79 		    library_handle,
80 		    (LPCSTR) "CloseHandle" );
81 
82 	if( function != NULL )
83 	{
84 		result = function(
85 			  file_handle );
86 	}
87 	/* This call should be after using the function
88 	 * in most cases kernel32.dll will still be available after free
89 	 */
90 	if( FreeLibrary(
91 	     library_handle ) != TRUE )
92 	{
93 		result = FALSE;
94 	}
95 	return( result );
96 }
97 
98 #endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
99 
100 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
101 
102 /* Cross Windows safe version of SetCurrentDirectoryA
103  * Returns TRUE if successful or FALSE on error
104  */
libcpath_SetCurrentDirectoryA(LPCSTR path)105 BOOL libcpath_SetCurrentDirectoryA(
106       LPCSTR path )
107 {
108 	FARPROC function       = NULL;
109 	HMODULE library_handle = NULL;
110 	BOOL result            = FALSE;
111 
112 	if( path == NULL )
113 	{
114 		return( FALSE );
115 	}
116 	library_handle = LoadLibrary(
117 	                  _SYSTEM_STRING( "kernel32.dll" ) );
118 
119 	if( library_handle == NULL )
120 	{
121 		return( FALSE );
122 	}
123 	function = GetProcAddress(
124 		    library_handle,
125 		    (LPCSTR) "SetCurrentDirectoryA" );
126 
127 	if( function != NULL )
128 	{
129 		result = function(
130 			  path );
131 	}
132 	/* This call should be after using the function
133 	 * in most cases kernel32.dll will still be available after free
134 	 */
135 	if( FreeLibrary(
136 	     library_handle ) != TRUE )
137 	{
138 		libcpath_CloseHandle(
139 		 library_handle );
140 
141 		return( FALSE );
142 	}
143 	return( result );
144 }
145 
146 #endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
147 
148 #if defined( WINAPI )
149 
150 /* Changes the directory
151  * This function uses the WINAPI function for Windows XP (0x0501) or later
152  * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
153  * Returns 1 if successful or -1 on error
154  */
libcpath_path_change_directory(const char * directory_name,libcerror_error_t ** error)155 int libcpath_path_change_directory(
156      const char *directory_name,
157      libcerror_error_t **error )
158 {
159 	static char *function = "libcpath_path_change_directory";
160 	DWORD error_code      = 0;
161 
162 	if( directory_name == NULL )
163 	{
164 		libcerror_error_set(
165 		 error,
166 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
167 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
168 		 "%s: invalid directory name.",
169 		 function );
170 
171 		return( -1 );
172 	}
173 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
174 	if( libcpath_SetCurrentDirectoryA(
175 	     directory_name ) == 0 )
176 #else
177 	if( SetCurrentDirectoryA(
178 	     directory_name ) == 0 )
179 #endif
180 	{
181 		error_code = GetLastError();
182 
183 		libcerror_system_set_error(
184 		 error,
185 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
186 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
187 		 error_code,
188 		 "%s: unable to change directory.",
189 		 function );
190 
191 		return( -1 );
192 	}
193 	return( 1 );
194 }
195 
196 #elif defined( HAVE_CHDIR )
197 
198 /* Changes the directory
199  * This function uses the POSIX chdir function or equivalent
200  * Returns 1 if successful or -1 on error
201  */
libcpath_path_change_directory(const char * directory_name,libcerror_error_t ** error)202 int libcpath_path_change_directory(
203      const char *directory_name,
204      libcerror_error_t **error )
205 {
206 	static char *function = "libcpath_path_change_directory";
207 
208 	if( directory_name == NULL )
209 	{
210 		libcerror_error_set(
211 		 error,
212 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
213 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
214 		 "%s: invalid directory name.",
215 		 function );
216 
217 		return( -1 );
218 	}
219 	if( chdir(
220 	     directory_name ) != 0 )
221 	{
222 		libcerror_system_set_error(
223 		 error,
224 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
225 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
226 		 errno,
227 		 "%s: unable to change directory.",
228 		 function );
229 
230 		return( -1 );
231 	}
232 	return( 1 );
233 }
234 
235 #else
236 #error Missing change directory function
237 #endif
238 
239 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
240 
241 /* Cross Windows safe version of GetCurrentDirectoryA
242  * Returns the number of characters in the current directory string or 0 on error
243  */
libcpath_GetCurrentDirectoryA(DWORD buffer_size,LPCSTR buffer)244 DWORD libcpath_GetCurrentDirectoryA(
245        DWORD buffer_size,
246        LPCSTR buffer )
247 {
248 	FARPROC function       = NULL;
249 	HMODULE library_handle = NULL;
250 	DWORD result           = 0;
251 
252 	library_handle = LoadLibrary(
253 	                  _SYSTEM_STRING( "kernel32.dll" ) );
254 
255 	if( library_handle == NULL )
256 	{
257 		return( 0 );
258 	}
259 	function = GetProcAddress(
260 		    library_handle,
261 		    (LPCSTR) "GetCurrentDirectoryA" );
262 
263 	if( function != NULL )
264 	{
265 		result = function(
266 			  buffer_size,
267 			  buffer );
268 	}
269 	/* This call should be after using the function
270 	 * in most cases kernel32.dll will still be available after free
271 	 */
272 	if( FreeLibrary(
273 	     library_handle ) != TRUE )
274 	{
275 		libcpath_CloseHandle(
276 		 library_handle );
277 
278 		return( 0 );
279 	}
280 	return( result );
281 }
282 
283 #endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
284 
285 #if defined( WINAPI )
286 
287 /* Retrieves the current working directory
288  * This function uses the WINAPI function for Windows XP (0x0501) or later
289  * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
290  * Returns 1 if successful or -1 on error
291  */
libcpath_path_get_current_working_directory(char ** current_working_directory,size_t * current_working_directory_size,libcerror_error_t ** error)292 int libcpath_path_get_current_working_directory(
293      char **current_working_directory,
294      size_t *current_working_directory_size,
295      libcerror_error_t **error )
296 {
297 	static char *function                     = "libcpath_path_get_current_working_directory";
298 	DWORD safe_current_working_directory_size = 0;
299 	DWORD error_code                          = 0;
300 
301 	if( current_working_directory == NULL )
302 	{
303 		libcerror_error_set(
304 		 error,
305 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
306 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
307 		 "%s: invalid current working directory.",
308 		 function );
309 
310 		return( -1 );
311 	}
312 	if( *current_working_directory != NULL )
313 	{
314 		libcerror_error_set(
315 		 error,
316 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
317 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
318 		 "%s: invalid current working directory value already set.",
319 		 function );
320 
321 		return( -1 );
322 	}
323 	if( current_working_directory_size == NULL )
324 	{
325 		libcerror_error_set(
326 		 error,
327 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
328 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
329 		 "%s: invalid current working directory size.",
330 		 function );
331 
332 		return( -1 );
333 	}
334 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
335 	safe_current_working_directory_size = libcpath_GetCurrentDirectoryA(
336 	                                       0,
337 	                                       NULL );
338 #else
339 	safe_current_working_directory_size = GetCurrentDirectoryA(
340 	                                       0,
341 	                                       NULL );
342 #endif
343 	if( safe_current_working_directory_size == 0 )
344 	{
345 		libcerror_error_set(
346 		 error,
347 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
348 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
349 		 "%s: unable to retrieve current working directory size.",
350 		 function );
351 
352 		goto on_error;
353 	}
354 	if( (size_t) safe_current_working_directory_size > (size_t) SSIZE_MAX )
355 	{
356 		libcerror_error_set(
357 		 error,
358 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
359 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
360 		 "%s: current working directory size value out of bounds.",
361 		 function );
362 
363 		goto on_error;
364 	}
365 	*current_working_directory_size = (size_t) safe_current_working_directory_size;
366 
367 	*current_working_directory = narrow_string_allocate(
368 	                              *current_working_directory_size );
369 
370 	if( *current_working_directory == NULL )
371 	{
372 		libcerror_error_set(
373 		 error,
374 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
375 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
376 		 "%s: unable to create current working directory.",
377 		 function );
378 
379 		goto on_error;
380 	}
381 	if( memory_set(
382 	     *current_working_directory,
383 	     0,
384 	     sizeof( char ) * *current_working_directory_size ) == NULL )
385 	{
386 		libcerror_error_set(
387 		 error,
388 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
389 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
390 		 "%s: unable to clear current working directory.",
391 		 function );
392 
393 		goto on_error;
394 	}
395 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
396 	if( libcpath_GetCurrentDirectoryA(
397 	     safe_current_working_directory_size,
398 	     *current_working_directory ) != ( safe_current_working_directory_size - 1 ) )
399 #else
400 	if( GetCurrentDirectoryA(
401 	     safe_current_working_directory_size,
402 	     *current_working_directory ) != ( safe_current_working_directory_size - 1 ) )
403 #endif
404 	{
405 		error_code = GetLastError();
406 
407 		libcerror_system_set_error(
408 		 error,
409 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
410 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
411 		 error_code,
412 		 "%s: unable to retrieve current working directory.",
413 		 function );
414 
415 		goto on_error;
416 	}
417 	return( 1 );
418 
419 on_error:
420 	if( *current_working_directory != NULL )
421 	{
422 		memory_free(
423 		 *current_working_directory );
424 
425 		*current_working_directory = NULL;
426 	}
427 	*current_working_directory_size = 0;
428 
429 	return( -1 );
430 }
431 
432 #elif defined( HAVE_GETCWD )
433 
434 /* Retrieves the current working directory
435  * This function uses the POSIX getcwd function or equivalent
436  * Returns 1 if successful or -1 on error
437  */
libcpath_path_get_current_working_directory(char ** current_working_directory,size_t * current_working_directory_size,libcerror_error_t ** error)438 int libcpath_path_get_current_working_directory(
439      char **current_working_directory,
440      size_t *current_working_directory_size,
441      libcerror_error_t **error )
442 {
443 	static char *function = "libcpath_path_get_current_working_directory";
444 
445 	if( current_working_directory == NULL )
446 	{
447 		libcerror_error_set(
448 		 error,
449 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
450 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
451 		 "%s: invalid current working directory.",
452 		 function );
453 
454 		return( -1 );
455 	}
456 	if( *current_working_directory != NULL )
457 	{
458 		libcerror_error_set(
459 		 error,
460 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
461 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
462 		 "%s: invalid current working directory value already set.",
463 		 function );
464 
465 		return( -1 );
466 	}
467 	if( current_working_directory_size == NULL )
468 	{
469 		libcerror_error_set(
470 		 error,
471 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
472 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
473 		 "%s: invalid current working directory size.",
474 		 function );
475 
476 		return( -1 );
477 	}
478 	*current_working_directory_size = (size_t) PATH_MAX;
479 
480 	*current_working_directory = narrow_string_allocate(
481 	                              *current_working_directory_size );
482 
483 	if( *current_working_directory == NULL )
484 	{
485 		libcerror_error_set(
486 		 error,
487 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
488 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
489 		 "%s: unable to create current working directory.",
490 		 function );
491 
492 		goto on_error;
493 	}
494 	if( memory_set(
495 	     *current_working_directory,
496 	     0,
497 	     sizeof( char ) * *current_working_directory_size ) == NULL )
498 	{
499 		libcerror_error_set(
500 		 error,
501 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
502 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
503 		 "%s: unable to clear current working directory.",
504 		 function );
505 
506 		goto on_error;
507 	}
508 	if( getcwd(
509 	     *current_working_directory,
510 	     *current_working_directory_size ) == NULL )
511 	{
512 		libcerror_system_set_error(
513 		 error,
514 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
515 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
516 		 errno,
517 		 "%s: unable to retrieve current working directory.",
518 		 function );
519 
520 		goto on_error;
521 	}
522 	return( 1 );
523 
524 on_error:
525 	if( *current_working_directory != NULL )
526 	{
527 		memory_free(
528 		 *current_working_directory );
529 
530 		*current_working_directory = NULL;
531 	}
532 	*current_working_directory_size = 0;
533 
534 	return( -1 );
535 }
536 
537 #else
538 #error Missing get current working directory function
539 #endif
540 
541 #if defined( WINAPI )
542 
543 /* Determines the path type
544  * Returns 1 if succesful or -1 on error
545  */
libcpath_path_get_path_type(const char * path,size_t path_length,uint8_t * path_type,libcerror_error_t ** error)546 int libcpath_path_get_path_type(
547      const char *path,
548      size_t path_length,
549      uint8_t *path_type,
550      libcerror_error_t **error )
551 {
552 	static char *function = "libcpath_path_get_path_type";
553 
554 	if( path == NULL )
555 	{
556 		libcerror_error_set(
557 		 error,
558 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
559 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
560 		 "%s: invalid path.",
561 		 function );
562 
563 		return( -1 );
564 	}
565 	if( path_length == 0 )
566 	{
567 		libcerror_error_set(
568 		 error,
569 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
570 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
571 		 "%s: invalid path length is zero.",
572 		 function );
573 
574 		return( -1 );
575 	}
576 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
577 	{
578 		libcerror_error_set(
579 		 error,
580 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
581 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
582 		 "%s: invalid path length value exceeds maximum.",
583 		 function );
584 
585 		return( -1 );
586 	}
587 	if( path_type == NULL )
588 	{
589 		libcerror_error_set(
590 		 error,
591 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
592 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
593 		 "%s: invalid path type.",
594 		 function );
595 
596 		return( -1 );
597 	}
598 	*path_type = LIBCPATH_TYPE_RELATIVE;
599 
600 	/* Determine if the path is a special path
601 	 * device path prefix:          \\.\
602 	 * extended-length path prefix: \\?\
603 	 */
604 	if( ( path_length >= 4 )
605 	 && ( path[ 0 ] == '\\' )
606 	 && ( path[ 1 ] == '\\' )
607 	 && ( ( path[ 2 ] == '.' )
608 	  ||  ( path[ 2 ] == '?' ) )
609 	 && ( path[ 3 ] == '\\' ) )
610 	{
611 		if( path[ 2 ] == '.' )
612 		{
613 			*path_type = LIBCPATH_TYPE_DEVICE;
614 		}
615 		/* Determine if the path in an extended-length UNC path
616 		 * \\?\UNC\server\share
617 		 */
618 		else if( ( path_length >= 8 )
619 		      && ( path[ 4 ] == 'U' )
620 		      && ( path[ 5 ] == 'N' )
621 		      && ( path[ 6 ] == 'C' )
622 		      && ( path[ 7 ] == '\\' ) )
623 		{
624 			*path_type = LIBCPATH_TYPE_EXTENDED_LENGTH_UNC;
625 		}
626 		else
627 		{
628 			*path_type = LIBCPATH_TYPE_EXTENDED_LENGTH;
629 		}
630 	}
631 	/* Determine if the path is an UNC path
632 	 * \\server\share
633 	 */
634 	else if( ( path_length >= 2 )
635 	      && ( path[ 0 ] == '\\' )
636 	      && ( path[ 1 ] == '\\' ) )
637 	{
638 		*path_type = LIBCPATH_TYPE_UNC;
639 	}
640 	else if( path[ 0 ] == '\\' )
641 	{
642 		*path_type = LIBCPATH_TYPE_ABSOLUTE;
643 	}
644 	else if( ( path_length >= 3 )
645 	      && ( path[ 1 ] == ':' )
646 	      && ( path[ 2 ] == '\\' )
647 	      && ( ( ( path[ 0 ] >= 'A' )
648 	        &&   ( path[ 0 ] <= 'Z' ) )
649 	       ||  ( ( path[ 0 ] >= 'a' )
650 	        &&   ( path[ 0 ] <= 'z' ) ) ) )
651 	{
652 		*path_type = LIBCPATH_TYPE_ABSOLUTE;
653 	}
654 	return( 1 );
655 }
656 
657 /* Determines the volume name
658  * Returns 1 if succesful or -1 on error
659  */
libcpath_path_get_volume_name(const char * path,size_t path_length,char ** volume_name,size_t * volume_name_length,size_t * directory_name_index,libcerror_error_t ** error)660 int libcpath_path_get_volume_name(
661      const char *path,
662      size_t path_length,
663      char **volume_name,
664      size_t *volume_name_length,
665      size_t *directory_name_index,
666      libcerror_error_t **error )
667 {
668 	static char *function    = "libcpath_path_get_volume_name";
669 	size_t path_index        = 0;
670 	size_t share_name_index  = 0;
671 	size_t volume_name_index = 0;
672 
673 	if( path == NULL )
674 	{
675 		libcerror_error_set(
676 		 error,
677 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
678 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
679 		 "%s: invalid path.",
680 		 function );
681 
682 		return( -1 );
683 	}
684 	if( path_length == 0 )
685 	{
686 		libcerror_error_set(
687 		 error,
688 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
689 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
690 		 "%s: invalid path length is zero.",
691 		 function );
692 
693 		return( -1 );
694 	}
695 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
696 	{
697 		libcerror_error_set(
698 		 error,
699 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
700 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
701 		 "%s: invalid path length value exceeds maximum.",
702 		 function );
703 
704 		return( -1 );
705 	}
706 	if( volume_name == NULL )
707 	{
708 		libcerror_error_set(
709 		 error,
710 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
711 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
712 		 "%s: invalid volume name.",
713 		 function );
714 
715 		return( -1 );
716 	}
717 	if( volume_name_length == NULL )
718 	{
719 		libcerror_error_set(
720 		 error,
721 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
722 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
723 		 "%s: invalid volume name length.",
724 		 function );
725 
726 		return( -1 );
727 	}
728 	if( directory_name_index == NULL )
729 	{
730 		libcerror_error_set(
731 		 error,
732 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
733 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
734 		 "%s: invalid directory name index.",
735 		 function );
736 
737 		return( -1 );
738 	}
739 	*volume_name          = NULL;
740 	*volume_name_length   = 0;
741 	*directory_name_index = 0;
742 
743 	/* Determine if the path is a special path
744 	 * device path prefix:          \\.\
745 	 * extended-length path prefix: \\?\
746 	 */
747 	if( ( path_length >= 4 )
748 	 && ( path[ 0 ] == '\\' )
749 	 && ( path[ 1 ] == '\\' )
750 	 && ( ( path[ 2 ] == '.' )
751 	  ||  ( path[ 2 ] == '?' ) )
752 	 && ( path[ 3 ] == '\\' ) )
753 	{
754 		if( path[ 2 ] == '.' )
755 		{
756 			volume_name_index = 4;
757 		}
758 		/* Determine if the path in an extended-length UNC path
759 		 * \\?\UNC\server\share
760 		 */
761 		else if( ( path_length >= 8 )
762 		      && ( path[ 4 ] == 'U' )
763 		      && ( path[ 5 ] == 'N' )
764 		      && ( path[ 6 ] == 'C' )
765 		      && ( path[ 7 ] == '\\' ) )
766 		{
767 			volume_name_index = 8;
768 		}
769 		else
770 		{
771 			volume_name_index = 4;
772 		}
773 	}
774 	/* Determine if the path is an UNC path
775 	 * \\server\share
776 	 */
777 	else if( ( path_length >= 2 )
778 	      && ( path[ 0 ] == '\\' )
779 	      && ( path[ 1 ] == '\\' ) )
780 	{
781 		volume_name_index = 2;
782 	}
783 	/* Check if the path contains a volume letter
784 	 */
785 	if( ( path_length >= 2 )
786 	 && ( volume_name_index <= ( path_length - 2 ) )
787 	 && ( path[ volume_name_index + 1 ] == ':' )
788 	 && ( ( ( path[ volume_name_index ] >= 'A' )
789 	   &&   ( path[ volume_name_index ] <= 'Z' ) )
790 	  ||  ( ( path[ volume_name_index ] >= 'a' )
791 	   &&   ( path[ volume_name_index ] <= 'z' ) ) ) )
792 	{
793 		path_index = volume_name_index + 2;
794 
795 		if( ( path_index < path_length )
796 		 && ( path[ path_index ] == '\\' ) )
797 		{
798 			path_index++;
799 		}
800 		*volume_name        = (char *) &( path[ volume_name_index ] );
801 		*volume_name_length = path_index - volume_name_index;
802 
803 		if( path[ path_index - 1 ] == '\\' )
804 		{
805 			*volume_name_length -= 1;
806 		}
807 		*directory_name_index = path_index;
808 	}
809 	else if( volume_name_index == 4 )
810 	{
811 		for( path_index = volume_name_index;
812 		     path_index < path_length;
813 		     path_index++ )
814 		{
815 			if( path[ path_index ] == '\\' )
816 			{
817 				path_index++;
818 
819 				break;
820 			}
821 		}
822 		*volume_name        = (char *) &( path[ 4 ] );
823 		*volume_name_length = path_index - 4;
824 
825 		if( path[ path_index - 1 ] == '\\' )
826 		{
827 			*volume_name_length -= 1;
828 		}
829 		*directory_name_index = path_index;
830 	}
831 	else if( ( volume_name_index == 2 )
832 	      || ( volume_name_index == 8 ) )
833 	{
834 		for( share_name_index = volume_name_index;
835 		     share_name_index < path_length;
836 		     share_name_index++ )
837 		{
838 			if( path[ share_name_index ] == '\\' )
839 			{
840 				share_name_index++;
841 
842 				break;
843 			}
844 		}
845 		if( share_name_index > path_length )
846 		{
847 			libcerror_error_set(
848 			 error,
849 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
850 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
851 			 "%s: invalid path - missing share name.",
852 			 function );
853 
854 			return( -1 );
855 		}
856 		for( path_index = share_name_index;
857 		     path_index < path_length;
858 		     path_index++ )
859 		{
860 			if( path[ path_index ] == '\\' )
861 			{
862 				path_index++;
863 
864 				break;
865 			}
866 		}
867 		*volume_name        = (char *) &( path[ volume_name_index ] );
868 		*volume_name_length = path_index - volume_name_index;
869 
870 		if( path[ path_index - 1 ] == '\\' )
871 		{
872 			*volume_name_length -= 1;
873 		}
874 		*directory_name_index = path_index;
875 	}
876 	return( 1 );
877 }
878 
879 /* Retrieves the current working directory of a specific volume
880  * Returns 1 if successful or -1 on error
881  */
libcpath_path_get_current_working_directory_by_volume(char * volume_name,size_t volume_name_length,char ** current_working_directory,size_t * current_working_directory_size,libcerror_error_t ** error)882 int libcpath_path_get_current_working_directory_by_volume(
883      char *volume_name,
884      size_t volume_name_length,
885      char **current_working_directory,
886      size_t *current_working_directory_size,
887      libcerror_error_t **error )
888 {
889 	char *change_volume_name                     = NULL;
890 	char *current_volume_working_directory       = NULL;
891 	static char *function                        = "libcpath_path_get_current_working_directory_by_volume";
892 	size_t current_volume_working_directory_size = 0;
893 	int result                                   = 1;
894 
895 	if( current_working_directory == NULL )
896 	{
897 		libcerror_error_set(
898 		 error,
899 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
900 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
901 		 "%s: invalid current working directory.",
902 		 function );
903 
904 		return( -1 );
905 	}
906 	if( current_working_directory_size == NULL )
907 	{
908 		libcerror_error_set(
909 		 error,
910 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
911 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
912 		 "%s: invalid current working directory size.",
913 		 function );
914 
915 		return( -1 );
916 	}
917 	/* If the path contains a volume name switch to that
918 	 * volume to determine the current directory
919 	 */
920 	if( volume_name != NULL )
921 	{
922 		if( volume_name_length > (size_t) ( SSIZE_MAX - 1 ) )
923 		{
924 			libcerror_error_set(
925 			 error,
926 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
927 			 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
928 			 "%s: invalid volume name length value exceeds maximum.",
929 			 function );
930 
931 			goto on_error;
932 		}
933 		if( libcpath_path_get_current_working_directory(
934 		     &current_volume_working_directory,
935 		     &current_volume_working_directory_size,
936 		     error ) != 1 )
937 		{
938 			libcerror_error_set(
939 			 error,
940 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
941 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
942 			 "%s: unable to retrieve current volume working directory.",
943 			 function );
944 
945 			goto on_error;
946 		}
947 		change_volume_name = narrow_string_allocate(
948 		                      volume_name_length + 1 );
949 
950 		if( change_volume_name == NULL )
951 		{
952 			libcerror_error_set(
953 			 error,
954 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
955 			 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
956 			 "%s: unable to create change volume name.",
957 			 function );
958 
959 			goto on_error;
960 		}
961 		if( narrow_string_copy(
962 		     change_volume_name,
963 		     volume_name,
964 		     volume_name_length ) == NULL )
965 		{
966 			libcerror_error_set(
967 			 error,
968 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
969 			 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
970 			 "%s: unable to set change volume name.",
971 			 function );
972 
973 			goto on_error;
974 		}
975 		change_volume_name[ volume_name_length ] = 0;
976 
977 		if( libcpath_path_change_directory(
978 		     change_volume_name,
979 		     error ) != 1 )
980 		{
981 			libcerror_error_set(
982 			 error,
983 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
984 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
985 			 "%s: unable to change current working directory.",
986 			 function );
987 
988 			goto on_error;
989 		}
990 		memory_free(
991 		 change_volume_name );
992 
993 		change_volume_name = NULL;
994 	}
995 	if( libcpath_path_get_current_working_directory(
996 	     current_working_directory,
997 	     current_working_directory_size,
998 	     error ) != 1 )
999 	{
1000 		libcerror_error_set(
1001 		 error,
1002 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1003 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1004 		 "%s: unable to retrieve current directory.",
1005 		 function );
1006 
1007 		/* Make sure the current working directory has been changed
1008 		 * back to its original value
1009 		 */
1010 		result = -1;
1011 	}
1012 	if( current_volume_working_directory != NULL )
1013 	{
1014 		if( libcpath_path_change_directory(
1015 		     current_volume_working_directory,
1016 		     error ) != 1 )
1017 		{
1018 			libcerror_error_set(
1019 			 error,
1020 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1021 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1022 			 "%s: unable to change current working directory.",
1023 			 function );
1024 
1025 			goto on_error;
1026 		}
1027 		memory_free(
1028 		 current_volume_working_directory );
1029 
1030 		current_volume_working_directory = NULL;
1031 	}
1032 	return( result );
1033 
1034 on_error:
1035 	if( change_volume_name != NULL )
1036 	{
1037 		memory_free(
1038 		 change_volume_name );
1039 	}
1040 	if( current_volume_working_directory != NULL )
1041 	{
1042 		memory_free(
1043 		 current_volume_working_directory );
1044 	}
1045 	if( *current_working_directory != NULL )
1046 	{
1047 		memory_free(
1048 		 *current_working_directory );
1049 
1050 		*current_working_directory = NULL;
1051 	}
1052 	*current_working_directory_size = 0;
1053 
1054 	return( -1 );
1055 }
1056 
1057 /* Determines the full path of the Windows path specified
1058  * The function uses the extended-length path format
1059  * (path with \\?\ prefix)
1060  *
1061  * Multiple successive \ not at the start of the path are combined into one
1062  *
1063  * Scenario's that are considered full paths:
1064  * Device path:			\\.\PhysicalDrive0
1065  * Extended-length path:	\\?\C:\directory\file.txt
1066  * Extended-length UNC path:	\\?\UNC\server\share\directory\file.txt
1067  *
1068  * Scenario's that are not considered full paths:
1069  * Local 'absolute' path:	\directory\file.txt
1070  *                       	\directory\\file.txt
1071  * Local 'relative' path:	..\directory\file.txt
1072  * Local 'relative' path:	.\directory\file.txt
1073  * Volume 'absolute' path:	C:\directory\file.txt
1074  *                              C:\..\directory\file.txt
1075  * Volume 'relative' path:	C:directory\file.txt
1076  * UNC path:			\\server\share\directory\file.txt
1077  *
1078  * TODO handle:
1079  * Volume device path:		\\.\C:
1080  * Volume file system path:	\\.\C:\
1081  *
1082  * Returns 1 if succesful or -1 on error
1083  */
libcpath_path_get_full_path(const char * path,size_t path_length,char ** full_path,size_t * full_path_size,libcerror_error_t ** error)1084 int libcpath_path_get_full_path(
1085      const char *path,
1086      size_t path_length,
1087      char **full_path,
1088      size_t *full_path_size,
1089      libcerror_error_t **error )
1090 {
1091 	libcsplit_narrow_split_string_t *current_directory_split_string = NULL;
1092 	libcsplit_narrow_split_string_t *path_split_string              = NULL;
1093 	char *current_directory                                         = NULL;
1094 	char *current_directory_string_segment                          = NULL;
1095 	char *full_path_prefix                                          = NULL;
1096 	char *last_used_path_string_segment                             = NULL;
1097 	char *path_string_segment                                       = NULL;
1098 	char *volume_name                                               = NULL;
1099 	static char *function                                           = "libcpath_path_get_full_path";
1100 	size_t current_directory_length                                 = 0;
1101 	size_t current_directory_name_index                             = 0;
1102 	size_t current_directory_size                                   = 0;
1103 	size_t current_directory_string_segment_size                    = 0;
1104 	size_t full_path_index                                          = 0;
1105 	size_t full_path_prefix_length                                  = 0;
1106 	size_t last_used_path_string_segment_size                       = 0;
1107 	size_t path_directory_name_index                                = 0;
1108 	size_t path_string_segment_size                                 = 0;
1109 	size_t safe_full_path_size                                      = 0;
1110 	size_t volume_name_length                                       = 0;
1111 	uint8_t path_type                                               = LIBCPATH_TYPE_RELATIVE;
1112 	int current_directory_number_of_segments                        = 0;
1113 	int current_directory_segment_index                             = 0;
1114 	int last_used_path_segment_index                                = -1;
1115 	int path_number_of_segments                                     = 0;
1116 	int path_segment_index                                          = 0;
1117 
1118 	if( path == NULL )
1119 	{
1120 		libcerror_error_set(
1121 		 error,
1122 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1123 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1124 		 "%s: invalid path.",
1125 		 function );
1126 
1127 		return( -1 );
1128 	}
1129 	if( path_length == 0 )
1130 	{
1131 		libcerror_error_set(
1132 		 error,
1133 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1134 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
1135 		 "%s: invalid path length is zero.",
1136 		 function );
1137 
1138 		return( -1 );
1139 	}
1140 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
1141 	{
1142 		libcerror_error_set(
1143 		 error,
1144 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1145 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1146 		 "%s: invalid path length value exceeds maximum.",
1147 		 function );
1148 
1149 		return( -1 );
1150 	}
1151 	if( full_path == NULL )
1152 	{
1153 		libcerror_error_set(
1154 		 error,
1155 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1156 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1157 		 "%s: invalid full path.",
1158 		 function );
1159 
1160 		return( -1 );
1161 	}
1162 	if( *full_path != NULL )
1163 	{
1164 		libcerror_error_set(
1165 		 error,
1166 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1167 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1168 		 "%s: invalid full path value already set.",
1169 		 function );
1170 
1171 		return( -1 );
1172 	}
1173 	if( full_path_size == NULL )
1174 	{
1175 		libcerror_error_set(
1176 		 error,
1177 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1178 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1179 		 "%s: invalid full path size.",
1180 		 function );
1181 
1182 		return( -1 );
1183 	}
1184 	if( libcpath_path_get_path_type(
1185 	     path,
1186 	     path_length,
1187 	     &path_type,
1188 	     error ) != 1 )
1189 	{
1190 		libcerror_error_set(
1191 		 error,
1192 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1193 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1194 		 "%s: unable to determine path type.",
1195 		 function );
1196 
1197 		goto on_error;
1198 	}
1199 	if( libcpath_path_get_volume_name(
1200 	     path,
1201 	     path_length,
1202 	     &volume_name,
1203 	     &volume_name_length,
1204 	     &path_directory_name_index,
1205 	     error ) != 1 )
1206 	{
1207 		libcerror_error_set(
1208 		 error,
1209 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1210 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1211 		 "%s: unable to determine volume name.",
1212 		 function );
1213 
1214 		goto on_error;
1215 	}
1216 	/* If the path is a device path, an extended-length path or an UNC
1217 	 * do not bother to lookup the current working directory
1218 	 */
1219 	if( ( path_type != LIBCPATH_TYPE_DEVICE )
1220 	 && ( path_type != LIBCPATH_TYPE_EXTENDED_LENGTH )
1221 	 && ( path_type != LIBCPATH_TYPE_EXTENDED_LENGTH_UNC )
1222 	 && ( path_type != LIBCPATH_TYPE_UNC ) )
1223 	{
1224 		if( libcpath_path_get_current_working_directory_by_volume(
1225 		     volume_name,
1226 		     volume_name_length,
1227 		     &current_directory,
1228 		     &current_directory_size,
1229 		     error ) != 1 )
1230 		{
1231 			libcerror_error_set(
1232 			 error,
1233 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1234 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1235 			 "%s: unable to retrieve current working directory by volume.",
1236 			 function );
1237 
1238 			goto on_error;
1239 		}
1240 		/* Determine the volume name using the current working directory if necessary
1241 		 */
1242 		if( libcpath_path_get_volume_name(
1243 		     current_directory,
1244 		     current_directory_size - 1,
1245 		     &volume_name,
1246 		     &volume_name_length,
1247 		     &current_directory_name_index,
1248 		     error ) != 1 )
1249 		{
1250 			libcerror_error_set(
1251 			 error,
1252 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1253 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1254 			 "%s: unable to determine volume name from current working directory.",
1255 			 function );
1256 
1257 			goto on_error;
1258 		}
1259 	}
1260 	if( ( current_directory != NULL )
1261 	 && ( current_directory_name_index < current_directory_size ) )
1262 	{
1263 		current_directory_length = narrow_string_length(
1264 		                            &( current_directory[ current_directory_name_index ] ) );
1265 
1266 		if( libcsplit_narrow_string_split(
1267 		     &( current_directory[ current_directory_name_index ] ),
1268 		     current_directory_length + 1,
1269 		     '\\',
1270 		     &current_directory_split_string,
1271 		     error ) != 1 )
1272 		{
1273 			libcerror_error_set(
1274 			 error,
1275 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1276 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1277 			 "%s: unable to split current working directory.",
1278 			 function );
1279 
1280 			goto on_error;
1281 		}
1282 	}
1283 	if( libcsplit_narrow_string_split(
1284 	     &( path[ path_directory_name_index ] ),
1285 	     path_length - path_directory_name_index + 1,
1286 	     '\\',
1287 	     &path_split_string,
1288 	     error ) != 1 )
1289 	{
1290 		libcerror_error_set(
1291 		 error,
1292 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1293 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1294 		 "%s: unable to split path.",
1295 		 function );
1296 
1297 		goto on_error;
1298 	}
1299 	/* The size of the full path consists of:
1300 	 * the size of the prefix (\\?\ or \\.\)
1301 	 */
1302 	safe_full_path_size = 4;
1303 
1304 	/* If the path contains a volume name
1305 	 * the length of the volume name
1306 	 * a directory separator
1307 	 */
1308 	if( volume_name != NULL )
1309 	{
1310 		safe_full_path_size += volume_name_length + 1;
1311 	}
1312 	/* If the path contains an UNC path
1313 	 * add the size of the UNC\ prefix
1314 	 */
1315 	if( ( path_type == LIBCPATH_TYPE_EXTENDED_LENGTH_UNC )
1316 	 || ( path_type == LIBCPATH_TYPE_UNC ) )
1317 	{
1318 		safe_full_path_size += 4;
1319 	}
1320 	/* If the path is relative
1321 	 * add the size of the current working directory
1322 	 * a directory separator, if necessary
1323 	 */
1324 	if( ( path_type == LIBCPATH_TYPE_RELATIVE )
1325 	 && ( current_directory_name_index < current_directory_size ) )
1326 	{
1327 		safe_full_path_size += ( current_directory_size - ( current_directory_name_index + 1 ) );
1328 
1329 		if( ( current_directory_size >= 2 )
1330 		 && ( current_directory[ current_directory_size - 2 ] != '\\' ) )
1331 		{
1332 			safe_full_path_size += 1;
1333 		}
1334 	}
1335 	if( current_directory_split_string != NULL )
1336 	{
1337 		if( libcsplit_narrow_split_string_get_number_of_segments(
1338 		     current_directory_split_string,
1339 		     &current_directory_number_of_segments,
1340 		     error ) != 1 )
1341 		{
1342 			libcerror_error_set(
1343 			 error,
1344 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1345 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1346 			 "%s: unable to retrieve number of current working directory string segments.",
1347 			 function );
1348 
1349 			goto on_error;
1350 		}
1351 		current_directory_segment_index = current_directory_number_of_segments - 1;
1352 	}
1353 	if( libcsplit_narrow_split_string_get_number_of_segments(
1354 	     path_split_string,
1355 	     &path_number_of_segments,
1356 	     error ) != 1 )
1357 	{
1358 		libcerror_error_set(
1359 		 error,
1360 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1361 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1362 		 "%s: unable to retrieve number of path string segments.",
1363 		 function );
1364 
1365 		goto on_error;
1366 	}
1367 	for( path_segment_index = 0;
1368 	     path_segment_index < path_number_of_segments;
1369 	     path_segment_index++ )
1370 	{
1371 		if( libcsplit_narrow_split_string_get_segment_by_index(
1372 		     path_split_string,
1373 		     path_segment_index,
1374 		     &path_string_segment,
1375 		     &path_string_segment_size,
1376 		     error ) != 1 )
1377 		{
1378 			libcerror_error_set(
1379 			 error,
1380 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1381 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1382 			 "%s: unable to retrieve path string segment: %d.",
1383 			 function,
1384 			 path_segment_index );
1385 
1386 			goto on_error;
1387 		}
1388 		if( path_string_segment == NULL )
1389 		{
1390 			libcerror_error_set(
1391 			 error,
1392 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1393 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1394 			 "%s: missing path string segment: %d.",
1395 			 function,
1396 			 path_segment_index );
1397 
1398 			goto on_error;
1399 		}
1400 		/* If the path is .. reverse the current path by one directory
1401 		 */
1402 		if( ( path_string_segment_size == 3 )
1403 		 && ( path_string_segment[ 0 ] == '.' )
1404 		 && ( path_string_segment[ 1 ] == '.' ) )
1405 		{
1406 			if( ( current_directory_split_string != NULL )
1407 			 && ( last_used_path_segment_index == -1 ) )
1408 			{
1409 				if( libcsplit_narrow_split_string_get_segment_by_index(
1410 				     current_directory_split_string,
1411 				     current_directory_segment_index,
1412 				     &current_directory_string_segment,
1413 				     &current_directory_string_segment_size,
1414 				     error ) != 1 )
1415 				{
1416 					libcerror_error_set(
1417 					 error,
1418 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1419 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1420 					 "%s: unable to retrieve current working directory string segment: %d.",
1421 					 function,
1422 					 current_directory_segment_index );
1423 
1424 					goto on_error;
1425 				}
1426 				if( current_directory_string_segment == NULL )
1427 				{
1428 					libcerror_error_set(
1429 					 error,
1430 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1431 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1432 					 "%s: missing current working directory string segment: %d.",
1433 					 function,
1434 					 current_directory_segment_index );
1435 
1436 					goto on_error;
1437 				}
1438 				/* Remove the size of the parent directory name and a directory separator
1439 				 * Note that the size includes the end of string character
1440 				 */
1441 				safe_full_path_size -= current_directory_string_segment_size;
1442 
1443 				if( libcsplit_narrow_split_string_set_segment_by_index(
1444 				     current_directory_split_string,
1445 				     current_directory_segment_index,
1446 				     NULL,
1447 				     0,
1448 				     error ) != 1 )
1449 				{
1450 					libcerror_error_set(
1451 					 error,
1452 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1453 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1454 					 "%s: unable to set current working directory string segment: %d.",
1455 					 function,
1456 					 current_directory_segment_index );
1457 
1458 					goto on_error;
1459 				}
1460 				current_directory_segment_index--;
1461 			}
1462 			else if( last_used_path_segment_index >= 0 )
1463 			{
1464 				if( libcsplit_narrow_split_string_get_segment_by_index(
1465 				     path_split_string,
1466 				     last_used_path_segment_index,
1467 				     &last_used_path_string_segment,
1468 				     &last_used_path_string_segment_size,
1469 				     error ) != 1 )
1470 				{
1471 					libcerror_error_set(
1472 					 error,
1473 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1474 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1475 					 "%s: unable to retrieve last used path string segment: %d.",
1476 					 function,
1477 					 last_used_path_segment_index );
1478 
1479 					goto on_error;
1480 				}
1481 				if( last_used_path_string_segment == NULL )
1482 				{
1483 					libcerror_error_set(
1484 					 error,
1485 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1486 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1487 					 "%s: missing last used path string string segment: %d.",
1488 					 function,
1489 					 last_used_path_segment_index );
1490 
1491 					goto on_error;
1492 				}
1493 				/* Remove the size of the parent directory name and a directory separator
1494 				 * Note that the size includes the end of string character
1495 				 */
1496 				safe_full_path_size -= last_used_path_string_segment_size;
1497 
1498 				if( libcsplit_narrow_split_string_set_segment_by_index(
1499 				     path_split_string,
1500 				     last_used_path_segment_index,
1501 				     NULL,
1502 				     0,
1503 				     error ) != 1 )
1504 				{
1505 					libcerror_error_set(
1506 					 error,
1507 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1508 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1509 					 "%s: unable to set path string segment: %d.",
1510 					 function,
1511 					 last_used_path_segment_index );
1512 
1513 					goto on_error;
1514 				}
1515 				/* Find the previous path split value that contains a name
1516 				 */
1517 				while( last_used_path_segment_index > 0 )
1518 				{
1519 					last_used_path_segment_index--;
1520 
1521 					if( libcsplit_narrow_split_string_get_segment_by_index(
1522 					     path_split_string,
1523 					     last_used_path_segment_index,
1524 					     &last_used_path_string_segment,
1525 					     &last_used_path_string_segment_size,
1526 					     error ) != 1 )
1527 					{
1528 						libcerror_error_set(
1529 						 error,
1530 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1531 						 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1532 						 "%s: unable to retrieve last used path string segment: %d.",
1533 						 function,
1534 						 last_used_path_segment_index );
1535 
1536 						goto on_error;
1537 					}
1538 					if( last_used_path_string_segment_size != 0 )
1539 					{
1540 						break;
1541 					}
1542 				}
1543 			}
1544 			if( libcsplit_narrow_split_string_set_segment_by_index(
1545 			     path_split_string,
1546 			     path_segment_index,
1547 			     NULL,
1548 			     0,
1549 			     error ) != 1 )
1550 			{
1551 				libcerror_error_set(
1552 				 error,
1553 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1554 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1555 				 "%s: unable to set path string segment: %d.",
1556 				 function,
1557 				 path_segment_index );
1558 
1559 				goto on_error;
1560 			}
1561 		}
1562 		/* If the path is . ignore the entry
1563 		 */
1564 		else if( ( path_string_segment_size == 2 )
1565 		      && ( path_string_segment[ 0 ] == '.' ) )
1566 		{
1567 			if( libcsplit_narrow_split_string_set_segment_by_index(
1568 			     path_split_string,
1569 			     path_segment_index,
1570 			     NULL,
1571 			     0,
1572 			     error ) != 1 )
1573 			{
1574 				libcerror_error_set(
1575 				 error,
1576 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1577 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1578 				 "%s: unable to set path string segment: %d.",
1579 				 function,
1580 				 path_segment_index );
1581 
1582 				goto on_error;
1583 			}
1584 		}
1585 		/* If the path is empty ignore the entry
1586 		 */
1587 		else if( path_string_segment_size <= 1 )
1588 		{
1589 			if( libcsplit_narrow_split_string_set_segment_by_index(
1590 			     path_split_string,
1591 			     path_segment_index,
1592 			     NULL,
1593 			     0,
1594 			     error ) != 1 )
1595 			{
1596 				libcerror_error_set(
1597 				 error,
1598 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1599 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1600 				 "%s: unable to set path string segment: %d.",
1601 				 function,
1602 				 path_segment_index );
1603 
1604 				goto on_error;
1605 			}
1606 		}
1607 		else
1608 		{
1609 			/* Add the size of the directory or file name and a directory separator
1610 			 * Note that the size includes the end of string character
1611 			 */
1612 			safe_full_path_size += path_string_segment_size;
1613 
1614 			last_used_path_segment_index = path_segment_index;
1615 		}
1616 	}
1617 	/* Note that the last path separator serves as the end of string
1618 	 */
1619 	full_path_index = 0;
1620 
1621 	*full_path = narrow_string_allocate(
1622 	              safe_full_path_size );
1623 
1624 	if( *full_path == NULL )
1625 	{
1626 		libcerror_error_set(
1627 		 error,
1628 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
1629 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1630 		 "%s: unable to create full path.",
1631 		 function );
1632 
1633 		goto on_error;
1634 	}
1635 	if( memory_set(
1636 	     *full_path,
1637 	     0,
1638 	     sizeof( char ) * safe_full_path_size ) == NULL )
1639 	{
1640 		libcerror_error_set(
1641 		 error,
1642 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
1643 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
1644 		 "%s: unable to clear full path.",
1645 		 function );
1646 
1647 		goto on_error;
1648 	}
1649 	*full_path_size = safe_full_path_size;
1650 
1651 	if( path_type == LIBCPATH_TYPE_DEVICE )
1652 	{
1653 		full_path_prefix        = "\\\\.\\";
1654 		full_path_prefix_length = 4;
1655 	}
1656 	else
1657 	{
1658 		full_path_prefix        = "\\\\?\\";
1659 		full_path_prefix_length = 4;
1660 	}
1661 	if( narrow_string_copy(
1662 	     &( ( *full_path )[ full_path_index ] ),
1663 	     full_path_prefix,
1664 	     full_path_prefix_length ) == NULL )
1665 	{
1666 		libcerror_error_set(
1667 		 error,
1668 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1669 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1670 		 "%s: unable to set prefix in full path.",
1671 		 function );
1672 
1673 		goto on_error;
1674 	}
1675 	full_path_index += full_path_prefix_length;
1676 
1677 	/* If there is a share name the path is an UNC path
1678 	 */
1679 	if( ( path_type == LIBCPATH_TYPE_EXTENDED_LENGTH_UNC )
1680 	 || ( path_type == LIBCPATH_TYPE_UNC ) )
1681 	{
1682 		if( narrow_string_copy(
1683 		     &( ( *full_path )[ full_path_index ] ),
1684 		     "UNC\\",
1685 		     4 ) == NULL )
1686 		{
1687 			libcerror_error_set(
1688 			 error,
1689 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1690 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1691 			 "%s: unable to set UNC\\ prefix in full path.",
1692 			 function );
1693 
1694 			goto on_error;
1695 		}
1696 		full_path_index += 4;
1697 	}
1698 	if( volume_name != NULL )
1699 	{
1700 		if( narrow_string_copy(
1701 		     &( ( *full_path )[ full_path_index ] ),
1702 		     volume_name,
1703 		     volume_name_length ) == NULL )
1704 		{
1705 			libcerror_error_set(
1706 			 error,
1707 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1708 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1709 			 "%s: unable to set volume name in full path.",
1710 			 function );
1711 
1712 			goto on_error;
1713 		}
1714 		full_path_index += volume_name_length;
1715 
1716 		( *full_path )[ full_path_index ] = '\\';
1717 
1718 		full_path_index += 1;
1719 	}
1720 	/* If the path is relative
1721 	 * add the current working directory elements
1722 	 */
1723 	if( ( path_type == LIBCPATH_TYPE_RELATIVE )
1724 	 && ( current_directory_split_string != NULL ) )
1725 	{
1726 		for( current_directory_segment_index = 0;
1727 		     current_directory_segment_index < current_directory_number_of_segments;
1728 		     current_directory_segment_index++ )
1729 		{
1730 			if( libcsplit_narrow_split_string_get_segment_by_index(
1731 			     current_directory_split_string,
1732 			     current_directory_segment_index,
1733 			     &current_directory_string_segment,
1734 			     &current_directory_string_segment_size,
1735 			     error ) != 1 )
1736 			{
1737 				libcerror_error_set(
1738 				 error,
1739 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1740 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1741 				 "%s: unable to retrieve current working directory string segment: %d.",
1742 				 function,
1743 				 current_directory_segment_index );
1744 
1745 				goto on_error;
1746 			}
1747 			if( current_directory_string_segment_size != 0 )
1748 			{
1749 				if( current_directory_string_segment == NULL )
1750 				{
1751 					libcerror_error_set(
1752 					 error,
1753 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1754 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1755 					 "%s: missing current working directory string segment: %d.",
1756 					 function,
1757 					 current_directory_segment_index );
1758 
1759 					goto on_error;
1760 				}
1761 				if( narrow_string_copy(
1762 				     &( ( *full_path )[ full_path_index ] ),
1763 				     current_directory_string_segment,
1764 				     current_directory_string_segment_size - 1 ) == NULL )
1765 				{
1766 					libcerror_error_set(
1767 					 error,
1768 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1769 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1770 					 "%s: unable to set current working directory split value: %d in full path.",
1771 					 function,
1772 					 current_directory_segment_index );
1773 
1774 					goto on_error;
1775 				}
1776 				full_path_index += current_directory_string_segment_size - 1;
1777 
1778 				( *full_path )[ full_path_index ] = '\\';
1779 
1780 				full_path_index += 1;
1781 			}
1782 		}
1783 	}
1784 	for( path_segment_index = 0;
1785 	     path_segment_index < path_number_of_segments;
1786 	     path_segment_index++ )
1787 	{
1788 		if( libcsplit_narrow_split_string_get_segment_by_index(
1789 		     path_split_string,
1790 		     path_segment_index,
1791 		     &path_string_segment,
1792 		     &path_string_segment_size,
1793 		     error ) != 1 )
1794 		{
1795 			libcerror_error_set(
1796 			 error,
1797 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1798 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1799 			 "%s: unable to retrieve path string segment: %d.",
1800 			 function,
1801 			 path_segment_index );
1802 
1803 			goto on_error;
1804 		}
1805 		if( path_string_segment_size != 0 )
1806 		{
1807 			if( path_string_segment == NULL )
1808 			{
1809 				libcerror_error_set(
1810 				 error,
1811 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1812 				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1813 				 "%s: missing path string segment: %d.",
1814 				 function,
1815 				 path_segment_index );
1816 
1817 				goto on_error;
1818 			}
1819 			if( narrow_string_copy(
1820 			     &( ( *full_path )[ full_path_index ] ),
1821 			     path_string_segment,
1822 			     path_string_segment_size - 1 ) == NULL )
1823 			{
1824 				libcerror_error_set(
1825 				 error,
1826 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1827 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1828 				 "%s: unable to set path split value: %d in full path.",
1829 				 function,
1830 				 path_segment_index );
1831 
1832 				goto on_error;
1833 			}
1834 			full_path_index += path_string_segment_size - 1;
1835 
1836 			( *full_path )[ full_path_index ] = '\\';
1837 
1838 			full_path_index += 1;
1839 		}
1840 	}
1841 	( *full_path )[ full_path_index - 1 ] = 0;
1842 
1843 	if( libcsplit_narrow_split_string_free(
1844 	     &path_split_string,
1845 	     error ) != 1 )
1846 	{
1847 		libcerror_error_set(
1848 		 error,
1849 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1850 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1851 		 "%s: unable to free path split string.",
1852 		 function );
1853 
1854 		goto on_error;
1855 	}
1856 	if( current_directory_split_string != NULL )
1857 	{
1858 		if( libcsplit_narrow_split_string_free(
1859 		     &current_directory_split_string,
1860 		     error ) != 1 )
1861 		{
1862 			libcerror_error_set(
1863 			 error,
1864 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1865 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1866 			 "%s: unable to free current working directory split string.",
1867 			 function );
1868 
1869 			goto on_error;
1870 		}
1871 	}
1872 	if( current_directory != NULL )
1873 	{
1874 		memory_free(
1875 		 current_directory );
1876 	}
1877 	return( 1 );
1878 
1879 on_error:
1880 	if( *full_path != NULL )
1881 	{
1882 		memory_free(
1883 		 *full_path );
1884 
1885 		*full_path = NULL;
1886 	}
1887 	*full_path_size = 0;
1888 
1889 	if( path_split_string != NULL )
1890 	{
1891 		libcsplit_narrow_split_string_free(
1892 		 &path_split_string,
1893 		 NULL );
1894 	}
1895 	if( current_directory_split_string != NULL )
1896 	{
1897 		libcsplit_narrow_split_string_free(
1898 		 &current_directory_split_string,
1899 		 NULL );
1900 	}
1901 	if( current_directory != NULL )
1902 	{
1903 		memory_free(
1904 		 current_directory );
1905 	}
1906 	return( -1 );
1907 }
1908 
1909 #else
1910 
1911 /* Determines the full path of the POSIX path specified
1912  * Multiple successive / are combined into one
1913  *
1914  * Scenarios:
1915  * /home/user/file.txt
1916  * /home/user//file.txt
1917  * /home/user/../user/file.txt
1918  * /../home/user/file.txt
1919  * user/../user/file.txt
1920  *
1921  * Returns 1 if succesful or -1 on error
1922  */
libcpath_path_get_full_path(const char * path,size_t path_length,char ** full_path,size_t * full_path_size,libcerror_error_t ** error)1923 int libcpath_path_get_full_path(
1924      const char *path,
1925      size_t path_length,
1926      char **full_path,
1927      size_t *full_path_size,
1928      libcerror_error_t **error )
1929 {
1930 	libcsplit_narrow_split_string_t *current_directory_split_string = NULL;
1931 	libcsplit_narrow_split_string_t *path_split_string              = NULL;
1932 	char *current_directory                                         = NULL;
1933 	char *current_directory_string_segment                          = NULL;
1934 	char *last_used_path_string_segment                             = NULL;
1935 	char *path_string_segment                                       = NULL;
1936 	static char *function                                           = "libcpath_path_get_full_path";
1937 	size_t current_directory_length                                 = 0;
1938 	size_t current_directory_size                                   = 0;
1939 	size_t current_directory_string_segment_size                    = 0;
1940 	size_t full_path_index                                          = 0;
1941 	size_t last_used_path_string_segment_size                       = 0;
1942 	size_t path_string_segment_size                                 = 0;
1943 	size_t safe_full_path_size                                      = 0;
1944 	uint8_t path_type                                               = LIBCPATH_TYPE_RELATIVE;
1945 	int current_directory_number_of_segments                        = 0;
1946 	int current_directory_segment_index                             = 0;
1947 	int last_used_path_segment_index                                = -1;
1948 	int path_number_of_segments                                     = 0;
1949 	int path_segment_index                                          = 0;
1950 
1951 	if( path == NULL )
1952 	{
1953 		libcerror_error_set(
1954 		 error,
1955 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1956 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1957 		 "%s: invalid path.",
1958 		 function );
1959 
1960 		return( -1 );
1961 	}
1962 	if( path_length == 0 )
1963 	{
1964 		libcerror_error_set(
1965 		 error,
1966 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1967 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
1968 		 "%s: invalid path length is zero.",
1969 		 function );
1970 
1971 		return( -1 );
1972 	}
1973 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
1974 	{
1975 		libcerror_error_set(
1976 		 error,
1977 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1978 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1979 		 "%s: invalid path length value exceeds maximum.",
1980 		 function );
1981 
1982 		return( -1 );
1983 	}
1984 	if( full_path == NULL )
1985 	{
1986 		libcerror_error_set(
1987 		 error,
1988 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1989 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1990 		 "%s: invalid full path.",
1991 		 function );
1992 
1993 		return( -1 );
1994 	}
1995 	if( *full_path != NULL )
1996 	{
1997 		libcerror_error_set(
1998 		 error,
1999 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2000 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
2001 		 "%s: invalid full path value already set.",
2002 		 function );
2003 
2004 		return( -1 );
2005 	}
2006 	if( full_path_size == NULL )
2007 	{
2008 		libcerror_error_set(
2009 		 error,
2010 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2011 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2012 		 "%s: invalid full path size.",
2013 		 function );
2014 
2015 		return( -1 );
2016 	}
2017 	if( path[ 0 ] == '/' )
2018 	{
2019 		path_type = LIBCPATH_TYPE_ABSOLUTE;
2020 	}
2021 	else
2022 	{
2023 		if( libcpath_path_get_current_working_directory(
2024 		     &current_directory,
2025 		     &current_directory_size,
2026 		     error ) != 1 )
2027 		{
2028 			libcerror_error_set(
2029 			 error,
2030 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2031 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2032 			 "%s: unable to retrieve current working directory.",
2033 			 function );
2034 
2035 			goto on_error;
2036 		}
2037 	}
2038 	if( current_directory != NULL )
2039 	{
2040 		current_directory_length = narrow_string_length(
2041 		                            current_directory );
2042 
2043 		if( libcsplit_narrow_string_split(
2044 		     current_directory,
2045 		     current_directory_length + 1,
2046 		     '/',
2047 		     &current_directory_split_string,
2048 		     error ) != 1 )
2049 		{
2050 			libcerror_error_set(
2051 			 error,
2052 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2053 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2054 			 "%s: unable to split current working directory.",
2055 			 function );
2056 
2057 			goto on_error;
2058 		}
2059 	}
2060 	if( libcsplit_narrow_string_split(
2061 	     path,
2062 	     path_length + 1,
2063 	     '/',
2064 	     &path_split_string,
2065 	     error ) != 1 )
2066 	{
2067 		libcerror_error_set(
2068 		 error,
2069 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2070 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2071 		 "%s: unable to split path.",
2072 		 function );
2073 
2074 		goto on_error;
2075 	}
2076 	/* Determine the full path size
2077 	 */
2078 	/* If the path is absolute
2079 	 * a directory separator
2080 	 */
2081 	if( path_type == LIBCPATH_TYPE_ABSOLUTE )
2082 	{
2083 		safe_full_path_size = 1;
2084 	}
2085 	/* If the path is relative
2086 	 * add the size of the current working directory
2087 	 * a directory separator, if necessary
2088 	 */
2089 	else if( path_type == LIBCPATH_TYPE_RELATIVE )
2090 	{
2091 		if( current_directory == NULL )
2092 		{
2093 			libcerror_error_set(
2094 			 error,
2095 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2096 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2097 			 "%s: missing current working directory.",
2098 			 function );
2099 
2100 			goto on_error;
2101 		}
2102 		/* We need to use the length here since current_directory_size will be PATH_MAX
2103 		 */
2104 		safe_full_path_size = current_directory_length;
2105 
2106 		if( ( current_directory_length >= 1 )
2107 		 && ( current_directory[ current_directory_length - 1 ] != '/' ) )
2108 		{
2109 			safe_full_path_size++;
2110 		}
2111 	}
2112 	if( current_directory_split_string != NULL )
2113 	{
2114 		if( libcsplit_narrow_split_string_get_number_of_segments(
2115 		     current_directory_split_string,
2116 		     &current_directory_number_of_segments,
2117 		     error ) != 1 )
2118 		{
2119 			libcerror_error_set(
2120 			 error,
2121 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2122 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2123 			 "%s: unable to retrieve number of current working directory string segments.",
2124 			 function );
2125 
2126 			goto on_error;
2127 		}
2128 		current_directory_segment_index = current_directory_number_of_segments - 1;
2129 	}
2130 	if( libcsplit_narrow_split_string_get_number_of_segments(
2131 	     path_split_string,
2132 	     &path_number_of_segments,
2133 	     error ) != 1 )
2134 	{
2135 		libcerror_error_set(
2136 		 error,
2137 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2138 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2139 		 "%s: unable to retrieve number of path string segments.",
2140 		 function );
2141 
2142 		goto on_error;
2143 	}
2144 	for( path_segment_index = 0;
2145 	     path_segment_index < path_number_of_segments;
2146 	     path_segment_index++ )
2147 	{
2148 		if( libcsplit_narrow_split_string_get_segment_by_index(
2149 		     path_split_string,
2150 		     path_segment_index,
2151 		     &path_string_segment,
2152 		     &path_string_segment_size,
2153 		     error ) != 1 )
2154 		{
2155 			libcerror_error_set(
2156 			 error,
2157 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2158 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2159 			 "%s: unable to retrieve path string segment: %d.",
2160 			 function,
2161 			 path_segment_index );
2162 
2163 			goto on_error;
2164 		}
2165 		if( path_string_segment == NULL )
2166 		{
2167 			libcerror_error_set(
2168 			 error,
2169 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2170 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2171 			 "%s: missing path string segment: %d.",
2172 			 function,
2173 			 path_segment_index );
2174 
2175 			goto on_error;
2176 		}
2177 		/* If the path is .. reverse the current path by one directory
2178 		 */
2179 		if( ( path_string_segment_size == 3 )
2180 		 && ( path_string_segment[ 0 ] == '.' )
2181 		 && ( path_string_segment[ 1 ] == '.' ) )
2182 		{
2183 			if( ( current_directory_split_string != NULL )
2184 			 && ( last_used_path_segment_index == -1 ) )
2185 			{
2186 				if( libcsplit_narrow_split_string_get_segment_by_index(
2187 				     current_directory_split_string,
2188 				     current_directory_segment_index,
2189 				     &current_directory_string_segment,
2190 				     &current_directory_string_segment_size,
2191 				     error ) != 1 )
2192 				{
2193 					libcerror_error_set(
2194 					 error,
2195 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2196 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2197 					 "%s: unable to retrieve current working directory string segment: %d.",
2198 					 function,
2199 					 current_directory_segment_index );
2200 
2201 					goto on_error;
2202 				}
2203 				if( current_directory_string_segment == NULL )
2204 				{
2205 					libcerror_error_set(
2206 					 error,
2207 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2208 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2209 					 "%s: missing current working directory string segment: %d.",
2210 					 function,
2211 					 current_directory_segment_index );
2212 
2213 					goto on_error;
2214 				}
2215 				/* Remove the size of the parent directory name and a directory separator
2216 				 * Note that the size includes the end of string character
2217 				 */
2218 				safe_full_path_size -= current_directory_string_segment_size;
2219 
2220 				if( libcsplit_narrow_split_string_set_segment_by_index(
2221 				     current_directory_split_string,
2222 				     current_directory_segment_index,
2223 				     NULL,
2224 				     0,
2225 				     error ) != 1 )
2226 				{
2227 					libcerror_error_set(
2228 					 error,
2229 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2230 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2231 					 "%s: unable to set current working directory string segment: %d.",
2232 					 function,
2233 					 current_directory_segment_index );
2234 
2235 					goto on_error;
2236 				}
2237 				current_directory_segment_index--;
2238 			}
2239 			else if( last_used_path_segment_index >= 0 )
2240 			{
2241 				if( libcsplit_narrow_split_string_get_segment_by_index(
2242 				     path_split_string,
2243 				     last_used_path_segment_index,
2244 				     &last_used_path_string_segment,
2245 				     &last_used_path_string_segment_size,
2246 				     error ) != 1 )
2247 				{
2248 					libcerror_error_set(
2249 					 error,
2250 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2251 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2252 					 "%s: unable to retrieve last used path string segment: %d.",
2253 					 function,
2254 					 last_used_path_segment_index );
2255 
2256 					goto on_error;
2257 				}
2258 				if( last_used_path_string_segment == NULL )
2259 				{
2260 					libcerror_error_set(
2261 					 error,
2262 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2263 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2264 					 "%s: missing last used path string string segment: %d.",
2265 					 function,
2266 					 last_used_path_segment_index );
2267 
2268 					goto on_error;
2269 				}
2270 				/* Remove the size of the parent directory name and a directory separator
2271 				 * Note that the size includes the end of string character
2272 				 */
2273 				safe_full_path_size -= last_used_path_string_segment_size;
2274 
2275 				if( libcsplit_narrow_split_string_set_segment_by_index(
2276 				     path_split_string,
2277 				     last_used_path_segment_index,
2278 				     NULL,
2279 				     0,
2280 				     error ) != 1 )
2281 				{
2282 					libcerror_error_set(
2283 					 error,
2284 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2285 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2286 					 "%s: unable to set path string segment: %d.",
2287 					 function,
2288 					 last_used_path_segment_index );
2289 
2290 					goto on_error;
2291 				}
2292 				/* Find the previous path split value that contains a name
2293 				 */
2294 				while( last_used_path_segment_index > 0 )
2295 				{
2296 					last_used_path_segment_index--;
2297 
2298 					if( libcsplit_narrow_split_string_get_segment_by_index(
2299 					     path_split_string,
2300 					     last_used_path_segment_index,
2301 					     &last_used_path_string_segment,
2302 					     &last_used_path_string_segment_size,
2303 					     error ) != 1 )
2304 					{
2305 						libcerror_error_set(
2306 						 error,
2307 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2308 						 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2309 						 "%s: unable to retrieve last used path string segment: %d.",
2310 						 function,
2311 						 last_used_path_segment_index );
2312 
2313 						goto on_error;
2314 					}
2315 					if( last_used_path_string_segment_size != 0 )
2316 					{
2317 						break;
2318 					}
2319 				}
2320 			}
2321 			if( libcsplit_narrow_split_string_set_segment_by_index(
2322 			     path_split_string,
2323 			     path_segment_index,
2324 			     NULL,
2325 			     0,
2326 			     error ) != 1 )
2327 			{
2328 				libcerror_error_set(
2329 				 error,
2330 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2331 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2332 				 "%s: unable to set path string segment: %d.",
2333 				 function,
2334 				 path_segment_index );
2335 
2336 				goto on_error;
2337 			}
2338 		}
2339 		/* If the path is . ignore the entry
2340 		 */
2341 		else if( ( path_string_segment_size == 2 )
2342 		      && ( path_string_segment[ 0 ] == '.' ) )
2343 		{
2344 			if( libcsplit_narrow_split_string_set_segment_by_index(
2345 			     path_split_string,
2346 			     path_segment_index,
2347 			     NULL,
2348 			     0,
2349 			     error ) != 1 )
2350 			{
2351 				libcerror_error_set(
2352 				 error,
2353 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2354 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2355 				 "%s: unable to set path string segment: %d.",
2356 				 function,
2357 				 path_segment_index );
2358 
2359 				goto on_error;
2360 			}
2361 		}
2362 		/* If the path is empty ignore the entry
2363 		 */
2364 		else if( path_string_segment_size <= 1 )
2365 		{
2366 			if( libcsplit_narrow_split_string_set_segment_by_index(
2367 			     path_split_string,
2368 			     path_segment_index,
2369 			     NULL,
2370 			     0,
2371 			     error ) != 1 )
2372 			{
2373 				libcerror_error_set(
2374 				 error,
2375 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2376 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2377 				 "%s: unable to set path string segment: %d.",
2378 				 function,
2379 				 path_segment_index );
2380 
2381 				goto on_error;
2382 			}
2383 		}
2384 		else
2385 		{
2386 			/* Add the size of the directory or file name and a directory separator
2387 			 * Note that the size includes the end of string character
2388 			 */
2389 			safe_full_path_size += path_string_segment_size;
2390 
2391 			last_used_path_segment_index = path_segment_index;
2392 		}
2393 	}
2394 	/* Note that the last path separator serves as the end of string
2395 	 */
2396 	full_path_index = 0;
2397 
2398 	*full_path = narrow_string_allocate(
2399 	              safe_full_path_size );
2400 
2401 	if( *full_path == NULL )
2402 	{
2403 		libcerror_error_set(
2404 		 error,
2405 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
2406 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
2407 		 "%s: unable to create full path.",
2408 		 function );
2409 
2410 		goto on_error;
2411 	}
2412 	if( memory_set(
2413 	     *full_path,
2414 	     0,
2415 	     sizeof( char ) * safe_full_path_size ) == NULL )
2416 	{
2417 		libcerror_error_set(
2418 		 error,
2419 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
2420 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
2421 		 "%s: unable to clear full path.",
2422 		 function );
2423 
2424 		goto on_error;
2425 	}
2426 	*full_path_size = safe_full_path_size;
2427 
2428 	if( path_type == LIBCPATH_TYPE_ABSOLUTE )
2429 	{
2430 		( *full_path )[ full_path_index ] = '/';
2431 
2432 		full_path_index += 1;
2433 	}
2434 	/* If the path is relative
2435 	 * add the current working directory elements
2436 	 */
2437 	if( ( path_type == LIBCPATH_TYPE_RELATIVE )
2438 	 && ( current_directory_split_string != NULL ) )
2439 	{
2440 		for( current_directory_segment_index = 0;
2441 		     current_directory_segment_index < current_directory_number_of_segments;
2442 		     current_directory_segment_index++ )
2443 		{
2444 			if( libcsplit_narrow_split_string_get_segment_by_index(
2445 			     current_directory_split_string,
2446 			     current_directory_segment_index,
2447 			     &current_directory_string_segment,
2448 			     &current_directory_string_segment_size,
2449 			     error ) != 1 )
2450 			{
2451 				libcerror_error_set(
2452 				 error,
2453 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2454 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2455 				 "%s: unable to retrieve current working directory string segment: %d.",
2456 				 function,
2457 				 current_directory_segment_index );
2458 
2459 				goto on_error;
2460 			}
2461 			if( current_directory_string_segment_size != 0 )
2462 			{
2463 				if( current_directory_string_segment == NULL )
2464 				{
2465 					libcerror_error_set(
2466 					 error,
2467 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2468 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2469 					 "%s: missing current working directory string segment: %d.",
2470 					 function,
2471 					 current_directory_segment_index );
2472 
2473 					goto on_error;
2474 				}
2475 				if( narrow_string_copy(
2476 				     &( ( *full_path )[ full_path_index ] ),
2477 				     current_directory_string_segment,
2478 				     current_directory_string_segment_size - 1 ) == NULL )
2479 				{
2480 					libcerror_error_set(
2481 					 error,
2482 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2483 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2484 					 "%s: unable to set current working directory split value: %d in full path.",
2485 					 function,
2486 					 current_directory_segment_index );
2487 
2488 					goto on_error;
2489 				}
2490 				full_path_index += current_directory_string_segment_size - 1;
2491 
2492 				( *full_path )[ full_path_index ] = '/';
2493 
2494 				full_path_index += 1;
2495 			}
2496 		}
2497 	}
2498 	for( path_segment_index = 0;
2499 	     path_segment_index < path_number_of_segments;
2500 	     path_segment_index++ )
2501 	{
2502 		if( libcsplit_narrow_split_string_get_segment_by_index(
2503 		     path_split_string,
2504 		     path_segment_index,
2505 		     &path_string_segment,
2506 		     &path_string_segment_size,
2507 		     error ) != 1 )
2508 		{
2509 			libcerror_error_set(
2510 			 error,
2511 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2512 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2513 			 "%s: unable to retrieve path string segment: %d.",
2514 			 function,
2515 			 path_segment_index );
2516 
2517 			goto on_error;
2518 		}
2519 		if( path_string_segment_size != 0 )
2520 		{
2521 			if( path_string_segment == NULL )
2522 			{
2523 				libcerror_error_set(
2524 				 error,
2525 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2526 				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2527 				 "%s: missing path string segment: %d.",
2528 				 function,
2529 				 path_segment_index );
2530 
2531 				goto on_error;
2532 			}
2533 			if( narrow_string_copy(
2534 			     &( ( *full_path )[ full_path_index ] ),
2535 			     path_string_segment,
2536 			     path_string_segment_size - 1 ) == NULL )
2537 			{
2538 				libcerror_error_set(
2539 				 error,
2540 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2541 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2542 				 "%s: unable to set path split value: %d in full path.",
2543 				 function,
2544 				 path_segment_index );
2545 
2546 				goto on_error;
2547 			}
2548 			full_path_index += path_string_segment_size - 1;
2549 
2550 			( *full_path )[ full_path_index ] = '/';
2551 
2552 			full_path_index += 1;
2553 		}
2554 	}
2555 	( *full_path )[ full_path_index - 1 ] = 0;
2556 
2557 	if( libcsplit_narrow_split_string_free(
2558 	     &path_split_string,
2559 	     error ) != 1 )
2560 	{
2561 		libcerror_error_set(
2562 		 error,
2563 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2564 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
2565 		 "%s: unable to free path split string.",
2566 		 function );
2567 
2568 		goto on_error;
2569 	}
2570 	if( current_directory_split_string != NULL )
2571 	{
2572 		if( libcsplit_narrow_split_string_free(
2573 		     &current_directory_split_string,
2574 		     error ) != 1 )
2575 		{
2576 			libcerror_error_set(
2577 			 error,
2578 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2579 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
2580 			 "%s: unable to free current working directory split string.",
2581 			 function );
2582 
2583 			goto on_error;
2584 		}
2585 	}
2586 	if( current_directory != NULL )
2587 	{
2588 		memory_free(
2589 		 current_directory );
2590 	}
2591 	return( 1 );
2592 
2593 on_error:
2594 	if( *full_path != NULL )
2595 	{
2596 		memory_free(
2597 		 *full_path );
2598 
2599 		*full_path = NULL;
2600 	}
2601 	*full_path_size = 0;
2602 
2603 	if( path_split_string != NULL )
2604 	{
2605 		libcsplit_narrow_split_string_free(
2606 		 &path_split_string,
2607 		 NULL );
2608 	}
2609 	if( current_directory_split_string != NULL )
2610 	{
2611 		libcsplit_narrow_split_string_free(
2612 		 &current_directory_split_string,
2613 		 NULL );
2614 	}
2615 	if( current_directory != NULL )
2616 	{
2617 		memory_free(
2618 		 current_directory );
2619 	}
2620 	return( -1 );
2621 }
2622 
2623 #endif /* defined( WINAPI ) */
2624 
2625 /* Retrieves the size of a sanitized version of the path character
2626  * Returns 1 if successful or -1 on error
2627  */
libcpath_path_get_sanitized_character_size(char character,size_t * sanitized_character_size,libcerror_error_t ** error)2628 int libcpath_path_get_sanitized_character_size(
2629      char character,
2630      size_t *sanitized_character_size,
2631      libcerror_error_t **error )
2632 {
2633 	static char *function = "libcpath_path_get_sanitized_character_size";
2634 
2635 	if( sanitized_character_size == NULL )
2636 	{
2637 		libcerror_error_set(
2638 		 error,
2639 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2640 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2641 		 "%s: invalid sanitized character size.",
2642 		 function );
2643 
2644 		return( -1 );
2645 	}
2646 	if( ( character >= 0x00 )
2647 	 && ( character <= 0x1f ) )
2648 	{
2649 		*sanitized_character_size = 4;
2650 	}
2651 	else if( character == LIBCPATH_ESCAPE_CHARACTER )
2652 	{
2653 		*sanitized_character_size = 2;
2654 	}
2655 #if defined( WINAPI )
2656 	else if( character == '/' )
2657 	{
2658 		*sanitized_character_size = 4;
2659 	}
2660 #endif
2661 	else if( ( character == '!' )
2662 	      || ( character == '$' )
2663 	      || ( character == '%' )
2664 	      || ( character == '&' )
2665 	      || ( character == '*' )
2666 	      || ( character == '+' )
2667 	      || ( character == ':' )
2668 	      || ( character == ';' )
2669 	      || ( character == '<' )
2670 	      || ( character == '>' )
2671 	      || ( character == '?' )
2672 	      || ( character == '|' )
2673 	      || ( character == 0x7f ) )
2674 	{
2675 		*sanitized_character_size = 4;
2676 	}
2677 	else
2678 	{
2679 		*sanitized_character_size = 1;
2680 	}
2681 	return( 1 );
2682 }
2683 
2684 /* Retrieves a sanitized version of the path character
2685  * Returns 1 if successful or -1 on error
2686  */
libcpath_path_get_sanitized_character(char character,size_t sanitized_character_size,char * sanitized_path,size_t sanitized_path_size,size_t * sanitized_path_index,libcerror_error_t ** error)2687 int libcpath_path_get_sanitized_character(
2688      char character,
2689      size_t sanitized_character_size,
2690      char *sanitized_path,
2691      size_t sanitized_path_size,
2692      size_t *sanitized_path_index,
2693      libcerror_error_t **error )
2694 {
2695 	static char *function            = "libcpath_path_get_sanitized_character";
2696 	size_t safe_sanitized_path_index = 0;
2697 	char lower_nibble                = 0;
2698 	char upper_nibble                = 0;
2699 
2700 	if( ( sanitized_character_size != 1 )
2701 	 && ( sanitized_character_size != 2 )
2702 	 && ( sanitized_character_size != 4 ) )
2703 	{
2704 		libcerror_error_set(
2705 		 error,
2706 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2707 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
2708 		 "%s: invalid sanitized character size value out of bounds.",
2709 		 function );
2710 
2711 		return( -1 );
2712 	}
2713 	if( sanitized_path == NULL )
2714 	{
2715 		libcerror_error_set(
2716 		 error,
2717 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2718 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2719 		 "%s: invalid sanitized path.",
2720 		 function );
2721 
2722 		return( -1 );
2723 	}
2724 	if( sanitized_path_size > (size_t) SSIZE_MAX )
2725 	{
2726 		libcerror_error_set(
2727 		 error,
2728 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2729 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
2730 		 "%s: invalid sanitized path size value exceeds maximum.",
2731 		 function );
2732 
2733 		return( -1 );
2734 	}
2735 	if( sanitized_path_index == NULL )
2736 	{
2737 		libcerror_error_set(
2738 		 error,
2739 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2740 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2741 		 "%s: invalid sanitized path index.",
2742 		 function );
2743 
2744 		return( -1 );
2745 	}
2746 	safe_sanitized_path_index = *sanitized_path_index;
2747 
2748 	if( safe_sanitized_path_index > sanitized_path_size )
2749 	{
2750 		libcerror_error_set(
2751 		 error,
2752 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2753 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
2754 		 "%s: invalid sanitized path index value out of bounds.",
2755 		 function );
2756 
2757 		return( -1 );
2758 	}
2759 	if( ( sanitized_character_size > sanitized_path_size )
2760 	 || ( safe_sanitized_path_index > ( sanitized_path_size - sanitized_character_size ) ) )
2761 	{
2762 		libcerror_error_set(
2763 		 error,
2764 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2765 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
2766 		 "%s: invalid sanitized path size value too small.",
2767 		 function );
2768 
2769 		return( -1 );
2770 	}
2771 	if( sanitized_character_size == 1 )
2772 	{
2773 		sanitized_path[ safe_sanitized_path_index++ ] = character;
2774 	}
2775 	else if( sanitized_character_size == 2 )
2776 	{
2777 		sanitized_path[ safe_sanitized_path_index++ ] = LIBCPATH_ESCAPE_CHARACTER;
2778 		sanitized_path[ safe_sanitized_path_index++ ] = LIBCPATH_ESCAPE_CHARACTER;
2779 	}
2780 	else if( sanitized_character_size == 4 )
2781 	{
2782 		lower_nibble = character & 0x0f;
2783 		upper_nibble = ( character >> 4 ) & 0x0f;
2784 
2785 		if( lower_nibble > 10 )
2786 		{
2787 			lower_nibble += 'a' - 10;
2788 		}
2789 		else
2790 		{
2791 			lower_nibble += '0';
2792 		}
2793 		if( upper_nibble > 10 )
2794 		{
2795 			upper_nibble += 'a' - 10;
2796 		}
2797 		else
2798 		{
2799 			upper_nibble += '0';
2800 		}
2801 		sanitized_path[ safe_sanitized_path_index++ ] = LIBCPATH_ESCAPE_CHARACTER;
2802 		sanitized_path[ safe_sanitized_path_index++ ] = 'x';
2803 		sanitized_path[ safe_sanitized_path_index++ ] = upper_nibble;
2804 		sanitized_path[ safe_sanitized_path_index++ ] = lower_nibble;
2805 	}
2806 	*sanitized_path_index = safe_sanitized_path_index;
2807 
2808 	return( 1 );
2809 }
2810 
2811 /* Retrieves a sanitized version of the filename
2812  * Returns 1 if successful or -1 on error
2813  */
libcpath_path_get_sanitized_filename(const char * filename,size_t filename_length,char ** sanitized_filename,size_t * sanitized_filename_size,libcerror_error_t ** error)2814 int libcpath_path_get_sanitized_filename(
2815      const char *filename,
2816      size_t filename_length,
2817      char **sanitized_filename,
2818      size_t *sanitized_filename_size,
2819      libcerror_error_t **error )
2820 {
2821 	static char *function               = "libcpath_path_get_sanitized_filename";
2822 	char *safe_sanitized_filename       = NULL;
2823 	size_t filename_index               = 0;
2824 	size_t sanitized_character_size     = 0;
2825 	size_t safe_sanitized_filename_size = 0;
2826 	size_t sanitized_filename_index     = 0;
2827 
2828 	if( filename == NULL )
2829 	{
2830 		libcerror_error_set(
2831 		 error,
2832 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2833 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2834 		 "%s: invalid filename.",
2835 		 function );
2836 
2837 		return( -1 );
2838 	}
2839 	if( filename_length == 0 )
2840 	{
2841 		libcerror_error_set(
2842 		 error,
2843 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2844 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
2845 		 "%s: invalid filename length is zero.",
2846 		 function );
2847 
2848 		return( -1 );
2849 	}
2850 	if( filename_length > (size_t) ( SSIZE_MAX - 1 ) )
2851 	{
2852 		libcerror_error_set(
2853 		 error,
2854 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2855 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
2856 		 "%s: invalid filename length value exceeds maximum.",
2857 		 function );
2858 
2859 		return( -1 );
2860 	}
2861 	if( sanitized_filename == NULL )
2862 	{
2863 		libcerror_error_set(
2864 		 error,
2865 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2866 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2867 		 "%s: invalid sanitized filename.",
2868 		 function );
2869 
2870 		return( -1 );
2871 	}
2872 	if( *sanitized_filename != NULL )
2873 	{
2874 		libcerror_error_set(
2875 		 error,
2876 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2877 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
2878 		 "%s: invalid sanitized filename value already set.",
2879 		 function );
2880 
2881 		return( -1 );
2882 	}
2883 	if( sanitized_filename_size == NULL )
2884 	{
2885 		libcerror_error_set(
2886 		 error,
2887 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2888 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2889 		 "%s: invalid sanitized filename size.",
2890 		 function );
2891 
2892 		return( -1 );
2893 	}
2894 	safe_sanitized_filename_size = 1;
2895 
2896 	for( filename_index = 0;
2897 	     filename_index < filename_length;
2898 	     filename_index++ )
2899 	{
2900 		if( filename[ filename_index ] == LIBCPATH_SEPARATOR )
2901 		{
2902 			sanitized_character_size = 4;
2903 		}
2904 		else if( libcpath_path_get_sanitized_character_size(
2905 		          filename[ filename_index ],
2906 		          &sanitized_character_size,
2907 		          error ) != 1 )
2908 		{
2909 			libcerror_error_set(
2910 			 error,
2911 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2912 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2913 			 "%s: unable to determine sanitize character size.",
2914 			 function );
2915 
2916 			goto on_error;
2917 		}
2918 		safe_sanitized_filename_size += sanitized_character_size;
2919 	}
2920 	if( safe_sanitized_filename_size > (size_t) SSIZE_MAX )
2921 	{
2922 		libcerror_error_set(
2923 		 error,
2924 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2925 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
2926 		 "%s: invalid sanitized filename size value exceeds maximum.",
2927 		 function );
2928 
2929 		goto on_error;
2930 	}
2931 	safe_sanitized_filename = narrow_string_allocate(
2932 	                           safe_sanitized_filename_size );
2933 
2934 	if( safe_sanitized_filename == NULL )
2935 	{
2936 		libcerror_error_set(
2937 		 error,
2938 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
2939 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
2940 		 "%s: unable to create sanitized filename.",
2941 		 function );
2942 
2943 		goto on_error;
2944 	}
2945 	for( filename_index = 0;
2946 	     filename_index < filename_length;
2947 	     filename_index++ )
2948 	{
2949 		if( filename[ filename_index ] == LIBCPATH_SEPARATOR )
2950 		{
2951 			sanitized_character_size = 4;
2952 		}
2953 		else if( libcpath_path_get_sanitized_character_size(
2954 		          filename[ filename_index ],
2955 		          &sanitized_character_size,
2956 		          error ) != 1 )
2957 		{
2958 			libcerror_error_set(
2959 			 error,
2960 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2961 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2962 			 "%s: unable to determine sanitize character size.",
2963 			 function );
2964 
2965 			goto on_error;
2966 		}
2967 		if( libcpath_path_get_sanitized_character(
2968 		     filename[ filename_index ],
2969 		     sanitized_character_size,
2970 		     safe_sanitized_filename,
2971 		     safe_sanitized_filename_size,
2972 		     &sanitized_filename_index,
2973 		     error ) != 1 )
2974 		{
2975 			libcerror_error_set(
2976 			 error,
2977 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2978 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2979 			 "%s: unable to determine sanitize character size.",
2980 			 function );
2981 
2982 			goto on_error;
2983 		}
2984 	}
2985 	safe_sanitized_filename[ sanitized_filename_index ] = 0;
2986 
2987 	*sanitized_filename      = safe_sanitized_filename;
2988 	*sanitized_filename_size = safe_sanitized_filename_size;
2989 
2990 	return( 1 );
2991 
2992 on_error:
2993 	if( safe_sanitized_filename != NULL )
2994 	{
2995 		memory_free(
2996 		 safe_sanitized_filename );
2997 	}
2998 	return( -1 );
2999 }
3000 
3001 /* Retrieves a sanitized version of the path
3002  * Returns 1 if successful or -1 on error
3003  */
libcpath_path_get_sanitized_path(const char * path,size_t path_length,char ** sanitized_path,size_t * sanitized_path_size,libcerror_error_t ** error)3004 int libcpath_path_get_sanitized_path(
3005      const char *path,
3006      size_t path_length,
3007      char **sanitized_path,
3008      size_t *sanitized_path_size,
3009      libcerror_error_t **error )
3010 {
3011 	static char *function                    = "libcpath_path_get_sanitized_path";
3012 	char *safe_sanitized_path                = NULL;
3013 	size_t path_index                        = 0;
3014 	size_t safe_sanitized_path_size          = 0;
3015 	size_t sanitized_character_size          = 0;
3016 	size_t sanitized_path_index              = 0;
3017 
3018 #if defined( WINAPI )
3019 	size_t last_path_segment_seperator_index = 0;
3020 #endif
3021 
3022 	if( path == NULL )
3023 	{
3024 		libcerror_error_set(
3025 		 error,
3026 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3027 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3028 		 "%s: invalid path.",
3029 		 function );
3030 
3031 		return( -1 );
3032 	}
3033 	if( path_length == 0 )
3034 	{
3035 		libcerror_error_set(
3036 		 error,
3037 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3038 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
3039 		 "%s: invalid path length is zero.",
3040 		 function );
3041 
3042 		return( -1 );
3043 	}
3044 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
3045 	{
3046 		libcerror_error_set(
3047 		 error,
3048 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3049 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
3050 		 "%s: invalid path length value exceeds maximum.",
3051 		 function );
3052 
3053 		return( -1 );
3054 	}
3055 	if( sanitized_path == NULL )
3056 	{
3057 		libcerror_error_set(
3058 		 error,
3059 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3060 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3061 		 "%s: invalid sanitized path.",
3062 		 function );
3063 
3064 		return( -1 );
3065 	}
3066 	if( *sanitized_path != NULL )
3067 	{
3068 		libcerror_error_set(
3069 		 error,
3070 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3071 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3072 		 "%s: invalid sanitized path value already set.",
3073 		 function );
3074 
3075 		return( -1 );
3076 	}
3077 	if( sanitized_path_size == NULL )
3078 	{
3079 		libcerror_error_set(
3080 		 error,
3081 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3082 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3083 		 "%s: invalid sanitized path size.",
3084 		 function );
3085 
3086 		return( -1 );
3087 	}
3088 	safe_sanitized_path_size = 1;
3089 
3090 	for( path_index = 0;
3091 	     path_index < path_length;
3092 	     path_index++ )
3093 	{
3094 		if( libcpath_path_get_sanitized_character_size(
3095 		     path[ path_index ],
3096 		     &sanitized_character_size,
3097 		     error ) != 1 )
3098 		{
3099 			libcerror_error_set(
3100 			 error,
3101 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3102 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3103 			 "%s: unable to determine sanitize character size.",
3104 			 function );
3105 
3106 			goto on_error;
3107 		}
3108 		safe_sanitized_path_size += sanitized_character_size;
3109 
3110 #if defined( WINAPI )
3111 		if( path[ path_index ] == LIBCPATH_SEPARATOR )
3112 		{
3113 			last_path_segment_seperator_index = path_index;
3114 		}
3115 #endif
3116 	}
3117 	if( safe_sanitized_path_size > (size_t) SSIZE_MAX )
3118 	{
3119 		libcerror_error_set(
3120 		 error,
3121 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3122 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
3123 		 "%s: invalid sanitized path size value exceeds maximum.",
3124 		 function );
3125 
3126 		goto on_error;
3127 	}
3128 #if defined( WINAPI )
3129 	if( last_path_segment_seperator_index > 32767 )
3130 	{
3131 		libcerror_error_set(
3132 		 error,
3133 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3134 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
3135 		 "%s: last path segment separator value out of bounds.",
3136 		 function );
3137 
3138 		goto on_error;
3139 	}
3140 	if( safe_sanitized_path_size > 32767 )
3141 	{
3142 		safe_sanitized_path_size = 32767;
3143 	}
3144 #endif
3145 	safe_sanitized_path = narrow_string_allocate(
3146 	                       safe_sanitized_path_size );
3147 
3148 	if( safe_sanitized_path == NULL )
3149 	{
3150 		libcerror_error_set(
3151 		 error,
3152 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3153 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
3154 		 "%s: unable to create sanitized path.",
3155 		 function );
3156 
3157 		goto on_error;
3158 	}
3159 	for( path_index = 0;
3160 	     path_index < path_length;
3161 	     path_index++ )
3162 	{
3163 		if( libcpath_path_get_sanitized_character_size(
3164 		     path[ path_index ],
3165 		     &sanitized_character_size,
3166 		     error ) != 1 )
3167 		{
3168 			libcerror_error_set(
3169 			 error,
3170 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3171 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3172 			 "%s: unable to determine sanitize character size.",
3173 			 function );
3174 
3175 			goto on_error;
3176 		}
3177 		if( libcpath_path_get_sanitized_character(
3178 		     path[ path_index ],
3179 		     sanitized_character_size,
3180 		     safe_sanitized_path,
3181 		     safe_sanitized_path_size,
3182 		     &sanitized_path_index,
3183 		     error ) != 1 )
3184 		{
3185 			libcerror_error_set(
3186 			 error,
3187 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3188 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3189 			 "%s: unable to determine sanitize character size.",
3190 			 function );
3191 
3192 			goto on_error;
3193 		}
3194 	}
3195 	safe_sanitized_path[ sanitized_path_index ] = 0;
3196 
3197 	*sanitized_path      = safe_sanitized_path;
3198 	*sanitized_path_size = safe_sanitized_path_size;
3199 
3200 	return( 1 );
3201 
3202 on_error:
3203 	if( safe_sanitized_path != NULL )
3204 	{
3205 		memory_free(
3206 		 safe_sanitized_path );
3207 	}
3208 	return( -1 );
3209 }
3210 
3211 /* Combines the directory name and filename into a path
3212  * Returns 1 if successful or -1 on error
3213  */
libcpath_path_join(char ** path,size_t * path_size,const char * directory_name,size_t directory_name_length,const char * filename,size_t filename_length,libcerror_error_t ** error)3214 int libcpath_path_join(
3215      char **path,
3216      size_t *path_size,
3217      const char *directory_name,
3218      size_t directory_name_length,
3219      const char *filename,
3220      size_t filename_length,
3221      libcerror_error_t **error )
3222 {
3223 	static char *function = "libcpath_path_join";
3224 	size_t filename_index = 0;
3225 	size_t path_index     = 0;
3226 
3227 	if( path == NULL )
3228 	{
3229 		libcerror_error_set(
3230 		 error,
3231 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3232 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3233 		 "%s: invalid path.",
3234 		 function );
3235 
3236 		return( -1 );
3237 	}
3238 	if( *path != NULL )
3239 	{
3240 		libcerror_error_set(
3241 		 error,
3242 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3243 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3244 		 "%s: invalid path value already set.",
3245 		 function );
3246 
3247 		return( -1 );
3248 	}
3249 	if( path_size == NULL )
3250 	{
3251 		libcerror_error_set(
3252 		 error,
3253 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3254 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3255 		 "%s: invalid path size.",
3256 		 function );
3257 
3258 		return( -1 );
3259 	}
3260 	if( directory_name == NULL )
3261 	{
3262 		libcerror_error_set(
3263 		 error,
3264 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3265 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3266 		 "%s: invalid directory name.",
3267 		 function );
3268 
3269 		return( -1 );
3270 	}
3271 	if( directory_name_length > (size_t) SSIZE_MAX )
3272 	{
3273 		libcerror_error_set(
3274 		 error,
3275 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3276 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
3277 		 "%s: invalid directory name length value exceeds maximum.",
3278 		 function );
3279 
3280 		return( -1 );
3281 	}
3282 	if( filename == NULL )
3283 	{
3284 		libcerror_error_set(
3285 		 error,
3286 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3287 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3288 		 "%s: invalid filename.",
3289 		 function );
3290 
3291 		return( -1 );
3292 	}
3293 	if( filename_length > (size_t) SSIZE_MAX )
3294 	{
3295 		libcerror_error_set(
3296 		 error,
3297 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3298 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
3299 		 "%s: invalid filename length value exceeds maximum.",
3300 		 function );
3301 
3302 		return( -1 );
3303 	}
3304 /* TODO strip other patterns like /./ */
3305 	while( directory_name_length > 0 )
3306 	{
3307 		if( directory_name[ directory_name_length - 1 ] != (char) LIBCPATH_SEPARATOR )
3308 		{
3309 			break;
3310 		}
3311 		directory_name_length--;
3312 	}
3313 	while( filename_length > 0 )
3314 	{
3315 		if( filename[ filename_index ] != (char) LIBCPATH_SEPARATOR )
3316 		{
3317 			break;
3318 		}
3319 		filename_index++;
3320 		filename_length--;
3321 	}
3322 	*path_size = directory_name_length + filename_length + 2;
3323 
3324 	*path = narrow_string_allocate(
3325 	         *path_size );
3326 
3327 	if( *path == NULL )
3328 	{
3329 		libcerror_error_set(
3330 		 error,
3331 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3332 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
3333 		 "%s: unable to create path.",
3334 		 function );
3335 
3336 		goto on_error;
3337 	}
3338 	if( narrow_string_copy(
3339 	     *path,
3340 	     directory_name,
3341 	     directory_name_length ) == NULL )
3342 	{
3343 		libcerror_error_set(
3344 		 error,
3345 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3346 		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
3347 		 "%s: unable to copy directory name to path.",
3348 		 function );
3349 
3350 		goto on_error;
3351 	}
3352 	path_index = directory_name_length;
3353 
3354 	( *path )[ path_index++ ] = (char) LIBCPATH_SEPARATOR;
3355 
3356 	if( narrow_string_copy(
3357 	     &( ( *path )[ path_index ] ),
3358 	     &( filename[ filename_index ] ),
3359 	     filename_length ) == NULL )
3360 	{
3361 		libcerror_error_set(
3362 		 error,
3363 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3364 		 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
3365 		 "%s: unable to copy filename to path.",
3366 		 function );
3367 
3368 		goto on_error;
3369 	}
3370 	path_index += filename_length;
3371 
3372 	( *path )[ path_index ] = 0;
3373 
3374 	return( 1 );
3375 
3376 on_error:
3377 	if( *path != NULL )
3378 	{
3379 		memory_free(
3380 		 *path );
3381 
3382 		*path = NULL;
3383 	}
3384 	*path_size = 0;
3385 
3386 	return( -1 );
3387 }
3388 
3389 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
3390 
3391 /* Cross Windows safe version of CreateDirectoryA
3392  * Returns TRUE if successful or FALSE on error
3393  */
libcpath_CreateDirectoryA(LPCSTR path,SECURITY_ATTRIBUTES * security_attributes)3394 BOOL libcpath_CreateDirectoryA(
3395       LPCSTR path,
3396       SECURITY_ATTRIBUTES *security_attributes )
3397 {
3398 	FARPROC function       = NULL;
3399 	HMODULE library_handle = NULL;
3400 	BOOL result            = FALSE;
3401 
3402 	if( path == NULL )
3403 	{
3404 		return( 0 );
3405 	}
3406 	library_handle = LoadLibrary(
3407 	                  _SYSTEM_STRING( "kernel32.dll" ) );
3408 
3409 	if( library_handle == NULL )
3410 	{
3411 		return( 0 );
3412 	}
3413 	function = GetProcAddress(
3414 		    library_handle,
3415 		    (LPCSTR) "CreateDirectoryA" );
3416 
3417 	if( function != NULL )
3418 	{
3419 		result = function(
3420 			  path,
3421 			  security_attributes );
3422 	}
3423 	/* This call should be after using the function
3424 	 * in most cases kernel32.dll will still be available after free
3425 	 */
3426 	if( FreeLibrary(
3427 	     library_handle ) != TRUE )
3428 	{
3429 		libcpath_CloseHandle(
3430 		 library_handle );
3431 
3432 		return( 0 );
3433 	}
3434 	return( result );
3435 }
3436 
3437 #endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
3438 
3439 #if defined( WINAPI )
3440 
3441 /* Makes the directory
3442  * This function uses the WINAPI function for Windows XP (0x0501) or later
3443  * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
3444  * Returns 1 if successful or -1 on error
3445  */
libcpath_path_make_directory(const char * directory_name,libcerror_error_t ** error)3446 int libcpath_path_make_directory(
3447      const char *directory_name,
3448      libcerror_error_t **error )
3449 {
3450 	static char *function = "libcpath_path_make_directory";
3451 	DWORD error_code      = 0;
3452 
3453 	if( directory_name == NULL )
3454 	{
3455 		libcerror_error_set(
3456 		 error,
3457 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3458 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3459 		 "%s: invalid directory name.",
3460 		 function );
3461 
3462 		return( -1 );
3463 	}
3464 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
3465 	if( libcpath_CreateDirectoryA(
3466 	     directory_name,
3467 	     NULL ) == 0 )
3468 #else
3469 	if( CreateDirectoryA(
3470 	     directory_name,
3471 	     NULL ) == 0 )
3472 #endif
3473 	{
3474 		error_code = GetLastError();
3475 
3476 		libcerror_system_set_error(
3477 		 error,
3478 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3479 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3480 		 error_code,
3481 		 "%s: unable to make directory.",
3482 		 function );
3483 
3484 		return( -1 );
3485 	}
3486 	return( 1 );
3487 }
3488 
3489 #elif defined( HAVE_MKDIR )
3490 
3491 /* Makes the directory
3492  * This function uses the POSIX mkdir function or equivalent
3493  * Returns 1 if successful or -1 on error
3494  */
libcpath_path_make_directory(const char * directory_name,libcerror_error_t ** error)3495 int libcpath_path_make_directory(
3496      const char *directory_name,
3497      libcerror_error_t **error )
3498 {
3499 	static char *function = "libcpath_path_make_directory";
3500 
3501 	if( directory_name == NULL )
3502 	{
3503 		libcerror_error_set(
3504 		 error,
3505 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3506 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3507 		 "%s: invalid directory name.",
3508 		 function );
3509 
3510 		return( -1 );
3511 	}
3512 	if( mkdir(
3513 	     directory_name,
3514 	     0755 ) != 0 )
3515 	{
3516 		libcerror_system_set_error(
3517 		 error,
3518 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3519 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3520 		 errno,
3521 		 "%s: unable to make directory.",
3522 		 function );
3523 
3524 		return( -1 );
3525 	}
3526 
3527 	return( 1 );
3528 }
3529 
3530 #else
3531 #error Missing make directory function
3532 #endif
3533 
3534 #if defined( HAVE_WIDE_CHARACTER_TYPE )
3535 
3536 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
3537 
3538 /* Cross Windows safe version of SetCurrentDirectoryW
3539  * Returns TRUE if successful or FALSE on error
3540  */
libcpath_SetCurrentDirectoryW(LPCWSTR path)3541 BOOL libcpath_SetCurrentDirectoryW(
3542       LPCWSTR path )
3543 {
3544 	FARPROC function       = NULL;
3545 	HMODULE library_handle = NULL;
3546 	BOOL result            = FALSE;
3547 
3548 	if( path == NULL )
3549 	{
3550 		return( FALSE );
3551 	}
3552 	library_handle = LoadLibrary(
3553 	                  _SYSTEM_STRING( "kernel32.dll" ) );
3554 
3555 	if( library_handle == NULL )
3556 	{
3557 		return( FALSE );
3558 	}
3559 	function = GetProcAddress(
3560 		    library_handle,
3561 		    (LPCSTR) "SetCurrentDirectoryW" );
3562 
3563 	if( function != NULL )
3564 	{
3565 		result = function(
3566 			  path );
3567 	}
3568 	/* This call should be after using the function
3569 	 * in most cases kernel32.dll will still be available after free
3570 	 */
3571 	if( FreeLibrary(
3572 	     library_handle ) != TRUE )
3573 	{
3574 		libcpath_CloseHandle(
3575 		 library_handle );
3576 
3577 		return( FALSE );
3578 	}
3579 	return( result );
3580 }
3581 
3582 #endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
3583 
3584 #if defined( WINAPI )
3585 
3586 /* Changes the directory
3587  * This function uses the WINAPI function for Windows XP (0x0501) or later
3588  * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
3589  * Returns 1 if successful or -1 on error
3590  */
libcpath_path_change_directory_wide(const wchar_t * directory_name,libcerror_error_t ** error)3591 int libcpath_path_change_directory_wide(
3592      const wchar_t *directory_name,
3593      libcerror_error_t **error )
3594 {
3595 	static char *function = "libcpath_path_change_directory_wide";
3596 	DWORD error_code      = 0;
3597 
3598 	if( directory_name == NULL )
3599 	{
3600 		libcerror_error_set(
3601 		 error,
3602 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3603 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3604 		 "%s: invalid directory name.",
3605 		 function );
3606 
3607 		return( -1 );
3608 	}
3609 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
3610 	if( libcpath_SetCurrentDirectoryW(
3611 	     directory_name ) == 0 )
3612 #else
3613 	if( SetCurrentDirectoryW(
3614 	     directory_name ) == 0 )
3615 #endif
3616 	{
3617 		error_code = GetLastError();
3618 
3619 		libcerror_system_set_error(
3620 		 error,
3621 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3622 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3623 		 error_code,
3624 		 "%s: unable to change directory.",
3625 		 function );
3626 
3627 		return( -1 );
3628 	}
3629 	return( 1 );
3630 }
3631 
3632 #elif defined( HAVE_CHDIR )
3633 
3634 /* Changes the directory
3635  * This function uses the POSIX chdir function or equivalent
3636  * Returns 1 if successful or -1 on error
3637  */
libcpath_path_change_directory_wide(const wchar_t * directory_name,libcerror_error_t ** error)3638 int libcpath_path_change_directory_wide(
3639      const wchar_t *directory_name,
3640      libcerror_error_t **error )
3641 {
3642 	static char *function             = "libcpath_path_change_directory_wide";
3643 	char *narrow_directory_name       = 0;
3644 	size_t directory_name_length      = 0;
3645 	size_t narrow_directory_name_size = 0;
3646 
3647 	if( directory_name == NULL )
3648 	{
3649 		libcerror_error_set(
3650 		 error,
3651 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3652 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3653 		 "%s: invalid directory name.",
3654 		 function );
3655 
3656 		return( -1 );
3657 	}
3658 	directory_name_length = wide_string_length(
3659 	                         directory_name );
3660 
3661 	if( libcpath_system_string_size_from_wide_string(
3662 	     directory_name,
3663 	     directory_name_length + 1,
3664 	     &narrow_directory_name_size,
3665 	     error ) != 1 )
3666 	{
3667 		libcerror_error_set(
3668 		 error,
3669 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
3670 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
3671 		 "%s: unable to determine narrow directory name size.",
3672 		 function );
3673 
3674 		goto on_error;
3675 	}
3676 	if( ( narrow_directory_name_size > (size_t) SSIZE_MAX )
3677 	 || ( ( sizeof( char ) * narrow_directory_name_size )  > (size_t) SSIZE_MAX ) )
3678 	{
3679 		libcerror_error_set(
3680 		 error,
3681 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3682 		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
3683 		 "%s: invalid narrow directory name size value exceeds maximum.",
3684 		 function );
3685 
3686 		goto on_error;
3687 	}
3688 	narrow_directory_name = narrow_string_allocate(
3689 	                         narrow_directory_name_size );
3690 
3691 	if( narrow_directory_name == NULL )
3692 	{
3693 		libcerror_error_set(
3694 		 error,
3695 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3696 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
3697 		 "%s: unable to create narrow directory name.",
3698 		 function );
3699 
3700 		goto on_error;
3701 	}
3702 	if( libcpath_system_string_copy_from_wide_string(
3703 	     narrow_directory_name,
3704 	     narrow_directory_name_size,
3705 	     directory_name,
3706 	     directory_name_length + 1,
3707 	     error ) != 1 )
3708 	{
3709 		libcerror_error_set(
3710 		 error,
3711 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
3712 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
3713 		 "%s: unable to set name.",
3714 		 function );
3715 
3716 		goto on_error;
3717 	}
3718 	if( chdir(
3719 	     narrow_directory_name ) != 0 )
3720 	{
3721 		libcerror_system_set_error(
3722 		 error,
3723 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3724 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3725 		 errno,
3726 		 "%s: unable to change directory.",
3727 		 function );
3728 
3729 		return( -1 );
3730 	}
3731 	memory_free(
3732 	 narrow_directory_name );
3733 
3734 	return( 1 );
3735 
3736 on_error:
3737 	if( narrow_directory_name != NULL )
3738 	{
3739 		memory_free(
3740 		 narrow_directory_name );
3741 	}
3742 	return( -1 );
3743 }
3744 
3745 #else
3746 #error Missing change directory function
3747 #endif
3748 
3749 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
3750 
3751 /* Cross Windows safe version of GetCurrentDirectoryW
3752  * Returns the number of characters in the current directory string or 0 on error
3753  */
libcpath_GetCurrentDirectoryW(DWORD buffer_size,LPCWSTR buffer)3754 DWORD libcpath_GetCurrentDirectoryW(
3755        DWORD buffer_size,
3756        LPCWSTR buffer )
3757 {
3758 	FARPROC function       = NULL;
3759 	HMODULE library_handle = NULL;
3760 	DWORD result           = 0;
3761 
3762 	library_handle = LoadLibrary(
3763 	                  _SYSTEM_STRING( "kernel32.dll" ) );
3764 
3765 	if( library_handle == NULL )
3766 	{
3767 		return( 0 );
3768 	}
3769 	function = GetProcAddress(
3770 		    library_handle,
3771 		    (LPCSTR) "GetCurrentDirectoryW" );
3772 
3773 	if( function != NULL )
3774 	{
3775 		result = function(
3776 			  buffer_size,
3777 			  buffer );
3778 	}
3779 	/* This call should be after using the function
3780 	 * in most cases kernel32.dll will still be available after free
3781 	 */
3782 	if( FreeLibrary(
3783 	     library_handle ) != TRUE )
3784 	{
3785 		libcpath_CloseHandle(
3786 		 library_handle );
3787 
3788 		return( 0 );
3789 	}
3790 	return( result );
3791 }
3792 
3793 #endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
3794 
3795 #if defined( WINAPI )
3796 
3797 /* Retrieves the current working directory
3798  * This function uses the WINAPI function for Windows XP (0x0501) or later
3799  * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
3800  * Returns 1 if successful or -1 on error
3801  */
libcpath_path_get_current_working_directory_wide(wchar_t ** current_working_directory,size_t * current_working_directory_size,libcerror_error_t ** error)3802 int libcpath_path_get_current_working_directory_wide(
3803      wchar_t **current_working_directory,
3804      size_t *current_working_directory_size,
3805      libcerror_error_t **error )
3806 {
3807 	static char *function                     = "libcpath_path_get_current_working_directory_wide";
3808 	DWORD safe_current_working_directory_size = 0;
3809 	DWORD error_code                          = 0;
3810 
3811 	if( current_working_directory == NULL )
3812 	{
3813 		libcerror_error_set(
3814 		 error,
3815 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3816 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3817 		 "%s: invalid current working directory.",
3818 		 function );
3819 
3820 		return( -1 );
3821 	}
3822 	if( *current_working_directory != NULL )
3823 	{
3824 		libcerror_error_set(
3825 		 error,
3826 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3827 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3828 		 "%s: invalid current working directory value already set.",
3829 		 function );
3830 
3831 		return( -1 );
3832 	}
3833 	if( current_working_directory_size == NULL )
3834 	{
3835 		libcerror_error_set(
3836 		 error,
3837 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3838 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3839 		 "%s: invalid current working directory size.",
3840 		 function );
3841 
3842 		return( -1 );
3843 	}
3844 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
3845 	safe_current_working_directory_size = libcpath_GetCurrentDirectoryW(
3846 	                                       0,
3847 	                                       NULL );
3848 #else
3849 	safe_current_working_directory_size = GetCurrentDirectoryW(
3850 	                                       0,
3851 	                                       NULL );
3852 #endif
3853 	if( safe_current_working_directory_size == 0 )
3854 	{
3855 		libcerror_error_set(
3856 		 error,
3857 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3858 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3859 		 "%s: unable to retrieve current working directory size.",
3860 		 function );
3861 
3862 		goto on_error;
3863 	}
3864 	if( (size_t) safe_current_working_directory_size > (size_t) SSIZE_MAX )
3865 	{
3866 		libcerror_error_set(
3867 		 error,
3868 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3869 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
3870 		 "%s: current working directory size value out of bounds.",
3871 		 function );
3872 
3873 		goto on_error;
3874 	}
3875 	*current_working_directory_size = (size_t) safe_current_working_directory_size;
3876 
3877 	*current_working_directory = wide_string_allocate(
3878 	                              *current_working_directory_size );
3879 
3880 	if( *current_working_directory == NULL )
3881 	{
3882 		libcerror_error_set(
3883 		 error,
3884 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3885 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
3886 		 "%s: unable to create current working directory.",
3887 		 function );
3888 
3889 		goto on_error;
3890 	}
3891 	if( memory_set(
3892 	     *current_working_directory,
3893 	     0,
3894 	     sizeof( wchar_t ) * *current_working_directory_size ) == NULL )
3895 	{
3896 		libcerror_error_set(
3897 		 error,
3898 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3899 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
3900 		 "%s: unable to clear current working directory.",
3901 		 function );
3902 
3903 		goto on_error;
3904 	}
3905 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
3906 	if( libcpath_GetCurrentDirectoryW(
3907 	     safe_current_working_directory_size,
3908 	     *current_working_directory ) != ( safe_current_working_directory_size - 1 ) )
3909 #else
3910 	if( GetCurrentDirectoryW(
3911 	     safe_current_working_directory_size,
3912 	     *current_working_directory ) != ( safe_current_working_directory_size - 1 ) )
3913 #endif
3914 	{
3915 		error_code = GetLastError();
3916 
3917 		libcerror_system_set_error(
3918 		 error,
3919 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3920 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3921 		 error_code,
3922 		 "%s: unable to retrieve current working directory.",
3923 		 function );
3924 
3925 		goto on_error;
3926 	}
3927 	return( 1 );
3928 
3929 on_error:
3930 	if( *current_working_directory != NULL )
3931 	{
3932 		memory_free(
3933 		 *current_working_directory );
3934 
3935 		*current_working_directory = NULL;
3936 	}
3937 	*current_working_directory_size = 0;
3938 
3939 	return( -1 );
3940 }
3941 
3942 #elif defined( HAVE_GETCWD )
3943 
3944 /* Retrieves the current working directory
3945  * This function uses the POSIX getcwd function or equivalent
3946  * Returns 1 if successful or -1 on error
3947  */
libcpath_path_get_current_working_directory_wide(wchar_t ** current_working_directory,size_t * current_working_directory_size,libcerror_error_t ** error)3948 int libcpath_path_get_current_working_directory_wide(
3949      wchar_t **current_working_directory,
3950      size_t *current_working_directory_size,
3951      libcerror_error_t **error )
3952 {
3953 	static char *function                          = "libcpath_path_get_current_working_directory_wide";
3954 	char *narrow_current_working_directory         = 0;
3955 	size_t narrow_current_working_directory_length = 0;
3956 
3957 	if( current_working_directory == NULL )
3958 	{
3959 		libcerror_error_set(
3960 		 error,
3961 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3962 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3963 		 "%s: invalid current working directory.",
3964 		 function );
3965 
3966 		return( -1 );
3967 	}
3968 	if( *current_working_directory != NULL )
3969 	{
3970 		libcerror_error_set(
3971 		 error,
3972 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3973 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3974 		 "%s: invalid current working directory value already set.",
3975 		 function );
3976 
3977 		return( -1 );
3978 	}
3979 	if( current_working_directory_size == NULL )
3980 	{
3981 		libcerror_error_set(
3982 		 error,
3983 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3984 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3985 		 "%s: invalid current working directory size.",
3986 		 function );
3987 
3988 		return( -1 );
3989 	}
3990 	narrow_current_working_directory = narrow_string_allocate(
3991 	                                    PATH_MAX );
3992 
3993 	if( narrow_current_working_directory == NULL )
3994 	{
3995 		libcerror_error_set(
3996 		 error,
3997 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3998 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
3999 		 "%s: unable to create narrow current working directory.",
4000 		 function );
4001 
4002 		goto on_error;
4003 	}
4004 	if( getcwd(
4005 	     narrow_current_working_directory,
4006 	     PATH_MAX ) == NULL )
4007 	{
4008 		libcerror_system_set_error(
4009 		 error,
4010 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4011 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4012 		 errno,
4013 		 "%s: unable to retrieve current working directory.",
4014 		 function );
4015 
4016 		goto on_error;
4017 	}
4018 	narrow_current_working_directory_length = narrow_string_length(
4019 	                                           narrow_current_working_directory );
4020 
4021 	/* Convert the current working directory to a wide string
4022 	 * if the platform has no wide character open function
4023 	 */
4024 	if( libcpath_system_string_size_from_narrow_string(
4025 	     narrow_current_working_directory,
4026 	     narrow_current_working_directory_length + 1,
4027 	     current_working_directory_size,
4028 	     error ) != 1 )
4029 	{
4030 		libcerror_error_set(
4031 		 error,
4032 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
4033 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
4034 		 "%s: unable to determine wide character current working directory size.",
4035 		 function );
4036 
4037 		return( -1 );
4038 	}
4039 	*current_working_directory = wide_string_allocate(
4040 	                              *current_working_directory_size );
4041 
4042 	if( *current_working_directory == NULL )
4043 	{
4044 		libcerror_error_set(
4045 		 error,
4046 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
4047 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
4048 		 "%s: unable to create current working directory.",
4049 		 function );
4050 
4051 		goto on_error;
4052 	}
4053 	if( memory_set(
4054 	     *current_working_directory,
4055 	     0,
4056 	     sizeof( wchar_t ) * *current_working_directory_size ) == NULL )
4057 	{
4058 		libcerror_error_set(
4059 		 error,
4060 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
4061 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
4062 		 "%s: unable to clear current working directory.",
4063 		 function );
4064 
4065 		goto on_error;
4066 	}
4067 	if( libcpath_system_string_copy_to_wide_string(
4068 	     narrow_current_working_directory,
4069 	     narrow_current_working_directory_length + 1,
4070 	     *current_working_directory,
4071 	     *current_working_directory_size,
4072 	     error ) != 1 )
4073 	{
4074 		libcerror_error_set(
4075 		 error,
4076 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
4077 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
4078 		 "%s: unable to set current working directory.",
4079 		 function );
4080 
4081 		goto on_error;
4082 	}
4083 	memory_free(
4084 	 narrow_current_working_directory );
4085 
4086 	return( 1 );
4087 
4088 on_error:
4089 	if( narrow_current_working_directory != NULL )
4090 	{
4091 		memory_free(
4092 		 narrow_current_working_directory );
4093 	}
4094 	if( *current_working_directory != NULL )
4095 	{
4096 		memory_free(
4097 		 *current_working_directory );
4098 
4099 		*current_working_directory = NULL;
4100 	}
4101 	*current_working_directory_size = 0;
4102 
4103 	return( -1 );
4104 }
4105 
4106 #else
4107 #error Missing get current working directory function
4108 #endif
4109 
4110 #if defined( WINAPI )
4111 
4112 /* Determines the path type
4113  * Returns 1 if succesful or -1 on error
4114  */
libcpath_path_get_path_type_wide(const wchar_t * path,size_t path_length,uint8_t * path_type,libcerror_error_t ** error)4115 int libcpath_path_get_path_type_wide(
4116      const wchar_t *path,
4117      size_t path_length,
4118      uint8_t *path_type,
4119      libcerror_error_t **error )
4120 {
4121 	static char *function = "libcpath_path_get_path_type_wide";
4122 
4123 	if( path == NULL )
4124 	{
4125 		libcerror_error_set(
4126 		 error,
4127 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4128 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4129 		 "%s: invalid path.",
4130 		 function );
4131 
4132 		return( -1 );
4133 	}
4134 	if( path_length == 0 )
4135 	{
4136 		libcerror_error_set(
4137 		 error,
4138 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4139 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
4140 		 "%s: invalid path length is zero.",
4141 		 function );
4142 
4143 		return( -1 );
4144 	}
4145 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
4146 	{
4147 		libcerror_error_set(
4148 		 error,
4149 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4150 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
4151 		 "%s: invalid path length value exceeds maximum.",
4152 		 function );
4153 
4154 		return( -1 );
4155 	}
4156 	if( path_type == NULL )
4157 	{
4158 		libcerror_error_set(
4159 		 error,
4160 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4161 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4162 		 "%s: invalid path type.",
4163 		 function );
4164 
4165 		return( -1 );
4166 	}
4167 	*path_type = LIBCPATH_TYPE_RELATIVE;
4168 
4169 	/* Determine if the path is a special path
4170 	 * device path prefix:          \\.\
4171 	 * extended-length path prefix: \\?\
4172 	 */
4173 	if( ( path_length >= 4 )
4174 	 && ( path[ 0 ] == (wchar_t) '\\' )
4175 	 && ( path[ 1 ] == (wchar_t) '\\' )
4176 	 && ( ( path[ 2 ] == (wchar_t) '.' )
4177 	  ||  ( path[ 2 ] == (wchar_t) '?' ) )
4178 	 && ( path[ 3 ] == (wchar_t) '\\' ) )
4179 	{
4180 		if( path[ 2 ] == (wchar_t) '.' )
4181 		{
4182 			*path_type = LIBCPATH_TYPE_DEVICE;
4183 		}
4184 		/* Determine if the path in an extended-length UNC path
4185 		 * \\?\UNC\server\share
4186 		 */
4187 		else if( ( path_length >= 8 )
4188 		      && ( path[ 4 ] == (wchar_t) 'U' )
4189 		      && ( path[ 5 ] == (wchar_t) 'N' )
4190 		      && ( path[ 6 ] == (wchar_t) 'C' )
4191 		      && ( path[ 7 ] == (wchar_t) '\\' ) )
4192 		{
4193 			*path_type = LIBCPATH_TYPE_EXTENDED_LENGTH_UNC;
4194 		}
4195 		else
4196 		{
4197 			*path_type = LIBCPATH_TYPE_EXTENDED_LENGTH;
4198 		}
4199 	}
4200 	/* Determine if the path is an UNC path
4201 	 * \\server\share
4202 	 */
4203 	else if( ( path_length >= 2 )
4204 	      && ( path[ 0 ] == (wchar_t) '\\' )
4205 	      && ( path[ 1 ] == (wchar_t) '\\' ) )
4206 	{
4207 		*path_type = LIBCPATH_TYPE_UNC;
4208 	}
4209 	else if( path[ 0 ] == (wchar_t) '\\' )
4210 	{
4211 		*path_type = LIBCPATH_TYPE_ABSOLUTE;
4212 	}
4213 	else if( ( path_length >= 3 )
4214 	      && ( path[ 1 ] == (wchar_t) ':' )
4215 	      && ( path[ 2 ] == (wchar_t) '\\' )
4216 	      && ( ( ( path[ 0 ] >= (wchar_t) 'A' )
4217 	        &&   ( path[ 0 ] <= (wchar_t) 'Z' ) )
4218 	       ||  ( ( path[ 0 ] >= (wchar_t) 'a' )
4219 	        &&   ( path[ 0 ] <= (wchar_t) 'z' ) ) ) )
4220 	{
4221 		*path_type = LIBCPATH_TYPE_ABSOLUTE;
4222 	}
4223 	return( 1 );
4224 }
4225 
4226 /* Determines the volume name
4227  * Returns 1 if succesful or -1 on error
4228  */
libcpath_path_get_volume_name_wide(const wchar_t * path,size_t path_length,wchar_t ** volume_name,size_t * volume_name_length,size_t * directory_name_index,libcerror_error_t ** error)4229 int libcpath_path_get_volume_name_wide(
4230      const wchar_t *path,
4231      size_t path_length,
4232      wchar_t **volume_name,
4233      size_t *volume_name_length,
4234      size_t *directory_name_index,
4235      libcerror_error_t **error )
4236 {
4237 	static char *function    = "libcpath_path_get_volume_name_wide";
4238 	size_t path_index        = 0;
4239 	size_t share_name_index  = 0;
4240 	size_t volume_name_index = 0;
4241 
4242 	if( path == NULL )
4243 	{
4244 		libcerror_error_set(
4245 		 error,
4246 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4247 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4248 		 "%s: invalid path.",
4249 		 function );
4250 
4251 		return( -1 );
4252 	}
4253 	if( path_length == 0 )
4254 	{
4255 		libcerror_error_set(
4256 		 error,
4257 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4258 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
4259 		 "%s: invalid path length is zero.",
4260 		 function );
4261 
4262 		return( -1 );
4263 	}
4264 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
4265 	{
4266 		libcerror_error_set(
4267 		 error,
4268 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4269 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
4270 		 "%s: invalid path length value exceeds maximum.",
4271 		 function );
4272 
4273 		return( -1 );
4274 	}
4275 	if( volume_name == NULL )
4276 	{
4277 		libcerror_error_set(
4278 		 error,
4279 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4280 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4281 		 "%s: invalid volume name.",
4282 		 function );
4283 
4284 		return( -1 );
4285 	}
4286 	if( volume_name_length == NULL )
4287 	{
4288 		libcerror_error_set(
4289 		 error,
4290 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4291 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4292 		 "%s: invalid volume name length.",
4293 		 function );
4294 
4295 		return( -1 );
4296 	}
4297 	if( directory_name_index == NULL )
4298 	{
4299 		libcerror_error_set(
4300 		 error,
4301 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4302 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4303 		 "%s: invalid directory name index.",
4304 		 function );
4305 
4306 		return( -1 );
4307 	}
4308 	*volume_name          = NULL;
4309 	*volume_name_length   = 0;
4310 	*directory_name_index = 0;
4311 
4312 	/* Determine if the path is a special path
4313 	 * device path prefix:          \\.\
4314 	 * extended-length path prefix: \\?\
4315 	 */
4316 	if( ( path_length >= 4 )
4317 	 && ( path[ 0 ] == (wchar_t) '\\' )
4318 	 && ( path[ 1 ] == (wchar_t) '\\' )
4319 	 && ( ( path[ 2 ] == (wchar_t) '.' )
4320 	  ||  ( path[ 2 ] == (wchar_t) '?' ) )
4321 	 && ( path[ 3 ] == (wchar_t) '\\' ) )
4322 	{
4323 		if( path[ 2 ] == (wchar_t) '.' )
4324 		{
4325 			volume_name_index = 4;
4326 		}
4327 		/* Determine if the path in an extended-length UNC path
4328 		 * \\?\UNC\server\share
4329 		 */
4330 		else if( ( path_length >= 8 )
4331 		      && ( path[ 4 ] == (wchar_t) 'U' )
4332 		      && ( path[ 5 ] == (wchar_t) 'N' )
4333 		      && ( path[ 6 ] == (wchar_t) 'C' )
4334 		      && ( path[ 7 ] == (wchar_t) '\\' ) )
4335 		{
4336 			volume_name_index = 8;
4337 		}
4338 		else
4339 		{
4340 			volume_name_index = 4;
4341 		}
4342 	}
4343 	/* Determine if the path is an UNC path
4344 	 * \\server\share
4345 	 */
4346 	else if( ( path_length >= 2 )
4347 	      && ( path[ 0 ] == (wchar_t) '\\' )
4348 	      && ( path[ 1 ] == (wchar_t) '\\' ) )
4349 	{
4350 		volume_name_index = 2;
4351 	}
4352 	/* Check if the path contains a volume letter
4353 	 */
4354 	if( ( path_length >= 2 )
4355 	 && ( volume_name_index <= ( path_length - 2 ) )
4356 	 && ( path[ volume_name_index + 1 ] == (wchar_t) ':' )
4357 	 && ( ( ( path[ volume_name_index ] >= (wchar_t) 'A' )
4358 	   &&   ( path[ volume_name_index ] <= (wchar_t) 'Z' ) )
4359 	  ||  ( ( path[ volume_name_index ] >= (wchar_t) 'a' )
4360 	   &&   ( path[ volume_name_index ] <= (wchar_t) 'z' ) ) ) )
4361 	{
4362 		path_index = volume_name_index + 2;
4363 
4364 		if( ( path_index < path_length )
4365 		 && ( path[ path_index ] == (wchar_t) '\\' ) )
4366 		{
4367 			path_index++;
4368 		}
4369 		*volume_name        = (wchar_t *) &( path[ volume_name_index ] );
4370 		*volume_name_length = path_index - volume_name_index;
4371 
4372 		if( path[ path_index - 1 ] == (wchar_t) '\\' )
4373 		{
4374 			*volume_name_length -= 1;
4375 		}
4376 		*directory_name_index = path_index;
4377 	}
4378 	else if( volume_name_index == 4 )
4379 	{
4380 		for( path_index = volume_name_index;
4381 		     path_index < path_length;
4382 		     path_index++ )
4383 		{
4384 			if( path[ path_index ] == (wchar_t) '\\' )
4385 			{
4386 				path_index++;
4387 
4388 				break;
4389 			}
4390 		}
4391 		*volume_name        = (wchar_t *) &( path[ 4 ] );
4392 		*volume_name_length = path_index - 4;
4393 
4394 		if( path[ path_index - 1 ] == (wchar_t) '\\' )
4395 		{
4396 			*volume_name_length -= 1;
4397 		}
4398 		*directory_name_index = path_index;
4399 	}
4400 	else if( ( volume_name_index == 2 )
4401 	      || ( volume_name_index == 8 ) )
4402 	{
4403 		for( share_name_index = volume_name_index;
4404 		     share_name_index < path_length;
4405 		     share_name_index++ )
4406 		{
4407 			if( path[ share_name_index ] == (wchar_t) '\\' )
4408 			{
4409 				share_name_index++;
4410 
4411 				break;
4412 			}
4413 		}
4414 		if( share_name_index > path_length )
4415 		{
4416 			libcerror_error_set(
4417 			 error,
4418 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4419 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
4420 			 "%s: invalid path - missing share name.",
4421 			 function );
4422 
4423 			return( -1 );
4424 		}
4425 		for( path_index = share_name_index;
4426 		     path_index < path_length;
4427 		     path_index++ )
4428 		{
4429 			if( path[ path_index ] == (wchar_t) '\\' )
4430 			{
4431 				path_index++;
4432 
4433 				break;
4434 			}
4435 		}
4436 		*volume_name        = (wchar_t *) &( path[ volume_name_index ] );
4437 		*volume_name_length = path_index - volume_name_index;
4438 
4439 		if( path[ path_index - 1 ] == (wchar_t) '\\' )
4440 		{
4441 			*volume_name_length -= 1;
4442 		}
4443 		*directory_name_index = path_index;
4444 	}
4445 	return( 1 );
4446 }
4447 
4448 /* Retrieves the current working directory of a specific volume
4449  * Returns 1 if successful or -1 on error
4450  */
libcpath_path_get_current_working_directory_by_volume_wide(wchar_t * volume_name,size_t volume_name_length,wchar_t ** current_working_directory,size_t * current_working_directory_size,libcerror_error_t ** error)4451 int libcpath_path_get_current_working_directory_by_volume_wide(
4452      wchar_t *volume_name,
4453      size_t volume_name_length,
4454      wchar_t **current_working_directory,
4455      size_t *current_working_directory_size,
4456      libcerror_error_t **error )
4457 {
4458 	wchar_t *change_volume_name                  = NULL;
4459 	wchar_t *current_volume_working_directory    = NULL;
4460 	static char *function                        = "libcpath_path_get_current_working_directory_by_volume_wide";
4461 	size_t current_volume_working_directory_size = 0;
4462 	int result                                   = 1;
4463 
4464 	if( current_working_directory == NULL )
4465 	{
4466 		libcerror_error_set(
4467 		 error,
4468 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4469 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4470 		 "%s: invalid current working directory.",
4471 		 function );
4472 
4473 		return( -1 );
4474 	}
4475 	if( current_working_directory_size == NULL )
4476 	{
4477 		libcerror_error_set(
4478 		 error,
4479 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4480 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4481 		 "%s: invalid current working directory size.",
4482 		 function );
4483 
4484 		return( -1 );
4485 	}
4486 	/* If the path contains a volume name switch to that
4487 	 * volume to determine the current directory
4488 	 */
4489 	if( volume_name != NULL )
4490 	{
4491 		if( volume_name_length > (size_t) ( SSIZE_MAX - 1 ) )
4492 		{
4493 			libcerror_error_set(
4494 			 error,
4495 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4496 			 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
4497 			 "%s: invalid volume name length value exceeds maximum.",
4498 			 function );
4499 
4500 			goto on_error;
4501 		}
4502 		if( libcpath_path_get_current_working_directory_wide(
4503 		     &current_volume_working_directory,
4504 		     &current_volume_working_directory_size,
4505 		     error ) != 1 )
4506 		{
4507 			libcerror_error_set(
4508 			 error,
4509 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4510 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4511 			 "%s: unable to retrieve current volume working directory.",
4512 			 function );
4513 
4514 			goto on_error;
4515 		}
4516 		change_volume_name = wide_string_allocate(
4517 		                      volume_name_length + 1 );
4518 
4519 		if( change_volume_name == NULL )
4520 		{
4521 			libcerror_error_set(
4522 			 error,
4523 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
4524 			 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
4525 			 "%s: unable to create change volume name.",
4526 			 function );
4527 
4528 			goto on_error;
4529 		}
4530 		if( wide_string_copy(
4531 		     change_volume_name,
4532 		     volume_name,
4533 		     volume_name_length ) == NULL )
4534 		{
4535 			libcerror_error_set(
4536 			 error,
4537 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
4538 			 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
4539 			 "%s: unable to set change volume name.",
4540 			 function );
4541 
4542 			goto on_error;
4543 		}
4544 		change_volume_name[ volume_name_length ] = 0;
4545 
4546 		if( libcpath_path_change_directory_wide(
4547 		     change_volume_name,
4548 		     error ) != 1 )
4549 		{
4550 			libcerror_error_set(
4551 			 error,
4552 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4553 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4554 			 "%s: unable to change current working directory.",
4555 			 function );
4556 
4557 			goto on_error;
4558 		}
4559 		memory_free(
4560 		 change_volume_name );
4561 
4562 		change_volume_name = NULL;
4563 	}
4564 	if( libcpath_path_get_current_working_directory_wide(
4565 	     current_working_directory,
4566 	     current_working_directory_size,
4567 	     error ) != 1 )
4568 	{
4569 		libcerror_error_set(
4570 		 error,
4571 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4572 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4573 		 "%s: unable to retrieve current directory.",
4574 		 function );
4575 
4576 		/* Make sure the current working directory has been changed
4577 		 * back to its original value
4578 		 */
4579 		result = -1;
4580 	}
4581 	if( current_volume_working_directory != NULL )
4582 	{
4583 		if( libcpath_path_change_directory_wide(
4584 		     current_volume_working_directory,
4585 		     error ) != 1 )
4586 		{
4587 			libcerror_error_set(
4588 			 error,
4589 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4590 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4591 			 "%s: unable to change current working directory.",
4592 			 function );
4593 
4594 			goto on_error;
4595 		}
4596 		memory_free(
4597 		 current_volume_working_directory );
4598 
4599 		current_volume_working_directory = NULL;
4600 	}
4601 	return( result );
4602 
4603 on_error:
4604 	if( change_volume_name != NULL )
4605 	{
4606 		memory_free(
4607 		 change_volume_name );
4608 	}
4609 	if( current_volume_working_directory != NULL )
4610 	{
4611 		memory_free(
4612 		 current_volume_working_directory );
4613 	}
4614 	if( *current_working_directory != NULL )
4615 	{
4616 		memory_free(
4617 		 *current_working_directory );
4618 
4619 		*current_working_directory = NULL;
4620 	}
4621 	*current_working_directory_size = 0;
4622 
4623 	return( -1 );
4624 }
4625 
4626 /* Determines the full path of the Windows path specified
4627  * The function uses the extended-length path format
4628  * (path with \\?\ prefix)
4629  *
4630  * Multiple successive \ not at the start of the path are combined into one
4631  *
4632  * Scenario's that are considered full paths:
4633  * Device path:			\\.\PhysicalDrive0
4634  * Extended-length path:	\\?\C:\directory\file.txt
4635  * Extended-length UNC path:	\\?\UNC\server\share\directory\file.txt
4636  *
4637  * Scenario's that are not considered full paths:
4638  * Local 'absolute' path:	\directory\file.txt
4639  * Local 'relative' path:	..\directory\file.txt
4640  * Local 'relative' path:	.\directory\file.txt
4641  * Volume 'absolute' path:	C:\directory\file.txt
4642  *                              C:\..\directory\file.txt
4643  * Volume 'relative' path:	C:directory\file.txt
4644  * UNC path:			\\server\share\directory\file.txt
4645  *
4646  * Returns 1 if succesful or -1 on error
4647  */
libcpath_path_get_full_path_wide(const wchar_t * path,size_t path_length,wchar_t ** full_path,size_t * full_path_size,libcerror_error_t ** error)4648 int libcpath_path_get_full_path_wide(
4649      const wchar_t *path,
4650      size_t path_length,
4651      wchar_t **full_path,
4652      size_t *full_path_size,
4653      libcerror_error_t **error )
4654 {
4655 	libcsplit_wide_split_string_t *current_directory_split_string = NULL;
4656 	libcsplit_wide_split_string_t *path_split_string              = NULL;
4657 	wchar_t *current_directory                                    = NULL;
4658 	wchar_t *current_directory_string_segment                     = NULL;
4659 	wchar_t *full_path_prefix                                     = NULL;
4660 	wchar_t *last_used_path_string_segment                        = NULL;
4661 	wchar_t *path_string_segment                                  = NULL;
4662 	wchar_t *volume_name                                          = NULL;
4663 	static char *function                                         = "libcpath_path_get_full_path_wide";
4664 	size_t current_directory_length                               = 0;
4665 	size_t current_directory_name_index                           = 0;
4666 	size_t current_directory_size                                 = 0;
4667 	size_t current_directory_string_segment_size                  = 0;
4668 	size_t full_path_index                                        = 0;
4669 	size_t full_path_prefix_length                                = 0;
4670 	size_t last_used_path_string_segment_size                     = 0;
4671 	size_t path_directory_name_index                              = 0;
4672 	size_t path_string_segment_size                               = 0;
4673 	size_t safe_full_path_size                                    = 0;
4674 	size_t volume_name_length                                     = 0;
4675 	uint8_t path_type                                             = LIBCPATH_TYPE_RELATIVE;
4676 	int current_directory_number_of_segments                      = 0;
4677 	int current_directory_segment_index                           = 0;
4678 	int last_used_path_segment_index                              = -1;
4679 	int path_number_of_segments                                   = 0;
4680 	int path_segment_index                                        = 0;
4681 
4682 	if( path == NULL )
4683 	{
4684 		libcerror_error_set(
4685 		 error,
4686 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4687 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4688 		 "%s: invalid path.",
4689 		 function );
4690 
4691 		return( -1 );
4692 	}
4693 	if( path_length == 0 )
4694 	{
4695 		libcerror_error_set(
4696 		 error,
4697 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4698 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
4699 		 "%s: invalid path length is zero.",
4700 		 function );
4701 
4702 		return( -1 );
4703 	}
4704 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
4705 	{
4706 		libcerror_error_set(
4707 		 error,
4708 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4709 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
4710 		 "%s: invalid path length value exceeds maximum.",
4711 		 function );
4712 
4713 		return( -1 );
4714 	}
4715 	if( full_path == NULL )
4716 	{
4717 		libcerror_error_set(
4718 		 error,
4719 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4720 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4721 		 "%s: invalid full path.",
4722 		 function );
4723 
4724 		return( -1 );
4725 	}
4726 	if( *full_path != NULL )
4727 	{
4728 		libcerror_error_set(
4729 		 error,
4730 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4731 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
4732 		 "%s: invalid full path value already set.",
4733 		 function );
4734 
4735 		return( -1 );
4736 	}
4737 	if( full_path_size == NULL )
4738 	{
4739 		libcerror_error_set(
4740 		 error,
4741 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4742 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4743 		 "%s: invalid full path size.",
4744 		 function );
4745 
4746 		return( -1 );
4747 	}
4748 	if( libcpath_path_get_path_type_wide(
4749 	     path,
4750 	     path_length,
4751 	     &path_type,
4752 	     error ) != 1 )
4753 	{
4754 		libcerror_error_set(
4755 		 error,
4756 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4757 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4758 		 "%s: unable to determine path type.",
4759 		 function );
4760 
4761 		goto on_error;
4762 	}
4763 	if( libcpath_path_get_volume_name_wide(
4764 	     path,
4765 	     path_length,
4766 	     &volume_name,
4767 	     &volume_name_length,
4768 	     &path_directory_name_index,
4769 	     error ) != 1 )
4770 	{
4771 		libcerror_error_set(
4772 		 error,
4773 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4774 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4775 		 "%s: unable to determine volume name.",
4776 		 function );
4777 
4778 		goto on_error;
4779 	}
4780 	/* If the path is a device path, an extended-length path or an UNC
4781 	 * do not bother to lookup the current working directory
4782 	 */
4783 	if( ( path_type != LIBCPATH_TYPE_DEVICE )
4784 	 && ( path_type != LIBCPATH_TYPE_EXTENDED_LENGTH )
4785 	 && ( path_type != LIBCPATH_TYPE_EXTENDED_LENGTH_UNC )
4786 	 && ( path_type != LIBCPATH_TYPE_UNC ) )
4787 	{
4788 		if( libcpath_path_get_current_working_directory_by_volume_wide(
4789 		     volume_name,
4790 		     volume_name_length,
4791 		     &current_directory,
4792 		     &current_directory_size,
4793 		     error ) != 1 )
4794 		{
4795 			libcerror_error_set(
4796 			 error,
4797 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4798 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4799 			 "%s: unable to retrieve current working directory by volume.",
4800 			 function );
4801 
4802 			goto on_error;
4803 		}
4804 		/* Determine the volume name using the current working directory if necessary
4805 		 */
4806 		if( libcpath_path_get_volume_name_wide(
4807 		     current_directory,
4808 		     current_directory_size - 1,
4809 		     &volume_name,
4810 		     &volume_name_length,
4811 		     &current_directory_name_index,
4812 		     error ) != 1 )
4813 		{
4814 			libcerror_error_set(
4815 			 error,
4816 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4817 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4818 			 "%s: unable to determine volume name from current working directory.",
4819 			 function );
4820 
4821 			goto on_error;
4822 		}
4823 	}
4824 	if( ( current_directory != NULL )
4825 	 && ( current_directory_name_index < current_directory_size ) )
4826 	{
4827 		current_directory_length = wide_string_length(
4828 		                            &( current_directory[ current_directory_name_index ] ) );
4829 
4830 		if( libcsplit_wide_string_split(
4831 		     &( current_directory[ current_directory_name_index ] ),
4832 		     current_directory_length + 1,
4833 		     (wchar_t) '\\',
4834 		     &current_directory_split_string,
4835 		     error ) != 1 )
4836 		{
4837 			libcerror_error_set(
4838 			 error,
4839 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4840 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
4841 			 "%s: unable to split current working directory.",
4842 			 function );
4843 
4844 			goto on_error;
4845 		}
4846 	}
4847 	if( libcsplit_wide_string_split(
4848 	     &( path[ path_directory_name_index ] ),
4849 	     path_length - path_directory_name_index + 1,
4850 	     (wchar_t) '\\',
4851 	     &path_split_string,
4852 	     error ) != 1 )
4853 	{
4854 		libcerror_error_set(
4855 		 error,
4856 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4857 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
4858 		 "%s: unable to split path.",
4859 		 function );
4860 
4861 		goto on_error;
4862 	}
4863 	/* The size of the full path consists of:
4864 	 * the size of the prefix (\\?\ or \\.\)
4865 	 * the length of the volume name
4866 	 * a directory separator
4867 	 */
4868 	safe_full_path_size = 4;
4869 
4870 	/* If the path contains a volume name
4871 	 * the length of the volume name
4872 	 * a directory separator
4873 	 */
4874 	if( volume_name != NULL )
4875 	{
4876 		safe_full_path_size += volume_name_length + 1;
4877 	}
4878 	/* If the path contains an UNC path
4879 	 * add the size of the UNC\ prefix
4880 	 */
4881 	if( ( path_type == LIBCPATH_TYPE_EXTENDED_LENGTH_UNC )
4882 	 || ( path_type == LIBCPATH_TYPE_UNC ) )
4883 	{
4884 		safe_full_path_size += 4;
4885 	}
4886 	/* If the path is relative
4887 	 * add the size of the current working directory
4888 	 * a directory separator, if necessary
4889 	 */
4890 	if( ( path_type == LIBCPATH_TYPE_RELATIVE )
4891 	 && ( current_directory_name_index < current_directory_size ) )
4892 	{
4893 		safe_full_path_size += ( current_directory_size - ( current_directory_name_index + 1 ) );
4894 
4895 		if( ( current_directory_size >= 2 )
4896 		 && ( current_directory[ current_directory_size - 2 ] != (wchar_t) '\\' ) )
4897 		{
4898 			safe_full_path_size += 1;
4899 		}
4900 	}
4901 	if( current_directory_split_string != NULL )
4902 	{
4903 		if( libcsplit_wide_split_string_get_number_of_segments(
4904 		     current_directory_split_string,
4905 		     &current_directory_number_of_segments,
4906 		     error ) != 1 )
4907 		{
4908 			libcerror_error_set(
4909 			 error,
4910 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4911 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4912 			 "%s: unable to retrieve number of current working directory string segments.",
4913 			 function );
4914 
4915 			goto on_error;
4916 		}
4917 		current_directory_segment_index = current_directory_number_of_segments - 1;
4918 	}
4919 	if( libcsplit_wide_split_string_get_number_of_segments(
4920 	     path_split_string,
4921 	     &path_number_of_segments,
4922 	     error ) != 1 )
4923 	{
4924 		libcerror_error_set(
4925 		 error,
4926 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4927 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4928 		 "%s: unable to retrieve number of path string segments.",
4929 		 function );
4930 
4931 		goto on_error;
4932 	}
4933 	for( path_segment_index = 0;
4934 	     path_segment_index < path_number_of_segments;
4935 	     path_segment_index++ )
4936 	{
4937 		if( libcsplit_wide_split_string_get_segment_by_index(
4938 		     path_split_string,
4939 		     path_segment_index,
4940 		     &path_string_segment,
4941 		     &path_string_segment_size,
4942 		     error ) != 1 )
4943 		{
4944 			libcerror_error_set(
4945 			 error,
4946 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4947 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4948 			 "%s: unable to retrieve path string segment: %d.",
4949 			 function,
4950 			 path_segment_index );
4951 
4952 			goto on_error;
4953 		}
4954 		if( path_string_segment == NULL )
4955 		{
4956 			libcerror_error_set(
4957 			 error,
4958 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4959 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
4960 			 "%s: missing path string segment: %d.",
4961 			 function,
4962 			 path_segment_index );
4963 
4964 			goto on_error;
4965 		}
4966 		/* If the path is .. reverse the current path by one directory
4967 		 */
4968 		if( ( path_string_segment_size == 3 )
4969 		 && ( path_string_segment[ 0 ] == (wchar_t) '.' )
4970 		 && ( path_string_segment[ 1 ] == (wchar_t) '.' ) )
4971 		{
4972 			if( ( current_directory_split_string != NULL )
4973 			 && ( last_used_path_segment_index == -1 ) )
4974 			{
4975 				if( libcsplit_wide_split_string_get_segment_by_index(
4976 				     current_directory_split_string,
4977 				     current_directory_segment_index,
4978 				     &current_directory_string_segment,
4979 				     &current_directory_string_segment_size,
4980 				     error ) != 1 )
4981 				{
4982 					libcerror_error_set(
4983 					 error,
4984 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4985 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4986 					 "%s: unable to retrieve current working directory string segment: %d.",
4987 					 function,
4988 					 current_directory_segment_index );
4989 
4990 					goto on_error;
4991 				}
4992 				if( current_directory_string_segment == NULL )
4993 				{
4994 					libcerror_error_set(
4995 					 error,
4996 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4997 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
4998 					 "%s: missing current working directory string segment: %d.",
4999 					 function,
5000 					 current_directory_segment_index );
5001 
5002 					goto on_error;
5003 				}
5004 				/* Remove the size of the parent directory name and a directory separator
5005 				 * Note that the size includes the end of string character
5006 				 */
5007 				safe_full_path_size -= current_directory_string_segment_size;
5008 
5009 				if( libcsplit_wide_split_string_set_segment_by_index(
5010 				     current_directory_split_string,
5011 				     current_directory_segment_index,
5012 				     NULL,
5013 				     0,
5014 				     error ) != 1 )
5015 				{
5016 					libcerror_error_set(
5017 					 error,
5018 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5019 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5020 					 "%s: unable to set current working directory string segment: %d.",
5021 					 function,
5022 					 current_directory_segment_index );
5023 
5024 					goto on_error;
5025 				}
5026 				current_directory_segment_index--;
5027 			}
5028 			else if( last_used_path_segment_index >= 0 )
5029 			{
5030 				if( libcsplit_wide_split_string_get_segment_by_index(
5031 				     path_split_string,
5032 				     last_used_path_segment_index,
5033 				     &last_used_path_string_segment,
5034 				     &last_used_path_string_segment_size,
5035 				     error ) != 1 )
5036 				{
5037 					libcerror_error_set(
5038 					 error,
5039 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5040 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5041 					 "%s: unable to retrieve last used path string segment: %d.",
5042 					 function,
5043 					 last_used_path_segment_index );
5044 
5045 					goto on_error;
5046 				}
5047 				if( last_used_path_string_segment == NULL )
5048 				{
5049 					libcerror_error_set(
5050 					 error,
5051 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5052 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5053 					 "%s: missing last used path string string segment: %d.",
5054 					 function,
5055 					 last_used_path_segment_index );
5056 
5057 					goto on_error;
5058 				}
5059 				/* Remove the size of the parent directory name and a directory separator
5060 				 * Note that the size includes the end of string character
5061 				 */
5062 				safe_full_path_size -= last_used_path_string_segment_size;
5063 
5064 				if( libcsplit_wide_split_string_set_segment_by_index(
5065 				     path_split_string,
5066 				     last_used_path_segment_index,
5067 				     NULL,
5068 				     0,
5069 				     error ) != 1 )
5070 				{
5071 					libcerror_error_set(
5072 					 error,
5073 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5074 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5075 					 "%s: unable to set path string segment: %d.",
5076 					 function,
5077 					 last_used_path_segment_index );
5078 
5079 					goto on_error;
5080 				}
5081 				/* Find the previous path split value that contains a name
5082 				 */
5083 				while( last_used_path_segment_index > 0 )
5084 				{
5085 					last_used_path_segment_index--;
5086 
5087 					if( libcsplit_wide_split_string_get_segment_by_index(
5088 					     path_split_string,
5089 					     last_used_path_segment_index,
5090 					     &last_used_path_string_segment,
5091 					     &last_used_path_string_segment_size,
5092 					     error ) != 1 )
5093 					{
5094 						libcerror_error_set(
5095 						 error,
5096 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5097 						 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5098 						 "%s: unable to retrieve last used path string segment: %d.",
5099 						 function,
5100 						 last_used_path_segment_index );
5101 
5102 						goto on_error;
5103 					}
5104 					if( last_used_path_string_segment_size != 0 )
5105 					{
5106 						break;
5107 					}
5108 				}
5109 			}
5110 			if( libcsplit_wide_split_string_set_segment_by_index(
5111 			     path_split_string,
5112 			     path_segment_index,
5113 			     NULL,
5114 			     0,
5115 			     error ) != 1 )
5116 			{
5117 				libcerror_error_set(
5118 				 error,
5119 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5120 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5121 				 "%s: unable to set path string segment: %d.",
5122 				 function,
5123 				 path_segment_index );
5124 
5125 				goto on_error;
5126 			}
5127 		}
5128 		/* If the path is . ignore the entry
5129 		 */
5130 		else if( ( path_string_segment_size == 2 )
5131 		      && ( path_string_segment[ 0 ] == (wchar_t) '.' ) )
5132 		{
5133 			if( libcsplit_wide_split_string_set_segment_by_index(
5134 			     path_split_string,
5135 			     path_segment_index,
5136 			     NULL,
5137 			     0,
5138 			     error ) != 1 )
5139 			{
5140 				libcerror_error_set(
5141 				 error,
5142 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5143 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5144 				 "%s: unable to set path string segment: %d.",
5145 				 function,
5146 				 path_segment_index );
5147 
5148 				goto on_error;
5149 			}
5150 		}
5151 		/* If the path is empty ignore the entry
5152 		 */
5153 		else if( path_string_segment_size <= 1 )
5154 		{
5155 			if( libcsplit_wide_split_string_set_segment_by_index(
5156 			     path_split_string,
5157 			     path_segment_index,
5158 			     NULL,
5159 			     0,
5160 			     error ) != 1 )
5161 			{
5162 				libcerror_error_set(
5163 				 error,
5164 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5165 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5166 				 "%s: unable to set path string segment: %d.",
5167 				 function,
5168 				 path_segment_index );
5169 
5170 				goto on_error;
5171 			}
5172 		}
5173 		else
5174 		{
5175 			/* Add the size of the directory or file name and a directory separator
5176 			 * Note that the size includes the end of string character
5177 			 */
5178 			safe_full_path_size += path_string_segment_size;
5179 
5180 			last_used_path_segment_index = path_segment_index;
5181 		}
5182 	}
5183 	/* Note that the last path separator serves as the end of string
5184 	 */
5185 	full_path_index = 0;
5186 
5187 	*full_path = wide_string_allocate(
5188 	              safe_full_path_size );
5189 
5190 	if( *full_path == NULL )
5191 	{
5192 		libcerror_error_set(
5193 		 error,
5194 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
5195 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
5196 		 "%s: unable to create full path.",
5197 		 function );
5198 
5199 		goto on_error;
5200 	}
5201 	if( memory_set(
5202 	     *full_path,
5203 	     0,
5204 	     sizeof( wchar_t ) * safe_full_path_size ) == NULL )
5205 	{
5206 		libcerror_error_set(
5207 		 error,
5208 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
5209 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
5210 		 "%s: unable to clear full path.",
5211 		 function );
5212 
5213 		goto on_error;
5214 	}
5215 	*full_path_size = safe_full_path_size;
5216 
5217 	if( path_type == LIBCPATH_TYPE_DEVICE )
5218 	{
5219 		full_path_prefix        = L"\\\\.\\";
5220 		full_path_prefix_length = 4;
5221 	}
5222 	else
5223 	{
5224 		full_path_prefix        = L"\\\\?\\";
5225 		full_path_prefix_length = 4;
5226 	}
5227 	if( wide_string_copy(
5228 	     &( ( *full_path )[ full_path_index ] ),
5229 	     full_path_prefix,
5230 	     full_path_prefix_length ) == NULL )
5231 	{
5232 		libcerror_error_set(
5233 		 error,
5234 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5235 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5236 		 "%s: unable to set prefix in full path.",
5237 		 function );
5238 
5239 		goto on_error;
5240 	}
5241 	full_path_index += full_path_prefix_length;
5242 
5243 	/* If there is a share name the path is an UNC path
5244 	 */
5245 	if( ( path_type == LIBCPATH_TYPE_EXTENDED_LENGTH_UNC )
5246 	 || ( path_type == LIBCPATH_TYPE_UNC ) )
5247 	{
5248 		if( wide_string_copy(
5249 		     &( ( *full_path )[ full_path_index ] ),
5250 		     L"UNC\\",
5251 		     4 ) == NULL )
5252 		{
5253 			libcerror_error_set(
5254 			 error,
5255 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5256 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5257 			 "%s: unable to set UNC\\ prefix in full path.",
5258 			 function );
5259 
5260 			goto on_error;
5261 		}
5262 		full_path_index += 4;
5263 	}
5264 	if( volume_name != NULL )
5265 	{
5266 		if( wide_string_copy(
5267 		     &( ( *full_path )[ full_path_index ] ),
5268 		     volume_name,
5269 		     volume_name_length ) == NULL )
5270 		{
5271 			libcerror_error_set(
5272 			 error,
5273 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5274 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5275 			 "%s: unable to set volume name in full path.",
5276 			 function );
5277 
5278 			goto on_error;
5279 		}
5280 		full_path_index += volume_name_length;
5281 
5282 		( *full_path )[ full_path_index ] = (wchar_t) '\\';
5283 
5284 		full_path_index += 1;
5285 	}
5286 	/* If the path is relative
5287 	 * add the current working directory elements
5288 	 */
5289 	if( ( path_type == LIBCPATH_TYPE_RELATIVE )
5290 	 && ( current_directory_split_string != NULL ) )
5291 	{
5292 		for( current_directory_segment_index = 0;
5293 		     current_directory_segment_index < current_directory_number_of_segments;
5294 		     current_directory_segment_index++ )
5295 		{
5296 			if( libcsplit_wide_split_string_get_segment_by_index(
5297 			     current_directory_split_string,
5298 			     current_directory_segment_index,
5299 			     &current_directory_string_segment,
5300 			     &current_directory_string_segment_size,
5301 			     error ) != 1 )
5302 			{
5303 				libcerror_error_set(
5304 				 error,
5305 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5306 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5307 				 "%s: unable to retrieve current working directory string segment: %d.",
5308 				 function,
5309 				 current_directory_segment_index );
5310 
5311 				goto on_error;
5312 			}
5313 			if( current_directory_string_segment_size != 0 )
5314 			{
5315 				if( current_directory_string_segment == NULL )
5316 				{
5317 					libcerror_error_set(
5318 					 error,
5319 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5320 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5321 					 "%s: missing current working directory string segment: %d.",
5322 					 function,
5323 					 current_directory_segment_index );
5324 
5325 					goto on_error;
5326 				}
5327 				if( wide_string_copy(
5328 				     &( ( *full_path )[ full_path_index ] ),
5329 				     current_directory_string_segment,
5330 				     current_directory_string_segment_size - 1 ) == NULL )
5331 				{
5332 					libcerror_error_set(
5333 					 error,
5334 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5335 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5336 					 "%s: unable to set current working directory split value: %d in full path.",
5337 					 function,
5338 					 current_directory_segment_index );
5339 
5340 					goto on_error;
5341 				}
5342 				full_path_index += current_directory_string_segment_size - 1;
5343 
5344 				( *full_path )[ full_path_index ] = (wchar_t) '\\';
5345 
5346 				full_path_index += 1;
5347 			}
5348 		}
5349 	}
5350 	for( path_segment_index = 0;
5351 	     path_segment_index < path_number_of_segments;
5352 	     path_segment_index++ )
5353 	{
5354 		if( libcsplit_wide_split_string_get_segment_by_index(
5355 		     path_split_string,
5356 		     path_segment_index,
5357 		     &path_string_segment,
5358 		     &path_string_segment_size,
5359 		     error ) != 1 )
5360 		{
5361 			libcerror_error_set(
5362 			 error,
5363 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5364 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5365 			 "%s: unable to retrieve path string segment: %d.",
5366 			 function,
5367 			 path_segment_index );
5368 
5369 			goto on_error;
5370 		}
5371 		if( path_string_segment_size != 0 )
5372 		{
5373 			if( path_string_segment == NULL )
5374 			{
5375 				libcerror_error_set(
5376 				 error,
5377 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5378 				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5379 				 "%s: missing path string segment: %d.",
5380 				 function,
5381 				 path_segment_index );
5382 
5383 				goto on_error;
5384 			}
5385 			if( wide_string_copy(
5386 			     &( ( *full_path )[ full_path_index ] ),
5387 			     path_string_segment,
5388 			     path_string_segment_size - 1 ) == NULL )
5389 			{
5390 				libcerror_error_set(
5391 				 error,
5392 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5393 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5394 				 "%s: unable to set path split value: %d in full path.",
5395 				 function,
5396 				 path_segment_index );
5397 
5398 				goto on_error;
5399 			}
5400 			full_path_index += path_string_segment_size - 1;
5401 
5402 			( *full_path )[ full_path_index ] = (wchar_t) '\\';
5403 
5404 			full_path_index += 1;
5405 		}
5406 	}
5407 	( *full_path )[ full_path_index - 1 ] = 0;
5408 
5409 	if( libcsplit_wide_split_string_free(
5410 	     &path_split_string,
5411 	     error ) != 1 )
5412 	{
5413 		libcerror_error_set(
5414 		 error,
5415 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5416 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
5417 		 "%s: unable to free path split string.",
5418 		 function );
5419 
5420 		goto on_error;
5421 	}
5422 	if( current_directory_split_string != NULL )
5423 	{
5424 		if( libcsplit_wide_split_string_free(
5425 		     &current_directory_split_string,
5426 		     error ) != 1 )
5427 		{
5428 			libcerror_error_set(
5429 			 error,
5430 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5431 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
5432 			 "%s: unable to free current working directory split string.",
5433 			 function );
5434 
5435 			goto on_error;
5436 		}
5437 	}
5438 	if( current_directory != NULL )
5439 	{
5440 		memory_free(
5441 		 current_directory );
5442 	}
5443 	return( 1 );
5444 
5445 on_error:
5446 	if( *full_path != NULL )
5447 	{
5448 		memory_free(
5449 		 *full_path );
5450 
5451 		*full_path = NULL;
5452 	}
5453 	*full_path_size = 0;
5454 
5455 	if( path_split_string != NULL )
5456 	{
5457 		libcsplit_wide_split_string_free(
5458 		 &path_split_string,
5459 		 NULL );
5460 	}
5461 	if( current_directory_split_string != NULL )
5462 	{
5463 		libcsplit_wide_split_string_free(
5464 		 &current_directory_split_string,
5465 		 NULL );
5466 	}
5467 	if( current_directory != NULL )
5468 	{
5469 		memory_free(
5470 		 current_directory );
5471 	}
5472 	return( -1 );
5473 }
5474 
5475 #else
5476 
5477 /* Determines the full path of the POSIX path specified
5478  * Multiple successive / are combined into one
5479  *
5480  * Scenarios:
5481  * /home/user/file.txt
5482  * /home/user//file.txt
5483  * /home/user/../user/file.txt
5484  * /../home/user/file.txt
5485  * user/../user/file.txt
5486  *
5487  * Returns 1 if succesful or -1 on error
5488  */
libcpath_path_get_full_path_wide(const wchar_t * path,size_t path_length,wchar_t ** full_path,size_t * full_path_size,libcerror_error_t ** error)5489 int libcpath_path_get_full_path_wide(
5490      const wchar_t *path,
5491      size_t path_length,
5492      wchar_t **full_path,
5493      size_t *full_path_size,
5494      libcerror_error_t **error )
5495 {
5496 	libcsplit_wide_split_string_t *current_directory_split_string = NULL;
5497 	libcsplit_wide_split_string_t *path_split_string              = NULL;
5498 	wchar_t *current_directory                                    = NULL;
5499 	wchar_t *current_directory_string_segment                     = NULL;
5500 	wchar_t *last_used_path_string_segment                        = NULL;
5501 	wchar_t *path_string_segment                                  = NULL;
5502 	static char *function                                         = "libcpath_path_get_full_path_wide";
5503 	size_t current_directory_length                               = 0;
5504 	size_t current_directory_size                                 = 0;
5505 	size_t current_directory_string_segment_size                  = 0;
5506 	size_t full_path_index                                        = 0;
5507 	size_t last_used_path_string_segment_size                     = 0;
5508 	size_t path_string_segment_size                               = 0;
5509 	size_t safe_full_path_size                                    = 0;
5510 	uint8_t path_type                                             = LIBCPATH_TYPE_RELATIVE;
5511 	int current_directory_number_of_segments                      = 0;
5512 	int current_directory_segment_index                           = 0;
5513 	int last_used_path_segment_index                              = -1;
5514 	int path_number_of_segments                                   = 0;
5515 	int path_segment_index                                        = 0;
5516 
5517 	if( path == NULL )
5518 	{
5519 		libcerror_error_set(
5520 		 error,
5521 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5522 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
5523 		 "%s: invalid path.",
5524 		 function );
5525 
5526 		return( -1 );
5527 	}
5528 	if( path_length == 0 )
5529 	{
5530 		libcerror_error_set(
5531 		 error,
5532 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5533 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
5534 		 "%s: invalid path length is zero.",
5535 		 function );
5536 
5537 		return( -1 );
5538 	}
5539 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
5540 	{
5541 		libcerror_error_set(
5542 		 error,
5543 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5544 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
5545 		 "%s: invalid path length value exceeds maximum.",
5546 		 function );
5547 
5548 		return( -1 );
5549 	}
5550 	if( full_path == NULL )
5551 	{
5552 		libcerror_error_set(
5553 		 error,
5554 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5555 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
5556 		 "%s: invalid full path.",
5557 		 function );
5558 
5559 		return( -1 );
5560 	}
5561 	if( *full_path != NULL )
5562 	{
5563 		libcerror_error_set(
5564 		 error,
5565 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5566 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
5567 		 "%s: invalid full path value already set.",
5568 		 function );
5569 
5570 		return( -1 );
5571 	}
5572 	if( full_path_size == NULL )
5573 	{
5574 		libcerror_error_set(
5575 		 error,
5576 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5577 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
5578 		 "%s: invalid full path size.",
5579 		 function );
5580 
5581 		return( -1 );
5582 	}
5583 	if( path[ 0 ] == (wchar_t) '/' )
5584 	{
5585 		path_type = LIBCPATH_TYPE_ABSOLUTE;
5586 	}
5587 	else
5588 	{
5589 		if( libcpath_path_get_current_working_directory_wide(
5590 		     &current_directory,
5591 		     &current_directory_size,
5592 		     error ) != 1 )
5593 		{
5594 			libcerror_error_set(
5595 			 error,
5596 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5597 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5598 			 "%s: unable to retrieve current working directory.",
5599 			 function );
5600 
5601 			goto on_error;
5602 		}
5603 	}
5604 	if( current_directory != NULL )
5605 	{
5606 		current_directory_length = wide_string_length(
5607 		                            current_directory );
5608 
5609 		if( libcsplit_wide_string_split(
5610 		     current_directory,
5611 		     current_directory_length + 1,
5612 		     (wchar_t) '/',
5613 		     &current_directory_split_string,
5614 		     error ) != 1 )
5615 		{
5616 			libcerror_error_set(
5617 			 error,
5618 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5619 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
5620 			 "%s: unable to split current working directory.",
5621 			 function );
5622 
5623 			goto on_error;
5624 		}
5625 	}
5626 	if( libcsplit_wide_string_split(
5627 	     path,
5628 	     path_length + 1,
5629 	     (wchar_t) '/',
5630 	     &path_split_string,
5631 	     error ) != 1 )
5632 	{
5633 		libcerror_error_set(
5634 		 error,
5635 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5636 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
5637 		 "%s: unable to split path.",
5638 		 function );
5639 
5640 		goto on_error;
5641 	}
5642 	/* Determine the full path size
5643 	 */
5644 	/* If the path is absolute
5645 	 * a directory separator
5646 	 */
5647 	if( path_type == LIBCPATH_TYPE_ABSOLUTE )
5648 	{
5649 		safe_full_path_size = 1;
5650 	}
5651 	/* If the path is relative
5652 	 * add the size of the current working directory
5653 	 * a directory separator, if necessary
5654 	 */
5655 	else if( path_type == LIBCPATH_TYPE_RELATIVE )
5656 	{
5657 		if( current_directory == NULL )
5658 		{
5659 			libcerror_error_set(
5660 			 error,
5661 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5662 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5663 			 "%s: missing current working directory.",
5664 			 function );
5665 
5666 			goto on_error;
5667 		}
5668 		/* We need to use the length here since current_directory_size will be PATH_MAX
5669 		 */
5670 		safe_full_path_size = current_directory_length;
5671 
5672 		if( ( current_directory_length >= 1 )
5673 		 && ( current_directory[ current_directory_length - 1 ] != (wchar_t) '/' ) )
5674 		{
5675 			safe_full_path_size++;
5676 		}
5677 	}
5678 	if( current_directory_split_string != NULL )
5679 	{
5680 		if( libcsplit_wide_split_string_get_number_of_segments(
5681 		     current_directory_split_string,
5682 		     &current_directory_number_of_segments,
5683 		     error ) != 1 )
5684 		{
5685 			libcerror_error_set(
5686 			 error,
5687 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5688 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5689 			 "%s: unable to retrieve number of current working directory string segments.",
5690 			 function );
5691 
5692 			goto on_error;
5693 		}
5694 		current_directory_segment_index = current_directory_number_of_segments - 1;
5695 	}
5696 	if( libcsplit_wide_split_string_get_number_of_segments(
5697 	     path_split_string,
5698 	     &path_number_of_segments,
5699 	     error ) != 1 )
5700 	{
5701 		libcerror_error_set(
5702 		 error,
5703 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5704 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5705 		 "%s: unable to retrieve number of path string segments.",
5706 		 function );
5707 
5708 		goto on_error;
5709 	}
5710 	for( path_segment_index = 0;
5711 	     path_segment_index < path_number_of_segments;
5712 	     path_segment_index++ )
5713 	{
5714 		if( libcsplit_wide_split_string_get_segment_by_index(
5715 		     path_split_string,
5716 		     path_segment_index,
5717 		     &path_string_segment,
5718 		     &path_string_segment_size,
5719 		     error ) != 1 )
5720 		{
5721 			libcerror_error_set(
5722 			 error,
5723 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5724 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5725 			 "%s: unable to retrieve path string segment: %d.",
5726 			 function,
5727 			 path_segment_index );
5728 
5729 			goto on_error;
5730 		}
5731 		if( path_string_segment == NULL )
5732 		{
5733 			libcerror_error_set(
5734 			 error,
5735 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5736 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5737 			 "%s: missing path string segment: %d.",
5738 			 function,
5739 			 path_segment_index );
5740 
5741 			goto on_error;
5742 		}
5743 		/* If the path is .. reverse the current path by one directory
5744 		 */
5745 		if( ( path_string_segment_size == 3 )
5746 		 && ( path_string_segment[ 0 ] == (wchar_t) '.' )
5747 		 && ( path_string_segment[ 1 ] == (wchar_t) '.' ) )
5748 		{
5749 			if( ( current_directory_split_string != NULL )
5750 			 && ( last_used_path_segment_index == -1 ) )
5751 			{
5752 				if( libcsplit_wide_split_string_get_segment_by_index(
5753 				     current_directory_split_string,
5754 				     current_directory_segment_index,
5755 				     &current_directory_string_segment,
5756 				     &current_directory_string_segment_size,
5757 				     error ) != 1 )
5758 				{
5759 					libcerror_error_set(
5760 					 error,
5761 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5762 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5763 					 "%s: unable to retrieve current working directory string segment: %d.",
5764 					 function,
5765 					 current_directory_segment_index );
5766 
5767 					goto on_error;
5768 				}
5769 				if( current_directory_string_segment == NULL )
5770 				{
5771 					libcerror_error_set(
5772 					 error,
5773 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5774 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5775 					 "%s: missing current working directory string segment: %d.",
5776 					 function,
5777 					 current_directory_segment_index );
5778 
5779 					goto on_error;
5780 				}
5781 				/* Remove the size of the parent directory name and a directory separator
5782 				 * Note that the size includes the end of string character
5783 				 */
5784 				safe_full_path_size -= current_directory_string_segment_size;
5785 
5786 				if( libcsplit_wide_split_string_set_segment_by_index(
5787 				     current_directory_split_string,
5788 				     current_directory_segment_index,
5789 				     NULL,
5790 				     0,
5791 				     error ) != 1 )
5792 				{
5793 					libcerror_error_set(
5794 					 error,
5795 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5796 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5797 					 "%s: unable to set current working directory string segment: %d.",
5798 					 function,
5799 					 current_directory_segment_index );
5800 
5801 					goto on_error;
5802 				}
5803 				current_directory_segment_index--;
5804 			}
5805 			else if( last_used_path_segment_index >= 0 )
5806 			{
5807 				if( libcsplit_wide_split_string_get_segment_by_index(
5808 				     path_split_string,
5809 				     last_used_path_segment_index,
5810 				     &last_used_path_string_segment,
5811 				     &last_used_path_string_segment_size,
5812 				     error ) != 1 )
5813 				{
5814 					libcerror_error_set(
5815 					 error,
5816 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5817 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5818 					 "%s: unable to retrieve last used path string segment: %d.",
5819 					 function,
5820 					 last_used_path_segment_index );
5821 
5822 					goto on_error;
5823 				}
5824 				if( last_used_path_string_segment == NULL )
5825 				{
5826 					libcerror_error_set(
5827 					 error,
5828 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5829 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5830 					 "%s: missing last used path string string segment: %d.",
5831 					 function,
5832 					 last_used_path_segment_index );
5833 
5834 					goto on_error;
5835 				}
5836 				/* Remove the size of the parent directory name and a directory separator
5837 				 * Note that the size includes the end of string character
5838 				 */
5839 				safe_full_path_size -= last_used_path_string_segment_size;
5840 
5841 				if( libcsplit_wide_split_string_set_segment_by_index(
5842 				     path_split_string,
5843 				     last_used_path_segment_index,
5844 				     NULL,
5845 				     0,
5846 				     error ) != 1 )
5847 				{
5848 					libcerror_error_set(
5849 					 error,
5850 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5851 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5852 					 "%s: unable to set path string segment: %d.",
5853 					 function,
5854 					 last_used_path_segment_index );
5855 
5856 					goto on_error;
5857 				}
5858 				/* Find the previous path split value that contains a name
5859 				 */
5860 				while( last_used_path_segment_index > 0 )
5861 				{
5862 					last_used_path_segment_index--;
5863 
5864 					if( libcsplit_wide_split_string_get_segment_by_index(
5865 					     path_split_string,
5866 					     last_used_path_segment_index,
5867 					     &last_used_path_string_segment,
5868 					     &last_used_path_string_segment_size,
5869 					     error ) != 1 )
5870 					{
5871 						libcerror_error_set(
5872 						 error,
5873 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5874 						 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5875 						 "%s: unable to retrieve last used path string segment: %d.",
5876 						 function,
5877 						 last_used_path_segment_index );
5878 
5879 						goto on_error;
5880 					}
5881 					if( last_used_path_string_segment_size != 0 )
5882 					{
5883 						break;
5884 					}
5885 				}
5886 			}
5887 			if( libcsplit_wide_split_string_set_segment_by_index(
5888 			     path_split_string,
5889 			     path_segment_index,
5890 			     NULL,
5891 			     0,
5892 			     error ) != 1 )
5893 			{
5894 				libcerror_error_set(
5895 				 error,
5896 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5897 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5898 				 "%s: unable to set path string segment: %d.",
5899 				 function,
5900 				 path_segment_index );
5901 
5902 				goto on_error;
5903 			}
5904 		}
5905 		/* If the path is . ignore the entry
5906 		 */
5907 		else if( ( path_string_segment_size == 2 )
5908 		      && ( path_string_segment[ 0 ] == (wchar_t) '.' ) )
5909 		{
5910 			if( libcsplit_wide_split_string_set_segment_by_index(
5911 			     path_split_string,
5912 			     path_segment_index,
5913 			     NULL,
5914 			     0,
5915 			     error ) != 1 )
5916 			{
5917 				libcerror_error_set(
5918 				 error,
5919 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5920 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5921 				 "%s: unable to set path string segment: %d.",
5922 				 function,
5923 				 path_segment_index );
5924 
5925 				goto on_error;
5926 			}
5927 		}
5928 		/* If the path is empty ignore the entry
5929 		 */
5930 		else if( path_string_segment_size <= 1 )
5931 		{
5932 			if( libcsplit_wide_split_string_set_segment_by_index(
5933 			     path_split_string,
5934 			     path_segment_index,
5935 			     NULL,
5936 			     0,
5937 			     error ) != 1 )
5938 			{
5939 				libcerror_error_set(
5940 				 error,
5941 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
5942 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5943 				 "%s: unable to set path string segment: %d.",
5944 				 function,
5945 				 path_segment_index );
5946 
5947 				goto on_error;
5948 			}
5949 		}
5950 		else
5951 		{
5952 			/* Add the size of the directory or file name and a directory separator
5953 			 * Note that the size includes the end of string character
5954 			 */
5955 			safe_full_path_size += path_string_segment_size;
5956 
5957 			last_used_path_segment_index = path_segment_index;
5958 		}
5959 	}
5960 	/* Note that the last path separator serves as the end of string
5961 	 */
5962 	full_path_index = 0;
5963 
5964 	*full_path = wide_string_allocate(
5965 	              safe_full_path_size );
5966 
5967 	if( *full_path == NULL )
5968 	{
5969 		libcerror_error_set(
5970 		 error,
5971 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
5972 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
5973 		 "%s: unable to create full path.",
5974 		 function );
5975 
5976 		goto on_error;
5977 	}
5978 	if( memory_set(
5979 	     *full_path,
5980 	     0,
5981 	     sizeof( wchar_t ) * safe_full_path_size ) == NULL )
5982 	{
5983 		libcerror_error_set(
5984 		 error,
5985 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
5986 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
5987 		 "%s: unable to clear full path.",
5988 		 function );
5989 
5990 		goto on_error;
5991 	}
5992 	*full_path_size = safe_full_path_size;
5993 
5994 	if( path_type == LIBCPATH_TYPE_ABSOLUTE )
5995 	{
5996 		( *full_path )[ full_path_index ] = (wchar_t) '/';
5997 
5998 		full_path_index += 1;
5999 	}
6000 	/* If the path is relative
6001 	 * add the current working directory elements
6002 	 */
6003 	if( ( path_type == LIBCPATH_TYPE_RELATIVE )
6004 	 && ( current_directory_split_string != NULL ) )
6005 	{
6006 		for( current_directory_segment_index = 0;
6007 		     current_directory_segment_index < current_directory_number_of_segments;
6008 		     current_directory_segment_index++ )
6009 		{
6010 			if( libcsplit_wide_split_string_get_segment_by_index(
6011 			     current_directory_split_string,
6012 			     current_directory_segment_index,
6013 			     &current_directory_string_segment,
6014 			     &current_directory_string_segment_size,
6015 			     error ) != 1 )
6016 			{
6017 				libcerror_error_set(
6018 				 error,
6019 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6020 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6021 				 "%s: unable to retrieve current working directory string segment: %d.",
6022 				 function,
6023 				 current_directory_segment_index );
6024 
6025 				goto on_error;
6026 			}
6027 			if( current_directory_string_segment_size != 0 )
6028 			{
6029 				if( current_directory_string_segment == NULL )
6030 				{
6031 					libcerror_error_set(
6032 					 error,
6033 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6034 					 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
6035 					 "%s: missing current working directory string segment: %d.",
6036 					 function,
6037 					 current_directory_segment_index );
6038 
6039 					goto on_error;
6040 				}
6041 				if( wide_string_copy(
6042 				     &( ( *full_path )[ full_path_index ] ),
6043 				     current_directory_string_segment,
6044 				     current_directory_string_segment_size - 1 ) == NULL )
6045 				{
6046 					libcerror_error_set(
6047 					 error,
6048 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6049 					 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
6050 					 "%s: unable to set current working directory split value: %d in full path.",
6051 					 function,
6052 					 current_directory_segment_index );
6053 
6054 					goto on_error;
6055 				}
6056 				full_path_index += current_directory_string_segment_size - 1;
6057 
6058 				( *full_path )[ full_path_index ] = (wchar_t) '/';
6059 
6060 				full_path_index += 1;
6061 			}
6062 		}
6063 	}
6064 	for( path_segment_index = 0;
6065 	     path_segment_index < path_number_of_segments;
6066 	     path_segment_index++ )
6067 	{
6068 		if( libcsplit_wide_split_string_get_segment_by_index(
6069 		     path_split_string,
6070 		     path_segment_index,
6071 		     &path_string_segment,
6072 		     &path_string_segment_size,
6073 		     error ) != 1 )
6074 		{
6075 			libcerror_error_set(
6076 			 error,
6077 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6078 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6079 			 "%s: unable to retrieve path string segment: %d.",
6080 			 function,
6081 			 path_segment_index );
6082 
6083 			goto on_error;
6084 		}
6085 		if( path_string_segment_size != 0 )
6086 		{
6087 			if( path_string_segment == NULL )
6088 			{
6089 				libcerror_error_set(
6090 				 error,
6091 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6092 				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
6093 				 "%s: missing path string segment: %d.",
6094 				 function,
6095 				 path_segment_index );
6096 
6097 				goto on_error;
6098 			}
6099 			if( wide_string_copy(
6100 			     &( ( *full_path )[ full_path_index ] ),
6101 			     path_string_segment,
6102 			     path_string_segment_size - 1 ) == NULL )
6103 			{
6104 				libcerror_error_set(
6105 				 error,
6106 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6107 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
6108 				 "%s: unable to set path split value: %d in full path.",
6109 				 function,
6110 				 path_segment_index );
6111 
6112 				goto on_error;
6113 			}
6114 			full_path_index += path_string_segment_size - 1;
6115 
6116 			( *full_path )[ full_path_index ] = (wchar_t) '/';
6117 
6118 			full_path_index += 1;
6119 		}
6120 	}
6121 	( *full_path )[ full_path_index - 1 ] = 0;
6122 
6123 	if( libcsplit_wide_split_string_free(
6124 	     &path_split_string,
6125 	     error ) != 1 )
6126 	{
6127 		libcerror_error_set(
6128 		 error,
6129 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6130 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
6131 		 "%s: unable to free path split string.",
6132 		 function );
6133 
6134 		goto on_error;
6135 	}
6136 	if( current_directory_split_string != NULL )
6137 	{
6138 		if( libcsplit_wide_split_string_free(
6139 		     &current_directory_split_string,
6140 		     error ) != 1 )
6141 		{
6142 			libcerror_error_set(
6143 			 error,
6144 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6145 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
6146 			 "%s: unable to free current working directory split string.",
6147 			 function );
6148 
6149 			goto on_error;
6150 		}
6151 	}
6152 	if( current_directory != NULL )
6153 	{
6154 		memory_free(
6155 		 current_directory );
6156 	}
6157 	return( 1 );
6158 
6159 on_error:
6160 	if( *full_path != NULL )
6161 	{
6162 		memory_free(
6163 		 *full_path );
6164 
6165 		*full_path = NULL;
6166 	}
6167 	*full_path_size = 0;
6168 
6169 	if( path_split_string != NULL )
6170 	{
6171 		libcsplit_wide_split_string_free(
6172 		 &path_split_string,
6173 		 NULL );
6174 	}
6175 	if( current_directory_split_string != NULL )
6176 	{
6177 		libcsplit_wide_split_string_free(
6178 		 &current_directory_split_string,
6179 		 NULL );
6180 	}
6181 	if( current_directory != NULL )
6182 	{
6183 		memory_free(
6184 		 current_directory );
6185 	}
6186 	return( -1 );
6187 }
6188 
6189 #endif /* defined( WINAPI ) */
6190 
6191 /* Retrieves the size of a sanitized version of the path character
6192  * Returns 1 if successful or -1 on error
6193  */
libcpath_path_get_sanitized_character_size_wide(wchar_t character,size_t * sanitized_character_size,libcerror_error_t ** error)6194 int libcpath_path_get_sanitized_character_size_wide(
6195      wchar_t character,
6196      size_t *sanitized_character_size,
6197      libcerror_error_t **error )
6198 {
6199 	static char *function = "libcpath_path_get_sanitized_character_size_wide";
6200 
6201 	if( sanitized_character_size == NULL )
6202 	{
6203 		libcerror_error_set(
6204 		 error,
6205 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6206 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6207 		 "%s: invalid sanitized character size.",
6208 		 function );
6209 
6210 		return( -1 );
6211 	}
6212 	if( ( character >= 0x00 )
6213 	 && ( character <= 0x1f ) )
6214 	{
6215 		*sanitized_character_size = 4;
6216 	}
6217 	else if( character == (wchar_t) LIBCPATH_ESCAPE_CHARACTER )
6218 	{
6219 		*sanitized_character_size = 2;
6220 	}
6221 #if defined( WINAPI )
6222 	else if( character == (wchar_t) '/' )
6223 	{
6224 		*sanitized_character_size = 4;
6225 	}
6226 #endif
6227 	else if( ( character == (wchar_t) '!' )
6228 	      || ( character == (wchar_t) '$' )
6229 	      || ( character == (wchar_t) '%' )
6230 	      || ( character == (wchar_t) '&' )
6231 	      || ( character == (wchar_t) '*' )
6232 	      || ( character == (wchar_t) '+' )
6233 	      || ( character == (wchar_t) ':' )
6234 	      || ( character == (wchar_t) ';' )
6235 	      || ( character == (wchar_t) '<' )
6236 	      || ( character == (wchar_t) '>' )
6237 	      || ( character == (wchar_t) '?' )
6238 	      || ( character == (wchar_t) '|' )
6239 	      || ( character == 0x7f ) )
6240 	{
6241 		*sanitized_character_size = 4;
6242 	}
6243 	else
6244 	{
6245 		*sanitized_character_size = 1;
6246 	}
6247 	return( 1 );
6248 }
6249 
6250 /* Retrieves a sanitized version of the path character
6251  * Returns 1 if successful or -1 on error
6252  */
libcpath_path_get_sanitized_character_wide(wchar_t character,size_t sanitized_character_size,wchar_t * sanitized_path,size_t sanitized_path_size,size_t * sanitized_path_index,libcerror_error_t ** error)6253 int libcpath_path_get_sanitized_character_wide(
6254      wchar_t character,
6255      size_t sanitized_character_size,
6256      wchar_t *sanitized_path,
6257      size_t sanitized_path_size,
6258      size_t *sanitized_path_index,
6259      libcerror_error_t **error )
6260 {
6261 	static char *function            = "libcpath_path_get_sanitized_character_wide";
6262 	size_t safe_sanitized_path_index = 0;
6263 	wchar_t lower_nibble             = 0;
6264 	wchar_t upper_nibble             = 0;
6265 
6266 	if( ( sanitized_character_size != 1 )
6267 	 && ( sanitized_character_size != 2 )
6268 	 && ( sanitized_character_size != 4 ) )
6269 	{
6270 		libcerror_error_set(
6271 		 error,
6272 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6273 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
6274 		 "%s: invalid sanitized character size value out of bounds.",
6275 		 function );
6276 
6277 		return( -1 );
6278 	}
6279 	if( sanitized_path == NULL )
6280 	{
6281 		libcerror_error_set(
6282 		 error,
6283 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6284 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6285 		 "%s: invalid sanitized path.",
6286 		 function );
6287 
6288 		return( -1 );
6289 	}
6290 	if( sanitized_path_size > (size_t) SSIZE_MAX )
6291 	{
6292 		libcerror_error_set(
6293 		 error,
6294 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6295 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6296 		 "%s: invalid sanitized path size value exceeds maximum.",
6297 		 function );
6298 
6299 		return( -1 );
6300 	}
6301 	if( sanitized_path_index == NULL )
6302 	{
6303 		libcerror_error_set(
6304 		 error,
6305 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6306 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6307 		 "%s: invalid sanitized path index.",
6308 		 function );
6309 
6310 		return( -1 );
6311 	}
6312 	safe_sanitized_path_index = *sanitized_path_index;
6313 
6314 	if( safe_sanitized_path_index > sanitized_path_size )
6315 	{
6316 		libcerror_error_set(
6317 		 error,
6318 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6319 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
6320 		 "%s: invalid sanitized path index value out of bounds.",
6321 		 function );
6322 
6323 		return( -1 );
6324 	}
6325 	if( ( sanitized_character_size > sanitized_path_size )
6326 	 || ( safe_sanitized_path_index > ( sanitized_path_size - sanitized_character_size ) ) )
6327 	{
6328 		libcerror_error_set(
6329 		 error,
6330 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6331 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
6332 		 "%s: invalid sanitized path size value too small.",
6333 		 function );
6334 
6335 		return( -1 );
6336 	}
6337 	if( sanitized_character_size == 1 )
6338 	{
6339 		sanitized_path[ safe_sanitized_path_index++ ] = character;
6340 	}
6341 	else if( sanitized_character_size == 2 )
6342 	{
6343 		sanitized_path[ safe_sanitized_path_index++ ] = (wchar_t) LIBCPATH_ESCAPE_CHARACTER;
6344 		sanitized_path[ safe_sanitized_path_index++ ] = (wchar_t) LIBCPATH_ESCAPE_CHARACTER;
6345 	}
6346 	else if( sanitized_character_size == 4 )
6347 	{
6348 		lower_nibble = character & 0x0f;
6349 		upper_nibble = ( character >> 4 ) & 0x0f;
6350 
6351 		if( lower_nibble > 10 )
6352 		{
6353 			lower_nibble += (wchar_t) 'a' - 10;
6354 		}
6355 		else
6356 		{
6357 			lower_nibble += '0';
6358 		}
6359 		if( upper_nibble > 10 )
6360 		{
6361 			upper_nibble += (wchar_t) 'a' - 10;
6362 		}
6363 		else
6364 		{
6365 			upper_nibble += '0';
6366 		}
6367 		sanitized_path[ safe_sanitized_path_index++ ] = (wchar_t) LIBCPATH_ESCAPE_CHARACTER;
6368 		sanitized_path[ safe_sanitized_path_index++ ] = (wchar_t) 'x';
6369 		sanitized_path[ safe_sanitized_path_index++ ] = upper_nibble;
6370 		sanitized_path[ safe_sanitized_path_index++ ] = lower_nibble;
6371 	}
6372 	*sanitized_path_index = safe_sanitized_path_index;
6373 
6374 	return( 1 );
6375 }
6376 
6377 /* Retrieves a sanitized version of the filename
6378  * Returns 1 if successful or -1 on error
6379  */
libcpath_path_get_sanitized_filename_wide(const wchar_t * filename,size_t filename_length,wchar_t ** sanitized_filename,size_t * sanitized_filename_size,libcerror_error_t ** error)6380 int libcpath_path_get_sanitized_filename_wide(
6381      const wchar_t *filename,
6382      size_t filename_length,
6383      wchar_t **sanitized_filename,
6384      size_t *sanitized_filename_size,
6385      libcerror_error_t **error )
6386 {
6387 	static char *function               = "libcpath_path_get_sanitized_filename_wide";
6388 	wchar_t *safe_sanitized_filename    = NULL;
6389 	size_t filename_index               = 0;
6390 	size_t sanitized_character_size     = 0;
6391 	size_t safe_sanitized_filename_size = 0;
6392 	size_t sanitized_filename_index     = 0;
6393 
6394 	if( filename == NULL )
6395 	{
6396 		libcerror_error_set(
6397 		 error,
6398 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6399 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6400 		 "%s: invalid filename.",
6401 		 function );
6402 
6403 		return( -1 );
6404 	}
6405 	if( filename_length == 0 )
6406 	{
6407 		libcerror_error_set(
6408 		 error,
6409 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6410 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
6411 		 "%s: invalid filename length is zero.",
6412 		 function );
6413 
6414 		return( -1 );
6415 	}
6416 	if( filename_length > (size_t) ( SSIZE_MAX - 1 ) )
6417 	{
6418 		libcerror_error_set(
6419 		 error,
6420 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6421 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6422 		 "%s: invalid filename length value exceeds maximum.",
6423 		 function );
6424 
6425 		return( -1 );
6426 	}
6427 	if( sanitized_filename == NULL )
6428 	{
6429 		libcerror_error_set(
6430 		 error,
6431 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6432 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6433 		 "%s: invalid sanitized filename.",
6434 		 function );
6435 
6436 		return( -1 );
6437 	}
6438 	if( *sanitized_filename != NULL )
6439 	{
6440 		libcerror_error_set(
6441 		 error,
6442 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6443 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
6444 		 "%s: invalid sanitized filename value already set.",
6445 		 function );
6446 
6447 		return( -1 );
6448 	}
6449 	if( sanitized_filename_size == NULL )
6450 	{
6451 		libcerror_error_set(
6452 		 error,
6453 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6454 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6455 		 "%s: invalid sanitized filename size.",
6456 		 function );
6457 
6458 		return( -1 );
6459 	}
6460 	safe_sanitized_filename_size = 1;
6461 
6462 	for( filename_index = 0;
6463 	     filename_index < filename_length;
6464 	     filename_index++ )
6465 	{
6466 		if( filename[ filename_index ] == LIBCPATH_SEPARATOR )
6467 		{
6468 			sanitized_character_size = 4;
6469 		}
6470 		else if( libcpath_path_get_sanitized_character_size_wide(
6471 		          filename[ filename_index ],
6472 		          &sanitized_character_size,
6473 		          error ) != 1 )
6474 		{
6475 			libcerror_error_set(
6476 			 error,
6477 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6478 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6479 			 "%s: unable to determine sanitize character size.",
6480 			 function );
6481 
6482 			goto on_error;
6483 		}
6484 		safe_sanitized_filename_size += sanitized_character_size;
6485 	}
6486 	if( safe_sanitized_filename_size > (size_t) SSIZE_MAX )
6487 	{
6488 		libcerror_error_set(
6489 		 error,
6490 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6491 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6492 		 "%s: invalid sanitized filename size value exceeds maximum.",
6493 		 function );
6494 
6495 		goto on_error;
6496 	}
6497 	safe_sanitized_filename = wide_string_allocate(
6498 	                           safe_sanitized_filename_size );
6499 
6500 	if( safe_sanitized_filename == NULL )
6501 	{
6502 		libcerror_error_set(
6503 		 error,
6504 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
6505 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
6506 		 "%s: unable to create sanitized filename.",
6507 		 function );
6508 
6509 		goto on_error;
6510 	}
6511 	for( filename_index = 0;
6512 	     filename_index < filename_length;
6513 	     filename_index++ )
6514 	{
6515 		if( filename[ filename_index ] == LIBCPATH_SEPARATOR )
6516 		{
6517 			sanitized_character_size = 4;
6518 		}
6519 		else if( libcpath_path_get_sanitized_character_size_wide(
6520 		          filename[ filename_index ],
6521 		          &sanitized_character_size,
6522 		          error ) != 1 )
6523 		{
6524 			libcerror_error_set(
6525 			 error,
6526 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6527 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6528 			 "%s: unable to determine sanitize character size.",
6529 			 function );
6530 
6531 			goto on_error;
6532 		}
6533 		if( libcpath_path_get_sanitized_character_wide(
6534 		     filename[ filename_index ],
6535 		     sanitized_character_size,
6536 		     safe_sanitized_filename,
6537 		     safe_sanitized_filename_size,
6538 		     &sanitized_filename_index,
6539 		     error ) != 1 )
6540 		{
6541 			libcerror_error_set(
6542 			 error,
6543 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6544 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6545 			 "%s: unable to determine sanitize character size.",
6546 			 function );
6547 
6548 			goto on_error;
6549 		}
6550 	}
6551 	safe_sanitized_filename[ sanitized_filename_index ] = 0;
6552 
6553 	*sanitized_filename      = safe_sanitized_filename;
6554 	*sanitized_filename_size = safe_sanitized_filename_size;
6555 
6556 	return( 1 );
6557 
6558 on_error:
6559 	if( safe_sanitized_filename != NULL )
6560 	{
6561 		memory_free(
6562 		 safe_sanitized_filename );
6563 	}
6564 	return( -1 );
6565 }
6566 
6567 /* Retrieves a sanitized version of the path
6568  * Returns 1 if successful or -1 on error
6569  */
libcpath_path_get_sanitized_path_wide(const wchar_t * path,size_t path_length,wchar_t ** sanitized_path,size_t * sanitized_path_size,libcerror_error_t ** error)6570 int libcpath_path_get_sanitized_path_wide(
6571      const wchar_t *path,
6572      size_t path_length,
6573      wchar_t **sanitized_path,
6574      size_t *sanitized_path_size,
6575      libcerror_error_t **error )
6576 {
6577 	static char *function                    = "libcpath_path_get_sanitized_path_wide";
6578 	wchar_t *safe_sanitized_path             = NULL;
6579 	size_t path_index                        = 0;
6580 	size_t safe_sanitized_path_size          = 0;
6581 	size_t sanitized_character_size          = 0;
6582 	size_t sanitized_path_index              = 0;
6583 
6584 #if defined( WINAPI )
6585 	size_t last_path_segment_seperator_index = 0;
6586 #endif
6587 
6588 	if( path == NULL )
6589 	{
6590 		libcerror_error_set(
6591 		 error,
6592 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6593 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6594 		 "%s: invalid path.",
6595 		 function );
6596 
6597 		return( -1 );
6598 	}
6599 	if( path_length == 0 )
6600 	{
6601 		libcerror_error_set(
6602 		 error,
6603 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6604 		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
6605 		 "%s: invalid path length is zero.",
6606 		 function );
6607 
6608 		return( -1 );
6609 	}
6610 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
6611 	{
6612 		libcerror_error_set(
6613 		 error,
6614 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6615 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6616 		 "%s: invalid path length value exceeds maximum.",
6617 		 function );
6618 
6619 		return( -1 );
6620 	}
6621 	if( sanitized_path == NULL )
6622 	{
6623 		libcerror_error_set(
6624 		 error,
6625 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6626 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6627 		 "%s: invalid sanitized path.",
6628 		 function );
6629 
6630 		return( -1 );
6631 	}
6632 	if( *sanitized_path != NULL )
6633 	{
6634 		libcerror_error_set(
6635 		 error,
6636 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6637 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
6638 		 "%s: invalid sanitized path value already set.",
6639 		 function );
6640 
6641 		return( -1 );
6642 	}
6643 	if( sanitized_path_size == NULL )
6644 	{
6645 		libcerror_error_set(
6646 		 error,
6647 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6648 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6649 		 "%s: invalid sanitized path size.",
6650 		 function );
6651 
6652 		return( -1 );
6653 	}
6654 	safe_sanitized_path_size = 1;
6655 
6656 	for( path_index = 0;
6657 	     path_index < path_length;
6658 	     path_index++ )
6659 	{
6660 		if( libcpath_path_get_sanitized_character_size_wide(
6661 		     path[ path_index ],
6662 		     &sanitized_character_size,
6663 		     error ) != 1 )
6664 		{
6665 			libcerror_error_set(
6666 			 error,
6667 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6668 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6669 			 "%s: unable to determine sanitize character size.",
6670 			 function );
6671 
6672 			goto on_error;
6673 		}
6674 		safe_sanitized_path_size += sanitized_character_size;
6675 
6676 #if defined( WINAPI )
6677 		if( path[ path_index ] == LIBCPATH_SEPARATOR )
6678 		{
6679 			last_path_segment_seperator_index = path_index;
6680 		}
6681 #endif
6682 	}
6683 	if( safe_sanitized_path_size > (size_t) SSIZE_MAX )
6684 	{
6685 		libcerror_error_set(
6686 		 error,
6687 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6688 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6689 		 "%s: invalid sanitized path size value exceeds maximum.",
6690 		 function );
6691 
6692 		goto on_error;
6693 	}
6694 #if defined( WINAPI )
6695 	if( last_path_segment_seperator_index > 32767 )
6696 	{
6697 		libcerror_error_set(
6698 		 error,
6699 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6700 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
6701 		 "%s: last path segment separator value out of bounds.",
6702 		 function );
6703 
6704 		goto on_error;
6705 	}
6706 	if( safe_sanitized_path_size > 32767 )
6707 	{
6708 		safe_sanitized_path_size = 32767;
6709 	}
6710 #endif
6711 	safe_sanitized_path = wide_string_allocate(
6712 	                       safe_sanitized_path_size );
6713 
6714 	if( safe_sanitized_path == NULL )
6715 	{
6716 		libcerror_error_set(
6717 		 error,
6718 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
6719 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
6720 		 "%s: unable to create sanitized path.",
6721 		 function );
6722 
6723 		goto on_error;
6724 	}
6725 	for( path_index = 0;
6726 	     path_index < path_length;
6727 	     path_index++ )
6728 	{
6729 		if( libcpath_path_get_sanitized_character_size_wide(
6730 		     path[ path_index ],
6731 		     &sanitized_character_size,
6732 		     error ) != 1 )
6733 		{
6734 			libcerror_error_set(
6735 			 error,
6736 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6737 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6738 			 "%s: unable to determine sanitize character size.",
6739 			 function );
6740 
6741 			goto on_error;
6742 		}
6743 		if( libcpath_path_get_sanitized_character_wide(
6744 		     path[ path_index ],
6745 		     sanitized_character_size,
6746 		     safe_sanitized_path,
6747 		     safe_sanitized_path_size,
6748 		     &sanitized_path_index,
6749 		     error ) != 1 )
6750 		{
6751 			libcerror_error_set(
6752 			 error,
6753 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6754 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6755 			 "%s: unable to determine sanitize character size.",
6756 			 function );
6757 
6758 			goto on_error;
6759 		}
6760 	}
6761 	safe_sanitized_path[ sanitized_path_index ] = 0;
6762 
6763 	*sanitized_path      = safe_sanitized_path;
6764 	*sanitized_path_size = safe_sanitized_path_size;
6765 
6766 	return( 1 );
6767 
6768 on_error:
6769 	if( safe_sanitized_path != NULL )
6770 	{
6771 		memory_free(
6772 		 safe_sanitized_path );
6773 	}
6774 	return( -1 );
6775 }
6776 
6777 /* Combines the directory name and filename into a path
6778  * Returns 1 if successful or -1 on error
6779  */
libcpath_path_join_wide(wchar_t ** path,size_t * path_size,const wchar_t * directory_name,size_t directory_name_length,const wchar_t * filename,size_t filename_length,libcerror_error_t ** error)6780 int libcpath_path_join_wide(
6781      wchar_t **path,
6782      size_t *path_size,
6783      const wchar_t *directory_name,
6784      size_t directory_name_length,
6785      const wchar_t *filename,
6786      size_t filename_length,
6787      libcerror_error_t **error )
6788 {
6789 	static char *function = "libcpath_path_join_wide";
6790 	size_t filename_index = 0;
6791 	size_t path_index     = 0;
6792 
6793 	if( path == NULL )
6794 	{
6795 		libcerror_error_set(
6796 		 error,
6797 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6798 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6799 		 "%s: invalid path.",
6800 		 function );
6801 
6802 		return( -1 );
6803 	}
6804 	if( *path != NULL )
6805 	{
6806 		libcerror_error_set(
6807 		 error,
6808 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6809 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
6810 		 "%s: invalid path value already set.",
6811 		 function );
6812 
6813 		return( -1 );
6814 	}
6815 	if( path_size == NULL )
6816 	{
6817 		libcerror_error_set(
6818 		 error,
6819 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6820 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6821 		 "%s: invalid path size.",
6822 		 function );
6823 
6824 		return( -1 );
6825 	}
6826 	if( directory_name == NULL )
6827 	{
6828 		libcerror_error_set(
6829 		 error,
6830 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6831 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6832 		 "%s: invalid directory name.",
6833 		 function );
6834 
6835 		return( -1 );
6836 	}
6837 	if( directory_name_length > (size_t) SSIZE_MAX )
6838 	{
6839 		libcerror_error_set(
6840 		 error,
6841 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6842 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6843 		 "%s: invalid directory name length value exceeds maximum.",
6844 		 function );
6845 
6846 		return( -1 );
6847 	}
6848 	if( filename == NULL )
6849 	{
6850 		libcerror_error_set(
6851 		 error,
6852 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6853 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6854 		 "%s: invalid filename.",
6855 		 function );
6856 
6857 		return( -1 );
6858 	}
6859 	if( filename_length > (size_t) SSIZE_MAX )
6860 	{
6861 		libcerror_error_set(
6862 		 error,
6863 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6864 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6865 		 "%s: invalid filename length value exceeds maximum.",
6866 		 function );
6867 
6868 		return( -1 );
6869 	}
6870 /* TODO strip other patterns like /./ */
6871 	while( directory_name_length > 0 )
6872 	{
6873 		if( directory_name[ directory_name_length - 1 ] != (wchar_t) LIBCPATH_SEPARATOR )
6874 		{
6875 			break;
6876 		}
6877 		directory_name_length--;
6878 	}
6879 	while( filename_length > 0 )
6880 	{
6881 		if( filename[ filename_index ] != (wchar_t) LIBCPATH_SEPARATOR )
6882 		{
6883 			break;
6884 		}
6885 		filename_index++;
6886 		filename_length--;
6887 	}
6888 	*path_size = directory_name_length + filename_length + 2;
6889 
6890 	*path = wide_string_allocate(
6891 	         *path_size );
6892 
6893 	if( *path == NULL )
6894 	{
6895 		libcerror_error_set(
6896 		 error,
6897 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
6898 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
6899 		 "%s: unable to create path.",
6900 		 function );
6901 
6902 		goto on_error;
6903 	}
6904 	if( wide_string_copy(
6905 	     *path,
6906 	     directory_name,
6907 	     directory_name_length ) == NULL )
6908 	{
6909 		libcerror_error_set(
6910 		 error,
6911 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
6912 		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
6913 		 "%s: unable to copy directory name to path.",
6914 		 function );
6915 
6916 		goto on_error;
6917 	}
6918 	path_index = directory_name_length;
6919 
6920 	( *path )[ path_index++ ] = (wchar_t) LIBCPATH_SEPARATOR;
6921 
6922 	if( wide_string_copy(
6923 	     &( ( *path )[ path_index ] ),
6924 	     &( filename[ filename_index ] ),
6925 	     filename_length ) == NULL )
6926 	{
6927 		libcerror_error_set(
6928 		 error,
6929 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
6930 		 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
6931 		 "%s: unable to copy filename to path.",
6932 		 function );
6933 
6934 		goto on_error;
6935 	}
6936 	path_index += filename_length;
6937 
6938 	( *path )[ path_index ] = 0;
6939 
6940 	return( 1 );
6941 
6942 on_error:
6943 	if( *path != NULL )
6944 	{
6945 		memory_free(
6946 		 *path );
6947 
6948 		*path = NULL;
6949 	}
6950 	*path_size = 0;
6951 
6952 	return( -1 );
6953 }
6954 
6955 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
6956 
6957 /* Cross Windows safe version of CreateDirectoryW
6958  * Returns TRUE if successful or FALSE on error
6959  */
libcpath_CreateDirectoryW(LPCWSTR path,SECURITY_ATTRIBUTES * security_attributes)6960 BOOL libcpath_CreateDirectoryW(
6961       LPCWSTR path,
6962       SECURITY_ATTRIBUTES *security_attributes )
6963 {
6964 	FARPROC function       = NULL;
6965 	HMODULE library_handle = NULL;
6966 	BOOL result            = FALSE;
6967 
6968 	if( path == NULL )
6969 	{
6970 		return( 0 );
6971 	}
6972 	library_handle = LoadLibrary(
6973 	                  _SYSTEM_STRING( "kernel32.dll" ) );
6974 
6975 	if( library_handle == NULL )
6976 	{
6977 		return( 0 );
6978 	}
6979 	function = GetProcAddress(
6980 		    library_handle,
6981 		    (LPCSTR) "CreateDirectoryW" );
6982 
6983 	if( function != NULL )
6984 	{
6985 		result = function(
6986 			  path,
6987 			  security_attributes );
6988 	}
6989 	/* This call should be after using the function
6990 	 * in most cases kernel32.dll will still be available after free
6991 	 */
6992 	if( FreeLibrary(
6993 	     library_handle ) != TRUE )
6994 	{
6995 		libcpath_CloseHandle(
6996 		 library_handle );
6997 
6998 		return( 0 );
6999 	}
7000 	return( result );
7001 }
7002 
7003 #endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
7004 
7005 #if defined( WINAPI )
7006 
7007 /* Makes the directory
7008  * This function uses the WINAPI function for Windows XP (0x0501) or later
7009  * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
7010  * Returns 1 if successful or -1 on error
7011  */
libcpath_path_make_directory_wide(const wchar_t * directory_name,libcerror_error_t ** error)7012 int libcpath_path_make_directory_wide(
7013      const wchar_t *directory_name,
7014      libcerror_error_t **error )
7015 {
7016 	static char *function = "libcpath_path_make_directory_wide";
7017 	DWORD error_code      = 0;
7018 
7019 	if( directory_name == NULL )
7020 	{
7021 		libcerror_error_set(
7022 		 error,
7023 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7024 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
7025 		 "%s: invalid directory name.",
7026 		 function );
7027 
7028 		return( -1 );
7029 	}
7030 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
7031 	if( libcpath_CreateDirectoryW(
7032 	     directory_name,
7033 	     NULL ) == 0 )
7034 #else
7035 	if( CreateDirectoryW(
7036 	     directory_name,
7037 	     NULL ) == 0 )
7038 #endif
7039 	{
7040 		error_code = GetLastError();
7041 
7042 		libcerror_system_set_error(
7043 		 error,
7044 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
7045 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
7046 		 error_code,
7047 		 "%s: unable to make directory.",
7048 		 function );
7049 
7050 		return( -1 );
7051 	}
7052 	return( 1 );
7053 }
7054 
7055 #elif defined( HAVE_MKDIR )
7056 
7057 /* Makes the directory
7058  * This function uses the POSIX mkdir function or equivalent
7059  * Returns 1 if successful or -1 on error
7060  */
libcpath_path_make_directory_wide(const wchar_t * directory_name,libcerror_error_t ** error)7061 int libcpath_path_make_directory_wide(
7062      const wchar_t *directory_name,
7063      libcerror_error_t **error )
7064 {
7065 	static char *function             = "libcpath_path_make_directory_wide";
7066 	char *narrow_directory_name       = 0;
7067 	size_t directory_name_length      = 0;
7068 	size_t narrow_directory_name_size = 0;
7069 
7070 	if( directory_name == NULL )
7071 	{
7072 		libcerror_error_set(
7073 		 error,
7074 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7075 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
7076 		 "%s: invalid directory name.",
7077 		 function );
7078 
7079 		return( -1 );
7080 	}
7081 	directory_name_length = wide_string_length(
7082 	                         directory_name );
7083 
7084 	if( libcpath_system_string_size_from_wide_string(
7085 	     directory_name,
7086 	     directory_name_length + 1,
7087 	     &narrow_directory_name_size,
7088 	     error ) != 1 )
7089 	{
7090 		libcerror_error_set(
7091 		 error,
7092 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
7093 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
7094 		 "%s: unable to determine narrow directory name size.",
7095 		 function );
7096 
7097 		goto on_error;
7098 	}
7099 	if( ( narrow_directory_name_size > (size_t) SSIZE_MAX )
7100 	 || ( ( sizeof( char ) * narrow_directory_name_size )  > (size_t) SSIZE_MAX ) )
7101 	{
7102 		libcerror_error_set(
7103 		 error,
7104 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
7105 		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
7106 		 "%s: invalid narrow directory name size value exceeds maximum.",
7107 		 function );
7108 
7109 		goto on_error;
7110 	}
7111 	narrow_directory_name = narrow_string_allocate(
7112 	                         narrow_directory_name_size );
7113 
7114 	if( narrow_directory_name == NULL )
7115 	{
7116 		libcerror_error_set(
7117 		 error,
7118 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
7119 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
7120 		 "%s: unable to create narrow directory name.",
7121 		 function );
7122 
7123 		goto on_error;
7124 	}
7125 	if( libcpath_system_string_copy_from_wide_string(
7126 	     narrow_directory_name,
7127 	     narrow_directory_name_size,
7128 	     directory_name,
7129 	     directory_name_length + 1,
7130 	     error ) != 1 )
7131 	{
7132 		libcerror_error_set(
7133 		 error,
7134 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
7135 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
7136 		 "%s: unable to set name.",
7137 		 function );
7138 
7139 		goto on_error;
7140 	}
7141 	if( mkdir(
7142 	     narrow_directory_name,
7143 	     0755 ) != 0 )
7144 	{
7145 		libcerror_system_set_error(
7146 		 error,
7147 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
7148 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
7149 		 errno,
7150 		 "%s: unable to make directory.",
7151 		 function );
7152 
7153 		goto on_error;
7154 	}
7155 	memory_free(
7156 	 narrow_directory_name );
7157 
7158 	return( 1 );
7159 
7160 on_error:
7161 	if( narrow_directory_name != NULL )
7162 	{
7163 		memory_free(
7164 		 narrow_directory_name );
7165 	}
7166 	return( -1 );
7167 }
7168 
7169 #else
7170 #error Missing make directory function
7171 #endif
7172 
7173 #endif /* defined( HAVE_WIDE_CHARACTER_TYPE ) */
7174 
7175