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 ¤t_volume_working_directory,
935 ¤t_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 ¤t_directory,
1228 ¤t_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 ¤t_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 ¤t_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 ¤t_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 ¤t_directory_string_segment,
1413 ¤t_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 ¤t_directory_string_segment,
1734 ¤t_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 ¤t_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 ¤t_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 ¤t_directory,
2025 ¤t_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 ¤t_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 ¤t_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 ¤t_directory_string_segment,
2190 ¤t_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 ¤t_directory_string_segment,
2448 ¤t_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 ¤t_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 ¤t_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 ¤t_volume_working_directory,
4504 ¤t_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 ¤t_directory,
4792 ¤t_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 ¤t_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 ¤t_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 ¤t_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 ¤t_directory_string_segment,
4979 ¤t_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 ¤t_directory_string_segment,
5300 ¤t_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 ¤t_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 ¤t_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 ¤t_directory,
5591 ¤t_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 ¤t_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 ¤t_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 ¤t_directory_string_segment,
5756 ¤t_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 ¤t_directory_string_segment,
6014 ¤t_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 ¤t_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 ¤t_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