Coverage Report

Created: 2026-01-20 07:11

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