Coverage Report

Created: 2026-07-10 07:32

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