Coverage Report

Created: 2026-05-30 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsxfs/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 defined( WINAPI ) && ( WINVER <= 0x0500 )
174
  if( libcpath_SetCurrentDirectoryA(
175
       directory_name ) == 0 )
176
#else
177
  if( SetCurrentDirectoryA(
178
       directory_name ) == 0 )
179
#endif
180
  {
181
    error_code = GetLastError();
182
183
    libcerror_system_set_error(
184
     error,
185
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
186
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
187
     error_code,
188
     "%s: unable to change directory.",
189
     function );
190
191
    return( -1 );
192
  }
193
  return( 1 );
194
}
195
196
#elif defined( HAVE_CHDIR )
197
198
/* Changes the directory
199
 * This function uses the POSIX chdir function or equivalent
200
 * Returns 1 if successful or -1 on error
201
 */
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 defined( WINAPI ) && ( 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 defined( WINAPI ) && ( 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 succesful 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 succesful 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 defined( WINAPI ) && ( 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 defined( WINAPI ) && ( 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 succesful 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
    full_path_index += 1;
1782
  }
1783
  /* If the path is relative
1784
   * add the current working directory elements
1785
   */
1786
  if( ( path_type == LIBCPATH_TYPE_RELATIVE )
1787
   && ( current_directory_split_string != NULL ) )
1788
  {
1789
    for( current_directory_segment_index = 0;
1790
         current_directory_segment_index < current_directory_number_of_segments;
1791
         current_directory_segment_index++ )
1792
    {
1793
      if( libcsplit_narrow_split_string_get_segment_by_index(
1794
           current_directory_split_string,
1795
           current_directory_segment_index,
1796
           &current_directory_string_segment,
1797
           &current_directory_string_segment_size,
1798
           error ) != 1 )
1799
      {
1800
        libcerror_error_set(
1801
         error,
1802
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1803
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1804
         "%s: unable to retrieve current working directory string segment: %d.",
1805
         function,
1806
         current_directory_segment_index );
1807
1808
        goto on_error;
1809
      }
1810
      if( current_directory_string_segment_size != 0 )
1811
      {
1812
        if( current_directory_string_segment == NULL )
1813
        {
1814
          libcerror_error_set(
1815
           error,
1816
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1817
           LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1818
           "%s: missing current working directory string segment: %d.",
1819
           function,
1820
           current_directory_segment_index );
1821
1822
          goto on_error;
1823
        }
1824
        /* Note that here we should have room for the segment string and
1825
         * one additional character
1826
         */
1827
        if( current_directory_string_segment_size > ( safe_full_path_size - full_path_index ) )
1828
        {
1829
          libcerror_error_set(
1830
           error,
1831
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1832
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1833
           "%s: invalid current working directory string segment: %d size value out of bounds.",
1834
           function,
1835
           current_directory_segment_index );
1836
1837
          goto on_error;
1838
        }
1839
        path_string_segment_length = current_directory_string_segment_size - 1;
1840
1841
        if( narrow_string_copy(
1842
             &( safe_full_path[ full_path_index ] ),
1843
             current_directory_string_segment,
1844
             path_string_segment_length ) == NULL )
1845
        {
1846
          libcerror_error_set(
1847
           error,
1848
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1849
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1850
           "%s: unable to set current working directory split value: %d in full path.",
1851
           function,
1852
           current_directory_segment_index );
1853
1854
          goto on_error;
1855
        }
1856
        full_path_index += path_string_segment_length;
1857
1858
        safe_full_path[ full_path_index ] = '\\';
1859
1860
        full_path_index += 1;
1861
      }
1862
    }
1863
  }
1864
  if( path_split_string != NULL )
1865
  {
1866
    for( path_segment_index = 0;
1867
         path_segment_index < path_number_of_segments;
1868
         path_segment_index++ )
1869
    {
1870
      if( libcsplit_narrow_split_string_get_segment_by_index(
1871
           path_split_string,
1872
           path_segment_index,
1873
           &path_string_segment,
1874
           &path_string_segment_size,
1875
           error ) != 1 )
1876
      {
1877
        libcerror_error_set(
1878
         error,
1879
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1880
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1881
         "%s: unable to retrieve path string segment: %d.",
1882
         function,
1883
         path_segment_index );
1884
1885
        goto on_error;
1886
      }
1887
      if( path_string_segment_size != 0 )
1888
      {
1889
        if( path_string_segment == NULL )
1890
        {
1891
          libcerror_error_set(
1892
           error,
1893
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1894
           LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1895
           "%s: missing path string segment: %d.",
1896
           function,
1897
           path_segment_index );
1898
1899
          goto on_error;
1900
        }
1901
        /* Note that here we should have room for the segment string and
1902
         * one additional character
1903
         */
1904
        if( path_string_segment_size > ( safe_full_path_size - full_path_index ) )
1905
        {
1906
          libcerror_error_set(
1907
           error,
1908
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1909
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1910
           "%s: invalid current path string segment: %d size value out of bounds.",
1911
           function,
1912
           path_segment_index );
1913
1914
          goto on_error;
1915
        }
1916
        path_string_segment_length = path_string_segment_size - 1;
1917
1918
        if( narrow_string_copy(
1919
             &( safe_full_path[ full_path_index ] ),
1920
             path_string_segment,
1921
             path_string_segment_length ) == NULL )
1922
        {
1923
          libcerror_error_set(
1924
           error,
1925
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1926
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1927
           "%s: unable to set path split value: %d in full path.",
1928
           function,
1929
           path_segment_index );
1930
1931
          goto on_error;
1932
        }
1933
        full_path_index += path_string_segment_length;
1934
1935
        safe_full_path[ full_path_index ] = '\\';
1936
1937
        full_path_index += 1;
1938
      }
1939
    }
1940
  }
1941
  safe_full_path[ full_path_index - 1 ] = 0;
1942
1943
  if( path_split_string != NULL )
1944
  {
1945
    if( libcsplit_narrow_split_string_free(
1946
         &path_split_string,
1947
         error ) != 1 )
1948
    {
1949
      libcerror_error_set(
1950
       error,
1951
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1952
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1953
       "%s: unable to free path split string.",
1954
       function );
1955
1956
      goto on_error;
1957
    }
1958
  }
1959
  if( current_directory_split_string != NULL )
1960
  {
1961
    if( libcsplit_narrow_split_string_free(
1962
         &current_directory_split_string,
1963
         error ) != 1 )
1964
    {
1965
      libcerror_error_set(
1966
       error,
1967
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1968
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1969
       "%s: unable to free current working directory split string.",
1970
       function );
1971
1972
      goto on_error;
1973
    }
1974
  }
1975
  if( current_directory != NULL )
1976
  {
1977
    memory_free(
1978
     current_directory );
1979
  }
1980
  *full_path      = safe_full_path;
1981
  *full_path_size = safe_full_path_size;
1982
1983
  return( 1 );
1984
1985
on_error:
1986
  if( safe_full_path != NULL )
1987
  {
1988
    memory_free(
1989
     safe_full_path );
1990
  }
1991
  if( path_split_string != NULL )
1992
  {
1993
    libcsplit_narrow_split_string_free(
1994
     &path_split_string,
1995
     NULL );
1996
  }
1997
  if( current_directory_split_string != NULL )
1998
  {
1999
    libcsplit_narrow_split_string_free(
2000
     &current_directory_split_string,
2001
     NULL );
2002
  }
2003
  if( current_directory != NULL )
2004
  {
2005
    memory_free(
2006
     current_directory );
2007
  }
2008
  return( -1 );
2009
}
2010
2011
#else
2012
2013
/* Determines the full path of the POSIX path specified
2014
 * Multiple successive / are combined into one
2015
 *
2016
 * Scenarios:
2017
 * /home/user/file.txt
2018
 * /home/user//file.txt
2019
 * /home/user/../user/file.txt
2020
 * /../home/user/file.txt
2021
 * user/../user/file.txt
2022
 *
2023
 * Returns 1 if succesful or -1 on error
2024
 */
2025
int libcpath_path_get_full_path(
2026
     const char *path,
2027
     size_t path_length,
2028
     char **full_path,
2029
     size_t *full_path_size,
2030
     libcerror_error_t **error )
2031
0
{
2032
0
  libcsplit_narrow_split_string_t *current_directory_split_string = NULL;
2033
0
  libcsplit_narrow_split_string_t *path_split_string              = NULL;
2034
0
  char *current_directory                                         = NULL;
2035
0
  char *current_directory_string_segment                          = NULL;
2036
0
  char *last_used_path_string_segment                             = NULL;
2037
0
  char *path_string_segment                                       = NULL;
2038
0
  char *safe_full_path                                            = NULL;
2039
0
  static char *function                                           = "libcpath_path_get_full_path";
2040
0
  size_t current_directory_length                                 = 0;
2041
0
  size_t current_directory_size                                   = 0;
2042
0
  size_t current_directory_string_segment_size                    = 0;
2043
0
  size_t full_path_index                                          = 0;
2044
0
  size_t full_path_prefix_length                                  = 0;
2045
0
  size_t last_used_path_string_segment_size                       = 0;
2046
0
  size_t path_string_segment_length                               = 0;
2047
0
  size_t path_string_segment_size                                 = 0;
2048
0
  size_t safe_full_path_size                                      = 0;
2049
0
  uint8_t path_type                                               = LIBCPATH_TYPE_RELATIVE;
2050
0
  int current_directory_number_of_segments                        = 0;
2051
0
  int current_directory_segment_index                             = 0;
2052
0
  int last_used_path_segment_index                                = -1;
2053
0
  int path_number_of_segments                                     = 0;
2054
0
  int path_segment_index                                          = 0;
2055
2056
0
  if( path == NULL )
2057
0
  {
2058
0
    libcerror_error_set(
2059
0
     error,
2060
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2061
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2062
0
     "%s: invalid path.",
2063
0
     function );
2064
2065
0
    return( -1 );
2066
0
  }
2067
0
  if( ( path_length == 0 )
2068
0
   || ( path_length > (size_t) ( SSIZE_MAX - 1 ) ) )
2069
0
  {
2070
0
    libcerror_error_set(
2071
0
     error,
2072
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2073
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
2074
0
     "%s: invalid path length value out of bounds.",
2075
0
     function );
2076
2077
0
    return( -1 );
2078
0
  }
2079
0
  if( full_path == NULL )
2080
0
  {
2081
0
    libcerror_error_set(
2082
0
     error,
2083
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2084
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2085
0
     "%s: invalid full path.",
2086
0
     function );
2087
2088
0
    return( -1 );
2089
0
  }
2090
0
  if( *full_path != NULL )
2091
0
  {
2092
0
    libcerror_error_set(
2093
0
     error,
2094
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2095
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
2096
0
     "%s: invalid full path value already set.",
2097
0
     function );
2098
2099
0
    return( -1 );
2100
0
  }
2101
0
  if( full_path_size == NULL )
2102
0
  {
2103
0
    libcerror_error_set(
2104
0
     error,
2105
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2106
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2107
0
     "%s: invalid full path size.",
2108
0
     function );
2109
2110
0
    return( -1 );
2111
0
  }
2112
  /* Determine the full path size
2113
   */
2114
0
  if( path[ 0 ] == '/' )
2115
0
  {
2116
0
    path_type = LIBCPATH_TYPE_ABSOLUTE;
2117
2118
    /* If the path is absolute
2119
     * a directory separator
2120
     */
2121
0
    full_path_prefix_length = 1;
2122
0
  }
2123
0
  else
2124
0
  {
2125
0
    if( libcpath_path_get_current_working_directory(
2126
0
         &current_directory,
2127
0
         &current_directory_size,
2128
0
         error ) != 1 )
2129
0
    {
2130
0
      libcerror_error_set(
2131
0
       error,
2132
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2133
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2134
0
       "%s: unable to retrieve current working directory.",
2135
0
       function );
2136
2137
0
      goto on_error;
2138
0
    }
2139
0
    if( current_directory == NULL )
2140
0
    {
2141
0
      libcerror_error_set(
2142
0
       error,
2143
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2144
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2145
0
       "%s: missing current working directory.",
2146
0
       function );
2147
2148
0
      goto on_error;
2149
0
    }
2150
    /* We need to use the length here since current_directory_size will be PATH_MAX
2151
     */
2152
0
    current_directory_length = narrow_string_length(
2153
0
                                current_directory );
2154
2155
0
    if( libcsplit_narrow_string_split(
2156
0
         current_directory,
2157
0
         current_directory_length + 1,
2158
0
         '/',
2159
0
         &current_directory_split_string,
2160
0
         error ) != 1 )
2161
0
    {
2162
0
      libcerror_error_set(
2163
0
       error,
2164
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2165
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2166
0
       "%s: unable to split current working directory.",
2167
0
       function );
2168
2169
0
      goto on_error;
2170
0
    }
2171
0
    if( libcsplit_narrow_split_string_get_number_of_segments(
2172
0
         current_directory_split_string,
2173
0
         &current_directory_number_of_segments,
2174
0
         error ) != 1 )
2175
0
    {
2176
0
      libcerror_error_set(
2177
0
       error,
2178
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2179
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2180
0
       "%s: unable to retrieve number of current working directory string segments.",
2181
0
       function );
2182
2183
0
      goto on_error;
2184
0
    }
2185
0
    current_directory_segment_index = current_directory_number_of_segments - 1;
2186
2187
    /* If the path is relative
2188
     * add the size of the current working directory
2189
     * a directory separator, if necessary
2190
     */
2191
0
    safe_full_path_size = current_directory_length;
2192
2193
0
    if( ( current_directory_length >= 1 )
2194
0
     && ( current_directory[ current_directory_length - 1 ] != '/' ) )
2195
0
    {
2196
0
      safe_full_path_size++;
2197
0
    }
2198
0
  }
2199
0
  if( libcsplit_narrow_string_split(
2200
0
       path,
2201
0
       path_length + 1,
2202
0
       '/',
2203
0
       &path_split_string,
2204
0
       error ) != 1 )
2205
0
  {
2206
0
    libcerror_error_set(
2207
0
     error,
2208
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2209
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2210
0
     "%s: unable to split path.",
2211
0
     function );
2212
2213
0
    goto on_error;
2214
0
  }
2215
0
  if( path_split_string != NULL )
2216
0
  {
2217
0
    if( libcsplit_narrow_split_string_get_number_of_segments(
2218
0
         path_split_string,
2219
0
         &path_number_of_segments,
2220
0
         error ) != 1 )
2221
0
    {
2222
0
      libcerror_error_set(
2223
0
       error,
2224
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2225
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2226
0
       "%s: unable to retrieve number of path string segments.",
2227
0
       function );
2228
2229
0
      goto on_error;
2230
0
    }
2231
0
    for( path_segment_index = 0;
2232
0
         path_segment_index < path_number_of_segments;
2233
0
         path_segment_index++ )
2234
0
    {
2235
0
      if( libcsplit_narrow_split_string_get_segment_by_index(
2236
0
           path_split_string,
2237
0
           path_segment_index,
2238
0
           &path_string_segment,
2239
0
           &path_string_segment_size,
2240
0
           error ) != 1 )
2241
0
      {
2242
0
        libcerror_error_set(
2243
0
         error,
2244
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
2245
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2246
0
         "%s: unable to retrieve path string segment: %d.",
2247
0
         function,
2248
0
         path_segment_index );
2249
2250
0
        goto on_error;
2251
0
      }
2252
0
      if( path_string_segment == NULL )
2253
0
      {
2254
0
        libcerror_error_set(
2255
0
         error,
2256
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
2257
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2258
0
         "%s: missing path string segment: %d.",
2259
0
         function,
2260
0
         path_segment_index );
2261
2262
0
        goto on_error;
2263
0
      }
2264
      /* If the path is "" (empty) or "." (current) ignore the entry
2265
       */
2266
0
      if( ( path_string_segment_size <= 1 )
2267
0
       || ( ( path_string_segment_size == 2 )
2268
0
        &&  ( path_string_segment[ 0 ] == '.' ) ) )
2269
0
      {
2270
0
        if( libcsplit_narrow_split_string_set_segment_by_index(
2271
0
             path_split_string,
2272
0
             path_segment_index,
2273
0
             NULL,
2274
0
             0,
2275
0
             error ) != 1 )
2276
0
        {
2277
0
          libcerror_error_set(
2278
0
           error,
2279
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
2280
0
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2281
0
           "%s: unable to set path string segment: %d.",
2282
0
           function,
2283
0
           path_segment_index );
2284
2285
0
          goto on_error;
2286
0
        }
2287
0
      }
2288
      /* If the path is ".." (parent) reverse the current path by one directory
2289
       */
2290
0
      else if( ( path_string_segment_size == 3 )
2291
0
            && ( path_string_segment[ 0 ] == '.' )
2292
0
            && ( path_string_segment[ 1 ] == '.' ) )
2293
0
      {
2294
0
        if( ( current_directory_split_string != NULL )
2295
0
         && ( last_used_path_segment_index == -1 ) )
2296
0
        {
2297
0
          if( libcsplit_narrow_split_string_get_segment_by_index(
2298
0
               current_directory_split_string,
2299
0
               current_directory_segment_index,
2300
0
               &current_directory_string_segment,
2301
0
               &current_directory_string_segment_size,
2302
0
               error ) != 1 )
2303
0
          {
2304
0
            libcerror_error_set(
2305
0
             error,
2306
0
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
2307
0
             LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2308
0
             "%s: unable to retrieve current working directory string segment: %d.",
2309
0
             function,
2310
0
             current_directory_segment_index );
2311
2312
0
            goto on_error;
2313
0
          }
2314
0
          if( current_directory_string_segment == NULL )
2315
0
          {
2316
0
            libcerror_error_set(
2317
0
             error,
2318
0
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
2319
0
             LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2320
0
             "%s: missing current working directory string segment: %d.",
2321
0
             function,
2322
0
             current_directory_segment_index );
2323
2324
0
            goto on_error;
2325
0
          }
2326
          /* Remove the size of the parent directory name and a directory separator
2327
           * Note that the size includes the end of string character
2328
           */
2329
0
          if( current_directory_string_segment_size < safe_full_path_size )
2330
0
          {
2331
0
            safe_full_path_size -= current_directory_string_segment_size;
2332
0
          }
2333
0
          else
2334
0
          {
2335
0
            safe_full_path_size = 0;
2336
0
          }
2337
0
          if( libcsplit_narrow_split_string_set_segment_by_index(
2338
0
               current_directory_split_string,
2339
0
               current_directory_segment_index,
2340
0
               NULL,
2341
0
               0,
2342
0
               error ) != 1 )
2343
0
          {
2344
0
            libcerror_error_set(
2345
0
             error,
2346
0
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
2347
0
             LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2348
0
             "%s: unable to set current working directory string segment: %d.",
2349
0
             function,
2350
0
             current_directory_segment_index );
2351
2352
0
            goto on_error;
2353
0
          }
2354
0
          current_directory_segment_index--;
2355
0
        }
2356
0
        else if( last_used_path_segment_index >= 0 )
2357
0
        {
2358
0
          if( libcsplit_narrow_split_string_get_segment_by_index(
2359
0
               path_split_string,
2360
0
               last_used_path_segment_index,
2361
0
               &last_used_path_string_segment,
2362
0
               &last_used_path_string_segment_size,
2363
0
               error ) != 1 )
2364
0
          {
2365
0
            libcerror_error_set(
2366
0
             error,
2367
0
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
2368
0
             LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2369
0
             "%s: unable to retrieve last used path string segment: %d.",
2370
0
             function,
2371
0
             last_used_path_segment_index );
2372
2373
0
            goto on_error;
2374
0
          }
2375
0
          if( last_used_path_string_segment == NULL )
2376
0
          {
2377
0
            libcerror_error_set(
2378
0
             error,
2379
0
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
2380
0
             LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2381
0
             "%s: missing last used path string string segment: %d.",
2382
0
             function,
2383
0
             last_used_path_segment_index );
2384
2385
0
            goto on_error;
2386
0
          }
2387
          /* Remove the size of the parent directory name and a directory separator
2388
           * Note that the size includes the end of string character
2389
           */
2390
0
          if( last_used_path_string_segment_size < safe_full_path_size )
2391
0
          {
2392
0
            safe_full_path_size -= last_used_path_string_segment_size;
2393
0
          }
2394
0
          else
2395
0
          {
2396
0
            safe_full_path_size = 0;
2397
0
          }
2398
0
          if( libcsplit_narrow_split_string_set_segment_by_index(
2399
0
               path_split_string,
2400
0
               last_used_path_segment_index,
2401
0
               NULL,
2402
0
               0,
2403
0
               error ) != 1 )
2404
0
          {
2405
0
            libcerror_error_set(
2406
0
             error,
2407
0
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
2408
0
             LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2409
0
             "%s: unable to set path string segment: %d.",
2410
0
             function,
2411
0
             last_used_path_segment_index );
2412
2413
0
            goto on_error;
2414
0
          }
2415
          /* Find the previous path split value that contains a name
2416
           */
2417
0
          while( last_used_path_segment_index > 0 )
2418
0
          {
2419
0
            last_used_path_segment_index--;
2420
2421
0
            if( libcsplit_narrow_split_string_get_segment_by_index(
2422
0
                 path_split_string,
2423
0
                 last_used_path_segment_index,
2424
0
                 &last_used_path_string_segment,
2425
0
                 &last_used_path_string_segment_size,
2426
0
                 error ) != 1 )
2427
0
            {
2428
0
              libcerror_error_set(
2429
0
               error,
2430
0
               LIBCERROR_ERROR_DOMAIN_RUNTIME,
2431
0
               LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2432
0
               "%s: unable to retrieve last used path string segment: %d.",
2433
0
               function,
2434
0
               last_used_path_segment_index );
2435
2436
0
              goto on_error;
2437
0
            }
2438
0
            if( last_used_path_string_segment_size != 0 )
2439
0
            {
2440
0
              break;
2441
0
            }
2442
0
          }
2443
0
        }
2444
0
        if( libcsplit_narrow_split_string_set_segment_by_index(
2445
0
             path_split_string,
2446
0
             path_segment_index,
2447
0
             NULL,
2448
0
             0,
2449
0
             error ) != 1 )
2450
0
        {
2451
0
          libcerror_error_set(
2452
0
           error,
2453
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
2454
0
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2455
0
           "%s: unable to set path string segment: %d.",
2456
0
           function,
2457
0
           path_segment_index );
2458
2459
0
          goto on_error;
2460
0
        }
2461
0
      }
2462
0
      else
2463
0
      {
2464
        /* Add the size of the directory or file name and a directory separator
2465
         * Note that the size includes the end of string character
2466
         */
2467
0
        safe_full_path_size += path_string_segment_size;
2468
2469
0
        last_used_path_segment_index = path_segment_index;
2470
0
      }
2471
0
    }
2472
0
    if( safe_full_path_size > 0 )
2473
0
    {
2474
      /* Remove the size reserved of the last directory separator
2475
       */
2476
0
      safe_full_path_size -= 1;
2477
0
    }
2478
0
  }
2479
0
  safe_full_path_size += full_path_prefix_length + 1;
2480
2481
0
  full_path_index = 0;
2482
2483
0
  safe_full_path = narrow_string_allocate(
2484
0
                    safe_full_path_size );
2485
2486
0
  if( safe_full_path == NULL )
2487
0
  {
2488
0
    libcerror_error_set(
2489
0
     error,
2490
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
2491
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
2492
0
     "%s: unable to create full path.",
2493
0
     function );
2494
2495
0
    goto on_error;
2496
0
  }
2497
0
  if( memory_set(
2498
0
       safe_full_path,
2499
0
       0,
2500
0
       sizeof( char ) * safe_full_path_size ) == NULL )
2501
0
  {
2502
0
    libcerror_error_set(
2503
0
     error,
2504
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
2505
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
2506
0
     "%s: unable to clear full path.",
2507
0
     function );
2508
2509
0
    goto on_error;
2510
0
  }
2511
0
  if( path_type == LIBCPATH_TYPE_ABSOLUTE )
2512
0
  {
2513
0
    safe_full_path[ full_path_index ] = '/';
2514
2515
0
    full_path_index += 1;
2516
0
  }
2517
  /* If the path is relative
2518
   * add the current working directory elements
2519
   */
2520
0
  if( current_directory_split_string != NULL )
2521
0
  {
2522
0
    for( current_directory_segment_index = 0;
2523
0
         current_directory_segment_index < current_directory_number_of_segments;
2524
0
         current_directory_segment_index++ )
2525
0
    {
2526
0
      if( libcsplit_narrow_split_string_get_segment_by_index(
2527
0
           current_directory_split_string,
2528
0
           current_directory_segment_index,
2529
0
           &current_directory_string_segment,
2530
0
           &current_directory_string_segment_size,
2531
0
           error ) != 1 )
2532
0
      {
2533
0
        libcerror_error_set(
2534
0
         error,
2535
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
2536
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2537
0
         "%s: unable to retrieve current working directory string segment: %d.",
2538
0
         function,
2539
0
         current_directory_segment_index );
2540
2541
0
        goto on_error;
2542
0
      }
2543
0
      if( current_directory_string_segment_size != 0 )
2544
0
      {
2545
0
        if( current_directory_string_segment == NULL )
2546
0
        {
2547
0
          libcerror_error_set(
2548
0
           error,
2549
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
2550
0
           LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2551
0
           "%s: missing current working directory string segment: %d.",
2552
0
           function,
2553
0
           current_directory_segment_index );
2554
2555
0
          goto on_error;
2556
0
        }
2557
        /* Note that here we should have room for the segment string and
2558
         * one additional character
2559
         */
2560
0
        if( current_directory_string_segment_size > ( safe_full_path_size - full_path_index ) )
2561
0
        {
2562
0
          libcerror_error_set(
2563
0
           error,
2564
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
2565
0
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2566
0
           "%s: invalid current working directory string segment: %d size value out of bounds.",
2567
0
           function,
2568
0
           current_directory_segment_index );
2569
2570
0
          goto on_error;
2571
0
        }
2572
0
        path_string_segment_length = current_directory_string_segment_size - 1;
2573
2574
0
        if( narrow_string_copy(
2575
0
             &( safe_full_path[ full_path_index ] ),
2576
0
             current_directory_string_segment,
2577
0
             path_string_segment_length ) == NULL )
2578
0
        {
2579
0
          libcerror_error_set(
2580
0
           error,
2581
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
2582
0
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2583
0
           "%s: unable to set current working directory split value: %d in full path.",
2584
0
           function,
2585
0
           current_directory_segment_index );
2586
2587
0
          goto on_error;
2588
0
        }
2589
0
        full_path_index += path_string_segment_length;
2590
2591
0
        safe_full_path[ full_path_index ] = '/';
2592
2593
0
        full_path_index += 1;
2594
0
      }
2595
0
    }
2596
0
  }
2597
0
  if( path_split_string != NULL )
2598
0
  {
2599
0
    for( path_segment_index = 0;
2600
0
         path_segment_index < path_number_of_segments;
2601
0
         path_segment_index++ )
2602
0
    {
2603
0
      if( libcsplit_narrow_split_string_get_segment_by_index(
2604
0
           path_split_string,
2605
0
           path_segment_index,
2606
0
           &path_string_segment,
2607
0
           &path_string_segment_size,
2608
0
           error ) != 1 )
2609
0
      {
2610
0
        libcerror_error_set(
2611
0
         error,
2612
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
2613
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2614
0
         "%s: unable to retrieve path string segment: %d.",
2615
0
         function,
2616
0
         path_segment_index );
2617
2618
0
        goto on_error;
2619
0
      }
2620
0
      if( path_string_segment_size != 0 )
2621
0
      {
2622
0
        if( path_string_segment == NULL )
2623
0
        {
2624
0
          libcerror_error_set(
2625
0
           error,
2626
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
2627
0
           LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2628
0
           "%s: missing path string segment: %d.",
2629
0
           function,
2630
0
           path_segment_index );
2631
2632
0
          goto on_error;
2633
0
        }
2634
        /* Note that here we should have room for the segment string and
2635
         * one additional character
2636
         */
2637
0
        if( path_string_segment_size > ( safe_full_path_size - full_path_index ) )
2638
0
        {
2639
0
          libcerror_error_set(
2640
0
           error,
2641
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
2642
0
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2643
0
           "%s: invalid current path string segment: %d size value out of bounds.",
2644
0
           function,
2645
0
           path_segment_index );
2646
2647
0
          goto on_error;
2648
0
        }
2649
0
        path_string_segment_length = path_string_segment_size - 1;
2650
2651
0
        if( narrow_string_copy(
2652
0
             &( safe_full_path[ full_path_index ] ),
2653
0
             path_string_segment,
2654
0
             path_string_segment_length ) == NULL )
2655
0
        {
2656
0
          libcerror_error_set(
2657
0
           error,
2658
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
2659
0
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2660
0
           "%s: unable to set path split value: %d in full path.",
2661
0
           function,
2662
0
           path_segment_index );
2663
2664
0
          goto on_error;
2665
0
        }
2666
0
        full_path_index += path_string_segment_length;
2667
2668
0
        safe_full_path[ full_path_index ] = '/';
2669
2670
0
        full_path_index += 1;
2671
0
      }
2672
0
    }
2673
0
  }
2674
0
  safe_full_path[ full_path_index - 1 ] = 0;
2675
2676
0
  if( path_split_string != NULL )
2677
0
  {
2678
0
    if( libcsplit_narrow_split_string_free(
2679
0
         &path_split_string,
2680
0
         error ) != 1 )
2681
0
    {
2682
0
      libcerror_error_set(
2683
0
       error,
2684
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2685
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
2686
0
       "%s: unable to free path split string.",
2687
0
       function );
2688
2689
0
      goto on_error;
2690
0
    }
2691
0
  }
2692
0
  if( current_directory_split_string != NULL )
2693
0
  {
2694
0
    if( libcsplit_narrow_split_string_free(
2695
0
         &current_directory_split_string,
2696
0
         error ) != 1 )
2697
0
    {
2698
0
      libcerror_error_set(
2699
0
       error,
2700
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2701
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
2702
0
       "%s: unable to free current working directory split string.",
2703
0
       function );
2704
2705
0
      goto on_error;
2706
0
    }
2707
0
  }
2708
0
  if( current_directory != NULL )
2709
0
  {
2710
0
    memory_free(
2711
0
     current_directory );
2712
0
  }
2713
0
  *full_path      = safe_full_path;
2714
0
  *full_path_size = safe_full_path_size;
2715
2716
0
  return( 1 );
2717
2718
0
on_error:
2719
0
  if( safe_full_path != NULL )
2720
0
  {
2721
0
    memory_free(
2722
0
     safe_full_path );
2723
0
  }
2724
0
  if( path_split_string != NULL )
2725
0
  {
2726
0
    libcsplit_narrow_split_string_free(
2727
0
     &path_split_string,
2728
0
     NULL );
2729
0
  }
2730
0
  if( current_directory_split_string != NULL )
2731
0
  {
2732
0
    libcsplit_narrow_split_string_free(
2733
0
     &current_directory_split_string,
2734
0
     NULL );
2735
0
  }
2736
0
  if( current_directory != NULL )
2737
0
  {
2738
0
    memory_free(
2739
0
     current_directory );
2740
0
  }
2741
0
  return( -1 );
2742
0
}
2743
2744
#endif /* defined( WINAPI ) */
2745
2746
/* Retrieves the size of a sanitized version of the path character
2747
 * Returns 1 if successful or -1 on error
2748
 */
2749
int libcpath_path_get_sanitized_character_size(
2750
     char character,
2751
     size_t *sanitized_character_size,
2752
     libcerror_error_t **error )
2753
0
{
2754
0
  static char *function = "libcpath_path_get_sanitized_character_size";
2755
2756
0
  if( sanitized_character_size == NULL )
2757
0
  {
2758
0
    libcerror_error_set(
2759
0
     error,
2760
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2761
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2762
0
     "%s: invalid sanitized character size.",
2763
0
     function );
2764
2765
0
    return( -1 );
2766
0
  }
2767
0
  if( ( character >= 0x00 )
2768
0
   && ( character <= 0x1f ) )
2769
0
  {
2770
0
    *sanitized_character_size = 4;
2771
0
  }
2772
0
  else if( character == LIBCPATH_ESCAPE_CHARACTER )
2773
0
  {
2774
0
    *sanitized_character_size = 2;
2775
0
  }
2776
#if defined( WINAPI )
2777
  else if( character == '/' )
2778
  {
2779
    *sanitized_character_size = 4;
2780
  }
2781
#endif
2782
0
  else if( ( character == '!' )
2783
0
        || ( character == '$' )
2784
0
        || ( character == '%' )
2785
0
        || ( character == '&' )
2786
0
        || ( character == '*' )
2787
0
        || ( character == '+' )
2788
0
        || ( character == ':' )
2789
0
        || ( character == ';' )
2790
0
        || ( character == '<' )
2791
0
        || ( character == '>' )
2792
0
        || ( character == '?' )
2793
0
        || ( character == '|' )
2794
0
        || ( character == 0x7f ) )
2795
0
  {
2796
0
    *sanitized_character_size = 4;
2797
0
  }
2798
0
  else
2799
0
  {
2800
0
    *sanitized_character_size = 1;
2801
0
  }
2802
0
  return( 1 );
2803
0
}
2804
2805
/* Retrieves a sanitized version of the path character
2806
 * Returns 1 if successful or -1 on error
2807
 */
2808
int libcpath_path_get_sanitized_character(
2809
     char character,
2810
     size_t sanitized_character_size,
2811
     char *sanitized_path,
2812
     size_t sanitized_path_size,
2813
     size_t *sanitized_path_index,
2814
     libcerror_error_t **error )
2815
0
{
2816
0
  static char *function            = "libcpath_path_get_sanitized_character";
2817
0
  size_t safe_sanitized_path_index = 0;
2818
0
  char lower_nibble                = 0;
2819
0
  char upper_nibble                = 0;
2820
2821
0
  if( ( sanitized_character_size != 1 )
2822
0
   && ( sanitized_character_size != 2 )
2823
0
   && ( sanitized_character_size != 4 ) )
2824
0
  {
2825
0
    libcerror_error_set(
2826
0
     error,
2827
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2828
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
2829
0
     "%s: invalid sanitized character size value out of bounds.",
2830
0
     function );
2831
2832
0
    return( -1 );
2833
0
  }
2834
0
  if( sanitized_path == NULL )
2835
0
  {
2836
0
    libcerror_error_set(
2837
0
     error,
2838
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2839
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2840
0
     "%s: invalid sanitized path.",
2841
0
     function );
2842
2843
0
    return( -1 );
2844
0
  }
2845
0
  if( sanitized_path_size > (size_t) SSIZE_MAX )
2846
0
  {
2847
0
    libcerror_error_set(
2848
0
     error,
2849
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2850
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
2851
0
     "%s: invalid sanitized path size value exceeds maximum.",
2852
0
     function );
2853
2854
0
    return( -1 );
2855
0
  }
2856
0
  if( sanitized_path_index == NULL )
2857
0
  {
2858
0
    libcerror_error_set(
2859
0
     error,
2860
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2861
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2862
0
     "%s: invalid sanitized path index.",
2863
0
     function );
2864
2865
0
    return( -1 );
2866
0
  }
2867
0
  safe_sanitized_path_index = *sanitized_path_index;
2868
2869
0
  if( safe_sanitized_path_index > sanitized_path_size )
2870
0
  {
2871
0
    libcerror_error_set(
2872
0
     error,
2873
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2874
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
2875
0
     "%s: invalid sanitized path index value out of bounds.",
2876
0
     function );
2877
2878
0
    return( -1 );
2879
0
  }
2880
0
  if( ( sanitized_character_size > sanitized_path_size )
2881
0
   || ( safe_sanitized_path_index > ( sanitized_path_size - sanitized_character_size ) ) )
2882
0
  {
2883
0
    libcerror_error_set(
2884
0
     error,
2885
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2886
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
2887
0
     "%s: invalid sanitized path size value too small.",
2888
0
     function );
2889
2890
0
    return( -1 );
2891
0
  }
2892
0
  if( sanitized_character_size == 1 )
2893
0
  {
2894
0
    sanitized_path[ safe_sanitized_path_index++ ] = character;
2895
0
  }
2896
0
  else if( sanitized_character_size == 2 )
2897
0
  {
2898
0
    sanitized_path[ safe_sanitized_path_index++ ] = LIBCPATH_ESCAPE_CHARACTER;
2899
0
    sanitized_path[ safe_sanitized_path_index++ ] = LIBCPATH_ESCAPE_CHARACTER;
2900
0
  }
2901
0
  else if( sanitized_character_size == 4 )
2902
0
  {
2903
0
    lower_nibble = character & 0x0f;
2904
0
    upper_nibble = ( character >> 4 ) & 0x0f;
2905
2906
0
    if( lower_nibble > 10 )
2907
0
    {
2908
0
      lower_nibble += 'a' - 10;
2909
0
    }
2910
0
    else
2911
0
    {
2912
0
      lower_nibble += '0';
2913
0
    }
2914
0
    if( upper_nibble > 10 )
2915
0
    {
2916
0
      upper_nibble += 'a' - 10;
2917
0
    }
2918
0
    else
2919
0
    {
2920
0
      upper_nibble += '0';
2921
0
    }
2922
0
    sanitized_path[ safe_sanitized_path_index++ ] = LIBCPATH_ESCAPE_CHARACTER;
2923
0
    sanitized_path[ safe_sanitized_path_index++ ] = 'x';
2924
0
    sanitized_path[ safe_sanitized_path_index++ ] = upper_nibble;
2925
0
    sanitized_path[ safe_sanitized_path_index++ ] = lower_nibble;
2926
0
  }
2927
0
  *sanitized_path_index = safe_sanitized_path_index;
2928
2929
0
  return( 1 );
2930
0
}
2931
2932
/* Retrieves a sanitized version of the filename
2933
 * Returns 1 if successful or -1 on error
2934
 */
2935
int libcpath_path_get_sanitized_filename(
2936
     const char *filename,
2937
     size_t filename_length,
2938
     char **sanitized_filename,
2939
     size_t *sanitized_filename_size,
2940
     libcerror_error_t **error )
2941
0
{
2942
0
  static char *function               = "libcpath_path_get_sanitized_filename";
2943
0
  char *safe_sanitized_filename       = NULL;
2944
0
  size_t filename_index               = 0;
2945
0
  size_t sanitized_character_size     = 0;
2946
0
  size_t safe_sanitized_filename_size = 0;
2947
0
  size_t sanitized_filename_index     = 0;
2948
2949
0
  if( filename == NULL )
2950
0
  {
2951
0
    libcerror_error_set(
2952
0
     error,
2953
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2954
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2955
0
     "%s: invalid filename.",
2956
0
     function );
2957
2958
0
    return( -1 );
2959
0
  }
2960
0
  if( ( filename_length == 0 )
2961
0
   || ( filename_length > (size_t) ( SSIZE_MAX - 1 ) ) )
2962
0
  {
2963
0
    libcerror_error_set(
2964
0
     error,
2965
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2966
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
2967
0
     "%s: invalid filename length value out of bounds.",
2968
0
     function );
2969
2970
0
    return( -1 );
2971
0
  }
2972
0
  if( sanitized_filename == NULL )
2973
0
  {
2974
0
    libcerror_error_set(
2975
0
     error,
2976
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2977
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2978
0
     "%s: invalid sanitized filename.",
2979
0
     function );
2980
2981
0
    return( -1 );
2982
0
  }
2983
0
  if( *sanitized_filename != NULL )
2984
0
  {
2985
0
    libcerror_error_set(
2986
0
     error,
2987
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2988
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
2989
0
     "%s: invalid sanitized filename value already set.",
2990
0
     function );
2991
2992
0
    return( -1 );
2993
0
  }
2994
0
  if( sanitized_filename_size == NULL )
2995
0
  {
2996
0
    libcerror_error_set(
2997
0
     error,
2998
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2999
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3000
0
     "%s: invalid sanitized filename size.",
3001
0
     function );
3002
3003
0
    return( -1 );
3004
0
  }
3005
0
  safe_sanitized_filename_size = 1;
3006
3007
0
  for( filename_index = 0;
3008
0
       filename_index < filename_length;
3009
0
       filename_index++ )
3010
0
  {
3011
0
    if( filename[ filename_index ] == LIBCPATH_SEPARATOR )
3012
0
    {
3013
0
      sanitized_character_size = 4;
3014
0
    }
3015
0
    else if( libcpath_path_get_sanitized_character_size(
3016
0
              filename[ filename_index ],
3017
0
              &sanitized_character_size,
3018
0
              error ) != 1 )
3019
0
    {
3020
0
      libcerror_error_set(
3021
0
       error,
3022
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
3023
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3024
0
       "%s: unable to determine sanitize character size.",
3025
0
       function );
3026
3027
0
      goto on_error;
3028
0
    }
3029
0
    safe_sanitized_filename_size += sanitized_character_size;
3030
0
  }
3031
0
  if( safe_sanitized_filename_size > (size_t) SSIZE_MAX )
3032
0
  {
3033
0
    libcerror_error_set(
3034
0
     error,
3035
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3036
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
3037
0
     "%s: invalid sanitized filename size value exceeds maximum.",
3038
0
     function );
3039
3040
0
    goto on_error;
3041
0
  }
3042
0
  safe_sanitized_filename = narrow_string_allocate(
3043
0
                             safe_sanitized_filename_size );
3044
3045
0
  if( safe_sanitized_filename == NULL )
3046
0
  {
3047
0
    libcerror_error_set(
3048
0
     error,
3049
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
3050
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
3051
0
     "%s: unable to create sanitized filename.",
3052
0
     function );
3053
3054
0
    goto on_error;
3055
0
  }
3056
0
  for( filename_index = 0;
3057
0
       filename_index < filename_length;
3058
0
       filename_index++ )
3059
0
  {
3060
0
    if( filename[ filename_index ] == LIBCPATH_SEPARATOR )
3061
0
    {
3062
0
      sanitized_character_size = 4;
3063
0
    }
3064
0
    else if( libcpath_path_get_sanitized_character_size(
3065
0
              filename[ filename_index ],
3066
0
              &sanitized_character_size,
3067
0
              error ) != 1 )
3068
0
    {
3069
0
      libcerror_error_set(
3070
0
       error,
3071
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
3072
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3073
0
       "%s: unable to determine sanitize character size.",
3074
0
       function );
3075
3076
0
      goto on_error;
3077
0
    }
3078
0
    if( libcpath_path_get_sanitized_character(
3079
0
         filename[ filename_index ],
3080
0
         sanitized_character_size,
3081
0
         safe_sanitized_filename,
3082
0
         safe_sanitized_filename_size,
3083
0
         &sanitized_filename_index,
3084
0
         error ) != 1 )
3085
0
    {
3086
0
      libcerror_error_set(
3087
0
       error,
3088
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
3089
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3090
0
       "%s: unable to determine sanitize character size.",
3091
0
       function );
3092
3093
0
      goto on_error;
3094
0
    }
3095
0
  }
3096
0
  safe_sanitized_filename[ sanitized_filename_index ] = 0;
3097
3098
0
  *sanitized_filename      = safe_sanitized_filename;
3099
0
  *sanitized_filename_size = safe_sanitized_filename_size;
3100
3101
0
  return( 1 );
3102
3103
0
on_error:
3104
0
  if( safe_sanitized_filename != NULL )
3105
0
  {
3106
0
    memory_free(
3107
0
     safe_sanitized_filename );
3108
0
  }
3109
0
  return( -1 );
3110
0
}
3111
3112
/* Retrieves a sanitized version of the path
3113
 * Returns 1 if successful or -1 on error
3114
 */
3115
int libcpath_path_get_sanitized_path(
3116
     const char *path,
3117
     size_t path_length,
3118
     char **sanitized_path,
3119
     size_t *sanitized_path_size,
3120
     libcerror_error_t **error )
3121
0
{
3122
0
  static char *function                    = "libcpath_path_get_sanitized_path";
3123
0
  char *safe_sanitized_path                = NULL;
3124
0
  size_t path_index                        = 0;
3125
0
  size_t safe_sanitized_path_size          = 0;
3126
0
  size_t sanitized_character_size          = 0;
3127
0
  size_t sanitized_path_index              = 0;
3128
3129
#if defined( WINAPI )
3130
  size_t last_path_segment_seperator_index = 0;
3131
#endif
3132
3133
0
  if( path == NULL )
3134
0
  {
3135
0
    libcerror_error_set(
3136
0
     error,
3137
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3138
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3139
0
     "%s: invalid path.",
3140
0
     function );
3141
3142
0
    return( -1 );
3143
0
  }
3144
0
  if( ( path_length == 0 )
3145
0
   || ( path_length > (size_t) ( SSIZE_MAX - 1 ) ) )
3146
0
  {
3147
0
    libcerror_error_set(
3148
0
     error,
3149
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3150
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
3151
0
     "%s: invalid path length value out of bounds.",
3152
0
     function );
3153
3154
0
    return( -1 );
3155
0
  }
3156
0
  if( sanitized_path == NULL )
3157
0
  {
3158
0
    libcerror_error_set(
3159
0
     error,
3160
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3161
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3162
0
     "%s: invalid sanitized path.",
3163
0
     function );
3164
3165
0
    return( -1 );
3166
0
  }
3167
0
  if( *sanitized_path != NULL )
3168
0
  {
3169
0
    libcerror_error_set(
3170
0
     error,
3171
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3172
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3173
0
     "%s: invalid sanitized path value already set.",
3174
0
     function );
3175
3176
0
    return( -1 );
3177
0
  }
3178
0
  if( sanitized_path_size == NULL )
3179
0
  {
3180
0
    libcerror_error_set(
3181
0
     error,
3182
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3183
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3184
0
     "%s: invalid sanitized path size.",
3185
0
     function );
3186
3187
0
    return( -1 );
3188
0
  }
3189
0
  safe_sanitized_path_size = 1;
3190
3191
0
  for( path_index = 0;
3192
0
       path_index < path_length;
3193
0
       path_index++ )
3194
0
  {
3195
0
    if( libcpath_path_get_sanitized_character_size(
3196
0
         path[ path_index ],
3197
0
         &sanitized_character_size,
3198
0
         error ) != 1 )
3199
0
    {
3200
0
      libcerror_error_set(
3201
0
       error,
3202
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
3203
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3204
0
       "%s: unable to determine sanitize character size.",
3205
0
       function );
3206
3207
0
      goto on_error;
3208
0
    }
3209
0
    safe_sanitized_path_size += sanitized_character_size;
3210
3211
#if defined( WINAPI )
3212
    if( path[ path_index ] == LIBCPATH_SEPARATOR )
3213
    {
3214
      last_path_segment_seperator_index = path_index;
3215
    }
3216
#endif
3217
0
  }
3218
0
  if( safe_sanitized_path_size > (size_t) SSIZE_MAX )
3219
0
  {
3220
0
    libcerror_error_set(
3221
0
     error,
3222
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3223
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
3224
0
     "%s: invalid sanitized path size value exceeds maximum.",
3225
0
     function );
3226
3227
0
    goto on_error;
3228
0
  }
3229
#if defined( WINAPI )
3230
  if( last_path_segment_seperator_index > 32767 )
3231
  {
3232
    libcerror_error_set(
3233
     error,
3234
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3235
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
3236
     "%s: invalid last path segment separator value out of bounds.",
3237
     function );
3238
3239
    goto on_error;
3240
  }
3241
  if( safe_sanitized_path_size > 32767 )
3242
  {
3243
    safe_sanitized_path_size = 32767;
3244
  }
3245
#endif
3246
0
  safe_sanitized_path = narrow_string_allocate(
3247
0
                         safe_sanitized_path_size );
3248
3249
0
  if( safe_sanitized_path == NULL )
3250
0
  {
3251
0
    libcerror_error_set(
3252
0
     error,
3253
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
3254
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
3255
0
     "%s: unable to create sanitized path.",
3256
0
     function );
3257
3258
0
    goto on_error;
3259
0
  }
3260
0
  for( path_index = 0;
3261
0
       path_index < path_length;
3262
0
       path_index++ )
3263
0
  {
3264
0
    if( libcpath_path_get_sanitized_character_size(
3265
0
         path[ path_index ],
3266
0
         &sanitized_character_size,
3267
0
         error ) != 1 )
3268
0
    {
3269
0
      libcerror_error_set(
3270
0
       error,
3271
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
3272
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3273
0
       "%s: unable to determine sanitize character size.",
3274
0
       function );
3275
3276
0
      goto on_error;
3277
0
    }
3278
0
    if( libcpath_path_get_sanitized_character(
3279
0
         path[ path_index ],
3280
0
         sanitized_character_size,
3281
0
         safe_sanitized_path,
3282
0
         safe_sanitized_path_size,
3283
0
         &sanitized_path_index,
3284
0
         error ) != 1 )
3285
0
    {
3286
0
      libcerror_error_set(
3287
0
       error,
3288
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
3289
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3290
0
       "%s: unable to determine sanitize character size.",
3291
0
       function );
3292
3293
0
      goto on_error;
3294
0
    }
3295
0
  }
3296
0
  if( sanitized_path_index >= safe_sanitized_path_size )
3297
0
  {
3298
0
    libcerror_error_set(
3299
0
     error,
3300
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3301
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
3302
0
     "%s: invalid sanitized path index value out of bounds.",
3303
0
     function );
3304
3305
0
    goto on_error;
3306
0
  }
3307
0
  safe_sanitized_path[ sanitized_path_index ] = 0;
3308
3309
0
  *sanitized_path      = safe_sanitized_path;
3310
0
  *sanitized_path_size = safe_sanitized_path_size;
3311
3312
0
  return( 1 );
3313
3314
0
on_error:
3315
0
  if( safe_sanitized_path != NULL )
3316
0
  {
3317
0
    memory_free(
3318
0
     safe_sanitized_path );
3319
0
  }
3320
0
  return( -1 );
3321
0
}
3322
3323
/* Combines the directory name and filename into a path
3324
 * Returns 1 if successful or -1 on error
3325
 */
3326
int libcpath_path_join(
3327
     char **path,
3328
     size_t *path_size,
3329
     const char *directory_name,
3330
     size_t directory_name_length,
3331
     const char *filename,
3332
     size_t filename_length,
3333
     libcerror_error_t **error )
3334
0
{
3335
0
  static char *function = "libcpath_path_join";
3336
0
  size_t filename_index = 0;
3337
0
  size_t path_index     = 0;
3338
3339
0
  if( path == NULL )
3340
0
  {
3341
0
    libcerror_error_set(
3342
0
     error,
3343
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3344
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3345
0
     "%s: invalid path.",
3346
0
     function );
3347
3348
0
    return( -1 );
3349
0
  }
3350
0
  if( *path != NULL )
3351
0
  {
3352
0
    libcerror_error_set(
3353
0
     error,
3354
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3355
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3356
0
     "%s: invalid path value already set.",
3357
0
     function );
3358
3359
0
    return( -1 );
3360
0
  }
3361
0
  if( path_size == NULL )
3362
0
  {
3363
0
    libcerror_error_set(
3364
0
     error,
3365
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3366
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3367
0
     "%s: invalid path size.",
3368
0
     function );
3369
3370
0
    return( -1 );
3371
0
  }
3372
0
  if( directory_name == NULL )
3373
0
  {
3374
0
    libcerror_error_set(
3375
0
     error,
3376
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3377
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3378
0
     "%s: invalid directory name.",
3379
0
     function );
3380
3381
0
    return( -1 );
3382
0
  }
3383
0
  if( directory_name_length > (size_t) SSIZE_MAX )
3384
0
  {
3385
0
    libcerror_error_set(
3386
0
     error,
3387
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3388
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
3389
0
     "%s: invalid directory name length value exceeds maximum.",
3390
0
     function );
3391
3392
0
    return( -1 );
3393
0
  }
3394
0
  if( filename == NULL )
3395
0
  {
3396
0
    libcerror_error_set(
3397
0
     error,
3398
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3399
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3400
0
     "%s: invalid filename.",
3401
0
     function );
3402
3403
0
    return( -1 );
3404
0
  }
3405
0
  if( filename_length > (size_t) SSIZE_MAX )
3406
0
  {
3407
0
    libcerror_error_set(
3408
0
     error,
3409
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3410
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
3411
0
     "%s: invalid filename length value exceeds maximum.",
3412
0
     function );
3413
3414
0
    return( -1 );
3415
0
  }
3416
/* TODO strip other patterns like /./ */
3417
0
  while( directory_name_length > 0 )
3418
0
  {
3419
0
    if( directory_name[ directory_name_length - 1 ] != (char) LIBCPATH_SEPARATOR )
3420
0
    {
3421
0
      break;
3422
0
    }
3423
0
    directory_name_length--;
3424
0
  }
3425
0
  while( filename_length > 0 )
3426
0
  {
3427
0
    if( filename[ filename_index ] != (char) LIBCPATH_SEPARATOR )
3428
0
    {
3429
0
      break;
3430
0
    }
3431
0
    filename_index++;
3432
0
    filename_length--;
3433
0
  }
3434
0
  *path_size = directory_name_length + filename_length + 2;
3435
3436
0
  *path = narrow_string_allocate(
3437
0
           *path_size );
3438
3439
0
  if( *path == NULL )
3440
0
  {
3441
0
    libcerror_error_set(
3442
0
     error,
3443
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
3444
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
3445
0
     "%s: unable to create path.",
3446
0
     function );
3447
3448
0
    goto on_error;
3449
0
  }
3450
0
  if( narrow_string_copy(
3451
0
       *path,
3452
0
       directory_name,
3453
0
       directory_name_length ) == NULL )
3454
0
  {
3455
0
    libcerror_error_set(
3456
0
     error,
3457
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
3458
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
3459
0
     "%s: unable to copy directory name to path.",
3460
0
     function );
3461
3462
0
    goto on_error;
3463
0
  }
3464
0
  path_index = directory_name_length;
3465
3466
0
  ( *path )[ path_index++ ] = (char) LIBCPATH_SEPARATOR;
3467
3468
0
  if( narrow_string_copy(
3469
0
       &( ( *path )[ path_index ] ),
3470
0
       &( filename[ filename_index ] ),
3471
0
       filename_length ) == NULL )
3472
0
  {
3473
0
    libcerror_error_set(
3474
0
     error,
3475
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3476
0
     LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
3477
0
     "%s: unable to copy filename to path.",
3478
0
     function );
3479
3480
0
    goto on_error;
3481
0
  }
3482
0
  path_index += filename_length;
3483
3484
0
  ( *path )[ path_index ] = 0;
3485
3486
0
  return( 1 );
3487
3488
0
on_error:
3489
0
  if( *path != NULL )
3490
0
  {
3491
0
    memory_free(
3492
0
     *path );
3493
3494
0
    *path = NULL;
3495
0
  }
3496
0
  *path_size = 0;
3497
3498
0
  return( -1 );
3499
0
}
3500
3501
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
3502
3503
/* Cross Windows safe version of CreateDirectoryA
3504
 * Returns TRUE if successful or FALSE on error
3505
 */
3506
BOOL libcpath_CreateDirectoryA(
3507
      LPCSTR path,
3508
      SECURITY_ATTRIBUTES *security_attributes )
3509
{
3510
  FARPROC function       = NULL;
3511
  HMODULE library_handle = NULL;
3512
  BOOL result            = FALSE;
3513
3514
  if( path == NULL )
3515
  {
3516
    return( 0 );
3517
  }
3518
  library_handle = LoadLibrary(
3519
                    _SYSTEM_STRING( "kernel32.dll" ) );
3520
3521
  if( library_handle == NULL )
3522
  {
3523
    return( 0 );
3524
  }
3525
  function = GetProcAddress(
3526
        library_handle,
3527
        (LPCSTR) "CreateDirectoryA" );
3528
3529
  if( function != NULL )
3530
  {
3531
    result = function(
3532
        path,
3533
        security_attributes );
3534
  }
3535
  /* This call should be after using the function
3536
   * in most cases kernel32.dll will still be available after free
3537
   */
3538
  if( FreeLibrary(
3539
       library_handle ) != TRUE )
3540
  {
3541
    libcpath_CloseHandle(
3542
     library_handle );
3543
3544
    return( 0 );
3545
  }
3546
  return( result );
3547
}
3548
3549
#endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
3550
3551
#if defined( WINAPI )
3552
3553
/* Makes the directory
3554
 * This function uses the WINAPI function for Windows XP (0x0501) or later
3555
 * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
3556
 * Returns 1 if successful or -1 on error
3557
 */
3558
int libcpath_path_make_directory(
3559
     const char *directory_name,
3560
     libcerror_error_t **error )
3561
{
3562
  static char *function = "libcpath_path_make_directory";
3563
  DWORD error_code      = 0;
3564
3565
  if( directory_name == NULL )
3566
  {
3567
    libcerror_error_set(
3568
     error,
3569
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3570
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3571
     "%s: invalid directory name.",
3572
     function );
3573
3574
    return( -1 );
3575
  }
3576
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
3577
  if( libcpath_CreateDirectoryA(
3578
       directory_name,
3579
       NULL ) == 0 )
3580
#else
3581
  if( CreateDirectoryA(
3582
       directory_name,
3583
       NULL ) == 0 )
3584
#endif
3585
  {
3586
    error_code = GetLastError();
3587
3588
    libcerror_system_set_error(
3589
     error,
3590
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3591
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3592
     error_code,
3593
     "%s: unable to make directory.",
3594
     function );
3595
3596
    return( -1 );
3597
  }
3598
  return( 1 );
3599
}
3600
3601
#elif defined( HAVE_MKDIR )
3602
3603
/* Makes the directory
3604
 * This function uses the POSIX mkdir function or equivalent
3605
 * Returns 1 if successful or -1 on error
3606
 */
3607
int libcpath_path_make_directory(
3608
     const char *directory_name,
3609
     libcerror_error_t **error )
3610
0
{
3611
0
  static char *function = "libcpath_path_make_directory";
3612
3613
0
  if( directory_name == NULL )
3614
0
  {
3615
0
    libcerror_error_set(
3616
0
     error,
3617
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3618
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3619
0
     "%s: invalid directory name.",
3620
0
     function );
3621
3622
0
    return( -1 );
3623
0
  }
3624
#if defined( __MINGW32__ ) || defined( _MSC_VER )
3625
  if( mkdir(
3626
       directory_name ) != 0 )
3627
#else
3628
0
  if( mkdir(
3629
0
       directory_name,
3630
0
       0755 ) != 0 )
3631
0
#endif
3632
0
  {
3633
0
    libcerror_system_set_error(
3634
0
     error,
3635
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3636
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3637
0
     errno,
3638
0
     "%s: unable to make directory.",
3639
0
     function );
3640
3641
0
    return( -1 );
3642
0
  }
3643
3644
0
  return( 1 );
3645
0
}
3646
3647
#else
3648
#error Missing make directory function
3649
#endif
3650
3651
#if defined( HAVE_WIDE_CHARACTER_TYPE )
3652
3653
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
3654
3655
/* Cross Windows safe version of SetCurrentDirectoryW
3656
 * Returns TRUE if successful or FALSE on error
3657
 */
3658
BOOL libcpath_SetCurrentDirectoryW(
3659
      LPCWSTR path )
3660
{
3661
  FARPROC function       = NULL;
3662
  HMODULE library_handle = NULL;
3663
  BOOL result            = FALSE;
3664
3665
  if( path == NULL )
3666
  {
3667
    return( FALSE );
3668
  }
3669
  library_handle = LoadLibrary(
3670
                    _SYSTEM_STRING( "kernel32.dll" ) );
3671
3672
  if( library_handle == NULL )
3673
  {
3674
    return( FALSE );
3675
  }
3676
  function = GetProcAddress(
3677
        library_handle,
3678
        (LPCSTR) "SetCurrentDirectoryW" );
3679
3680
  if( function != NULL )
3681
  {
3682
    result = function(
3683
        path );
3684
  }
3685
  /* This call should be after using the function
3686
   * in most cases kernel32.dll will still be available after free
3687
   */
3688
  if( FreeLibrary(
3689
       library_handle ) != TRUE )
3690
  {
3691
    libcpath_CloseHandle(
3692
     library_handle );
3693
3694
    return( FALSE );
3695
  }
3696
  return( result );
3697
}
3698
3699
#endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
3700
3701
#if defined( WINAPI )
3702
3703
/* Changes the directory
3704
 * This function uses the WINAPI function for Windows XP (0x0501) or later
3705
 * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
3706
 * Returns 1 if successful or -1 on error
3707
 */
3708
int libcpath_path_change_directory_wide(
3709
     const wchar_t *directory_name,
3710
     libcerror_error_t **error )
3711
{
3712
  static char *function = "libcpath_path_change_directory_wide";
3713
  DWORD error_code      = 0;
3714
3715
  if( directory_name == NULL )
3716
  {
3717
    libcerror_error_set(
3718
     error,
3719
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3720
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3721
     "%s: invalid directory name.",
3722
     function );
3723
3724
    return( -1 );
3725
  }
3726
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
3727
  if( libcpath_SetCurrentDirectoryW(
3728
       directory_name ) == 0 )
3729
#else
3730
  if( SetCurrentDirectoryW(
3731
       directory_name ) == 0 )
3732
#endif
3733
  {
3734
    error_code = GetLastError();
3735
3736
    libcerror_system_set_error(
3737
     error,
3738
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3739
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3740
     error_code,
3741
     "%s: unable to change directory.",
3742
     function );
3743
3744
    return( -1 );
3745
  }
3746
  return( 1 );
3747
}
3748
3749
#elif defined( HAVE_CHDIR )
3750
3751
/* Changes the directory
3752
 * This function uses the POSIX chdir function or equivalent
3753
 * Returns 1 if successful or -1 on error
3754
 */
3755
int libcpath_path_change_directory_wide(
3756
     const wchar_t *directory_name,
3757
     libcerror_error_t **error )
3758
{
3759
  static char *function             = "libcpath_path_change_directory_wide";
3760
  char *narrow_directory_name       = 0;
3761
  size_t directory_name_length      = 0;
3762
  size_t narrow_directory_name_size = 0;
3763
3764
  if( directory_name == NULL )
3765
  {
3766
    libcerror_error_set(
3767
     error,
3768
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3769
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3770
     "%s: invalid directory name.",
3771
     function );
3772
3773
    return( -1 );
3774
  }
3775
  directory_name_length = wide_string_length(
3776
                           directory_name );
3777
3778
  if( libcpath_system_string_size_from_wide_string(
3779
       directory_name,
3780
       directory_name_length + 1,
3781
       &narrow_directory_name_size,
3782
       error ) != 1 )
3783
  {
3784
    libcerror_error_set(
3785
     error,
3786
     LIBCERROR_ERROR_DOMAIN_CONVERSION,
3787
     LIBCERROR_CONVERSION_ERROR_GENERIC,
3788
     "%s: unable to determine narrow directory name size.",
3789
     function );
3790
3791
    goto on_error;
3792
  }
3793
  if( ( narrow_directory_name_size > (size_t) SSIZE_MAX )
3794
   || ( ( sizeof( char ) * narrow_directory_name_size )  > (size_t) SSIZE_MAX ) )
3795
  {
3796
    libcerror_error_set(
3797
     error,
3798
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3799
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
3800
     "%s: invalid narrow directory name size value exceeds maximum.",
3801
     function );
3802
3803
    goto on_error;
3804
  }
3805
  narrow_directory_name = narrow_string_allocate(
3806
                           narrow_directory_name_size );
3807
3808
  if( narrow_directory_name == NULL )
3809
  {
3810
    libcerror_error_set(
3811
     error,
3812
     LIBCERROR_ERROR_DOMAIN_MEMORY,
3813
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
3814
     "%s: unable to create narrow directory name.",
3815
     function );
3816
3817
    goto on_error;
3818
  }
3819
  if( libcpath_system_string_copy_from_wide_string(
3820
       narrow_directory_name,
3821
       narrow_directory_name_size,
3822
       directory_name,
3823
       directory_name_length + 1,
3824
       error ) != 1 )
3825
  {
3826
    libcerror_error_set(
3827
     error,
3828
     LIBCERROR_ERROR_DOMAIN_CONVERSION,
3829
     LIBCERROR_CONVERSION_ERROR_GENERIC,
3830
     "%s: unable to set name.",
3831
     function );
3832
3833
    goto on_error;
3834
  }
3835
  if( chdir(
3836
       narrow_directory_name ) != 0 )
3837
  {
3838
    libcerror_system_set_error(
3839
     error,
3840
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3841
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3842
     errno,
3843
     "%s: unable to change directory.",
3844
     function );
3845
3846
    return( -1 );
3847
  }
3848
  memory_free(
3849
   narrow_directory_name );
3850
3851
  return( 1 );
3852
3853
on_error:
3854
  if( narrow_directory_name != NULL )
3855
  {
3856
    memory_free(
3857
     narrow_directory_name );
3858
  }
3859
  return( -1 );
3860
}
3861
3862
#else
3863
#error Missing change directory function
3864
#endif
3865
3866
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
3867
3868
/* Cross Windows safe version of GetCurrentDirectoryW
3869
 * Returns the number of characters in the current directory string or 0 on error
3870
 */
3871
DWORD libcpath_GetCurrentDirectoryW(
3872
       DWORD buffer_size,
3873
       LPCWSTR buffer )
3874
{
3875
  FARPROC function       = NULL;
3876
  HMODULE library_handle = NULL;
3877
  DWORD result           = 0;
3878
3879
  library_handle = LoadLibrary(
3880
                    _SYSTEM_STRING( "kernel32.dll" ) );
3881
3882
  if( library_handle == NULL )
3883
  {
3884
    return( 0 );
3885
  }
3886
  function = GetProcAddress(
3887
        library_handle,
3888
        (LPCSTR) "GetCurrentDirectoryW" );
3889
3890
  if( function != NULL )
3891
  {
3892
    result = function(
3893
        buffer_size,
3894
        buffer );
3895
  }
3896
  /* This call should be after using the function
3897
   * in most cases kernel32.dll will still be available after free
3898
   */
3899
  if( FreeLibrary(
3900
       library_handle ) != TRUE )
3901
  {
3902
    libcpath_CloseHandle(
3903
     library_handle );
3904
3905
    return( 0 );
3906
  }
3907
  return( result );
3908
}
3909
3910
#endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
3911
3912
#if defined( WINAPI )
3913
3914
/* Retrieves the current working directory
3915
 * This function uses the WINAPI function for Windows XP (0x0501) or later
3916
 * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
3917
 * Returns 1 if successful or -1 on error
3918
 */
3919
int libcpath_path_get_current_working_directory_wide(
3920
     wchar_t **current_working_directory,
3921
     size_t *current_working_directory_size,
3922
     libcerror_error_t **error )
3923
{
3924
  static char *function                     = "libcpath_path_get_current_working_directory_wide";
3925
  wchar_t *safe_current_working_directory   = NULL;
3926
  DWORD error_code                          = 0;
3927
  DWORD result                              = 0;
3928
  DWORD safe_current_working_directory_size = 0;
3929
3930
  if( current_working_directory == NULL )
3931
  {
3932
    libcerror_error_set(
3933
     error,
3934
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3935
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3936
     "%s: invalid current working directory.",
3937
     function );
3938
3939
    return( -1 );
3940
  }
3941
  if( *current_working_directory != NULL )
3942
  {
3943
    libcerror_error_set(
3944
     error,
3945
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3946
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3947
     "%s: invalid current working directory value already set.",
3948
     function );
3949
3950
    return( -1 );
3951
  }
3952
  if( current_working_directory_size == NULL )
3953
  {
3954
    libcerror_error_set(
3955
     error,
3956
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3957
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3958
     "%s: invalid current working directory size.",
3959
     function );
3960
3961
    return( -1 );
3962
  }
3963
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
3964
  safe_current_working_directory_size = libcpath_GetCurrentDirectoryW(
3965
                                         0,
3966
                                         NULL );
3967
#else
3968
  safe_current_working_directory_size = GetCurrentDirectoryW(
3969
                                         0,
3970
                                         NULL );
3971
#endif
3972
  if( safe_current_working_directory_size == 0 )
3973
  {
3974
    libcerror_error_set(
3975
     error,
3976
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3977
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3978
     "%s: unable to retrieve current working directory size.",
3979
     function );
3980
3981
    goto on_error;
3982
  }
3983
  if( (size_t) safe_current_working_directory_size > (size_t) SSIZE_MAX )
3984
  {
3985
    libcerror_error_set(
3986
     error,
3987
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
3988
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
3989
     "%s: invalid current working directory size value out of bounds.",
3990
     function );
3991
3992
    goto on_error;
3993
  }
3994
  safe_current_working_directory = wide_string_allocate(
3995
                                    safe_current_working_directory_size );
3996
3997
  if( safe_current_working_directory == NULL )
3998
  {
3999
    libcerror_error_set(
4000
     error,
4001
     LIBCERROR_ERROR_DOMAIN_MEMORY,
4002
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
4003
     "%s: unable to create current working directory.",
4004
     function );
4005
4006
    goto on_error;
4007
  }
4008
  if( memory_set(
4009
       safe_current_working_directory,
4010
       0,
4011
       sizeof( wchar_t ) * safe_current_working_directory_size ) == NULL )
4012
  {
4013
    libcerror_error_set(
4014
     error,
4015
     LIBCERROR_ERROR_DOMAIN_MEMORY,
4016
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
4017
     "%s: unable to clear current working directory.",
4018
     function );
4019
4020
    goto on_error;
4021
  }
4022
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
4023
  result = libcpath_GetCurrentDirectoryW(
4024
            safe_current_working_directory_size,
4025
            safe_current_working_directory )
4026
#else
4027
  result = GetCurrentDirectoryW(
4028
            safe_current_working_directory_size,
4029
            safe_current_working_directory );
4030
#endif
4031
  /* Note that safe_current_working_directory_size can be larger than result
4032
   */
4033
  if( ( result == 0 )
4034
   || ( result > safe_current_working_directory_size ) )
4035
  {
4036
    error_code = GetLastError();
4037
4038
    libcerror_system_set_error(
4039
     error,
4040
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4041
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4042
     error_code,
4043
     "%s: unable to retrieve current working directory.",
4044
     function );
4045
4046
    goto on_error;
4047
  }
4048
  *current_working_directory      = safe_current_working_directory;
4049
  *current_working_directory_size = (size_t) safe_current_working_directory_size;
4050
4051
  return( 1 );
4052
4053
on_error:
4054
  if( safe_current_working_directory != NULL )
4055
  {
4056
    memory_free(
4057
     safe_current_working_directory );
4058
  }
4059
  return( -1 );
4060
}
4061
4062
#elif defined( HAVE_GETCWD )
4063
4064
/* Retrieves the current working directory
4065
 * This function uses the POSIX getcwd function or equivalent
4066
 * Returns 1 if successful or -1 on error
4067
 */
4068
int libcpath_path_get_current_working_directory_wide(
4069
     wchar_t **current_working_directory,
4070
     size_t *current_working_directory_size,
4071
     libcerror_error_t **error )
4072
{
4073
  static char *function                          = "libcpath_path_get_current_working_directory_wide";
4074
  wchar_t *safe_current_working_directory        = NULL;
4075
  char *narrow_current_working_directory         = 0;
4076
  size_t narrow_current_working_directory_length = 0;
4077
  size_t safe_current_working_directory_size     = 0;
4078
4079
  if( current_working_directory == NULL )
4080
  {
4081
    libcerror_error_set(
4082
     error,
4083
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4084
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4085
     "%s: invalid current working directory.",
4086
     function );
4087
4088
    return( -1 );
4089
  }
4090
  if( *current_working_directory != NULL )
4091
  {
4092
    libcerror_error_set(
4093
     error,
4094
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4095
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
4096
     "%s: invalid current working directory value already set.",
4097
     function );
4098
4099
    return( -1 );
4100
  }
4101
  if( current_working_directory_size == NULL )
4102
  {
4103
    libcerror_error_set(
4104
     error,
4105
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4106
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4107
     "%s: invalid current working directory size.",
4108
     function );
4109
4110
    return( -1 );
4111
  }
4112
  narrow_current_working_directory = narrow_string_allocate(
4113
                                      PATH_MAX );
4114
4115
  if( narrow_current_working_directory == NULL )
4116
  {
4117
    libcerror_error_set(
4118
     error,
4119
     LIBCERROR_ERROR_DOMAIN_MEMORY,
4120
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
4121
     "%s: unable to create narrow current working directory.",
4122
     function );
4123
4124
    goto on_error;
4125
  }
4126
  if( getcwd(
4127
       narrow_current_working_directory,
4128
       PATH_MAX ) == NULL )
4129
  {
4130
    libcerror_system_set_error(
4131
     error,
4132
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4133
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4134
     errno,
4135
     "%s: unable to retrieve current working directory.",
4136
     function );
4137
4138
    goto on_error;
4139
  }
4140
  narrow_current_working_directory_length = narrow_string_length(
4141
                                             narrow_current_working_directory );
4142
4143
  /* Convert the current working directory to a wide string
4144
   * if the platform has no wide character open function
4145
   */
4146
  if( libcpath_system_string_size_from_narrow_string(
4147
       narrow_current_working_directory,
4148
       narrow_current_working_directory_length + 1,
4149
       &safe_current_working_directory_size,
4150
       error ) != 1 )
4151
  {
4152
    libcerror_error_set(
4153
     error,
4154
     LIBCERROR_ERROR_DOMAIN_CONVERSION,
4155
     LIBCERROR_CONVERSION_ERROR_GENERIC,
4156
     "%s: unable to determine wide character current working directory size.",
4157
     function );
4158
4159
    return( -1 );
4160
  }
4161
  safe_current_working_directory = wide_string_allocate(
4162
                                    safe_current_working_directory_size );
4163
4164
  if( safe_current_working_directory == NULL )
4165
  {
4166
    libcerror_error_set(
4167
     error,
4168
     LIBCERROR_ERROR_DOMAIN_MEMORY,
4169
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
4170
     "%s: unable to create current working directory.",
4171
     function );
4172
4173
    goto on_error;
4174
  }
4175
  if( memory_set(
4176
       safe_current_working_directory,
4177
       0,
4178
       sizeof( wchar_t ) * safe_current_working_directory_size ) == NULL )
4179
  {
4180
    libcerror_error_set(
4181
     error,
4182
     LIBCERROR_ERROR_DOMAIN_MEMORY,
4183
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
4184
     "%s: unable to clear current working directory.",
4185
     function );
4186
4187
    goto on_error;
4188
  }
4189
  if( libcpath_system_string_copy_to_wide_string(
4190
       narrow_current_working_directory,
4191
       narrow_current_working_directory_length + 1,
4192
       safe_current_working_directory,
4193
       safe_current_working_directory_size,
4194
       error ) != 1 )
4195
  {
4196
    libcerror_error_set(
4197
     error,
4198
     LIBCERROR_ERROR_DOMAIN_CONVERSION,
4199
     LIBCERROR_CONVERSION_ERROR_GENERIC,
4200
     "%s: unable to set current working directory.",
4201
     function );
4202
4203
    goto on_error;
4204
  }
4205
  memory_free(
4206
   narrow_current_working_directory );
4207
4208
  *current_working_directory      = safe_current_working_directory;
4209
  *current_working_directory_size = safe_current_working_directory_size;
4210
4211
  return( 1 );
4212
4213
on_error:
4214
  if( narrow_current_working_directory != NULL )
4215
  {
4216
    memory_free(
4217
     narrow_current_working_directory );
4218
  }
4219
  if( safe_current_working_directory != NULL )
4220
  {
4221
    memory_free(
4222
     safe_current_working_directory );
4223
  }
4224
  return( -1 );
4225
}
4226
4227
#else
4228
#error Missing get current working directory function
4229
#endif
4230
4231
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
4232
4233
/* Cross Windows safe version of GetFullPathNameW
4234
 * Returns the number of characters in the current directory string or 0 on error
4235
 */
4236
DWORD libcpath_GetFullPathNameW(
4237
       LPCWSTR filename,
4238
       DWORD  buffer_size,
4239
       LPWSTR  buffer,
4240
       LPWSTR  *file_part )
4241
{
4242
  FARPROC function       = NULL;
4243
  HMODULE library_handle = NULL;
4244
  DWORD result           = 0;
4245
4246
  library_handle = LoadLibrary(
4247
                    _SYSTEM_STRING( "kernel32.dll" ) );
4248
4249
  if( library_handle == NULL )
4250
  {
4251
    return( 0 );
4252
  }
4253
  function = GetProcAddress(
4254
        library_handle,
4255
        (LPCSTR) "GetFullPathNameW" );
4256
4257
  if( function != NULL )
4258
  {
4259
    result = function(
4260
        filename,
4261
        buffer_size,
4262
        buffer,
4263
        file_part );
4264
  }
4265
  /* This call should be after using the function
4266
   * in most cases kernel32.dll will still be available after free
4267
   */
4268
  if( FreeLibrary(
4269
       library_handle ) != TRUE )
4270
  {
4271
    libcpath_CloseHandle(
4272
     library_handle );
4273
4274
    return( 0 );
4275
  }
4276
  return( result );
4277
}
4278
4279
#endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
4280
4281
#if defined( WINAPI )
4282
4283
/* Determines the path type
4284
 * Returns 1 if succesful or -1 on error
4285
 */
4286
int libcpath_path_get_path_type_wide(
4287
     const wchar_t *path,
4288
     size_t path_length,
4289
     uint8_t *path_type,
4290
     libcerror_error_t **error )
4291
{
4292
  static char *function = "libcpath_path_get_path_type_wide";
4293
4294
  if( path == NULL )
4295
  {
4296
    libcerror_error_set(
4297
     error,
4298
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4299
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4300
     "%s: invalid path.",
4301
     function );
4302
4303
    return( -1 );
4304
  }
4305
  if( ( path_length == 0 )
4306
   || ( path_length > (size_t) ( SSIZE_MAX - 1 ) ) )
4307
  {
4308
    libcerror_error_set(
4309
     error,
4310
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4311
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
4312
     "%s: invalid path length value out of bounds.",
4313
     function );
4314
4315
    return( -1 );
4316
  }
4317
  if( path_type == NULL )
4318
  {
4319
    libcerror_error_set(
4320
     error,
4321
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4322
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4323
     "%s: invalid path type.",
4324
     function );
4325
4326
    return( -1 );
4327
  }
4328
  *path_type = LIBCPATH_TYPE_RELATIVE;
4329
4330
  /* Determine if the path is a special path
4331
   * device path prefix:          \\.\
4332
   * extended-length path prefix: \\?\
4333
   */
4334
  if( ( path_length >= 4 )
4335
   && ( path[ 0 ] == (wchar_t) '\\' )
4336
   && ( path[ 1 ] == (wchar_t) '\\' )
4337
   && ( ( path[ 2 ] == (wchar_t) '.' )
4338
    ||  ( path[ 2 ] == (wchar_t) '?' ) )
4339
   && ( path[ 3 ] == (wchar_t) '\\' ) )
4340
  {
4341
    if( path[ 2 ] == (wchar_t) '.' )
4342
    {
4343
      *path_type = LIBCPATH_TYPE_DEVICE;
4344
    }
4345
    /* Determine if the path in an extended-length UNC path
4346
     * \\?\UNC\server\share
4347
     */
4348
    else if( ( path_length >= 8 )
4349
          && ( path[ 4 ] == (wchar_t) 'U' )
4350
          && ( path[ 5 ] == (wchar_t) 'N' )
4351
          && ( path[ 6 ] == (wchar_t) 'C' )
4352
          && ( path[ 7 ] == (wchar_t) '\\' ) )
4353
    {
4354
      *path_type = LIBCPATH_TYPE_EXTENDED_LENGTH_UNC;
4355
    }
4356
    else
4357
    {
4358
      *path_type = LIBCPATH_TYPE_EXTENDED_LENGTH;
4359
    }
4360
  }
4361
  /* Determine if the path is an UNC path
4362
   * \\server\share
4363
   */
4364
  else if( ( path_length >= 2 )
4365
        && ( path[ 0 ] == (wchar_t) '\\' )
4366
        && ( path[ 1 ] == (wchar_t) '\\' ) )
4367
  {
4368
    *path_type = LIBCPATH_TYPE_UNC;
4369
  }
4370
  else if( path[ 0 ] == (wchar_t) '\\' )
4371
  {
4372
    *path_type = LIBCPATH_TYPE_ABSOLUTE;
4373
  }
4374
  else if( ( path_length >= 3 )
4375
        && ( path[ 1 ] == (wchar_t) ':' )
4376
        && ( path[ 2 ] == (wchar_t) '\\' )
4377
        && ( ( ( path[ 0 ] >= (wchar_t) 'A' )
4378
          &&   ( path[ 0 ] <= (wchar_t) 'Z' ) )
4379
         ||  ( ( path[ 0 ] >= (wchar_t) 'a' )
4380
          &&   ( path[ 0 ] <= (wchar_t) 'z' ) ) ) )
4381
  {
4382
    *path_type = LIBCPATH_TYPE_ABSOLUTE;
4383
  }
4384
  return( 1 );
4385
}
4386
4387
/* Determines the volume name
4388
 * Returns 1 if succesful or -1 on error
4389
 */
4390
int libcpath_path_get_volume_name_wide(
4391
     const wchar_t *path,
4392
     size_t path_length,
4393
     wchar_t **volume_name,
4394
     size_t *volume_name_length,
4395
     size_t *directory_name_index,
4396
     libcerror_error_t **error )
4397
{
4398
  static char *function    = "libcpath_path_get_volume_name_wide";
4399
  size_t path_index        = 0;
4400
  size_t share_name_index  = 0;
4401
  size_t volume_name_index = 0;
4402
4403
  if( path == NULL )
4404
  {
4405
    libcerror_error_set(
4406
     error,
4407
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4408
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4409
     "%s: invalid path.",
4410
     function );
4411
4412
    return( -1 );
4413
  }
4414
  if( ( path_length == 0 )
4415
   || ( path_length > (size_t) ( SSIZE_MAX - 1 ) ) )
4416
  {
4417
    libcerror_error_set(
4418
     error,
4419
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4420
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
4421
     "%s: invalid path length value out of bounds.",
4422
     function );
4423
4424
    return( -1 );
4425
  }
4426
  if( volume_name == NULL )
4427
  {
4428
    libcerror_error_set(
4429
     error,
4430
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4431
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4432
     "%s: invalid volume name.",
4433
     function );
4434
4435
    return( -1 );
4436
  }
4437
  if( volume_name_length == NULL )
4438
  {
4439
    libcerror_error_set(
4440
     error,
4441
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4442
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4443
     "%s: invalid volume name length.",
4444
     function );
4445
4446
    return( -1 );
4447
  }
4448
  if( directory_name_index == NULL )
4449
  {
4450
    libcerror_error_set(
4451
     error,
4452
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4453
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4454
     "%s: invalid directory name index.",
4455
     function );
4456
4457
    return( -1 );
4458
  }
4459
  *volume_name          = NULL;
4460
  *volume_name_length   = 0;
4461
  *directory_name_index = 0;
4462
4463
  /* Determine if the path is a special path
4464
   * device path prefix:          \\.\
4465
   * extended-length path prefix: \\?\
4466
   */
4467
  if( ( path_length >= 4 )
4468
   && ( path[ 0 ] == (wchar_t) '\\' )
4469
   && ( path[ 1 ] == (wchar_t) '\\' )
4470
   && ( ( path[ 2 ] == (wchar_t) '.' )
4471
    ||  ( path[ 2 ] == (wchar_t) '?' ) )
4472
   && ( path[ 3 ] == (wchar_t) '\\' ) )
4473
  {
4474
    if( path[ 2 ] == (wchar_t) '.' )
4475
    {
4476
      volume_name_index = 4;
4477
    }
4478
    /* Determine if the path in an extended-length UNC path
4479
     * \\?\UNC\server\share
4480
     */
4481
    else if( ( path_length >= 8 )
4482
          && ( path[ 4 ] == (wchar_t) 'U' )
4483
          && ( path[ 5 ] == (wchar_t) 'N' )
4484
          && ( path[ 6 ] == (wchar_t) 'C' )
4485
          && ( path[ 7 ] == (wchar_t) '\\' ) )
4486
    {
4487
      volume_name_index = 8;
4488
    }
4489
    else
4490
    {
4491
      volume_name_index = 4;
4492
    }
4493
  }
4494
  /* Determine if the path is an UNC path
4495
   * \\server\share
4496
   */
4497
  else if( ( path_length >= 2 )
4498
        && ( path[ 0 ] == (wchar_t) '\\' )
4499
        && ( path[ 1 ] == (wchar_t) '\\' ) )
4500
  {
4501
    volume_name_index = 2;
4502
  }
4503
  /* Check if the path contains a volume letter
4504
   */
4505
  if( ( path_length >= 2 )
4506
   && ( volume_name_index <= ( path_length - 2 ) )
4507
   && ( path[ volume_name_index + 1 ] == (wchar_t) ':' )
4508
   && ( ( ( path[ volume_name_index ] >= (wchar_t) 'A' )
4509
     &&   ( path[ volume_name_index ] <= (wchar_t) 'Z' ) )
4510
    ||  ( ( path[ volume_name_index ] >= (wchar_t) 'a' )
4511
     &&   ( path[ volume_name_index ] <= (wchar_t) 'z' ) ) ) )
4512
  {
4513
    path_index = volume_name_index + 2;
4514
4515
    if( ( path_index < path_length )
4516
     && ( path[ path_index ] == (wchar_t) '\\' ) )
4517
    {
4518
      path_index++;
4519
    }
4520
    *volume_name        = (wchar_t *) &( path[ volume_name_index ] );
4521
    *volume_name_length = path_index - volume_name_index;
4522
4523
    if( path[ path_index - 1 ] == (wchar_t) '\\' )
4524
    {
4525
      *volume_name_length -= 1;
4526
    }
4527
    *directory_name_index = path_index;
4528
  }
4529
  else if( volume_name_index == 4 )
4530
  {
4531
    for( path_index = volume_name_index;
4532
         path_index < path_length;
4533
         path_index++ )
4534
    {
4535
      if( path[ path_index ] == (wchar_t) '\\' )
4536
      {
4537
        path_index++;
4538
4539
        break;
4540
      }
4541
    }
4542
    *volume_name        = (wchar_t *) &( path[ 4 ] );
4543
    *volume_name_length = path_index - 4;
4544
4545
    if( path[ path_index - 1 ] == (wchar_t) '\\' )
4546
    {
4547
      *volume_name_length -= 1;
4548
    }
4549
    *directory_name_index = path_index;
4550
  }
4551
  else if( ( volume_name_index == 2 )
4552
        || ( volume_name_index == 8 ) )
4553
  {
4554
    for( share_name_index = volume_name_index;
4555
         share_name_index < path_length;
4556
         share_name_index++ )
4557
    {
4558
      if( path[ share_name_index ] == (wchar_t) '\\' )
4559
      {
4560
        share_name_index++;
4561
4562
        break;
4563
      }
4564
    }
4565
    if( share_name_index > path_length )
4566
    {
4567
      libcerror_error_set(
4568
       error,
4569
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
4570
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
4571
       "%s: invalid path - missing share name.",
4572
       function );
4573
4574
      return( -1 );
4575
    }
4576
    for( path_index = share_name_index;
4577
         path_index < path_length;
4578
         path_index++ )
4579
    {
4580
      if( path[ path_index ] == (wchar_t) '\\' )
4581
      {
4582
        path_index++;
4583
4584
        break;
4585
      }
4586
    }
4587
    *volume_name        = (wchar_t *) &( path[ volume_name_index ] );
4588
    *volume_name_length = path_index - volume_name_index;
4589
4590
    if( path[ path_index - 1 ] == (wchar_t) '\\' )
4591
    {
4592
      *volume_name_length -= 1;
4593
    }
4594
    *directory_name_index = path_index;
4595
  }
4596
  return( 1 );
4597
}
4598
4599
/* Retrieves the current working directory of a specific volume
4600
 * Returns 1 if successful or -1 on error
4601
 */
4602
int libcpath_path_get_current_working_directory_by_volume_wide(
4603
     wchar_t *volume_name,
4604
     size_t volume_name_length,
4605
     wchar_t **current_working_directory,
4606
     size_t *current_working_directory_size,
4607
     libcerror_error_t **error )
4608
{
4609
  static char *function                     = "libcpath_path_get_current_working_directory_by_volume_wide";
4610
  wchar_t *safe_current_working_directory   = NULL;
4611
  DWORD error_code                          = 0;
4612
  DWORD result                              = 0;
4613
  DWORD safe_current_working_directory_size = 0;
4614
4615
  if( volume_name == NULL )
4616
  {
4617
    libcerror_error_set(
4618
     error,
4619
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4620
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4621
     "%s: invalid volume name.",
4622
     function );
4623
4624
    return( -1 );
4625
  }
4626
  if( ( volume_name_length == 0 )
4627
   || ( volume_name_length > (size_t) ( SSIZE_MAX - 1 ) ) )
4628
  {
4629
    libcerror_error_set(
4630
     error,
4631
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4632
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
4633
     "%s: invalid volume name length value out of bounds.",
4634
     function );
4635
4636
    return( -1 );
4637
  }
4638
  if( current_working_directory == NULL )
4639
  {
4640
    libcerror_error_set(
4641
     error,
4642
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4643
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4644
     "%s: invalid current working directory.",
4645
     function );
4646
4647
    return( -1 );
4648
  }
4649
  if( *current_working_directory != NULL )
4650
  {
4651
    libcerror_error_set(
4652
     error,
4653
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4654
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
4655
     "%s: invalid current working directory value already set.",
4656
     function );
4657
4658
    return( -1 );
4659
  }
4660
  if( current_working_directory_size == NULL )
4661
  {
4662
    libcerror_error_set(
4663
     error,
4664
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4665
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4666
     "%s: invalid current working directory size.",
4667
     function );
4668
4669
    return( -1 );
4670
  }
4671
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
4672
  safe_current_working_directory_size = libcpath_GetFullPathNameW(
4673
                                         volume_name,
4674
                                         0,
4675
                                         NULL,
4676
                                         NULL );
4677
#else
4678
  safe_current_working_directory_size = GetFullPathNameW(
4679
                                         volume_name,
4680
                                         0,
4681
                                         NULL,
4682
                                         NULL );
4683
#endif
4684
  if( safe_current_working_directory_size == 0 )
4685
  {
4686
    libcerror_error_set(
4687
     error,
4688
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4689
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4690
     "%s: unable to retrieve current working directory size.",
4691
     function );
4692
4693
    goto on_error;
4694
  }
4695
  if( (size_t) safe_current_working_directory_size > (size_t) SSIZE_MAX )
4696
  {
4697
    libcerror_error_set(
4698
     error,
4699
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4700
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
4701
     "%s: invalid current working directory size value out of bounds.",
4702
     function );
4703
4704
    goto on_error;
4705
  }
4706
  safe_current_working_directory = wide_string_allocate(
4707
                                    safe_current_working_directory_size );
4708
4709
  if( safe_current_working_directory == NULL )
4710
  {
4711
    libcerror_error_set(
4712
     error,
4713
     LIBCERROR_ERROR_DOMAIN_MEMORY,
4714
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
4715
     "%s: unable to create current working directory.",
4716
     function );
4717
4718
    goto on_error;
4719
  }
4720
  if( memory_set(
4721
       safe_current_working_directory,
4722
       0,
4723
       sizeof( wchar_t ) * safe_current_working_directory_size ) == NULL )
4724
  {
4725
    libcerror_error_set(
4726
     error,
4727
     LIBCERROR_ERROR_DOMAIN_MEMORY,
4728
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
4729
     "%s: unable to clear current working directory.",
4730
     function );
4731
4732
    goto on_error;
4733
  }
4734
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
4735
  result = libcpath_GetFullPathNameW(
4736
            volume_name,
4737
            safe_current_working_directory_size,
4738
            safe_current_working_directory,
4739
            NULL );
4740
#else
4741
  result = GetFullPathNameW(
4742
            volume_name,
4743
            safe_current_working_directory_size,
4744
            safe_current_working_directory,
4745
            NULL );
4746
#endif
4747
  /* Note that safe_current_working_directory_size can be larger than result
4748
   */
4749
  if( ( result == 0 )
4750
   || ( result > safe_current_working_directory_size ) )
4751
  {
4752
    error_code = GetLastError();
4753
4754
    libcerror_system_set_error(
4755
     error,
4756
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4757
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4758
     error_code,
4759
     "%s: unable to retrieve current working directory.",
4760
     function );
4761
4762
    goto on_error;
4763
  }
4764
  *current_working_directory      = safe_current_working_directory;
4765
  *current_working_directory_size = (size_t) safe_current_working_directory_size;
4766
4767
  return( 1 );
4768
4769
on_error:
4770
  if( safe_current_working_directory != NULL )
4771
  {
4772
    memory_free(
4773
     safe_current_working_directory );
4774
  }
4775
  return( -1 );
4776
}
4777
4778
/* Determines the full path of the Windows path specified
4779
 * The function uses the extended-length path format
4780
 * (path with \\?\ prefix)
4781
 *
4782
 * Multiple successive \ not at the start of the path are combined into one
4783
 *
4784
 * Scenario's that are considered full paths:
4785
 * Device path:     \\.\PhysicalDrive0
4786
 * Extended-length path:  \\?\C:\directory\file.txt
4787
 * Extended-length UNC path:  \\?\UNC\server\share\directory\file.txt
4788
 *
4789
 * Scenario's that are not considered full paths:
4790
 * Local 'absolute' path: \directory\file.txt
4791
 * Local 'relative' path: ..\directory\file.txt
4792
 * Local 'relative' path: .\directory\file.txt
4793
 * Volume 'absolute' path:  C:\directory\file.txt
4794
 *                              C:\..\directory\file.txt
4795
 * Volume 'relative' path:  C:directory\file.txt
4796
 * UNC path:      \\server\share\directory\file.txt
4797
 *
4798
 * Returns 1 if succesful or -1 on error
4799
 */
4800
int libcpath_path_get_full_path_wide(
4801
     const wchar_t *path,
4802
     size_t path_length,
4803
     wchar_t **full_path,
4804
     size_t *full_path_size,
4805
     libcerror_error_t **error )
4806
{
4807
  libcsplit_wide_split_string_t *current_directory_split_string = NULL;
4808
  libcsplit_wide_split_string_t *path_split_string              = NULL;
4809
  wchar_t *current_directory                                    = NULL;
4810
  wchar_t *current_directory_string_segment                     = NULL;
4811
  wchar_t *full_path_prefix                                     = NULL;
4812
  wchar_t *last_used_path_string_segment                        = NULL;
4813
  wchar_t *path_string_segment                                  = NULL;
4814
  wchar_t *safe_full_path                                       = NULL;
4815
  wchar_t *volume_name                                          = NULL;
4816
  static char *function                                         = "libcpath_path_get_full_path_wide";
4817
  size_t current_directory_length                               = 0;
4818
  size_t current_directory_name_index                           = 0;
4819
  size_t current_directory_size                                 = 0;
4820
  size_t current_directory_string_segment_size                  = 0;
4821
  size_t full_path_index                                        = 0;
4822
  size_t full_path_prefix_length                                = 0;
4823
  size_t last_used_path_string_segment_size                     = 0;
4824
  size_t path_directory_name_index                              = 0;
4825
  size_t path_string_segment_length                             = 0;
4826
  size_t path_string_segment_size                               = 0;
4827
  size_t safe_full_path_size                                    = 0;
4828
  size_t volume_name_length                                     = 0;
4829
  uint8_t path_type                                             = LIBCPATH_TYPE_RELATIVE;
4830
  int current_directory_number_of_segments                      = 0;
4831
  int current_directory_segment_index                           = 0;
4832
  int last_used_path_segment_index                              = -1;
4833
  int path_number_of_segments                                   = 0;
4834
  int path_segment_index                                        = 0;
4835
  int result                                                    = 0;
4836
4837
  if( path == NULL )
4838
  {
4839
    libcerror_error_set(
4840
     error,
4841
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4842
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4843
     "%s: invalid path.",
4844
     function );
4845
4846
    return( -1 );
4847
  }
4848
  if( ( path_length == 0 )
4849
   || ( path_length > (size_t) ( SSIZE_MAX - 1 ) ) )
4850
  {
4851
    libcerror_error_set(
4852
     error,
4853
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4854
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
4855
     "%s: invalid path length value out of bounds.",
4856
     function );
4857
4858
    return( -1 );
4859
  }
4860
  if( full_path == NULL )
4861
  {
4862
    libcerror_error_set(
4863
     error,
4864
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4865
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4866
     "%s: invalid full path.",
4867
     function );
4868
4869
    return( -1 );
4870
  }
4871
  if( *full_path != NULL )
4872
  {
4873
    libcerror_error_set(
4874
     error,
4875
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4876
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
4877
     "%s: invalid full path value already set.",
4878
     function );
4879
4880
    return( -1 );
4881
  }
4882
  if( full_path_size == NULL )
4883
  {
4884
    libcerror_error_set(
4885
     error,
4886
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4887
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4888
     "%s: invalid full path size.",
4889
     function );
4890
4891
    return( -1 );
4892
  }
4893
  if( libcpath_path_get_path_type_wide(
4894
       path,
4895
       path_length,
4896
       &path_type,
4897
       error ) != 1 )
4898
  {
4899
    libcerror_error_set(
4900
     error,
4901
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4902
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4903
     "%s: unable to determine path type.",
4904
     function );
4905
4906
    goto on_error;
4907
  }
4908
  if( libcpath_path_get_volume_name_wide(
4909
       path,
4910
       path_length,
4911
       &volume_name,
4912
       &volume_name_length,
4913
       &path_directory_name_index,
4914
       error ) != 1 )
4915
  {
4916
    libcerror_error_set(
4917
     error,
4918
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
4919
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4920
     "%s: unable to determine volume name.",
4921
     function );
4922
4923
    goto on_error;
4924
  }
4925
  /* If the path is a device path, an extended-length path or an UNC
4926
   * do not bother to lookup the current working directory
4927
   */
4928
  if( ( path_type != LIBCPATH_TYPE_DEVICE )
4929
   && ( path_type != LIBCPATH_TYPE_EXTENDED_LENGTH )
4930
   && ( path_type != LIBCPATH_TYPE_EXTENDED_LENGTH_UNC )
4931
   && ( path_type != LIBCPATH_TYPE_UNC ) )
4932
  {
4933
    if( volume_name == NULL )
4934
    {
4935
      result = libcpath_path_get_current_working_directory_wide(
4936
                &current_directory,
4937
                &current_directory_size,
4938
                error );
4939
    }
4940
    else
4941
    {
4942
      result = libcpath_path_get_current_working_directory_by_volume_wide(
4943
                volume_name,
4944
                volume_name_length,
4945
                &current_directory,
4946
                &current_directory_size,
4947
                error );
4948
    }
4949
    if( result != 1 )
4950
    {
4951
      libcerror_error_set(
4952
       error,
4953
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
4954
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4955
       "%s: unable to retrieve current working directory.",
4956
       function );
4957
4958
      goto on_error;
4959
    }
4960
    if( volume_name == NULL )
4961
    {
4962
      /* Determine the volume name using the current working directory if necessary
4963
       */
4964
      if( libcpath_path_get_volume_name_wide(
4965
           current_directory,
4966
           current_directory_size - 1,
4967
           &volume_name,
4968
           &volume_name_length,
4969
           &current_directory_name_index,
4970
           error ) != 1 )
4971
      {
4972
        libcerror_error_set(
4973
         error,
4974
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
4975
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4976
         "%s: unable to determine volume name from current working directory.",
4977
         function );
4978
4979
        goto on_error;
4980
      }
4981
    }
4982
  }
4983
  /* The full path prefix consists of "\\?\" or "\\.\"
4984
   */
4985
  full_path_prefix_length = 4;
4986
4987
  if( volume_name != NULL )
4988
  {
4989
    /* Add the volume or device name
4990
     */
4991
    full_path_prefix_length += volume_name_length;
4992
  }
4993
  if( ( path_type == LIBCPATH_TYPE_EXTENDED_LENGTH_UNC )
4994
   || ( path_type == LIBCPATH_TYPE_UNC ) )
4995
  {
4996
    /* Add the "UNC\" prefix
4997
     */
4998
    full_path_prefix_length += 4;
4999
  }
5000
  if( ( current_directory != NULL )
5001
   && ( current_directory_name_index < current_directory_size ) )
5002
  {
5003
    current_directory_length = wide_string_length(
5004
                                &( current_directory[ current_directory_name_index ] ) );
5005
5006
    if( libcsplit_wide_string_split(
5007
         &( current_directory[ current_directory_name_index ] ),
5008
         current_directory_length + 1,
5009
         (wchar_t) '\\',
5010
         &current_directory_split_string,
5011
         error ) != 1 )
5012
    {
5013
      libcerror_error_set(
5014
       error,
5015
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5016
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
5017
       "%s: unable to split current working directory.",
5018
       function );
5019
5020
      goto on_error;
5021
    }
5022
    if( libcsplit_wide_split_string_get_number_of_segments(
5023
         current_directory_split_string,
5024
         &current_directory_number_of_segments,
5025
         error ) != 1 )
5026
    {
5027
      libcerror_error_set(
5028
       error,
5029
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5030
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5031
       "%s: unable to retrieve number of current working directory string segments.",
5032
       function );
5033
5034
      goto on_error;
5035
    }
5036
    current_directory_segment_index = current_directory_number_of_segments - 1;
5037
5038
    if( path_type == LIBCPATH_TYPE_RELATIVE )
5039
    {
5040
      /* If the path is relative
5041
       * add the size of the current working directory
5042
       * a directory separator, if necessary
5043
       */
5044
      safe_full_path_size += ( current_directory_size - ( current_directory_name_index + 1 ) );
5045
5046
      if( ( current_directory_size >= 2 )
5047
       && ( current_directory[ current_directory_size - 2 ] != (wchar_t) '\\' ) )
5048
      {
5049
        safe_full_path_size += 1;
5050
      }
5051
    }
5052
  }
5053
  if( libcsplit_wide_string_split(
5054
       &( path[ path_directory_name_index ] ),
5055
       path_length - path_directory_name_index + 1,
5056
       (wchar_t) '\\',
5057
       &path_split_string,
5058
       error ) != 1 )
5059
  {
5060
    libcerror_error_set(
5061
     error,
5062
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
5063
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
5064
     "%s: unable to split path.",
5065
     function );
5066
5067
    goto on_error;
5068
  }
5069
  if( path_split_string != NULL )
5070
  {
5071
    if( libcsplit_wide_split_string_get_number_of_segments(
5072
         path_split_string,
5073
         &path_number_of_segments,
5074
         error ) != 1 )
5075
    {
5076
      libcerror_error_set(
5077
       error,
5078
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5079
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5080
       "%s: unable to retrieve number of path string segments.",
5081
       function );
5082
5083
      goto on_error;
5084
    }
5085
    for( path_segment_index = 0;
5086
         path_segment_index < path_number_of_segments;
5087
         path_segment_index++ )
5088
    {
5089
      if( libcsplit_wide_split_string_get_segment_by_index(
5090
           path_split_string,
5091
           path_segment_index,
5092
           &path_string_segment,
5093
           &path_string_segment_size,
5094
           error ) != 1 )
5095
      {
5096
        libcerror_error_set(
5097
         error,
5098
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
5099
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5100
         "%s: unable to retrieve path string segment: %d.",
5101
         function,
5102
         path_segment_index );
5103
5104
        goto on_error;
5105
      }
5106
      if( path_string_segment == NULL )
5107
      {
5108
        libcerror_error_set(
5109
         error,
5110
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
5111
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5112
         "%s: missing path string segment: %d.",
5113
         function,
5114
         path_segment_index );
5115
5116
        goto on_error;
5117
      }
5118
      /* If the path is "" (empty) or "." (current) ignore the entry
5119
       */
5120
      if( ( path_string_segment_size <= 1 )
5121
       || ( ( path_string_segment_size == 2 )
5122
        &&  ( path_string_segment[ 0 ] == (wchar_t) '.' ) ) )
5123
      {
5124
        if( libcsplit_wide_split_string_set_segment_by_index(
5125
             path_split_string,
5126
             path_segment_index,
5127
             NULL,
5128
             0,
5129
             error ) != 1 )
5130
        {
5131
          libcerror_error_set(
5132
           error,
5133
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
5134
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5135
           "%s: unable to set path string segment: %d.",
5136
           function,
5137
           path_segment_index );
5138
5139
          goto on_error;
5140
        }
5141
      }
5142
      /* If the path is ".." (parent) reverse the current path by one directory
5143
       */
5144
      else if( ( path_string_segment_size == 3 )
5145
            && ( path_string_segment[ 0 ] == (wchar_t) '.' )
5146
            && ( path_string_segment[ 1 ] == (wchar_t) '.' ) )
5147
      {
5148
        if( ( current_directory_split_string != NULL )
5149
         && ( last_used_path_segment_index == -1 ) )
5150
        {
5151
          if( libcsplit_wide_split_string_get_segment_by_index(
5152
               current_directory_split_string,
5153
               current_directory_segment_index,
5154
               &current_directory_string_segment,
5155
               &current_directory_string_segment_size,
5156
               error ) != 1 )
5157
          {
5158
            libcerror_error_set(
5159
             error,
5160
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
5161
             LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5162
             "%s: unable to retrieve current working directory string segment: %d.",
5163
             function,
5164
             current_directory_segment_index );
5165
5166
            goto on_error;
5167
          }
5168
          if( current_directory_string_segment == NULL )
5169
          {
5170
            libcerror_error_set(
5171
             error,
5172
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
5173
             LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5174
             "%s: missing current working directory string segment: %d.",
5175
             function,
5176
             current_directory_segment_index );
5177
5178
            goto on_error;
5179
          }
5180
          /* Remove the size of the parent directory name and a directory separator
5181
           * Note that the size includes the end of string character
5182
           */
5183
          if( current_directory_string_segment_size < safe_full_path_size )
5184
          {
5185
            safe_full_path_size -= current_directory_string_segment_size;
5186
          }
5187
          else
5188
          {
5189
            safe_full_path_size = 0;
5190
          }
5191
          if( libcsplit_wide_split_string_set_segment_by_index(
5192
               current_directory_split_string,
5193
               current_directory_segment_index,
5194
               NULL,
5195
               0,
5196
               error ) != 1 )
5197
          {
5198
            libcerror_error_set(
5199
             error,
5200
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
5201
             LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5202
             "%s: unable to set current working directory string segment: %d.",
5203
             function,
5204
             current_directory_segment_index );
5205
5206
            goto on_error;
5207
          }
5208
          current_directory_segment_index--;
5209
        }
5210
        else if( last_used_path_segment_index >= 0 )
5211
        {
5212
          if( libcsplit_wide_split_string_get_segment_by_index(
5213
               path_split_string,
5214
               last_used_path_segment_index,
5215
               &last_used_path_string_segment,
5216
               &last_used_path_string_segment_size,
5217
               error ) != 1 )
5218
          {
5219
            libcerror_error_set(
5220
             error,
5221
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
5222
             LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5223
             "%s: unable to retrieve last used path string segment: %d.",
5224
             function,
5225
             last_used_path_segment_index );
5226
5227
            goto on_error;
5228
          }
5229
          if( last_used_path_string_segment == NULL )
5230
          {
5231
            libcerror_error_set(
5232
             error,
5233
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
5234
             LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5235
             "%s: missing last used path string string segment: %d.",
5236
             function,
5237
             last_used_path_segment_index );
5238
5239
            goto on_error;
5240
          }
5241
          /* Remove the size of the parent directory name and a directory separator
5242
           * Note that the size includes the end of string character
5243
           */
5244
          if( last_used_path_string_segment_size < safe_full_path_size )
5245
          {
5246
            safe_full_path_size -= last_used_path_string_segment_size;
5247
          }
5248
          else
5249
          {
5250
            safe_full_path_size = 0;
5251
          }
5252
          if( libcsplit_wide_split_string_set_segment_by_index(
5253
               path_split_string,
5254
               last_used_path_segment_index,
5255
               NULL,
5256
               0,
5257
               error ) != 1 )
5258
          {
5259
            libcerror_error_set(
5260
             error,
5261
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
5262
             LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5263
             "%s: unable to set path string segment: %d.",
5264
             function,
5265
             last_used_path_segment_index );
5266
5267
            goto on_error;
5268
          }
5269
          /* Find the previous path split value that contains a name
5270
           */
5271
          while( last_used_path_segment_index > 0 )
5272
          {
5273
            last_used_path_segment_index--;
5274
5275
            if( libcsplit_wide_split_string_get_segment_by_index(
5276
                 path_split_string,
5277
                 last_used_path_segment_index,
5278
                 &last_used_path_string_segment,
5279
                 &last_used_path_string_segment_size,
5280
                 error ) != 1 )
5281
            {
5282
              libcerror_error_set(
5283
               error,
5284
               LIBCERROR_ERROR_DOMAIN_RUNTIME,
5285
               LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5286
               "%s: unable to retrieve last used path string segment: %d.",
5287
               function,
5288
               last_used_path_segment_index );
5289
5290
              goto on_error;
5291
            }
5292
            if( last_used_path_string_segment_size != 0 )
5293
            {
5294
              break;
5295
            }
5296
          }
5297
        }
5298
        if( libcsplit_wide_split_string_set_segment_by_index(
5299
             path_split_string,
5300
             path_segment_index,
5301
             NULL,
5302
             0,
5303
             error ) != 1 )
5304
        {
5305
          libcerror_error_set(
5306
           error,
5307
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
5308
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5309
           "%s: unable to set path string segment: %d.",
5310
           function,
5311
           path_segment_index );
5312
5313
          goto on_error;
5314
        }
5315
      }
5316
      else
5317
      {
5318
        /* Add the size of the directory or file name and a directory separator
5319
         * Note that the size includes the end of string character
5320
         */
5321
        safe_full_path_size += path_string_segment_size;
5322
5323
        last_used_path_segment_index = path_segment_index;
5324
      }
5325
    }
5326
    /* Use the size reserved of the last directory separator for
5327
     * the directory separator after the path prefix.
5328
     */
5329
  }
5330
  safe_full_path_size += full_path_prefix_length + 1;
5331
5332
  full_path_index = 0;
5333
5334
  safe_full_path = wide_string_allocate(
5335
                    safe_full_path_size );
5336
5337
  if( safe_full_path == NULL )
5338
  {
5339
    libcerror_error_set(
5340
     error,
5341
     LIBCERROR_ERROR_DOMAIN_MEMORY,
5342
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
5343
     "%s: unable to create full path.",
5344
     function );
5345
5346
    goto on_error;
5347
  }
5348
  if( memory_set(
5349
       safe_full_path,
5350
       0,
5351
       sizeof( wchar_t ) * safe_full_path_size ) == NULL )
5352
  {
5353
    libcerror_error_set(
5354
     error,
5355
     LIBCERROR_ERROR_DOMAIN_MEMORY,
5356
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
5357
     "%s: unable to clear full path.",
5358
     function );
5359
5360
    goto on_error;
5361
  }
5362
  if( path_type == LIBCPATH_TYPE_DEVICE )
5363
  {
5364
    full_path_prefix        = L"\\\\.\\";
5365
    full_path_prefix_length = 4;
5366
  }
5367
  else
5368
  {
5369
    full_path_prefix        = L"\\\\?\\";
5370
    full_path_prefix_length = 4;
5371
  }
5372
  if( full_path_prefix_length > ( safe_full_path_size - full_path_index ) )
5373
  {
5374
    libcerror_error_set(
5375
     error,
5376
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5377
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
5378
     "%s: invalid full path size value out of bounds.",
5379
     function );
5380
5381
    goto on_error;
5382
  }
5383
  if( wide_string_copy(
5384
       &( safe_full_path[ full_path_index ] ),
5385
       full_path_prefix,
5386
       full_path_prefix_length ) == NULL )
5387
  {
5388
    libcerror_error_set(
5389
     error,
5390
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
5391
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5392
     "%s: unable to set prefix in full path.",
5393
     function );
5394
5395
    goto on_error;
5396
  }
5397
  full_path_index += full_path_prefix_length;
5398
5399
  /* If there is a share name the path is an UNC path
5400
   */
5401
  if( ( path_type == LIBCPATH_TYPE_EXTENDED_LENGTH_UNC )
5402
   || ( path_type == LIBCPATH_TYPE_UNC ) )
5403
  {
5404
    if( ( safe_full_path_size - full_path_index ) < 4 )
5405
    {
5406
      libcerror_error_set(
5407
       error,
5408
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5409
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
5410
       "%s: invalid full path size value out of bounds.",
5411
       function );
5412
5413
      goto on_error;
5414
    }
5415
    if( wide_string_copy(
5416
         &( safe_full_path[ full_path_index ] ),
5417
         L"UNC\\",
5418
         4 ) == NULL )
5419
    {
5420
      libcerror_error_set(
5421
       error,
5422
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5423
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5424
       "%s: unable to set UNC\\ prefix in full path.",
5425
       function );
5426
5427
      goto on_error;
5428
    }
5429
    full_path_index += 4;
5430
  }
5431
  if( volume_name != NULL )
5432
  {
5433
    if( volume_name_length > ( safe_full_path_size - full_path_index ) )
5434
    {
5435
      libcerror_error_set(
5436
       error,
5437
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5438
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
5439
       "%s: invalid full path size value out of bounds.",
5440
       function );
5441
5442
      goto on_error;
5443
    }
5444
    if( wide_string_copy(
5445
         &( safe_full_path[ full_path_index ] ),
5446
         volume_name,
5447
         volume_name_length ) == NULL )
5448
    {
5449
      libcerror_error_set(
5450
       error,
5451
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5452
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5453
       "%s: unable to set volume name in full path.",
5454
       function );
5455
5456
      goto on_error;
5457
    }
5458
    full_path_index += volume_name_length;
5459
5460
    safe_full_path[ full_path_index ] = (wchar_t) '\\';
5461
5462
    full_path_index += 1;
5463
  }
5464
  /* If the path is relative
5465
   * add the current working directory elements
5466
   */
5467
  if( ( path_type == LIBCPATH_TYPE_RELATIVE )
5468
   && ( current_directory_split_string != NULL ) )
5469
  {
5470
    for( current_directory_segment_index = 0;
5471
         current_directory_segment_index < current_directory_number_of_segments;
5472
         current_directory_segment_index++ )
5473
    {
5474
      if( libcsplit_wide_split_string_get_segment_by_index(
5475
           current_directory_split_string,
5476
           current_directory_segment_index,
5477
           &current_directory_string_segment,
5478
           &current_directory_string_segment_size,
5479
           error ) != 1 )
5480
      {
5481
        libcerror_error_set(
5482
         error,
5483
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
5484
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5485
         "%s: unable to retrieve current working directory string segment: %d.",
5486
         function,
5487
         current_directory_segment_index );
5488
5489
        goto on_error;
5490
      }
5491
      if( current_directory_string_segment_size != 0 )
5492
      {
5493
        if( current_directory_string_segment == NULL )
5494
        {
5495
          libcerror_error_set(
5496
           error,
5497
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
5498
           LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5499
           "%s: missing current working directory string segment: %d.",
5500
           function,
5501
           current_directory_segment_index );
5502
5503
          goto on_error;
5504
        }
5505
        /* Note that here we should have room for the segment string and
5506
         * one additional character
5507
         */
5508
        if( current_directory_string_segment_size > ( safe_full_path_size - full_path_index ) )
5509
        {
5510
          libcerror_error_set(
5511
           error,
5512
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
5513
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
5514
           "%s: invalid current working directory string segment: %d size value out of bounds.",
5515
           function,
5516
           current_directory_segment_index );
5517
5518
          goto on_error;
5519
        }
5520
        path_string_segment_length = current_directory_string_segment_size - 1;
5521
5522
        if( wide_string_copy(
5523
             &( safe_full_path[ full_path_index ] ),
5524
             current_directory_string_segment,
5525
             path_string_segment_length ) == NULL )
5526
        {
5527
          libcerror_error_set(
5528
           error,
5529
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
5530
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5531
           "%s: unable to set current working directory split value: %d in full path.",
5532
           function,
5533
           current_directory_segment_index );
5534
5535
          goto on_error;
5536
        }
5537
        full_path_index += path_string_segment_length;
5538
5539
        safe_full_path[ full_path_index ] = (wchar_t) '\\';
5540
5541
        full_path_index += 1;
5542
      }
5543
    }
5544
  }
5545
  if( path_split_string != NULL )
5546
  {
5547
    for( path_segment_index = 0;
5548
         path_segment_index < path_number_of_segments;
5549
         path_segment_index++ )
5550
    {
5551
      if( libcsplit_wide_split_string_get_segment_by_index(
5552
           path_split_string,
5553
           path_segment_index,
5554
           &path_string_segment,
5555
           &path_string_segment_size,
5556
           error ) != 1 )
5557
      {
5558
        libcerror_error_set(
5559
         error,
5560
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
5561
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5562
         "%s: unable to retrieve path string segment: %d.",
5563
         function,
5564
         path_segment_index );
5565
5566
        goto on_error;
5567
      }
5568
      if( path_string_segment_size != 0 )
5569
      {
5570
        if( path_string_segment == NULL )
5571
        {
5572
          libcerror_error_set(
5573
           error,
5574
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
5575
           LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5576
           "%s: missing path string segment: %d.",
5577
           function,
5578
           path_segment_index );
5579
5580
          goto on_error;
5581
        }
5582
        /* Note that here we should have room for the segment string and
5583
         * one additional character
5584
         */
5585
        if( path_string_segment_size > ( safe_full_path_size - full_path_index ) )
5586
        {
5587
          libcerror_error_set(
5588
           error,
5589
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
5590
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
5591
           "%s: invalid current path string segment: %d size value out of bounds.",
5592
           function,
5593
           path_segment_index );
5594
5595
          goto on_error;
5596
        }
5597
        path_string_segment_length = path_string_segment_size - 1;
5598
5599
        if( wide_string_copy(
5600
             &( safe_full_path[ full_path_index ] ),
5601
             path_string_segment,
5602
             path_string_segment_length ) == NULL )
5603
        {
5604
          libcerror_error_set(
5605
           error,
5606
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
5607
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5608
           "%s: unable to set path split value: %d in full path.",
5609
           function,
5610
           path_segment_index );
5611
5612
          goto on_error;
5613
        }
5614
        full_path_index += path_string_segment_length;
5615
5616
        safe_full_path[ full_path_index ] = (wchar_t) '\\';
5617
5618
        full_path_index += 1;
5619
      }
5620
    }
5621
  }
5622
  safe_full_path[ full_path_index - 1 ] = 0;
5623
5624
  if( path_split_string != NULL )
5625
  {
5626
    if( libcsplit_wide_split_string_free(
5627
         &path_split_string,
5628
         error ) != 1 )
5629
    {
5630
      libcerror_error_set(
5631
       error,
5632
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5633
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
5634
       "%s: unable to free path split string.",
5635
       function );
5636
5637
      goto on_error;
5638
    }
5639
  }
5640
  if( current_directory_split_string != NULL )
5641
  {
5642
    if( libcsplit_wide_split_string_free(
5643
         &current_directory_split_string,
5644
         error ) != 1 )
5645
    {
5646
      libcerror_error_set(
5647
       error,
5648
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5649
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
5650
       "%s: unable to free current working directory split string.",
5651
       function );
5652
5653
      goto on_error;
5654
    }
5655
  }
5656
  if( current_directory != NULL )
5657
  {
5658
    memory_free(
5659
     current_directory );
5660
  }
5661
  *full_path      = safe_full_path;
5662
  *full_path_size = safe_full_path_size;
5663
5664
  return( 1 );
5665
5666
on_error:
5667
  if( safe_full_path != NULL )
5668
  {
5669
    memory_free(
5670
     safe_full_path );
5671
  }
5672
  if( path_split_string != NULL )
5673
  {
5674
    libcsplit_wide_split_string_free(
5675
     &path_split_string,
5676
     NULL );
5677
  }
5678
  if( current_directory_split_string != NULL )
5679
  {
5680
    libcsplit_wide_split_string_free(
5681
     &current_directory_split_string,
5682
     NULL );
5683
  }
5684
  if( current_directory != NULL )
5685
  {
5686
    memory_free(
5687
     current_directory );
5688
  }
5689
  return( -1 );
5690
}
5691
5692
#else
5693
5694
/* Determines the full path of the POSIX path specified
5695
 * Multiple successive / are combined into one
5696
 *
5697
 * Scenarios:
5698
 * /home/user/file.txt
5699
 * /home/user//file.txt
5700
 * /home/user/../user/file.txt
5701
 * /../home/user/file.txt
5702
 * user/../user/file.txt
5703
 *
5704
 * Returns 1 if succesful or -1 on error
5705
 */
5706
int libcpath_path_get_full_path_wide(
5707
     const wchar_t *path,
5708
     size_t path_length,
5709
     wchar_t **full_path,
5710
     size_t *full_path_size,
5711
     libcerror_error_t **error )
5712
{
5713
  libcsplit_wide_split_string_t *current_directory_split_string = NULL;
5714
  libcsplit_wide_split_string_t *path_split_string              = NULL;
5715
  wchar_t *current_directory                                    = NULL;
5716
  wchar_t *current_directory_string_segment                     = NULL;
5717
  wchar_t *last_used_path_string_segment                        = NULL;
5718
  wchar_t *path_string_segment                                  = NULL;
5719
  wchar_t *safe_full_path                                       = NULL;
5720
  static char *function                                         = "libcpath_path_get_full_path_wide";
5721
  size_t current_directory_length                               = 0;
5722
  size_t current_directory_size                                 = 0;
5723
  size_t current_directory_string_segment_size                  = 0;
5724
  size_t full_path_index                                        = 0;
5725
  size_t full_path_prefix_length                                = 0;
5726
  size_t last_used_path_string_segment_size                     = 0;
5727
  size_t path_string_segment_length                             = 0;
5728
  size_t path_string_segment_size                               = 0;
5729
  size_t safe_full_path_size                                    = 0;
5730
  uint8_t path_type                                             = LIBCPATH_TYPE_RELATIVE;
5731
  int current_directory_number_of_segments                      = 0;
5732
  int current_directory_segment_index                           = 0;
5733
  int last_used_path_segment_index                              = -1;
5734
  int path_number_of_segments                                   = 0;
5735
  int path_segment_index                                        = 0;
5736
5737
  if( path == NULL )
5738
  {
5739
    libcerror_error_set(
5740
     error,
5741
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5742
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
5743
     "%s: invalid path.",
5744
     function );
5745
5746
    return( -1 );
5747
  }
5748
  if( ( path_length == 0 )
5749
   || ( path_length > (size_t) ( SSIZE_MAX - 1 ) ) )
5750
  {
5751
    libcerror_error_set(
5752
     error,
5753
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5754
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
5755
     "%s: invalid path length value out of bounds.",
5756
     function );
5757
5758
    return( -1 );
5759
  }
5760
  if( full_path == NULL )
5761
  {
5762
    libcerror_error_set(
5763
     error,
5764
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5765
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
5766
     "%s: invalid full path.",
5767
     function );
5768
5769
    return( -1 );
5770
  }
5771
  if( *full_path != NULL )
5772
  {
5773
    libcerror_error_set(
5774
     error,
5775
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
5776
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
5777
     "%s: invalid full path value already set.",
5778
     function );
5779
5780
    return( -1 );
5781
  }
5782
  if( full_path_size == NULL )
5783
  {
5784
    libcerror_error_set(
5785
     error,
5786
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
5787
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
5788
     "%s: invalid full path size.",
5789
     function );
5790
5791
    return( -1 );
5792
  }
5793
  /* Determine the full path size
5794
   */
5795
  if( path[ 0 ] == (wchar_t) '/' )
5796
  {
5797
    path_type = LIBCPATH_TYPE_ABSOLUTE;
5798
5799
    /* If the path is absolute
5800
     * a directory separator
5801
     */
5802
    full_path_prefix_length = 1;
5803
  }
5804
  else
5805
  {
5806
    if( libcpath_path_get_current_working_directory_wide(
5807
         &current_directory,
5808
         &current_directory_size,
5809
         error ) != 1 )
5810
    {
5811
      libcerror_error_set(
5812
       error,
5813
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5814
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5815
       "%s: unable to retrieve current working directory.",
5816
       function );
5817
5818
      goto on_error;
5819
    }
5820
    if( current_directory == NULL )
5821
    {
5822
      libcerror_error_set(
5823
       error,
5824
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5825
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5826
       "%s: missing current working directory.",
5827
       function );
5828
5829
      goto on_error;
5830
    }
5831
    /* We need to use the length here since current_directory_size will be PATH_MAX
5832
     */
5833
    current_directory_length = wide_string_length(
5834
                                current_directory );
5835
5836
    if( libcsplit_wide_string_split(
5837
         current_directory,
5838
         current_directory_length + 1,
5839
         (wchar_t) '/',
5840
         &current_directory_split_string,
5841
         error ) != 1 )
5842
    {
5843
      libcerror_error_set(
5844
       error,
5845
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5846
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
5847
       "%s: unable to split current working directory.",
5848
       function );
5849
5850
      goto on_error;
5851
    }
5852
    if( libcsplit_wide_split_string_get_number_of_segments(
5853
         current_directory_split_string,
5854
         &current_directory_number_of_segments,
5855
         error ) != 1 )
5856
    {
5857
      libcerror_error_set(
5858
       error,
5859
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5860
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5861
       "%s: unable to retrieve number of current working directory string segments.",
5862
       function );
5863
5864
      goto on_error;
5865
    }
5866
    current_directory_segment_index = current_directory_number_of_segments - 1;
5867
5868
    /* If the path is relative
5869
     * add the size of the current working directory
5870
     * a directory separator, if necessary
5871
     */
5872
    safe_full_path_size = current_directory_length;
5873
5874
    if( ( current_directory_length >= 1 )
5875
     && ( current_directory[ current_directory_length - 1 ] != (wchar_t) '/' ) )
5876
    {
5877
      safe_full_path_size++;
5878
    }
5879
  }
5880
  if( libcsplit_wide_string_split(
5881
       path,
5882
       path_length + 1,
5883
       (wchar_t) '/',
5884
       &path_split_string,
5885
       error ) != 1 )
5886
  {
5887
    libcerror_error_set(
5888
     error,
5889
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
5890
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
5891
     "%s: unable to split path.",
5892
     function );
5893
5894
    goto on_error;
5895
  }
5896
  if( path_split_string != NULL )
5897
  {
5898
    if( libcsplit_wide_split_string_get_number_of_segments(
5899
         path_split_string,
5900
         &path_number_of_segments,
5901
         error ) != 1 )
5902
    {
5903
      libcerror_error_set(
5904
       error,
5905
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
5906
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5907
       "%s: unable to retrieve number of path string segments.",
5908
       function );
5909
5910
      goto on_error;
5911
    }
5912
    for( path_segment_index = 0;
5913
         path_segment_index < path_number_of_segments;
5914
         path_segment_index++ )
5915
    {
5916
      if( libcsplit_wide_split_string_get_segment_by_index(
5917
           path_split_string,
5918
           path_segment_index,
5919
           &path_string_segment,
5920
           &path_string_segment_size,
5921
           error ) != 1 )
5922
      {
5923
        libcerror_error_set(
5924
         error,
5925
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
5926
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5927
         "%s: unable to retrieve path string segment: %d.",
5928
         function,
5929
         path_segment_index );
5930
5931
        goto on_error;
5932
      }
5933
      if( path_string_segment == NULL )
5934
      {
5935
        libcerror_error_set(
5936
         error,
5937
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
5938
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
5939
         "%s: missing path string segment: %d.",
5940
         function,
5941
         path_segment_index );
5942
5943
        goto on_error;
5944
      }
5945
      /* If the path is "" (empty) or "." (current) ignore the entry
5946
       */
5947
      if( ( path_string_segment_size <= 1 )
5948
       || ( ( path_string_segment_size == 2 )
5949
        &&  ( path_string_segment[ 0 ] == (wchar_t) '.' ) ) )
5950
      {
5951
        if( libcsplit_wide_split_string_set_segment_by_index(
5952
             path_split_string,
5953
             path_segment_index,
5954
             NULL,
5955
             0,
5956
             error ) != 1 )
5957
        {
5958
          libcerror_error_set(
5959
           error,
5960
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
5961
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
5962
           "%s: unable to set path string segment: %d.",
5963
           function,
5964
           path_segment_index );
5965
5966
          goto on_error;
5967
        }
5968
      }
5969
      /* If the path is ".." (parent) reverse the current path by one directory
5970
       */
5971
      else if( ( path_string_segment_size == 3 )
5972
            && ( path_string_segment[ 0 ] == (wchar_t) '.' )
5973
            && ( path_string_segment[ 1 ] == (wchar_t) '.' ) )
5974
      {
5975
        if( ( current_directory_split_string != NULL )
5976
         && ( last_used_path_segment_index == -1 ) )
5977
        {
5978
          if( libcsplit_wide_split_string_get_segment_by_index(
5979
               current_directory_split_string,
5980
               current_directory_segment_index,
5981
               &current_directory_string_segment,
5982
               &current_directory_string_segment_size,
5983
               error ) != 1 )
5984
          {
5985
            libcerror_error_set(
5986
             error,
5987
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
5988
             LIBCERROR_RUNTIME_ERROR_GET_FAILED,
5989
             "%s: unable to retrieve current working directory string segment: %d.",
5990
             function,
5991
             current_directory_segment_index );
5992
5993
            goto on_error;
5994
          }
5995
          if( current_directory_string_segment == NULL )
5996
          {
5997
            libcerror_error_set(
5998
             error,
5999
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
6000
             LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
6001
             "%s: missing current working directory string segment: %d.",
6002
             function,
6003
             current_directory_segment_index );
6004
6005
            goto on_error;
6006
          }
6007
          /* Remove the size of the parent directory name and a directory separator
6008
           * Note that the size includes the end of string character
6009
           */
6010
          if( current_directory_string_segment_size < safe_full_path_size )
6011
          {
6012
            safe_full_path_size -= current_directory_string_segment_size;
6013
          }
6014
          else
6015
          {
6016
            safe_full_path_size = 0;
6017
          }
6018
          if( libcsplit_wide_split_string_set_segment_by_index(
6019
               current_directory_split_string,
6020
               current_directory_segment_index,
6021
               NULL,
6022
               0,
6023
               error ) != 1 )
6024
          {
6025
            libcerror_error_set(
6026
             error,
6027
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
6028
             LIBCERROR_RUNTIME_ERROR_SET_FAILED,
6029
             "%s: unable to set current working directory string segment: %d.",
6030
             function,
6031
             current_directory_segment_index );
6032
6033
            goto on_error;
6034
          }
6035
          current_directory_segment_index--;
6036
        }
6037
        else if( last_used_path_segment_index >= 0 )
6038
        {
6039
          if( libcsplit_wide_split_string_get_segment_by_index(
6040
               path_split_string,
6041
               last_used_path_segment_index,
6042
               &last_used_path_string_segment,
6043
               &last_used_path_string_segment_size,
6044
               error ) != 1 )
6045
          {
6046
            libcerror_error_set(
6047
             error,
6048
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
6049
             LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6050
             "%s: unable to retrieve last used path string segment: %d.",
6051
             function,
6052
             last_used_path_segment_index );
6053
6054
            goto on_error;
6055
          }
6056
          if( last_used_path_string_segment == NULL )
6057
          {
6058
            libcerror_error_set(
6059
             error,
6060
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
6061
             LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
6062
             "%s: missing last used path string string segment: %d.",
6063
             function,
6064
             last_used_path_segment_index );
6065
6066
            goto on_error;
6067
          }
6068
          /* Remove the size of the parent directory name and a directory separator
6069
           * Note that the size includes the end of string character
6070
           */
6071
          if( last_used_path_string_segment_size < safe_full_path_size )
6072
          {
6073
            safe_full_path_size -= last_used_path_string_segment_size;
6074
          }
6075
          else
6076
          {
6077
            safe_full_path_size = 0;
6078
          }
6079
          if( libcsplit_wide_split_string_set_segment_by_index(
6080
               path_split_string,
6081
               last_used_path_segment_index,
6082
               NULL,
6083
               0,
6084
               error ) != 1 )
6085
          {
6086
            libcerror_error_set(
6087
             error,
6088
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
6089
             LIBCERROR_RUNTIME_ERROR_SET_FAILED,
6090
             "%s: unable to set path string segment: %d.",
6091
             function,
6092
             last_used_path_segment_index );
6093
6094
            goto on_error;
6095
          }
6096
          /* Find the previous path split value that contains a name
6097
           */
6098
          while( last_used_path_segment_index > 0 )
6099
          {
6100
            last_used_path_segment_index--;
6101
6102
            if( libcsplit_wide_split_string_get_segment_by_index(
6103
                 path_split_string,
6104
                 last_used_path_segment_index,
6105
                 &last_used_path_string_segment,
6106
                 &last_used_path_string_segment_size,
6107
                 error ) != 1 )
6108
            {
6109
              libcerror_error_set(
6110
               error,
6111
               LIBCERROR_ERROR_DOMAIN_RUNTIME,
6112
               LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6113
               "%s: unable to retrieve last used path string segment: %d.",
6114
               function,
6115
               last_used_path_segment_index );
6116
6117
              goto on_error;
6118
            }
6119
            if( last_used_path_string_segment_size != 0 )
6120
            {
6121
              break;
6122
            }
6123
          }
6124
        }
6125
        if( libcsplit_wide_split_string_set_segment_by_index(
6126
             path_split_string,
6127
             path_segment_index,
6128
             NULL,
6129
             0,
6130
             error ) != 1 )
6131
        {
6132
          libcerror_error_set(
6133
           error,
6134
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
6135
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
6136
           "%s: unable to set path string segment: %d.",
6137
           function,
6138
           path_segment_index );
6139
6140
          goto on_error;
6141
        }
6142
      }
6143
      else
6144
      {
6145
        /* Add the size of the directory or file name and a directory separator
6146
         * Note that the size includes the end of string character
6147
         */
6148
        safe_full_path_size += path_string_segment_size;
6149
6150
        last_used_path_segment_index = path_segment_index;
6151
      }
6152
    }
6153
    if( safe_full_path_size > 0 )
6154
    {
6155
      /* Remove the size reserved of the last directory separator
6156
       */
6157
      safe_full_path_size -= 1;
6158
    }
6159
  }
6160
  safe_full_path_size += full_path_prefix_length + 1;
6161
6162
  full_path_index = 0;
6163
6164
  safe_full_path = wide_string_allocate(
6165
                    safe_full_path_size );
6166
6167
  if( safe_full_path == NULL )
6168
  {
6169
    libcerror_error_set(
6170
     error,
6171
     LIBCERROR_ERROR_DOMAIN_MEMORY,
6172
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
6173
     "%s: unable to create full path.",
6174
     function );
6175
6176
    goto on_error;
6177
  }
6178
  if( memory_set(
6179
       safe_full_path,
6180
       0,
6181
       sizeof( wchar_t ) * safe_full_path_size ) == NULL )
6182
  {
6183
    libcerror_error_set(
6184
     error,
6185
     LIBCERROR_ERROR_DOMAIN_MEMORY,
6186
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
6187
     "%s: unable to clear full path.",
6188
     function );
6189
6190
    goto on_error;
6191
  }
6192
  if( path_type == LIBCPATH_TYPE_ABSOLUTE )
6193
  {
6194
    safe_full_path[ full_path_index ] = (wchar_t) '/';
6195
6196
    full_path_index += 1;
6197
  }
6198
  /* If the path is relative
6199
   * add the current working directory elements
6200
   */
6201
  if( current_directory_split_string != NULL )
6202
  {
6203
    for( current_directory_segment_index = 0;
6204
         current_directory_segment_index < current_directory_number_of_segments;
6205
         current_directory_segment_index++ )
6206
    {
6207
      if( libcsplit_wide_split_string_get_segment_by_index(
6208
           current_directory_split_string,
6209
           current_directory_segment_index,
6210
           &current_directory_string_segment,
6211
           &current_directory_string_segment_size,
6212
           error ) != 1 )
6213
      {
6214
        libcerror_error_set(
6215
         error,
6216
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
6217
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6218
         "%s: unable to retrieve current working directory string segment: %d.",
6219
         function,
6220
         current_directory_segment_index );
6221
6222
        goto on_error;
6223
      }
6224
      if( current_directory_string_segment_size != 0 )
6225
      {
6226
        if( current_directory_string_segment == NULL )
6227
        {
6228
          libcerror_error_set(
6229
           error,
6230
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
6231
           LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
6232
           "%s: missing current working directory string segment: %d.",
6233
           function,
6234
           current_directory_segment_index );
6235
6236
          goto on_error;
6237
        }
6238
        /* Note that here we should have room for the segment string and
6239
         * one additional character
6240
         */
6241
        if( current_directory_string_segment_size > ( safe_full_path_size - full_path_index ) )
6242
        {
6243
          libcerror_error_set(
6244
           error,
6245
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
6246
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
6247
           "%s: invalid current working directory string segment: %d size value out of bounds.",
6248
           function,
6249
           current_directory_segment_index );
6250
6251
          goto on_error;
6252
        }
6253
        path_string_segment_length = current_directory_string_segment_size - 1;
6254
6255
        if( wide_string_copy(
6256
             &( safe_full_path[ full_path_index ] ),
6257
             current_directory_string_segment,
6258
             path_string_segment_length ) == NULL )
6259
        {
6260
          libcerror_error_set(
6261
           error,
6262
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
6263
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
6264
           "%s: unable to set current working directory split value: %d in full path.",
6265
           function,
6266
           current_directory_segment_index );
6267
6268
          goto on_error;
6269
        }
6270
        full_path_index += path_string_segment_length;
6271
6272
        safe_full_path[ full_path_index ] = (wchar_t) '/';
6273
6274
        full_path_index += 1;
6275
      }
6276
    }
6277
  }
6278
  if( path_split_string != NULL )
6279
  {
6280
    for( path_segment_index = 0;
6281
         path_segment_index < path_number_of_segments;
6282
         path_segment_index++ )
6283
    {
6284
      if( libcsplit_wide_split_string_get_segment_by_index(
6285
           path_split_string,
6286
           path_segment_index,
6287
           &path_string_segment,
6288
           &path_string_segment_size,
6289
           error ) != 1 )
6290
      {
6291
        libcerror_error_set(
6292
         error,
6293
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
6294
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6295
         "%s: unable to retrieve path string segment: %d.",
6296
         function,
6297
         path_segment_index );
6298
6299
        goto on_error;
6300
      }
6301
      if( path_string_segment_size != 0 )
6302
      {
6303
        if( path_string_segment == NULL )
6304
        {
6305
          libcerror_error_set(
6306
           error,
6307
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
6308
           LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
6309
           "%s: missing path string segment: %d.",
6310
           function,
6311
           path_segment_index );
6312
6313
          goto on_error;
6314
        }
6315
        /* Note that here we should have room for the segment string and
6316
         * one additional character
6317
         */
6318
        if( path_string_segment_size > ( safe_full_path_size - full_path_index ) )
6319
        {
6320
          libcerror_error_set(
6321
           error,
6322
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
6323
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
6324
           "%s: invalid current path string segment: %d size value out of bounds.",
6325
           function,
6326
           path_segment_index );
6327
6328
          goto on_error;
6329
        }
6330
        path_string_segment_length = path_string_segment_size - 1;
6331
6332
        if( wide_string_copy(
6333
             &( safe_full_path[ full_path_index ] ),
6334
             path_string_segment,
6335
             path_string_segment_length ) == NULL )
6336
        {
6337
          libcerror_error_set(
6338
           error,
6339
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
6340
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
6341
           "%s: unable to set path split value: %d in full path.",
6342
           function,
6343
           path_segment_index );
6344
6345
          goto on_error;
6346
        }
6347
        full_path_index += path_string_segment_length;
6348
6349
        safe_full_path[ full_path_index ] = (wchar_t) '/';
6350
6351
        full_path_index += 1;
6352
      }
6353
    }
6354
  }
6355
  safe_full_path[ full_path_index - 1 ] = 0;
6356
6357
  if( path_split_string != NULL )
6358
  {
6359
    if( libcsplit_wide_split_string_free(
6360
         &path_split_string,
6361
         error ) != 1 )
6362
    {
6363
      libcerror_error_set(
6364
       error,
6365
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
6366
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
6367
       "%s: unable to free path split string.",
6368
       function );
6369
6370
      goto on_error;
6371
    }
6372
  }
6373
  if( current_directory_split_string != NULL )
6374
  {
6375
    if( libcsplit_wide_split_string_free(
6376
         &current_directory_split_string,
6377
         error ) != 1 )
6378
    {
6379
      libcerror_error_set(
6380
       error,
6381
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
6382
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
6383
       "%s: unable to free current working directory split string.",
6384
       function );
6385
6386
      goto on_error;
6387
    }
6388
  }
6389
  if( current_directory != NULL )
6390
  {
6391
    memory_free(
6392
     current_directory );
6393
  }
6394
  *full_path      = safe_full_path;
6395
  *full_path_size = safe_full_path_size;
6396
6397
  return( 1 );
6398
6399
on_error:
6400
  if( safe_full_path != NULL )
6401
  {
6402
    memory_free(
6403
     safe_full_path );
6404
  }
6405
  if( path_split_string != NULL )
6406
  {
6407
    libcsplit_wide_split_string_free(
6408
     &path_split_string,
6409
     NULL );
6410
  }
6411
  if( current_directory_split_string != NULL )
6412
  {
6413
    libcsplit_wide_split_string_free(
6414
     &current_directory_split_string,
6415
     NULL );
6416
  }
6417
  if( current_directory != NULL )
6418
  {
6419
    memory_free(
6420
     current_directory );
6421
  }
6422
  return( -1 );
6423
}
6424
6425
#endif /* defined( WINAPI ) */
6426
6427
/* Retrieves the size of a sanitized version of the path character
6428
 * Returns 1 if successful or -1 on error
6429
 */
6430
int libcpath_path_get_sanitized_character_size_wide(
6431
     wchar_t character,
6432
     size_t *sanitized_character_size,
6433
     libcerror_error_t **error )
6434
{
6435
  static char *function = "libcpath_path_get_sanitized_character_size_wide";
6436
6437
  if( sanitized_character_size == NULL )
6438
  {
6439
    libcerror_error_set(
6440
     error,
6441
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6442
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6443
     "%s: invalid sanitized character size.",
6444
     function );
6445
6446
    return( -1 );
6447
  }
6448
  if( ( character >= 0x00 )
6449
   && ( character <= 0x1f ) )
6450
  {
6451
    *sanitized_character_size = 4;
6452
  }
6453
  else if( character == (wchar_t) LIBCPATH_ESCAPE_CHARACTER )
6454
  {
6455
    *sanitized_character_size = 2;
6456
  }
6457
#if defined( WINAPI )
6458
  else if( character == (wchar_t) '/' )
6459
  {
6460
    *sanitized_character_size = 4;
6461
  }
6462
#endif
6463
  else if( ( character == (wchar_t) '!' )
6464
        || ( character == (wchar_t) '$' )
6465
        || ( character == (wchar_t) '%' )
6466
        || ( character == (wchar_t) '&' )
6467
        || ( character == (wchar_t) '*' )
6468
        || ( character == (wchar_t) '+' )
6469
        || ( character == (wchar_t) ':' )
6470
        || ( character == (wchar_t) ';' )
6471
        || ( character == (wchar_t) '<' )
6472
        || ( character == (wchar_t) '>' )
6473
        || ( character == (wchar_t) '?' )
6474
        || ( character == (wchar_t) '|' )
6475
        || ( character == 0x7f ) )
6476
  {
6477
    *sanitized_character_size = 4;
6478
  }
6479
  else
6480
  {
6481
    *sanitized_character_size = 1;
6482
  }
6483
  return( 1 );
6484
}
6485
6486
/* Retrieves a sanitized version of the path character
6487
 * Returns 1 if successful or -1 on error
6488
 */
6489
int libcpath_path_get_sanitized_character_wide(
6490
     wchar_t character,
6491
     size_t sanitized_character_size,
6492
     wchar_t *sanitized_path,
6493
     size_t sanitized_path_size,
6494
     size_t *sanitized_path_index,
6495
     libcerror_error_t **error )
6496
{
6497
  static char *function            = "libcpath_path_get_sanitized_character_wide";
6498
  size_t safe_sanitized_path_index = 0;
6499
  wchar_t lower_nibble             = 0;
6500
  wchar_t upper_nibble             = 0;
6501
6502
  if( ( sanitized_character_size != 1 )
6503
   && ( sanitized_character_size != 2 )
6504
   && ( sanitized_character_size != 4 ) )
6505
  {
6506
    libcerror_error_set(
6507
     error,
6508
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6509
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
6510
     "%s: invalid sanitized character size value out of bounds.",
6511
     function );
6512
6513
    return( -1 );
6514
  }
6515
  if( sanitized_path == NULL )
6516
  {
6517
    libcerror_error_set(
6518
     error,
6519
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6520
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6521
     "%s: invalid sanitized path.",
6522
     function );
6523
6524
    return( -1 );
6525
  }
6526
  if( sanitized_path_size > (size_t) SSIZE_MAX )
6527
  {
6528
    libcerror_error_set(
6529
     error,
6530
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6531
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6532
     "%s: invalid sanitized path size value exceeds maximum.",
6533
     function );
6534
6535
    return( -1 );
6536
  }
6537
  if( sanitized_path_index == NULL )
6538
  {
6539
    libcerror_error_set(
6540
     error,
6541
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6542
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6543
     "%s: invalid sanitized path index.",
6544
     function );
6545
6546
    return( -1 );
6547
  }
6548
  safe_sanitized_path_index = *sanitized_path_index;
6549
6550
  if( safe_sanitized_path_index > sanitized_path_size )
6551
  {
6552
    libcerror_error_set(
6553
     error,
6554
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6555
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
6556
     "%s: invalid sanitized path index value out of bounds.",
6557
     function );
6558
6559
    return( -1 );
6560
  }
6561
  if( ( sanitized_character_size > sanitized_path_size )
6562
   || ( safe_sanitized_path_index > ( sanitized_path_size - sanitized_character_size ) ) )
6563
  {
6564
    libcerror_error_set(
6565
     error,
6566
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6567
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
6568
     "%s: invalid sanitized path size value too small.",
6569
     function );
6570
6571
    return( -1 );
6572
  }
6573
  if( sanitized_character_size == 1 )
6574
  {
6575
    sanitized_path[ safe_sanitized_path_index++ ] = character;
6576
  }
6577
  else if( sanitized_character_size == 2 )
6578
  {
6579
    sanitized_path[ safe_sanitized_path_index++ ] = (wchar_t) LIBCPATH_ESCAPE_CHARACTER;
6580
    sanitized_path[ safe_sanitized_path_index++ ] = (wchar_t) LIBCPATH_ESCAPE_CHARACTER;
6581
  }
6582
  else if( sanitized_character_size == 4 )
6583
  {
6584
    lower_nibble = character & 0x0f;
6585
    upper_nibble = ( character >> 4 ) & 0x0f;
6586
6587
    if( lower_nibble > 10 )
6588
    {
6589
      lower_nibble += (wchar_t) 'a' - 10;
6590
    }
6591
    else
6592
    {
6593
      lower_nibble += '0';
6594
    }
6595
    if( upper_nibble > 10 )
6596
    {
6597
      upper_nibble += (wchar_t) 'a' - 10;
6598
    }
6599
    else
6600
    {
6601
      upper_nibble += '0';
6602
    }
6603
    sanitized_path[ safe_sanitized_path_index++ ] = (wchar_t) LIBCPATH_ESCAPE_CHARACTER;
6604
    sanitized_path[ safe_sanitized_path_index++ ] = (wchar_t) 'x';
6605
    sanitized_path[ safe_sanitized_path_index++ ] = upper_nibble;
6606
    sanitized_path[ safe_sanitized_path_index++ ] = lower_nibble;
6607
  }
6608
  *sanitized_path_index = safe_sanitized_path_index;
6609
6610
  return( 1 );
6611
}
6612
6613
/* Retrieves a sanitized version of the filename
6614
 * Returns 1 if successful or -1 on error
6615
 */
6616
int libcpath_path_get_sanitized_filename_wide(
6617
     const wchar_t *filename,
6618
     size_t filename_length,
6619
     wchar_t **sanitized_filename,
6620
     size_t *sanitized_filename_size,
6621
     libcerror_error_t **error )
6622
{
6623
  static char *function               = "libcpath_path_get_sanitized_filename_wide";
6624
  wchar_t *safe_sanitized_filename    = NULL;
6625
  size_t filename_index               = 0;
6626
  size_t sanitized_character_size     = 0;
6627
  size_t safe_sanitized_filename_size = 0;
6628
  size_t sanitized_filename_index     = 0;
6629
6630
  if( filename == NULL )
6631
  {
6632
    libcerror_error_set(
6633
     error,
6634
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6635
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6636
     "%s: invalid filename.",
6637
     function );
6638
6639
    return( -1 );
6640
  }
6641
  if( ( filename_length == 0 )
6642
   || ( filename_length > (size_t) ( SSIZE_MAX - 1 ) ) )
6643
  {
6644
    libcerror_error_set(
6645
     error,
6646
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6647
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
6648
     "%s: invalid filename length value out of bounds.",
6649
     function );
6650
6651
    return( -1 );
6652
  }
6653
  if( sanitized_filename == NULL )
6654
  {
6655
    libcerror_error_set(
6656
     error,
6657
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6658
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6659
     "%s: invalid sanitized filename.",
6660
     function );
6661
6662
    return( -1 );
6663
  }
6664
  if( *sanitized_filename != NULL )
6665
  {
6666
    libcerror_error_set(
6667
     error,
6668
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
6669
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
6670
     "%s: invalid sanitized filename value already set.",
6671
     function );
6672
6673
    return( -1 );
6674
  }
6675
  if( sanitized_filename_size == NULL )
6676
  {
6677
    libcerror_error_set(
6678
     error,
6679
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6680
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6681
     "%s: invalid sanitized filename size.",
6682
     function );
6683
6684
    return( -1 );
6685
  }
6686
  safe_sanitized_filename_size = 1;
6687
6688
  for( filename_index = 0;
6689
       filename_index < filename_length;
6690
       filename_index++ )
6691
  {
6692
    if( filename[ filename_index ] == LIBCPATH_SEPARATOR )
6693
    {
6694
      sanitized_character_size = 4;
6695
    }
6696
    else if( libcpath_path_get_sanitized_character_size_wide(
6697
              filename[ filename_index ],
6698
              &sanitized_character_size,
6699
              error ) != 1 )
6700
    {
6701
      libcerror_error_set(
6702
       error,
6703
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
6704
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6705
       "%s: unable to determine sanitize character size.",
6706
       function );
6707
6708
      goto on_error;
6709
    }
6710
    safe_sanitized_filename_size += sanitized_character_size;
6711
  }
6712
  if( safe_sanitized_filename_size > (size_t) SSIZE_MAX )
6713
  {
6714
    libcerror_error_set(
6715
     error,
6716
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6717
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6718
     "%s: invalid sanitized filename size value exceeds maximum.",
6719
     function );
6720
6721
    goto on_error;
6722
  }
6723
  safe_sanitized_filename = wide_string_allocate(
6724
                             safe_sanitized_filename_size );
6725
6726
  if( safe_sanitized_filename == NULL )
6727
  {
6728
    libcerror_error_set(
6729
     error,
6730
     LIBCERROR_ERROR_DOMAIN_MEMORY,
6731
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
6732
     "%s: unable to create sanitized filename.",
6733
     function );
6734
6735
    goto on_error;
6736
  }
6737
  for( filename_index = 0;
6738
       filename_index < filename_length;
6739
       filename_index++ )
6740
  {
6741
    if( filename[ filename_index ] == LIBCPATH_SEPARATOR )
6742
    {
6743
      sanitized_character_size = 4;
6744
    }
6745
    else if( libcpath_path_get_sanitized_character_size_wide(
6746
              filename[ filename_index ],
6747
              &sanitized_character_size,
6748
              error ) != 1 )
6749
    {
6750
      libcerror_error_set(
6751
       error,
6752
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
6753
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6754
       "%s: unable to determine sanitize character size.",
6755
       function );
6756
6757
      goto on_error;
6758
    }
6759
    if( libcpath_path_get_sanitized_character_wide(
6760
         filename[ filename_index ],
6761
         sanitized_character_size,
6762
         safe_sanitized_filename,
6763
         safe_sanitized_filename_size,
6764
         &sanitized_filename_index,
6765
         error ) != 1 )
6766
    {
6767
      libcerror_error_set(
6768
       error,
6769
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
6770
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6771
       "%s: unable to determine sanitize character size.",
6772
       function );
6773
6774
      goto on_error;
6775
    }
6776
  }
6777
  safe_sanitized_filename[ sanitized_filename_index ] = 0;
6778
6779
  *sanitized_filename      = safe_sanitized_filename;
6780
  *sanitized_filename_size = safe_sanitized_filename_size;
6781
6782
  return( 1 );
6783
6784
on_error:
6785
  if( safe_sanitized_filename != NULL )
6786
  {
6787
    memory_free(
6788
     safe_sanitized_filename );
6789
  }
6790
  return( -1 );
6791
}
6792
6793
/* Retrieves a sanitized version of the path
6794
 * Returns 1 if successful or -1 on error
6795
 */
6796
int libcpath_path_get_sanitized_path_wide(
6797
     const wchar_t *path,
6798
     size_t path_length,
6799
     wchar_t **sanitized_path,
6800
     size_t *sanitized_path_size,
6801
     libcerror_error_t **error )
6802
{
6803
  static char *function                    = "libcpath_path_get_sanitized_path_wide";
6804
  wchar_t *safe_sanitized_path             = NULL;
6805
  size_t path_index                        = 0;
6806
  size_t safe_sanitized_path_size          = 0;
6807
  size_t sanitized_character_size          = 0;
6808
  size_t sanitized_path_index              = 0;
6809
6810
#if defined( WINAPI )
6811
  size_t last_path_segment_seperator_index = 0;
6812
#endif
6813
6814
  if( path == NULL )
6815
  {
6816
    libcerror_error_set(
6817
     error,
6818
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6819
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6820
     "%s: invalid path.",
6821
     function );
6822
6823
    return( -1 );
6824
  }
6825
  if( ( path_length == 0 )
6826
   || ( path_length > (size_t) ( SSIZE_MAX - 1 ) ) )
6827
  {
6828
    libcerror_error_set(
6829
     error,
6830
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6831
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
6832
     "%s: invalid path length value out of bounds.",
6833
     function );
6834
6835
    return( -1 );
6836
  }
6837
  if( sanitized_path == NULL )
6838
  {
6839
    libcerror_error_set(
6840
     error,
6841
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6842
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6843
     "%s: invalid sanitized path.",
6844
     function );
6845
6846
    return( -1 );
6847
  }
6848
  if( *sanitized_path != NULL )
6849
  {
6850
    libcerror_error_set(
6851
     error,
6852
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
6853
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
6854
     "%s: invalid sanitized path value already set.",
6855
     function );
6856
6857
    return( -1 );
6858
  }
6859
  if( sanitized_path_size == NULL )
6860
  {
6861
    libcerror_error_set(
6862
     error,
6863
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6864
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
6865
     "%s: invalid sanitized path size.",
6866
     function );
6867
6868
    return( -1 );
6869
  }
6870
  safe_sanitized_path_size = 1;
6871
6872
  for( path_index = 0;
6873
       path_index < path_length;
6874
       path_index++ )
6875
  {
6876
    if( libcpath_path_get_sanitized_character_size_wide(
6877
         path[ path_index ],
6878
         &sanitized_character_size,
6879
         error ) != 1 )
6880
    {
6881
      libcerror_error_set(
6882
       error,
6883
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
6884
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6885
       "%s: unable to determine sanitize character size.",
6886
       function );
6887
6888
      goto on_error;
6889
    }
6890
    safe_sanitized_path_size += sanitized_character_size;
6891
6892
#if defined( WINAPI )
6893
    if( path[ path_index ] == LIBCPATH_SEPARATOR )
6894
    {
6895
      last_path_segment_seperator_index = path_index;
6896
    }
6897
#endif
6898
  }
6899
  if( safe_sanitized_path_size > (size_t) SSIZE_MAX )
6900
  {
6901
    libcerror_error_set(
6902
     error,
6903
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
6904
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
6905
     "%s: invalid sanitized path size value exceeds maximum.",
6906
     function );
6907
6908
    goto on_error;
6909
  }
6910
#if defined( WINAPI )
6911
  if( last_path_segment_seperator_index > 32767 )
6912
  {
6913
    libcerror_error_set(
6914
     error,
6915
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
6916
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
6917
     "%s: invalid last path segment separator value out of bounds.",
6918
     function );
6919
6920
    goto on_error;
6921
  }
6922
  if( safe_sanitized_path_size > 32767 )
6923
  {
6924
    safe_sanitized_path_size = 32767;
6925
  }
6926
#endif
6927
  safe_sanitized_path = wide_string_allocate(
6928
                         safe_sanitized_path_size );
6929
6930
  if( safe_sanitized_path == NULL )
6931
  {
6932
    libcerror_error_set(
6933
     error,
6934
     LIBCERROR_ERROR_DOMAIN_MEMORY,
6935
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
6936
     "%s: unable to create sanitized path.",
6937
     function );
6938
6939
    goto on_error;
6940
  }
6941
  for( path_index = 0;
6942
       path_index < path_length;
6943
       path_index++ )
6944
  {
6945
    if( libcpath_path_get_sanitized_character_size_wide(
6946
         path[ path_index ],
6947
         &sanitized_character_size,
6948
         error ) != 1 )
6949
    {
6950
      libcerror_error_set(
6951
       error,
6952
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
6953
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6954
       "%s: unable to determine sanitize character size.",
6955
       function );
6956
6957
      goto on_error;
6958
    }
6959
    if( libcpath_path_get_sanitized_character_wide(
6960
         path[ path_index ],
6961
         sanitized_character_size,
6962
         safe_sanitized_path,
6963
         safe_sanitized_path_size,
6964
         &sanitized_path_index,
6965
         error ) != 1 )
6966
    {
6967
      libcerror_error_set(
6968
       error,
6969
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
6970
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
6971
       "%s: unable to determine sanitize character size.",
6972
       function );
6973
6974
      goto on_error;
6975
    }
6976
  }
6977
  if( sanitized_path_index >= safe_sanitized_path_size )
6978
  {
6979
    libcerror_error_set(
6980
     error,
6981
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
6982
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
6983
     "%s: invalid sanitized path index value out of bounds.",
6984
     function );
6985
6986
    goto on_error;
6987
  }
6988
  safe_sanitized_path[ sanitized_path_index ] = 0;
6989
6990
  *sanitized_path      = safe_sanitized_path;
6991
  *sanitized_path_size = safe_sanitized_path_size;
6992
6993
  return( 1 );
6994
6995
on_error:
6996
  if( safe_sanitized_path != NULL )
6997
  {
6998
    memory_free(
6999
     safe_sanitized_path );
7000
  }
7001
  return( -1 );
7002
}
7003
7004
/* Combines the directory name and filename into a path
7005
 * Returns 1 if successful or -1 on error
7006
 */
7007
int libcpath_path_join_wide(
7008
     wchar_t **path,
7009
     size_t *path_size,
7010
     const wchar_t *directory_name,
7011
     size_t directory_name_length,
7012
     const wchar_t *filename,
7013
     size_t filename_length,
7014
     libcerror_error_t **error )
7015
{
7016
  static char *function = "libcpath_path_join_wide";
7017
  size_t filename_index = 0;
7018
  size_t path_index     = 0;
7019
7020
  if( path == NULL )
7021
  {
7022
    libcerror_error_set(
7023
     error,
7024
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7025
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
7026
     "%s: invalid path.",
7027
     function );
7028
7029
    return( -1 );
7030
  }
7031
  if( *path != NULL )
7032
  {
7033
    libcerror_error_set(
7034
     error,
7035
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
7036
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
7037
     "%s: invalid path value already set.",
7038
     function );
7039
7040
    return( -1 );
7041
  }
7042
  if( path_size == NULL )
7043
  {
7044
    libcerror_error_set(
7045
     error,
7046
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7047
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
7048
     "%s: invalid path size.",
7049
     function );
7050
7051
    return( -1 );
7052
  }
7053
  if( directory_name == NULL )
7054
  {
7055
    libcerror_error_set(
7056
     error,
7057
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7058
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
7059
     "%s: invalid directory name.",
7060
     function );
7061
7062
    return( -1 );
7063
  }
7064
  if( directory_name_length > (size_t) SSIZE_MAX )
7065
  {
7066
    libcerror_error_set(
7067
     error,
7068
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7069
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
7070
     "%s: invalid directory name length value exceeds maximum.",
7071
     function );
7072
7073
    return( -1 );
7074
  }
7075
  if( filename == NULL )
7076
  {
7077
    libcerror_error_set(
7078
     error,
7079
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7080
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
7081
     "%s: invalid filename.",
7082
     function );
7083
7084
    return( -1 );
7085
  }
7086
  if( filename_length > (size_t) SSIZE_MAX )
7087
  {
7088
    libcerror_error_set(
7089
     error,
7090
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7091
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
7092
     "%s: invalid filename length value exceeds maximum.",
7093
     function );
7094
7095
    return( -1 );
7096
  }
7097
/* TODO strip other patterns like /./ */
7098
  while( directory_name_length > 0 )
7099
  {
7100
    if( directory_name[ directory_name_length - 1 ] != (wchar_t) LIBCPATH_SEPARATOR )
7101
    {
7102
      break;
7103
    }
7104
    directory_name_length--;
7105
  }
7106
  while( filename_length > 0 )
7107
  {
7108
    if( filename[ filename_index ] != (wchar_t) LIBCPATH_SEPARATOR )
7109
    {
7110
      break;
7111
    }
7112
    filename_index++;
7113
    filename_length--;
7114
  }
7115
  *path_size = directory_name_length + filename_length + 2;
7116
7117
  *path = wide_string_allocate(
7118
           *path_size );
7119
7120
  if( *path == NULL )
7121
  {
7122
    libcerror_error_set(
7123
     error,
7124
     LIBCERROR_ERROR_DOMAIN_MEMORY,
7125
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
7126
     "%s: unable to create path.",
7127
     function );
7128
7129
    goto on_error;
7130
  }
7131
  if( wide_string_copy(
7132
       *path,
7133
       directory_name,
7134
       directory_name_length ) == NULL )
7135
  {
7136
    libcerror_error_set(
7137
     error,
7138
     LIBCERROR_ERROR_DOMAIN_MEMORY,
7139
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
7140
     "%s: unable to copy directory name to path.",
7141
     function );
7142
7143
    goto on_error;
7144
  }
7145
  path_index = directory_name_length;
7146
7147
  ( *path )[ path_index++ ] = (wchar_t) LIBCPATH_SEPARATOR;
7148
7149
  if( wide_string_copy(
7150
       &( ( *path )[ path_index ] ),
7151
       &( filename[ filename_index ] ),
7152
       filename_length ) == NULL )
7153
  {
7154
    libcerror_error_set(
7155
     error,
7156
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
7157
     LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
7158
     "%s: unable to copy filename to path.",
7159
     function );
7160
7161
    goto on_error;
7162
  }
7163
  path_index += filename_length;
7164
7165
  ( *path )[ path_index ] = 0;
7166
7167
  return( 1 );
7168
7169
on_error:
7170
  if( *path != NULL )
7171
  {
7172
    memory_free(
7173
     *path );
7174
7175
    *path = NULL;
7176
  }
7177
  *path_size = 0;
7178
7179
  return( -1 );
7180
}
7181
7182
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
7183
7184
/* Cross Windows safe version of CreateDirectoryW
7185
 * Returns TRUE if successful or FALSE on error
7186
 */
7187
BOOL libcpath_CreateDirectoryW(
7188
      LPCWSTR path,
7189
      SECURITY_ATTRIBUTES *security_attributes )
7190
{
7191
  FARPROC function       = NULL;
7192
  HMODULE library_handle = NULL;
7193
  BOOL result            = FALSE;
7194
7195
  if( path == NULL )
7196
  {
7197
    return( 0 );
7198
  }
7199
  library_handle = LoadLibrary(
7200
                    _SYSTEM_STRING( "kernel32.dll" ) );
7201
7202
  if( library_handle == NULL )
7203
  {
7204
    return( 0 );
7205
  }
7206
  function = GetProcAddress(
7207
        library_handle,
7208
        (LPCSTR) "CreateDirectoryW" );
7209
7210
  if( function != NULL )
7211
  {
7212
    result = function(
7213
        path,
7214
        security_attributes );
7215
  }
7216
  /* This call should be after using the function
7217
   * in most cases kernel32.dll will still be available after free
7218
   */
7219
  if( FreeLibrary(
7220
       library_handle ) != TRUE )
7221
  {
7222
    libcpath_CloseHandle(
7223
     library_handle );
7224
7225
    return( 0 );
7226
  }
7227
  return( result );
7228
}
7229
7230
#endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
7231
7232
#if defined( WINAPI )
7233
7234
/* Makes the directory
7235
 * This function uses the WINAPI function for Windows XP (0x0501) or later
7236
 * or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
7237
 * Returns 1 if successful or -1 on error
7238
 */
7239
int libcpath_path_make_directory_wide(
7240
     const wchar_t *directory_name,
7241
     libcerror_error_t **error )
7242
{
7243
  static char *function = "libcpath_path_make_directory_wide";
7244
  DWORD error_code      = 0;
7245
7246
  if( directory_name == NULL )
7247
  {
7248
    libcerror_error_set(
7249
     error,
7250
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7251
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
7252
     "%s: invalid directory name.",
7253
     function );
7254
7255
    return( -1 );
7256
  }
7257
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
7258
  if( libcpath_CreateDirectoryW(
7259
       directory_name,
7260
       NULL ) == 0 )
7261
#else
7262
  if( CreateDirectoryW(
7263
       directory_name,
7264
       NULL ) == 0 )
7265
#endif
7266
  {
7267
    error_code = GetLastError();
7268
7269
    libcerror_system_set_error(
7270
     error,
7271
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
7272
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
7273
     error_code,
7274
     "%s: unable to make directory.",
7275
     function );
7276
7277
    return( -1 );
7278
  }
7279
  return( 1 );
7280
}
7281
7282
#elif defined( HAVE_MKDIR )
7283
7284
/* Makes the directory
7285
 * This function uses the POSIX mkdir function or equivalent
7286
 * Returns 1 if successful or -1 on error
7287
 */
7288
int libcpath_path_make_directory_wide(
7289
     const wchar_t *directory_name,
7290
     libcerror_error_t **error )
7291
{
7292
  static char *function             = "libcpath_path_make_directory_wide";
7293
  char *narrow_directory_name       = 0;
7294
  size_t directory_name_length      = 0;
7295
  size_t narrow_directory_name_size = 0;
7296
7297
  if( directory_name == NULL )
7298
  {
7299
    libcerror_error_set(
7300
     error,
7301
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
7302
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
7303
     "%s: invalid directory name.",
7304
     function );
7305
7306
    return( -1 );
7307
  }
7308
  directory_name_length = wide_string_length(
7309
                           directory_name );
7310
7311
  if( libcpath_system_string_size_from_wide_string(
7312
       directory_name,
7313
       directory_name_length + 1,
7314
       &narrow_directory_name_size,
7315
       error ) != 1 )
7316
  {
7317
    libcerror_error_set(
7318
     error,
7319
     LIBCERROR_ERROR_DOMAIN_CONVERSION,
7320
     LIBCERROR_CONVERSION_ERROR_GENERIC,
7321
     "%s: unable to determine narrow directory name size.",
7322
     function );
7323
7324
    goto on_error;
7325
  }
7326
  if( ( narrow_directory_name_size > (size_t) SSIZE_MAX )
7327
   || ( ( sizeof( char ) * narrow_directory_name_size )  > (size_t) SSIZE_MAX ) )
7328
  {
7329
    libcerror_error_set(
7330
     error,
7331
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
7332
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
7333
     "%s: invalid narrow directory name size value exceeds maximum.",
7334
     function );
7335
7336
    goto on_error;
7337
  }
7338
  narrow_directory_name = narrow_string_allocate(
7339
                           narrow_directory_name_size );
7340
7341
  if( narrow_directory_name == NULL )
7342
  {
7343
    libcerror_error_set(
7344
     error,
7345
     LIBCERROR_ERROR_DOMAIN_MEMORY,
7346
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
7347
     "%s: unable to create narrow directory name.",
7348
     function );
7349
7350
    goto on_error;
7351
  }
7352
  if( libcpath_system_string_copy_from_wide_string(
7353
       narrow_directory_name,
7354
       narrow_directory_name_size,
7355
       directory_name,
7356
       directory_name_length + 1,
7357
       error ) != 1 )
7358
  {
7359
    libcerror_error_set(
7360
     error,
7361
     LIBCERROR_ERROR_DOMAIN_CONVERSION,
7362
     LIBCERROR_CONVERSION_ERROR_GENERIC,
7363
     "%s: unable to set name.",
7364
     function );
7365
7366
    goto on_error;
7367
  }
7368
#if defined( __MINGW32__ ) || defined( _MSC_VER )
7369
  if( mkdir(
7370
       narrow_directory_name ) != 0 )
7371
#else
7372
  if( mkdir(
7373
       narrow_directory_name,
7374
       0755 ) != 0 )
7375
#endif
7376
  {
7377
    libcerror_system_set_error(
7378
     error,
7379
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
7380
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
7381
     errno,
7382
     "%s: unable to make directory.",
7383
     function );
7384
7385
    goto on_error;
7386
  }
7387
  memory_free(
7388
   narrow_directory_name );
7389
7390
  return( 1 );
7391
7392
on_error:
7393
  if( narrow_directory_name != NULL )
7394
  {
7395
    memory_free(
7396
     narrow_directory_name );
7397
  }
7398
  return( -1 );
7399
}
7400
7401
#else
7402
#error Missing make directory function
7403
#endif
7404
7405
#endif /* defined( HAVE_WIDE_CHARACTER_TYPE ) */
7406