summaryrefslogtreecommitdiffstats
path: root/include/iprt/path.h
blob: 3a41b991ba10f4f36cf90236834ca2b99b8dd001 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
/** @file
 * IPRT - Path Manipulation.
 */

/*
 * Copyright (C) 2006-2019 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
 * VirtualBox OSE distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 */

#ifndef IPRT_INCLUDED_path_h
#define IPRT_INCLUDED_path_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <iprt/cdefs.h>
#include <iprt/types.h>
#ifdef IN_RING3
# include <iprt/fs.h>
#endif



RT_C_DECLS_BEGIN

/** @defgroup grp_rt_path   RTPath - Path Manipulation
 * @ingroup grp_rt
 * @{
 */

/**
 * Host max path (the reasonable value).
 * @remarks defined both by iprt/param.h and iprt/path.h.
 */
#if !defined(IPRT_INCLUDED_param_h) || defined(DOXYGEN_RUNNING)
# define RTPATH_MAX         (4096 + 4)    /* (PATH_MAX + 1) on linux w/ some alignment */
#endif

/** @def RTPATH_TAG
 * The default allocation tag used by the RTPath allocation APIs.
 *
 * When not defined before the inclusion of iprt/string.h, this will default to
 * the pointer to the current file name.  The string API will make of use of
 * this as pointer to a volatile but read-only string.
 */
#ifndef RTPATH_TAG
# define RTPATH_TAG     (__FILE__)
#endif


/** @name RTPATH_F_XXX - Generic flags for APIs working on the file system.
 * @{ */
/** Last component: Work on the link. */
#define RTPATH_F_ON_LINK            RT_BIT_32(0)
/** Last component: Follow if link. */
#define RTPATH_F_FOLLOW_LINK        RT_BIT_32(1)
/** Don't allow symbolic links as part of the path.
 * @remarks this flag is currently not implemented and will be ignored. */
#define RTPATH_F_NO_SYMLINKS        RT_BIT_32(2)
/** Current RTPATH_F_XXX flag mask. */
#define RTPATH_F_MASK               UINT32_C(0x00000007)
/** @} */

/** Validates a flags parameter containing RTPATH_F_*.
 * @remarks The parameters will be referenced multiple times. */
#define RTPATH_F_IS_VALID(a_fFlags, a_fIgnore) \
    (    ((a_fFlags) & ~(uint32_t)((a_fIgnore) | RTPATH_F_NO_SYMLINKS)) == RTPATH_F_ON_LINK \
      || ((a_fFlags) & ~(uint32_t)((a_fIgnore) | RTPATH_F_NO_SYMLINKS)) == RTPATH_F_FOLLOW_LINK )


/** @name RTPATH_STR_F_XXX - Generic flags for APIs working with path strings.
 * @{
 */
/** Host OS path style (default 0 value). */
#define RTPATH_STR_F_STYLE_HOST         UINT32_C(0x00000000)
/** DOS, OS/2 and Windows path style. */
#define RTPATH_STR_F_STYLE_DOS          UINT32_C(0x00000001)
/** Unix path style. */
#define RTPATH_STR_F_STYLE_UNIX         UINT32_C(0x00000002)
/** Reserved path style. */
#define RTPATH_STR_F_STYLE_RESERVED     UINT32_C(0x00000003)
/** The path style mask. */
#define RTPATH_STR_F_STYLE_MASK         UINT32_C(0x00000003)
/** Partial path - no start.
 * This causes the API to skip the root specification parsing.  */
#define RTPATH_STR_F_NO_START           UINT32_C(0x00000010)
/** Partial path - no end.
 * This causes the API to skip the filename and dir-slash parsing.  */
#define RTPATH_STR_F_NO_END             UINT32_C(0x00000020)
/** Partial path - no start and no end. */
#define RTPATH_STR_F_MIDDLE             (RTPATH_STR_F_NO_START | RTPATH_STR_F_NO_END)

/** Reserved for future use. */
#define RTPATH_STR_F_RESERVED_MASK      UINT32_C(0x0000ffcc)
/** @} */

/** Validates a flags parameter containing RTPATH_FSTR_.
 * @remarks The parameters will be references multiple times.  */
#define RTPATH_STR_F_IS_VALID(a_fFlags, a_fIgnore) \
      (   ((a_fFlags) & ~((uint32_t)(a_fIgnore) | RTPATH_STR_F_STYLE_MASK | RTPATH_STR_F_MIDDLE)) == 0 \
       && ((a_fFlags) & RTPATH_STR_F_STYLE_MASK) != RTPATH_STR_F_STYLE_RESERVED \
       && ((a_fFlags) & RTPATH_STR_F_RESERVED_MASK) == 0 )


/** @def RTPATH_STYLE
 * The host path style. This is set to RTPATH_STR_F_STYLE_DOS,
 * RTPATH_STR_F_STYLE_UNIX, or other future styles. */
#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
# define RTPATH_STYLE       RTPATH_STR_F_STYLE_DOS
#else
# define RTPATH_STYLE       RTPATH_STR_F_STYLE_UNIX
#endif


/** @def RTPATH_SLASH
 * The preferred slash character.
 *
 * @remark IPRT will always accept unix slashes. So, normally you would
 *         never have to use this define.
 */
#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
# define RTPATH_SLASH       '\\'
#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX
# define RTPATH_SLASH       '/'
#else
# error "Unsupported RTPATH_STYLE value."
#endif

/** @deprecated Use '/'! */
#define RTPATH_DELIMITER    RTPATH_SLASH


/** @def RTPATH_SLASH_STR
 * The preferred slash character as a string, handy for concatenations
 * with other strings.
 *
 * @remark IPRT will always accept unix slashes. So, normally you would
 *         never have to use this define.
 */
#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
# define RTPATH_SLASH_STR   "\\"
#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX
# define RTPATH_SLASH_STR   "/"
#else
# error "Unsupported RTPATH_STYLE value."
#endif


/** @def RTPATH_IS_SLASH
 * Checks if a character is a slash.
 *
 * @returns true if it's a slash and false if not.
 * @returns @param      a_ch    Char to check.
 */
#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
# define RTPATH_IS_SLASH(a_ch)      ( (a_ch) == '\\' || (a_ch) == '/' )
#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX
# define RTPATH_IS_SLASH(a_ch)      ( (a_ch) == '/' )
#else
# error "Unsupported RTPATH_STYLE value."
#endif


/** @def RTPATH_IS_VOLSEP
 * Checks if a character marks the end of the volume specification.
 *
 * @remark  This is sufficient for the drive letter concept on PC.
 *          However it might be insufficient on other platforms
 *          and even on PC a UNC volume spec won't be detected this way.
 *          Use the RTPath@<too be created@>() instead.
 *
 * @returns true if it is and false if it isn't.
 * @returns @param      a_ch    Char to check.
 */
#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
# define RTPATH_IS_VOLSEP(a_ch)   ( (a_ch) == ':' )
#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX
# define RTPATH_IS_VOLSEP(a_ch)   (false)
#else
# error "Unsupported RTPATH_STYLE value."
#endif


/** @def RTPATH_IS_SEP
 * Checks if a character is path component separator
 *
 * @returns true if it is and false if it isn't.
 * @returns @param      a_ch    Char to check.
 * @
 */
#define RTPATH_IS_SEP(a_ch)     ( RTPATH_IS_SLASH(a_ch) || RTPATH_IS_VOLSEP(a_ch) )

#if defined(RT_OS_WINDOWS) || defined(DOXYGEN_RUNNING)
/** @def RTPATH_NT_PASSTHRU_PREFIX
 * Prefix used to access the NT namespace directly.
 * This forms an invalid UNC name. */
# define RTPATH_NT_PASSTHRU_PREFIX      "\\\\:iprtnt:\\"
#endif

/**
 * Checks if the path exists.
 *
 * Symbolic links will all be attempted resolved and broken links means false.
 *
 * @returns true if it exists and false if it doesn't.
 * @param   pszPath     The path to check.
 */
RTDECL(bool) RTPathExists(const char *pszPath);

/**
 * Checks if the path exists.
 *
 * @returns true if it exists and false if it doesn't.
 * @param   pszPath     The path to check.
 * @param   fFlags      RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK.
 */
RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags);

/**
 * Sets the current working directory of the process.
 *
 * @returns IPRT status code.
 * @param   pszPath         The path to the new working directory.
 */
RTDECL(int)  RTPathSetCurrent(const char *pszPath);

/**
 * Gets the current working directory of the process.
 *
 * @returns IPRT status code.
 * @param   pszPath         Where to store the path.
 * @param   cchPath         The size of the buffer pszPath points to.
 */
RTDECL(int)  RTPathGetCurrent(char *pszPath, size_t cchPath);

/**
 * Gets the current working directory on the specified drive.
 *
 * On systems without drive letters, the root slash will be returned.
 *
 * @returns IPRT status code.
 * @param   chDrive         The drive we're querying the driver letter on.
 * @param   pszPath         Where to store the working directroy path.
 * @param   cbPath          The size of the buffer pszPath points to.
 */
RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath);

/**
 * Gets the current working drive of the process.
 *
 * Normally drive letter and colon will be returned, never trailing a root
 * slash.  If the current directory is on a UNC share, the root of the share
 * will be returned.  On systems without drive letters, an empty string is
 * returned for consistency.
 *
 * @returns IPRT status code.
 * @param   pszPath         Where to store the working drive or UNC root.
 * @param   cbPath          The size of the buffer pszPath points to.
 */
RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath);

/**
 * Get the real path (no symlinks, no . or .. components), must exist.
 *
 * @returns iprt status code.
 * @param   pszPath         The path to resolve.
 * @param   pszRealPath     Where to store the real path.
 * @param   cchRealPath     Size of the buffer.
 */
RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath);

/**
 * Same as RTPathReal only the result is RTStrDup()'ed.
 *
 * @returns Pointer to real path. Use RTStrFree() to free this string.
 * @returns NULL if RTPathReal() or RTStrDup() fails.
 * @param   pszPath         The path to resolve.
 */
RTDECL(char *) RTPathRealDup(const char *pszPath);

/**
 * Get the absolute path (starts from root, no . or .. components), doesn't have
 * to exist.
 *
 * Note that this method is designed to never perform actual file system access,
 * therefore symlinks are not resolved.
 *
 * @returns iprt status code.
 * @param   pszPath         The path to resolve.
 * @param   pszAbsPath      Where to store the absolute path.
 * @param   cchAbsPath      Size of the buffer.
 *
 * @note    Current implementation is buggy and will remove trailing slashes
 *          that would normally specify a directory.  Don't depend on this.
 */
RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath);

/**
 * Same as RTPathAbs only the result is RTStrDup()'ed.
 *
 * @returns Pointer to the absolute path. Use RTStrFree() to free this string.
 * @returns NULL if RTPathAbs() or RTStrDup() fails.
 * @param   pszPath         The path to resolve.
 *
 * @note    Current implementation is buggy and will remove trailing slashes
 *          that would normally specify a directory.  Don't depend on this.
 */
RTDECL(char *) RTPathAbsDup(const char *pszPath);

/**
 * Get the absolute path (no symlinks, no . or .. components), assuming the
 * given base path as the current directory. The resulting path doesn't have
 * to exist.
 *
 * @returns iprt status code.
 * @param   pszBase         The base path to act like a current directory.
 *                          When NULL, the actual cwd is used (i.e. the call
 *                          is equivalent to RTPathAbs(pszPath, ...).
 * @param   pszPath         The path to resolve.
 * @param   pszAbsPath      Where to store the absolute path.
 * @param   cchAbsPath      Size of the buffer.
 *
 * @note    Current implementation is buggy and will remove trailing slashes
 *          that would normally specify a directory.  Don't depend on this.
 */
RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, char *pszAbsPath, size_t cchAbsPath);

/**
 * Same as RTPathAbsEx only the result is RTStrDup()'ed.
 *
 * @returns Pointer to the absolute path. Use RTStrFree() to free this string.
 * @returns NULL if RTPathAbsEx() or RTStrDup() fails.
 * @param   pszBase         The base path to act like a current directory.
 *                          When NULL, the actual cwd is used (i.e. the call
 *                          is equivalent to RTPathAbs(pszPath, ...).
 * @param   pszPath         The path to resolve.
 *
 * @note    Current implementation is buggy and will remove trailing slashes
 *          that would normally specify a directory.  Don't depend on this.
 */
RTDECL(char *) RTPathAbsExDup(const char *pszBase, const char *pszPath);

/**
 * Strips the filename from a path. Truncates the given string in-place by overwriting the
 * last path separator character with a null byte in a platform-neutral way.
 *
 * @param   pszPath     Path from which filename should be extracted, will be truncated.
 *                      If the string contains no path separator, it will be changed to a "." string.
 */
RTDECL(void) RTPathStripFilename(char *pszPath);

/**
 * Strips the last suffix from a path.
 *
 * @param   pszPath     Path which suffix should be stripped.
 */
RTDECL(void) RTPathStripSuffix(char *pszPath);

/**
 * Strips the trailing slashes of a path name.
 *
 * Won't strip root slashes.
 *
 * @returns The new length of pszPath.
 * @param   pszPath     Path to strip.
 */
RTDECL(size_t) RTPathStripTrailingSlash(char *pszPath);

/**
 * Skips the root specification, if present.
 *
 * @return  Pointer to the first char after the root specification.  This can be
 *          pointing to the terminator, if the path is only a root
 *          specification.
 * @param   pszPath     The path to skip ahead in.
 */
RTDECL(char *) RTPathSkipRootSpec(const char *pszPath);

/**
 * Ensures that the path has a trailing path separator such that file names can
 * be appended without further work.
 *
 * This can be helpful when preparing for efficiently combining a directory path
 * with the filenames returned by RTDirRead.  The return value gives you the
 * position at which you copy the RTDIRENTRY::szName to construct a valid path
 * to it.
 *
 * @returns The length of the path, 0 on buffer overflow.
 * @param   pszPath     The path.
 * @param   cbPath      The length of the path buffer @a pszPath points to.
 */
RTDECL(size_t) RTPathEnsureTrailingSeparator(char *pszPath, size_t cbPath);

/**
 * Changes all the slashes in the specified path to DOS style.
 *
 * Unless @a fForce is set, nothing will be done when on a UNIX flavored system
 * since paths wont work with DOS style slashes there.
 *
 * @returns @a pszPath.
 * @param   pszPath             The path to modify.
 * @param   fForce              Whether to force the conversion on non-DOS OSes.
 */
RTDECL(char *) RTPathChangeToDosSlashes(char *pszPath, bool fForce);

/**
 * Changes all the slashes in the specified path to unix style.
 *
 * Unless @a fForce is set, nothing will be done when on a UNIX flavored system
 * since paths wont work with DOS style slashes there.
 *
 * @returns @a pszPath.
 * @param   pszPath             The path to modify.
 * @param   fForce              Whether to force the conversion on non-DOS OSes.
 */
RTDECL(char *) RTPathChangeToUnixSlashes(char *pszPath, bool fForce);

/**
 * Simple parsing of the a path.
 *
 * It figures the length of the directory component, the offset of
 * the file name and the location of the suffix dot.
 *
 * @returns The path length.
 *
 * @param   pszPath     Path to find filename in.
 * @param   pcchDir     Where to put the length of the directory component. If
 *                      no directory, this will be 0. Optional.
 * @param   poffName    Where to store the filename offset.
 *                      If empty string or if it's ending with a slash this
 *                      will be set to -1. Optional.
 * @param   poffSuff    Where to store the suffix offset (the last dot).
 *                      If empty string or if it's ending with a slash this
 *                      will be set to -1. Optional.
 */
RTDECL(size_t) RTPathParseSimple(const char *pszPath, size_t *pcchDir, ssize_t *poffName, ssize_t *poffSuff);

/**
 * Finds the filename in a path.
 *
 * @returns Pointer to filename within pszPath.
 * @returns NULL if no filename (i.e. empty string or ends with a slash).
 * @param   pszPath     Path to find filename in.
 */
RTDECL(char *) RTPathFilename(const char *pszPath);
RTDECL(PRTUTF16) RTPathFilenameUtf16(PCRTUTF16 pwszPath);

/**
 * Finds the filename in a path, extended version.
 *
 * @returns Pointer to filename within pszPath.
 * @returns NULL if no filename (i.e. empty string or ends with a slash).
 * @param   pszPath     Path to find filename in.
 * @param   fFlags      RTPATH_STR_F_STYLE_XXX. Other RTPATH_STR_F_XXX flags
 *                      will be ignored.
 */
RTDECL(char *) RTPathFilenameEx(const char *pszPath, uint32_t fFlags);
RTDECL(PRTUTF16) RTPathFilenameExUtf16(PCRTUTF16 pwszPath, uint32_t fFlags);

/**
 * Finds the suffix part of in a path (last dot and onwards).
 *
 * @returns Pointer to suffix within pszPath.
 * @returns NULL if no suffix
 * @param   pszPath     Path to find suffix in.
 *
 * @remarks IPRT terminology: A suffix includes the dot, the extension starts
 *          after the dot. For instance suffix '.txt' and extension 'txt'.
 */
RTDECL(char *) RTPathSuffix(const char *pszPath);

/**
 * Checks if a path has an extension / suffix.
 *
 * @returns true if extension / suffix present.
 * @returns false if no extension / suffix.
 * @param   pszPath     Path to check.
 */
RTDECL(bool) RTPathHasSuffix(const char *pszPath);
/** Same thing, different name.  */
#define RTPathHasExt RTPathHasSuffix

/**
 * Checks if a path includes more than a filename.
 *
 * @returns true if path present.
 * @returns false if no path.
 * @param   pszPath     Path to check.
 */
RTDECL(bool) RTPathHasPath(const char *pszPath);
/** Misspelled, don't use.  */
#define RTPathHavePath  RTPathHasPath

/**
 * Checks if the path starts with a root specifier or not.
 *
 * @returns @c true if it starts with root, @c false if not.
 *
 * @param   pszPath     Path to check.
 */
RTDECL(bool) RTPathStartsWithRoot(const char *pszPath);



/**
 * Counts the components in the specified path.
 *
 * An empty string has zero components.  A lone root slash is considered have
 * one.  The paths "/init" and "/bin/" are considered having two components.  An
 * UNC share specifier like "\\myserver\share" will be considered as one single
 * component.
 *
 * @returns The number of path components.
 * @param   pszPath     The path to parse.
 */
RTDECL(size_t) RTPathCountComponents(const char *pszPath);

/**
 * Copies the specified number of path components from @a pszSrc and into @a
 * pszDst.
 *
 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.  In the latter case the buffer
 *          is not touched.
 *
 * @param   pszDst      The destination buffer.
 * @param   cbDst       The size of the destination buffer.
 * @param   pszSrc      The source path.
 * @param   cComponents The number of components to copy from @a pszSrc.
 */
RTDECL(int) RTPathCopyComponents(char *pszDst, size_t cbDst, const char *pszSrc, size_t cComponents);

/** @name Path properties returned by RTPathParse and RTPathSplit.
 * @{ */

/** Indicates that there is a filename.
 * If not set, either a lone root spec was given (RTPATH_PROP_UNC,
 * RTPATH_PROP_ROOT_SLASH, or RTPATH_PROP_VOLUME) or the final component had a
 * trailing slash (RTPATH_PROP_DIR_SLASH). */
#define RTPATH_PROP_FILENAME        UINT16_C(0x0001)
/** Indicates that a directory was specified using a trailing slash.
 * @note This is not set for lone root specifications (RTPATH_PROP_UNC,
 *       RTPATH_PROP_ROOT_SLASH, or RTPATH_PROP_VOLUME).
 * @note The slash is not counted into the last component. However, it is
 *       counted into cchPath. */
#define RTPATH_PROP_DIR_SLASH       UINT16_C(0x0002)

/** The filename has a suffix (extension). */
#define RTPATH_PROP_SUFFIX          UINT16_C(0x0004)
/** Indicates that this is an UNC path (Windows and OS/2 only).
 *
 * UNC = Universal Naming Convention.  It is on the form '//Computer/',
 * '//Namespace/', '//ComputerName/Resource' and '//Namespace/Resource'.
 * RTPathParse, RTPathSplit and friends does not consider the 'Resource'  as
 * part of the UNC root specifier.  Thus the root specs for the above examples
 * would be '//ComputerName/' or '//Namespace/'.
 *
 * Please note that  '//something' is not a UNC path, there must be a slash
 * following the computer or namespace.
 */
#define RTPATH_PROP_UNC             UINT16_C(0x0010)
/** A root slash was specified (unix style root).
 * (While the path must relative if not set, this being set doesn't make it
 * absolute.)
 *
 * This will be set in the following examples: '/', '/bin', 'C:/', 'C:/Windows',
 * '//./', '//./PhysicalDisk0', '//example.org/', and '//example.org/share'.
 *
 * It will not be set for the following examples: '.', 'bin/ls', 'C:', and
 * 'C:Windows'.
 */
#define RTPATH_PROP_ROOT_SLASH      UINT16_C(0x0020)
/** A volume is specified (Windows, DOS and OS/2).
 * For examples: 'C:', 'C:/', and 'A:/AutoExec.bat'. */
#define RTPATH_PROP_VOLUME          UINT16_C(0x0040)
/** The path is absolute, i.e. has a root specifier (root-slash,
 * volume or UNC) and contains no winding '..' bits, though it may contain
 * unnecessary slashes (RTPATH_PROP_EXTRA_SLASHES) and '.' components
 * (RTPATH_PROP_DOT_REFS).
 *
 * On systems without volumes and UNC (unix style) it will be set for '/',
 * '/bin/ls', and '/bin//./ls', but not for 'bin/ls', /bin/../usr/bin/env',
 * '/./bin/ls' or '/.'.
 *
 * On systems with volumes, it will be set for 'C:/', C:/Windows', and
 * 'C:/./Windows//', but not for 'C:', 'C:Windows', or 'C:/Windows/../boot.ini'.
 *
 * On systems with UNC paths, it will be set for '//localhost/',
 * '//localhost/C$', '//localhost/C$/Windows/System32', '//localhost/.', and
 * '//localhost/C$//./AutoExec.bat', but not for
 * '//localhost/C$/Windows/../AutoExec.bat'.
 *
 * @note For the RTPathAbs definition, this flag needs to be set while both
 *       RTPATH_PROP_EXTRA_SLASHES and RTPATH_PROP_DOT_REFS must be cleared.
 */
#define RTPATH_PROP_ABSOLUTE        UINT16_C(0x0100)
/** Relative path. Inverse of RTPATH_PROP_ABSOLUTE. */
#define RTPATH_PROP_RELATIVE        UINT16_C(0x0200)
/** The path contains unnecessary slashes. Meaning, that if  */
#define RTPATH_PROP_EXTRA_SLASHES   UINT16_C(0x0400)
/** The path contains references to the special '.' (dot) directory link. */
#define RTPATH_PROP_DOT_REFS        UINT16_C(0x0800)
/** The path contains references to the special '..' (dot) directory link.
 * RTPATH_PROP_RELATIVE will always be set together with this.  */
#define RTPATH_PROP_DOTDOT_REFS     UINT16_C(0x1000)


/** Macro to determin whether to insert a slash after the first component when
 * joining it with something else.
 * (All other components in a split or parsed path requies slashes added.) */
#define RTPATH_PROP_FIRST_NEEDS_NO_SLASH(a_fProps) \
    RT_BOOL( (a_fProps) & (RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_VOLUME | RTPATH_PROP_UNC) )

/** Macro to determin whether there is a root specification of any kind
 * (unix, volumes, unc). */
#define RTPATH_PROP_HAS_ROOT_SPEC(a_fProps) \
    RT_BOOL( (a_fProps) & (RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_VOLUME | RTPATH_PROP_UNC) )

/** @} */


/**
 * Parsed path.
 *
 * The first component is the root, volume or UNC specifier, if present.  Use
 * RTPATH_PROP_HAS_ROOT_SPEC() on RTPATHPARSED::fProps to determine its
 * presence.
 *
 * Other than the root component, no component will include directory separators
 * (slashes).
 */
typedef struct RTPATHPARSED
{
    /** Number of path components.
     * This will always be set on VERR_BUFFER_OVERFLOW returns from RTPathParsed
     * so the caller can calculate the required buffer size. */
    uint16_t    cComps;
    /** Path property flags, RTPATH_PROP_XXX */
    uint16_t    fProps;
    /** On success this is the length of the described path, i.e. sum of all
     * component lengths and necessary separators.
     * Do NOT use this to index in the source path in case it contains
     * unnecessary slashes that RTPathParsed has ignored here. */
    uint16_t    cchPath;
    /** Reserved for future use. */
    uint16_t    u16Reserved;
    /** The offset of the filename suffix, offset of the NUL char if none. */
    uint16_t    offSuffix;
    /** The lenght of the suffix. */
    uint16_t    cchSuffix;
    /** Array of component descriptors (variable size).
     * @note Don't try figure the end of the input path by adding up off and cch
     *       of the last component.  If RTPATH_PROP_DIR_SLASH is set, there may
     *       be one or more trailing slashes that are unaccounted for! */
    struct
    {
        /** The offset of the component. */
        uint16_t    off;
        /** The length of the component. */
        uint16_t    cch;
    } aComps[1];
} RTPATHPARSED;
/** Pointer to to a parsed path result. */
typedef RTPATHPARSED *PRTPATHPARSED;
/** Pointer to to a const parsed path result. */
typedef RTPATHPARSED *PCRTPATHPARSED;


/**
 * Parses the path.
 *
 * @returns IPRT status code.
 * @retval  VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer.
 * @retval  VERR_INVALID_PARAMETER if cbOutput is less than the RTPATHPARSED
 *          strucuture. No output. (asserted)
 * @retval  VERR_BUFFER_OVERFLOW there are more components in the path than
 *          there is space in aComps. The required amount of space can be
 *          determined from the pParsed->cComps:
 *          @code
 *              RT_OFFSETOF(RTPATHPARSED, aComps[pParsed->cComps])
 *          @endcode
 * @retval  VERR_PATH_ZERO_LENGTH if the path is empty.
 *
 * @param   pszPath             The path to parse.
 * @param   pParsed             Where to store the details of the parsed path.
 * @param   cbParsed            The size of the buffer. Must be at least the
 *                              size of RTPATHPARSED.
 * @param   fFlags              Combination of RTPATH_STR_F_XXX flags.
 *                              Most users will pass 0.
 * @sa      RTPathSplit, RTPathSplitA.
 */
RTDECL(int) RTPathParse(const char *pszPath, PRTPATHPARSED pParsed, size_t cbParsed, uint32_t fFlags);

/**
 * Reassembles a path parsed by RTPathParse.
 *
 * This will be more useful as more APIs manipulating the RTPATHPARSED output
 * are added.
 *
 * @returns IPRT status code.
 * @retval  VERR_BUFFER_OVERFLOW if @a cbDstPath is less than or equal to
 *          RTPATHPARSED::cchPath.
 *
 * @param   pszSrcPath          The source path.
 * @param   pParsed             The parser output for @a pszSrcPath.
 * @param   fFlags              Combination of RTPATH_STR_F_STYLE_XXX.
 *                              Most users will pass 0.
 * @param   pszDstPath          Pointer to the buffer where the path is to be
 *                              reassembled.
 * @param   cbDstPath           The size of the output buffer.
 */
RTDECL(int) RTPathParsedReassemble(const char *pszSrcPath, PRTPATHPARSED pParsed, uint32_t fFlags,
                                   char *pszDstPath, size_t cbDstPath);


/**
 * Output buffer for RTPathSplit and RTPathSplitA.
 */
typedef struct RTPATHSPLIT
{
    /** Number of path components.
     * This will always be set on VERR_BUFFER_OVERFLOW returns from RTPathParsed
     * so the caller can calculate the required buffer size. */
    uint16_t    cComps;
    /** Path property flags, RTPATH_PROP_XXX */
    uint16_t    fProps;
    /** On success this is the length of the described path, i.e. sum of all
     * component lengths and necessary separators.
     * Do NOT use this to index in the source path in case it contains
     * unnecessary slashes that RTPathSplit has ignored here. */
    uint16_t    cchPath;
    /** Reserved (internal use).  */
    uint16_t    u16Reserved;
    /** The amount of memory used (on success) or required (on
     *  VERR_BUFFER_OVERFLOW) of this structure and it's strings. */
    uint32_t    cbNeeded;
    /** Pointer to the filename suffix (the dot), if any. Points to the NUL
     * character of the last component if none or if RTPATH_PROP_DIR_SLASH is
     * present. */
    const char *pszSuffix;
    /** Array of component strings (variable size). */
    char       *apszComps[1];
} RTPATHSPLIT;
/** Pointer to a split path buffer. */
typedef RTPATHSPLIT *PRTPATHSPLIT;
/** Pointer to a const split path buffer. */
typedef RTPATHSPLIT const *PCRTPATHSPLIT;

/**
 * Splits the path into individual component strings, carved from user supplied
 * the given buffer block.
 *
 * @returns IPRT status code.
 * @retval  VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer.
 * @retval  VERR_INVALID_PARAMETER if cbOutput is less than the RTPATHSPLIT
 *          strucuture. No output. (asserted)
 * @retval  VERR_BUFFER_OVERFLOW there are more components in the path than
 *          there is space in aComps. The required amount of space can be
 *          determined from the pParsed->cComps:
 *          @code
 *              RT_OFFSETOF(RTPATHPARSED, aComps[pParsed->cComps])
 *          @endcode
 * @retval  VERR_PATH_ZERO_LENGTH if the path is empty.
 * @retval  VERR_FILENAME_TOO_LONG if the filename is too long (close to 64 KB).
 *
 * @param   pszPath             The path to parse.
 * @param   pSplit              Where to store the details of the parsed path.
 * @param   cbSplit             The size of the buffer pointed to by @a pSplit
 *                              (variable sized array at the end).  Must be at
 *                              least the size of RTPATHSPLIT.
 * @param   fFlags              Combination of RTPATH_STR_F_XXX flags.
 *                              Most users will pass 0.
 *
 * @sa      RTPathSplitA, RTPathParse.
 */
RTDECL(int) RTPathSplit(const char *pszPath, PRTPATHSPLIT pSplit, size_t cbSplit, uint32_t fFlags);

/**
 * Splits the path into individual component strings, allocating the buffer on
 * the default thread heap.
 *
 * @returns IPRT status code.
 * @retval  VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer.
 * @retval  VERR_PATH_ZERO_LENGTH if the path is empty.
 *
 * @param   pszPath             The path to parse.
 * @param   ppSplit             Where to return the pointer to the output on
 *                              success.  This must be freed by calling
 *                              RTPathSplitFree().
 * @param   fFlags              Combination of RTPATH_STR_F_XXX flags.
 *                              Most users will pass 0.
 * @sa      RTPathSplitFree, RTPathSplit, RTPathParse.
 */
#define RTPathSplitA(pszPath, ppSplit, fFlags)      RTPathSplitATag(pszPath, ppSplit, fFlags, RTPATH_TAG)

/**
 * Splits the path into individual component strings, allocating the buffer on
 * the default thread heap.
 *
 * @returns IPRT status code.
 * @retval  VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer.
 * @retval  VERR_PATH_ZERO_LENGTH if the path is empty.
 *
 * @param   pszPath             The path to parse.
 * @param   ppSplit             Where to return the pointer to the output on
 *                              success.  This must be freed by calling
 *                              RTPathSplitFree().
 * @param   fFlags              Combination of RTPATH_STR_F_XXX flags.
 *                              Most users will pass 0.
 * @param   pszTag              Allocation tag used for statistics and such.
 * @sa      RTPathSplitFree, RTPathSplit, RTPathParse.
 */
RTDECL(int) RTPathSplitATag(const char *pszPath, PRTPATHSPLIT *ppSplit, uint32_t fFlags, const char *pszTag);

/**
 * Frees buffer returned by RTPathSplitA.
 *
 * @param   pSplit              What RTPathSplitA returned.
 * @sa      RTPathSplitA
 */
RTDECL(void) RTPathSplitFree(PRTPATHSPLIT pSplit);

/**
 * Reassembles a path parsed by RTPathSplit.
 *
 * This will be more useful as more APIs manipulating the RTPATHSPLIT output are
 * added.
 *
 * @returns IPRT status code.
 * @retval  VERR_BUFFER_OVERFLOW if @a cbDstPath is less than or equal to
 *          RTPATHSPLIT::cchPath.
 *
 * @param   pSplit              A split path (see RTPathSplit, RTPathSplitA).
 * @param   fFlags              Combination of RTPATH_STR_F_STYLE_XXX.
 *                              Most users will pass 0.
 * @param   pszDstPath          Pointer to the buffer where the path is to be
 *                              reassembled.
 * @param   cbDstPath           The size of the output buffer.
 */
RTDECL(int) RTPathSplitReassemble(PRTPATHSPLIT pSplit, uint32_t fFlags, char *pszDstPath, size_t cbDstPath);

/**
 * Checks if the two paths leads to the file system object.
 *
 * If the objects exist, we'll query attributes for them.  If that's not
 * conclusive (some OSes) or one of them doesn't exist, we'll use a combination
 * of RTPathAbs and RTPathCompare to determine the result.
 *
 * @returns true, false, or VERR_FILENAME_TOO_LONG.
 * @param   pszPath1            The first path.
 * @param   pszPath2            The seoncd path.
 */
RTDECL(int) RTPathIsSame(const char *pszPath1, const char *pszPath2);


/**
 * Compares two paths.
 *
 * The comparison takes platform-dependent details into account,
 * such as:
 * <ul>
 * <li>On DOS-like platforms, both separator chars (|\| and |/|) are considered
 *     to be equal.
 * <li>On platforms with case-insensitive file systems, mismatching characters
 *     are uppercased and compared again.
 * </ul>
 *
 * @returns @< 0 if the first path less than the second path.
 * @returns 0 if the first path identical to the second path.
 * @returns @> 0 if the first path greater than the second path.
 *
 * @param   pszPath1    Path to compare (must be an absolute path).
 * @param   pszPath2    Path to compare (must be an absolute path).
 *
 * @remarks File system details are currently ignored. This means that you won't
 *          get case-insensitive compares on unix systems when a path goes into a
 *          case-insensitive filesystem like FAT, HPFS, HFS, NTFS, JFS, or
 *          similar. For NT, OS/2 and similar you'll won't get case-sensitive
 *          compares on a case-sensitive file system.
 */
RTDECL(int) RTPathCompare(const char *pszPath1, const char *pszPath2);

/**
 * Checks if a path starts with the given parent path.
 *
 * This means that either the path and the parent path matches completely, or
 * that the path is to some file or directory residing in the tree given by the
 * parent directory.
 *
 * The path comparison takes platform-dependent details into account,
 * see RTPathCompare() for details.
 *
 * @returns |true| when \a pszPath starts with \a pszParentPath (or when they
 *          are identical), or |false| otherwise.
 *
 * @param   pszPath         Path to check, must be an absolute path.
 * @param   pszParentPath   Parent path, must be an absolute path.
 *                          No trailing directory slash!
 *
 * @remarks This API doesn't currently handle root directory compares in a
 *          manner consistent with the other APIs. RTPathStartsWith(pszSomePath,
 *          "/") will not work if pszSomePath isn't "/".
 */
RTDECL(bool) RTPathStartsWith(const char *pszPath, const char *pszParentPath);

/**
 * Appends one partial path to another.
 *
 * The main purpose of this function is to deal correctly with the slashes when
 * concatenating the two partial paths.
 *
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_BUFFER_OVERFLOW if the result is too big to fit within
 *          cbPathDst bytes. No changes has been made.
 * @retval  VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer
 *          than cbPathDst-1 bytes (failed to find terminator). Asserted.
 *
 * @param   pszPath         The path to append pszAppend to. This serves as both
 *                          input and output. This can be empty, in which case
 *                          pszAppend is just copied over.
 * @param   cbPathDst       The size of the buffer pszPath points to, terminator
 *                          included. This should NOT be strlen(pszPath).
 * @param   pszAppend       The partial path to append to pszPath. This can be
 *                          NULL, in which case nothing is done.
 *
 * @remarks See the RTPathAppendEx remarks.
 */
RTDECL(int) RTPathAppend(char *pszPath, size_t cbPathDst, const char *pszAppend);

/**
 * Appends one partial path to another.
 *
 * The main purpose of this function is to deal correctly with the slashes when
 * concatenating the two partial paths.
 *
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_BUFFER_OVERFLOW if the result is too big to fit within
 *          cbPathDst bytes. No changes has been made.
 * @retval  VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer
 *          than cbPathDst-1 bytes (failed to find terminator). Asserted.
 *
 * @param   pszPath         The path to append pszAppend to. This serves as both
 *                          input and output. This can be empty, in which case
 *                          pszAppend is just copied over.
 * @param   cbPathDst       The size of the buffer pszPath points to, terminator
 *                          included. This should NOT be strlen(pszPath).
 * @param   pszAppend       The partial path to append to pszPath. This can be
 *                          NULL, in which case nothing is done.
 * @param   cchAppendMax    The maximum number or characters to take from @a
 *                          pszAppend.  RTSTR_MAX is fine.
 *
 * @remarks On OS/2, Window and similar systems, concatenating a drive letter
 *          specifier with a slash prefixed path will result in an absolute
 *          path. Meaning, RTPathAppend(strcpy(szBuf, "C:"), sizeof(szBuf),
 *          "/bar") will result in "C:/bar". (This follows directly from the
 *          behavior when pszPath is empty.)
 *
 *          On the other hand, when joining a drive letter specifier with a
 *          partial path that does not start with a slash, the result is not an
 *          absolute path. Meaning, RTPathAppend(strcpy(szBuf, "C:"),
 *          sizeof(szBuf), "bar") will result in "C:bar".
 */
RTDECL(int) RTPathAppendEx(char *pszPath, size_t cbPathDst, const char *pszAppend, size_t cchAppendMax);

/**
 * Like RTPathAppend, but with the base path as a separate argument instead of
 * in the path buffer.
 *
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_BUFFER_OVERFLOW if the result is too big to fit within
 *          cbPathDst bytes.
 * @retval  VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer
 *          than cbPathDst-1 bytes (failed to find terminator). Asserted.
 *
 * @param   pszPathDst      Where to store the resulting path.
 * @param   cbPathDst       The size of the buffer pszPathDst points to,
 *                          terminator included.
 * @param   pszPathSrc      The base path to copy into @a pszPathDst before
 *                          appending @a pszAppend.
 * @param   pszAppend       The partial path to append to pszPathSrc. This can
 *                          be NULL, in which case nothing is done.
 *
 */
RTDECL(int) RTPathJoin(char *pszPathDst, size_t cbPathDst, const char *pszPathSrc,
                       const char *pszAppend);

/**
 * Same as RTPathJoin, except that the output buffer is allocated.
 *
 * @returns Buffer containing the joined up path, call RTStrFree to free.  NULL
 *          on allocation failure.
 * @param   pszPathSrc      The base path to copy into @a pszPathDst before
 *                          appending @a pszAppend.
 * @param   pszAppend       The partial path to append to pszPathSrc. This can
 *                          be NULL, in which case nothing is done.
 *
 */
RTDECL(char *) RTPathJoinA(const char *pszPathSrc, const char *pszAppend);

/**
 * Extended version of RTPathJoin, both inputs can be specified as substrings.
 *
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_BUFFER_OVERFLOW if the result is too big to fit within
 *          cbPathDst bytes.
 * @retval  VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer
 *          than cbPathDst-1 bytes (failed to find terminator). Asserted.
 *
 * @param   pszPathDst      Where to store the resulting path.
 * @param   cbPathDst       The size of the buffer pszPathDst points to,
 *                          terminator included.
 * @param   pszPathSrc      The base path to copy into @a pszPathDst before
 *                          appending @a pszAppend.
 * @param   cchPathSrcMax   The maximum number of bytes to copy from @a
 *                          pszPathSrc.  RTSTR_MAX is find.
 * @param   pszAppend       The partial path to append to pszPathSrc. This can
 *                          be NULL, in which case nothing is done.
 * @param   cchAppendMax    The maximum number of bytes to copy from @a
 *                          pszAppend.  RTSTR_MAX is find.
 *
 */
RTDECL(int) RTPathJoinEx(char *pszPathDst, size_t cbPathDst,
                         const char *pszPathSrc, size_t cchPathSrcMax,
                         const char *pszAppend, size_t cchAppendMax);

/**
 * Callback for RTPathTraverseList that's called for each element.
 *
 * @returns IPRT style status code. Return VERR_TRY_AGAIN to continue, any other
 *          value will abort the traversing and be returned to the caller.
 *
 * @param   pchPath         Pointer to the start of the current path. This is
 *                          not null terminated.
 * @param   cchPath         The length of the path.
 * @param   pvUser1         The first user parameter.
 * @param   pvUser2         The second user parameter.
 */
typedef DECLCALLBACK(int) FNRTPATHTRAVERSER(char const *pchPath, size_t cchPath, void *pvUser1, void *pvUser2);
/** Pointer to a FNRTPATHTRAVERSER. */
typedef FNRTPATHTRAVERSER *PFNRTPATHTRAVERSER;

/**
 * Traverses a string that can contain multiple paths separated by a special
 * character.
 *
 * @returns IPRT style status code from the callback or VERR_END_OF_STRING if
 *          the callback returned VERR_TRY_AGAIN for all paths in the string.
 *
 * @param   pszPathList     The string to traverse.
 * @param   chSep           The separator character.  Using the null terminator
 *                          is fine, but the result will simply be that there
 *                          will only be one callback for the entire string
 *                          (save any leading white space).
 * @param   pfnCallback     The callback.
 * @param   pvUser1         First user argument for the callback.
 * @param   pvUser2         Second user argument for the callback.
 */
RTDECL(int) RTPathTraverseList(const char *pszPathList, char chSep, PFNRTPATHTRAVERSER pfnCallback, void *pvUser1, void *pvUser2);


/**
 * Calculate a relative path between the two given paths.
 *
 * @returns IPRT status code.
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_BUFFER_OVERFLOW if the result is too big to fit within
 *          cbPathDst bytes.
 * @retval  VERR_NOT_SUPPORTED if both paths start with different volume specifiers.
 * @param   pszPathDst      Where to store the resulting path.
 * @param   cbPathDst       The size of the buffer pszPathDst points to,
 *                          terminator included.
 * @param   pszPathFrom     The path to start from creating the relative path.
 * @param   fFromFile       Whether @a pszPathFrom is a file and we should work
 *                          relative to it's parent directory (@c true), or if
 *                          we should assume @a pszPathFrom is a directory and
 *                          work relative to it.
 * @param   pszPathTo       The path to reach with the created relative path.
 */
RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst, const char *pszPathFrom, bool fFromFile, const char *pszPathTo);

#ifdef IN_RING3

/**
 * Gets the path to the directory containing the executable.
 *
 * @returns iprt status code.
 * @param   pszPath     Buffer where to store the path.
 * @param   cchPath     Buffer size in bytes.
 */
RTDECL(int) RTPathExecDir(char *pszPath, size_t cchPath);

/**
 * Gets the user home directory.
 *
 * @returns iprt status code.
 * @param   pszPath     Buffer where to store the path.
 * @param   cchPath     Buffer size in bytes.
 */
RTDECL(int) RTPathUserHome(char *pszPath, size_t cchPath);

/**
 * Gets the user documents directory.
 *
 * The returned path isn't guaranteed to exist.
 *
 * @returns iprt status code.
 * @param   pszPath     Buffer where to store the path.
 * @param   cchPath     Buffer size in bytes.
 */
RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath);

/**
 * Gets the directory of shared libraries.
 *
 * This is not the same as RTPathAppPrivateArch() as Linux depends all shared
 * libraries in a common global directory where ld.so can find them.
 *
 * Linux:    /usr/lib
 * Solaris:  /opt/@<application@>/@<arch>@ or something
 * Windows:  @<program files directory@>/@<application@>
 * Old path: same as RTPathExecDir()
 *
 * @returns iprt status code.
 * @param   pszPath     Buffer where to store the path.
 * @param   cchPath     Buffer size in bytes.
 */
RTDECL(int) RTPathSharedLibs(char *pszPath, size_t cchPath);

/**
 * Gets the directory for architecture-independent application data, for
 * example NLS files, module sources, ...
 *
 * Linux:    /usr/shared/@<application@>
 * Solaris:  /opt/@<application@>
 * Windows:  @<program files directory@>/@<application@>
 * Old path: same as RTPathExecDir()
 *
 * @returns iprt status code.
 * @param   pszPath     Buffer where to store the path.
 * @param   cchPath     Buffer size in bytes.
 */
RTDECL(int) RTPathAppPrivateNoArch(char *pszPath, size_t cchPath);

/**
 * Gets the directory for architecture-dependent application data, for
 * example modules which can be loaded at runtime.
 *
 * Linux:    /usr/lib/@<application@>
 * Solaris:  /opt/@<application@>/@<arch>@ or something
 * Windows:  @<program files directory@>/@<application@>
 * Old path: same as RTPathExecDir()
 *
 * @returns iprt status code.
 * @param   pszPath     Buffer where to store the path.
 * @param   cchPath     Buffer size in bytes.
 */
RTDECL(int) RTPathAppPrivateArch(char *pszPath, size_t cchPath);

/**
 * Gets the toplevel directory for architecture-dependent application data.
 *
 * This differs from RTPathAppPrivateArch on Solaris only where it will work
 * around the /opt/@<application@>/amd64 and /opt/@<application@>/i386 multi
 * architecture installation style.
 *
 * Linux:    /usr/lib/@<application@>
 * Solaris:  /opt/@<application@>
 * Windows:  @<program files directory@>/@<application@>
 * Old path: same as RTPathExecDir()
 *
 * @returns iprt status code.
 * @param   pszPath     Buffer where to store the path.
 * @param   cchPath     Buffer size in bytes.
 */
RTDECL(int) RTPathAppPrivateArchTop(char *pszPath, size_t cchPath);

/**
 * Gets the directory for documentation.
 *
 * Linux:    /usr/share/doc/@<application@>
 * Solaris:  /opt/@<application@>
 * Windows:  @<program files directory@>/@<application@>
 * Old path: same as RTPathExecDir()
 *
 * @returns iprt status code.
 * @param   pszPath     Buffer where to store the path.
 * @param   cchPath     Buffer size in bytes.
 */
RTDECL(int) RTPathAppDocs(char *pszPath, size_t cchPath);

/**
 * Gets the temporary directory path.
 *
 * @returns iprt status code.
 * @param   pszPath     Buffer where to store the path.
 * @param   cchPath     Buffer size in bytes.
 */
RTDECL(int) RTPathTemp(char *pszPath, size_t cchPath);


/**
 * RTPathGlobl result entry.
 */
typedef struct RTPATHGLOBENTRY
{
    /** List entry. */
    struct RTPATHGLOBENTRY *pNext;
    /** RTDIRENTRYTYPE value. */
    uint8_t                 uType;
    /** Unused explicit padding. */
    uint8_t                 bUnused;
    /** The length of the path. */
    uint16_t                cchPath;
    /** The path to the file (variable length). */
    char                    szPath[1];
} RTPATHGLOBENTRY;
/** Pointer to a GLOB result entry. */
typedef RTPATHGLOBENTRY *PRTPATHGLOBENTRY;
/** Pointer to a const GLOB result entry. */
typedef RTPATHGLOBENTRY const *PCRTPATHGLOBENTRY;
/** Pointer to a GLOB result entry pointer. */
typedef PCRTPATHGLOBENTRY *PPCRTPATHGLOBENTRY;

/**
 * Performs wildcard expansion on a path pattern.
 *
 * @returns IPRT status code.
 *
 * @param   pszPattern      The pattern to expand.
 * @param   fFlags          RTPATHGLOB_F_XXX.
 * @param   ppHead          Where to return the head of the result list.  This
 *                          is always set to NULL on failure.
 * @param   pcResults       Where to return the number of the result. Optional.
 */
RTDECL(int) RTPathGlob(const char *pszPattern, uint32_t fFlags, PPCRTPATHGLOBENTRY ppHead, uint32_t *pcResults);

/** @name RTPATHGLOB_F_XXX - RTPathGlob flags
 *  @{ */
/** Case insensitive. */
#define RTPATHGLOB_F_IGNORE_CASE        RT_BIT_32(0)
/** Do not expand \${EnvOrSpecialVariable} in the pattern. */
#define RTPATHGLOB_F_NO_VARIABLES       RT_BIT_32(1)
/** Do not interpret a leading tilde as a home directory reference. */
#define RTPATHGLOB_F_NO_TILDE           RT_BIT_32(2)
/** Only return the first match. */
#define RTPATHGLOB_F_FIRST_ONLY         RT_BIT_32(3)
/** Only match directories (implied if pattern ends with slash). */
#define RTPATHGLOB_F_ONLY_DIRS          RT_BIT_32(4)
/** Do not match directories.  (Can't be used with RTPATHGLOB_F_ONLY_DIRS or
 * patterns containing a trailing slash.) */
#define RTPATHGLOB_F_NO_DIRS            RT_BIT_32(5)
/** Disables the '**' wildcard pattern for matching zero or more subdirs. */
#define RTPATHGLOB_F_NO_STARSTAR        RT_BIT_32(6)
/** Mask of valid flags. */
#define RTPATHGLOB_F_MASK               UINT32_C(0x0000007f)
/** @} */

/**
 * Frees the results produced by RTPathGlob.
 *
 * @param   pHead           What RTPathGlob returned.  NULL ignored.
 */
RTDECL(void) RTPathGlobFree(PCRTPATHGLOBENTRY pHead);


/**
 * Query information about a file system object.
 *
 * This API will resolve NOT symbolic links in the last component (just like
 * unix lstat()).
 *
 * @returns IPRT status code.
 * @retval  VINF_SUCCESS if the object exists, information returned.
 * @retval  VERR_PATH_NOT_FOUND if any but the last component in the specified
 *          path was not found or was not a directory.
 * @retval  VERR_FILE_NOT_FOUND if the object does not exist (but path to the
 *          parent directory exists).
 *
 * @param   pszPath     Path to the file system object.
 * @param   pObjInfo    Object information structure to be filled on successful
 *                      return.
 * @param   enmAdditionalAttribs
 *                      Which set of additional attributes to request.
 *                      Use RTFSOBJATTRADD_NOTHING if this doesn't matter.
 */
RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs);

/**
 * Query information about a file system object.
 *
 * @returns IPRT status code.
 * @retval  VINF_SUCCESS if the object exists, information returned.
 * @retval  VERR_PATH_NOT_FOUND if any but the last component in the specified
 *          path was not found or was not a directory.
 * @retval  VERR_FILE_NOT_FOUND if the object does not exist (but path to the
 *          parent directory exists).
 *
 * @param   pszPath     Path to the file system object.
 * @param   pObjInfo    Object information structure to be filled on successful return.
 * @param   enmAdditionalAttribs
 *                      Which set of additional attributes to request.
 *                      Use RTFSOBJATTRADD_NOTHING if this doesn't matter.
 * @param   fFlags      RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK.
 */
RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags);

/**
 * Changes the mode flags of a file system object.
 *
 * The API requires at least one of the mode flag sets (Unix/Dos) to
 * be set. The type is ignored.
 *
 * This API will resolve symbolic links in the last component since
 * mode isn't important for symbolic links.
 *
 * @returns iprt status code.
 * @param   pszPath     Path to the file system object.
 * @param   fMode       The new file mode, see @ref grp_rt_fs for details.
 */
RTR3DECL(int) RTPathSetMode(const char *pszPath, RTFMODE fMode);

/**
 * Gets the mode flags of a file system object.
 *
 * @returns iprt status code.
 * @param   pszPath     Path to the file system object.
 * @param   pfMode      Where to store the file mode, see @ref grp_rt_fs for details.
 *
 * @remark  This is wrapper around RTPathQueryInfoEx(RTPATH_F_FOLLOW_LINK) and
 *          exists to complement RTPathSetMode().
 */
RTR3DECL(int) RTPathGetMode(const char *pszPath, PRTFMODE pfMode);

/**
 * Changes one or more of the timestamps associated of file system object.
 *
 * This API will not resolve symbolic links in the last component (just
 * like unix lutimes()).
 *
 * @returns iprt status code.
 * @param   pszPath             Path to the file system object.
 * @param   pAccessTime         Pointer to the new access time.
 * @param   pModificationTime   Pointer to the new modification time.
 * @param   pChangeTime         Pointer to the new change time. NULL if not to be changed.
 * @param   pBirthTime          Pointer to the new time of birth. NULL if not to be changed.
 *
 * @remark  The file system might not implement all these time attributes,
 *          the API will ignore the ones which aren't supported.
 *
 * @remark  The file system might not implement the time resolution
 *          employed by this interface, the time will be chopped to fit.
 *
 * @remark  The file system may update the change time even if it's
 *          not specified.
 *
 * @remark  POSIX can only set Access & Modification and will always set both.
 */
RTR3DECL(int) RTPathSetTimes(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
                             PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime);

/**
 * Changes one or more of the timestamps associated of file system object.
 *
 * @returns iprt status code.
 * @param   pszPath             Path to the file system object.
 * @param   pAccessTime         Pointer to the new access time.
 * @param   pModificationTime   Pointer to the new modification time.
 * @param   pChangeTime         Pointer to the new change time. NULL if not to be changed.
 * @param   pBirthTime          Pointer to the new time of birth. NULL if not to be changed.
 * @param   fFlags              RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK.
 *
 * @remark  The file system might not implement all these time attributes,
 *          the API will ignore the ones which aren't supported.
 *
 * @remark  The file system might not implement the time resolution
 *          employed by this interface, the time will be chopped to fit.
 *
 * @remark  The file system may update the change time even if it's
 *          not specified.
 *
 * @remark  POSIX can only set Access & Modification and will always set both.
 */
RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
                               PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags);

/**
 * Gets one or more of the timestamps associated of file system object.
 *
 * @returns iprt status code.
 * @param   pszPath             Path to the file system object.
 * @param   pAccessTime         Where to store the access time. NULL is ok.
 * @param   pModificationTime   Where to store the modification time. NULL is ok.
 * @param   pChangeTime         Where to store the change time. NULL is ok.
 * @param   pBirthTime          Where to store the creation time. NULL is ok.
 *
 * @remark  This is wrapper around RTPathQueryInfo() and exists to complement
 *          RTPathSetTimes().  If the last component is a symbolic link, it will
 *          not be resolved.
 */
RTR3DECL(int) RTPathGetTimes(const char *pszPath, PRTTIMESPEC pAccessTime, PRTTIMESPEC pModificationTime,
                             PRTTIMESPEC pChangeTime, PRTTIMESPEC pBirthTime);

/**
 * Changes the owner and/or group of a file system object.
 *
 * This API will not resolve symbolic links in the last component (just
 * like unix lchown()).
 *
 * @returns iprt status code.
 * @param   pszPath     Path to the file system object.
 * @param   uid         The new file owner user id.  Pass NIL_RTUID to leave
 *                      this unchanged.
 * @param   gid         The new group id.  Pass NIL_RTGUID to leave this
 *                      unchanged.
 */
RTR3DECL(int) RTPathSetOwner(const char *pszPath, uint32_t uid, uint32_t gid);

/**
 * Changes the owner and/or group of a file system object.
 *
 * @returns iprt status code.
 * @param   pszPath     Path to the file system object.
 * @param   uid         The new file owner user id.  Pass NIL_RTUID to leave
 *                      this unchanged.
 * @param   gid         The new group id.  Pass NIL_RTGID to leave this
 *                      unchanged.
 * @param   fFlags      RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK.
 */
RTR3DECL(int) RTPathSetOwnerEx(const char *pszPath, uint32_t uid, uint32_t gid, uint32_t fFlags);

/**
 * Gets the owner and/or group of a file system object.
 *
 * @returns iprt status code.
 * @param   pszPath     Path to the file system object.
 * @param   pUid        Where to store the owner user id. NULL is ok.
 * @param   pGid        Where to store the group id. NULL is ok.
 *
 * @remark  This is wrapper around RTPathQueryInfo() and exists to complement
 *          RTPathGetOwner().  If the last component is a symbolic link, it will
 *          not be resolved.
 */
RTR3DECL(int) RTPathGetOwner(const char *pszPath, uint32_t *pUid, uint32_t *pGid);


/** @name RTPathRename, RTDirRename & RTFileRename flags.
 * @{ */
/** Do not replace anything. */
#define RTPATHRENAME_FLAGS_NO_REPLACE   UINT32_C(0)
/** This will replace attempt any target which isn't a directory. */
#define RTPATHRENAME_FLAGS_REPLACE      RT_BIT(0)
/** Don't allow symbolic links as part of the path.
 * @remarks this flag is currently not implemented and will be ignored. */
#define RTPATHRENAME_FLAGS_NO_SYMLINKS  RT_BIT(1)
/** @} */

/**
 * Renames a path within a filesystem.
 *
 * This will rename symbolic links.  If RTPATHRENAME_FLAGS_REPLACE is used and
 * pszDst is a symbolic link, it will be replaced and not its target.
 *
 * @returns IPRT status code.
 * @param   pszSrc      The source path.
 * @param   pszDst      The destination path.
 * @param   fRename     Rename flags, RTPATHRENAME_FLAGS_*.
 */
RTR3DECL(int) RTPathRename(const char *pszSrc,  const char *pszDst, unsigned fRename);

/** @name RTPathUnlink flags.
 * @{ */
/** Don't allow symbolic links as part of the path.
 * @remarks this flag is currently not implemented and will be ignored. */
#define RTPATHUNLINK_FLAGS_NO_SYMLINKS  RT_BIT(0)
/** @} */

/**
 * Removes the last component of the path.
 *
 * @returns IPRT status code.
 * @param   pszPath     The path.
 * @param   fUnlink     Unlink flags, RTPATHUNLINK_FLAGS_*.
 */
RTR3DECL(int) RTPathUnlink(const char *pszPath, uint32_t fUnlink);

/**
 * A /bin/rm tool.
 *
 * @returns Program exit code.
 *
 * @param   cArgs               The number of arguments.
 * @param   papszArgs           The argument vector.  (Note that this may be
 *                              reordered, so the memory must be writable.)
 */
RTDECL(RTEXITCODE) RTPathRmCmd(unsigned cArgs, char **papszArgs);

# ifdef RT_OS_WINDOWS

/**
 * Converts the given UTF-8 path into a native windows path.
 *
 * @returns IPRT status code.
 * @param   ppwszPath           Where to return the path.  This will always be
 *                              set to NULL on failure.  Use RTPathWinFree to
 *                              free it when done.
 * @param   pszPath             The UTF-8 path to convert.
 * @param   fFlags              MBZ, reserved for future hacks.
 * @sa      RTPathWinFree, RTNtPathFromWinUtf8, RTNtPathRelativeFromUtf8.
 */
RTDECL(int)  RTPathWinFromUtf8(PRTUTF16 *ppwszPath, const char *pszPath, uint32_t fFlags);

/**
 * Frees a native windows path returned by RTPathWinFromUtf8
 *
 * @param   pwszPath            The path to free.  NULL is ignored.
 */
RTDECL(void) RTPathWinFree(PRTUTF16 pwszPath);

# endif /* RT_OS_WINDOWS */

#endif /* IN_RING3 */

/** @} */

RT_C_DECLS_END

#endif /* !IPRT_INCLUDED_path_h */