Coverage Report

Created: 2024-02-25 07:19

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