Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/winpr/libwinpr/path/path.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Path Functions
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
22
#include <winpr/crt.h>
23
#include <winpr/tchar.h>
24
25
#include <winpr/path.h>
26
#include <winpr/file.h>
27
28
0
#define PATH_SLASH_CHR '/'
29
0
#define PATH_SLASH_STR "/"
30
31
0
#define PATH_BACKSLASH_CHR '\\'
32
0
#define PATH_BACKSLASH_STR "\\"
33
34
#ifdef _WIN32
35
#define PATH_SLASH_STR_W L"/"
36
#define PATH_BACKSLASH_STR_W L"\\"
37
#else
38
#define PATH_SLASH_STR_W \
39
0
  {                    \
40
0
    '/', '\0'        \
41
0
  }
42
#define PATH_BACKSLASH_STR_W \
43
0
  {                        \
44
0
    '\\', '\0'           \
45
0
  }
46
#endif
47
48
#ifdef _WIN32
49
#define PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
50
#define PATH_SEPARATOR_STR PATH_BACKSLASH_STR
51
#define PATH_SEPARATOR_STR_W PATH_BACKSLASH_STR_W
52
#else
53
0
#define PATH_SEPARATOR_CHR PATH_SLASH_CHR
54
0
#define PATH_SEPARATOR_STR PATH_SLASH_STR
55
0
#define PATH_SEPARATOR_STR_W PATH_SLASH_STR_W
56
#endif
57
58
#define SHARED_LIBRARY_EXT_DLL "dll"
59
#define SHARED_LIBRARY_EXT_SO "so"
60
#define SHARED_LIBRARY_EXT_DYLIB "dylib"
61
62
#ifdef _WIN32
63
#define SHARED_LIBRARY_EXT SHARED_LIBRARY_EXT_DLL
64
#elif defined(__APPLE__)
65
#define SHARED_LIBRARY_EXT SHARED_LIBRARY_EXT_DYLIB
66
#else
67
#define SHARED_LIBRARY_EXT SHARED_LIBRARY_EXT_SO
68
#endif
69
70
#include "../log.h"
71
#define TAG WINPR_TAG("path")
72
73
/*
74
 * PathCchAddBackslash
75
 */
76
77
/* Windows-style Paths */
78
79
#define DEFINE_UNICODE FALSE
80
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
81
#define PATH_CCH_ADD_SEPARATOR PathCchAddBackslashA
82
#include "include/PathCchAddSeparator.c"
83
#undef DEFINE_UNICODE
84
#undef CUR_PATH_SEPARATOR_CHR
85
#undef PATH_CCH_ADD_SEPARATOR
86
87
#define DEFINE_UNICODE TRUE
88
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
89
#define PATH_CCH_ADD_SEPARATOR PathCchAddBackslashW
90
#include "include/PathCchAddSeparator.c"
91
#undef DEFINE_UNICODE
92
#undef CUR_PATH_SEPARATOR_CHR
93
#undef PATH_CCH_ADD_SEPARATOR
94
95
/* Unix-style Paths */
96
97
#define DEFINE_UNICODE FALSE
98
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
99
#define PATH_CCH_ADD_SEPARATOR PathCchAddSlashA
100
#include "include/PathCchAddSeparator.c"
101
#undef DEFINE_UNICODE
102
#undef CUR_PATH_SEPARATOR_CHR
103
#undef PATH_CCH_ADD_SEPARATOR
104
105
#define DEFINE_UNICODE TRUE
106
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
107
#define PATH_CCH_ADD_SEPARATOR PathCchAddSlashW
108
#include "include/PathCchAddSeparator.c"
109
#undef DEFINE_UNICODE
110
#undef CUR_PATH_SEPARATOR_CHR
111
#undef PATH_CCH_ADD_SEPARATOR
112
113
/* Native-style Paths */
114
115
#define DEFINE_UNICODE FALSE
116
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
117
#define PATH_CCH_ADD_SEPARATOR PathCchAddSeparatorA
118
#include "include/PathCchAddSeparator.c"
119
#undef DEFINE_UNICODE
120
#undef CUR_PATH_SEPARATOR_CHR
121
#undef PATH_CCH_ADD_SEPARATOR
122
123
#define DEFINE_UNICODE TRUE
124
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
125
#define PATH_CCH_ADD_SEPARATOR PathCchAddSeparatorW
126
#include "include/PathCchAddSeparator.c"
127
#undef DEFINE_UNICODE
128
#undef CUR_PATH_SEPARATOR_CHR
129
#undef PATH_CCH_ADD_SEPARATOR
130
131
/*
132
 * PathCchRemoveBackslash
133
 */
134
135
HRESULT PathCchRemoveBackslashA(PSTR pszPath, size_t cchPath)
136
0
{
137
0
  WLog_ERR(TAG, "not implemented");
138
0
  return E_NOTIMPL;
139
0
}
140
141
HRESULT PathCchRemoveBackslashW(PWSTR pszPath, size_t cchPath)
142
0
{
143
0
  WLog_ERR(TAG, "not implemented");
144
0
  return E_NOTIMPL;
145
0
}
146
147
/*
148
 * PathCchAddBackslashEx
149
 */
150
151
/* Windows-style Paths */
152
153
#define DEFINE_UNICODE FALSE
154
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
155
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddBackslashExA
156
#include "include/PathCchAddSeparatorEx.c"
157
#undef DEFINE_UNICODE
158
#undef CUR_PATH_SEPARATOR_CHR
159
#undef PATH_CCH_ADD_SEPARATOR_EX
160
161
#define DEFINE_UNICODE TRUE
162
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
163
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddBackslashExW
164
#include "include/PathCchAddSeparatorEx.c"
165
#undef DEFINE_UNICODE
166
#undef CUR_PATH_SEPARATOR_CHR
167
#undef PATH_CCH_ADD_SEPARATOR_EX
168
169
/* Unix-style Paths */
170
171
#define DEFINE_UNICODE FALSE
172
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
173
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSlashExA
174
#include "include/PathCchAddSeparatorEx.c"
175
#undef DEFINE_UNICODE
176
#undef CUR_PATH_SEPARATOR_CHR
177
#undef PATH_CCH_ADD_SEPARATOR_EX
178
179
#define DEFINE_UNICODE TRUE
180
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
181
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSlashExW
182
#include "include/PathCchAddSeparatorEx.c"
183
#undef DEFINE_UNICODE
184
#undef CUR_PATH_SEPARATOR_CHR
185
#undef PATH_CCH_ADD_SEPARATOR_EX
186
187
/* Native-style Paths */
188
189
#define DEFINE_UNICODE FALSE
190
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
191
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSeparatorExA
192
#include "include/PathCchAddSeparatorEx.c"
193
#undef DEFINE_UNICODE
194
#undef CUR_PATH_SEPARATOR_CHR
195
#undef PATH_CCH_ADD_SEPARATOR_EX
196
197
#define DEFINE_UNICODE TRUE
198
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
199
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSeparatorExW
200
#include "include/PathCchAddSeparatorEx.c"
201
#undef DEFINE_UNICODE
202
#undef CUR_PATH_SEPARATOR_CHR
203
#undef PATH_CCH_ADD_SEPARATOR_EX
204
205
HRESULT PathCchRemoveBackslashExA(PSTR pszPath, size_t cchPath, PSTR* ppszEnd,
206
                                  size_t* pcchRemaining)
207
0
{
208
0
  WLog_ERR(TAG, "not implemented");
209
0
  return E_NOTIMPL;
210
0
}
211
212
HRESULT PathCchRemoveBackslashExW(PWSTR pszPath, size_t cchPath, PWSTR* ppszEnd,
213
                                  size_t* pcchRemaining)
214
0
{
215
0
  WLog_ERR(TAG, "not implemented");
216
0
  return E_NOTIMPL;
217
0
}
218
219
/*
220
 * PathCchAddExtension
221
 */
222
223
/* Windows-style Paths */
224
225
#define DEFINE_UNICODE FALSE
226
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
227
#define PATH_CCH_ADD_EXTENSION PathCchAddExtensionA
228
#include "include/PathCchAddExtension.c"
229
#undef DEFINE_UNICODE
230
#undef CUR_PATH_SEPARATOR_CHR
231
#undef PATH_CCH_ADD_EXTENSION
232
233
#define DEFINE_UNICODE TRUE
234
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
235
#define PATH_CCH_ADD_EXTENSION PathCchAddExtensionW
236
#include "include/PathCchAddExtension.c"
237
#undef DEFINE_UNICODE
238
#undef CUR_PATH_SEPARATOR_CHR
239
#undef PATH_CCH_ADD_EXTENSION
240
241
/* Unix-style Paths */
242
243
#define DEFINE_UNICODE FALSE
244
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
245
#define PATH_CCH_ADD_EXTENSION UnixPathCchAddExtensionA
246
#include "include/PathCchAddExtension.c"
247
#undef DEFINE_UNICODE
248
#undef CUR_PATH_SEPARATOR_CHR
249
#undef PATH_CCH_ADD_EXTENSION
250
251
#define DEFINE_UNICODE TRUE
252
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
253
#define PATH_CCH_ADD_EXTENSION UnixPathCchAddExtensionW
254
#include "include/PathCchAddExtension.c"
255
#undef DEFINE_UNICODE
256
#undef CUR_PATH_SEPARATOR_CHR
257
#undef PATH_CCH_ADD_EXTENSION
258
259
/* Native-style Paths */
260
261
#define DEFINE_UNICODE FALSE
262
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
263
#define PATH_CCH_ADD_EXTENSION NativePathCchAddExtensionA
264
#include "include/PathCchAddExtension.c"
265
#undef DEFINE_UNICODE
266
#undef CUR_PATH_SEPARATOR_CHR
267
#undef PATH_CCH_ADD_EXTENSION
268
269
#define DEFINE_UNICODE TRUE
270
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
271
#define PATH_CCH_ADD_EXTENSION NativePathCchAddExtensionW
272
#include "include/PathCchAddExtension.c"
273
#undef DEFINE_UNICODE
274
#undef CUR_PATH_SEPARATOR_CHR
275
#undef PATH_CCH_ADD_EXTENSION
276
277
/*
278
 * PathCchAppend
279
 */
280
281
/* Windows-style Paths */
282
283
#define DEFINE_UNICODE FALSE
284
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
285
0
#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR
286
#define PATH_CCH_APPEND PathCchAppendA
287
#include "include/PathCchAppend.c"
288
#undef DEFINE_UNICODE
289
#undef CUR_PATH_SEPARATOR_CHR
290
#undef CUR_PATH_SEPARATOR_STR
291
#undef PATH_CCH_APPEND
292
293
#define DEFINE_UNICODE TRUE
294
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
295
0
#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR_W
296
#define PATH_CCH_APPEND PathCchAppendW
297
#include "include/PathCchAppend.c"
298
#undef DEFINE_UNICODE
299
#undef CUR_PATH_SEPARATOR_CHR
300
#undef CUR_PATH_SEPARATOR_STR
301
#undef PATH_CCH_APPEND
302
303
/* Unix-style Paths */
304
305
#define DEFINE_UNICODE FALSE
306
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
307
0
#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR
308
#define PATH_CCH_APPEND UnixPathCchAppendA
309
#include "include/PathCchAppend.c"
310
#undef DEFINE_UNICODE
311
#undef CUR_PATH_SEPARATOR_CHR
312
#undef CUR_PATH_SEPARATOR_STR
313
#undef PATH_CCH_APPEND
314
315
#define DEFINE_UNICODE TRUE
316
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
317
0
#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR_W
318
#define PATH_CCH_APPEND UnixPathCchAppendW
319
#include "include/PathCchAppend.c"
320
#undef DEFINE_UNICODE
321
#undef CUR_PATH_SEPARATOR_CHR
322
#undef CUR_PATH_SEPARATOR_STR
323
#undef PATH_CCH_APPEND
324
325
/* Native-style Paths */
326
327
#define DEFINE_UNICODE FALSE
328
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
329
0
#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR
330
#define PATH_CCH_APPEND NativePathCchAppendA
331
#include "include/PathCchAppend.c"
332
#undef DEFINE_UNICODE
333
#undef CUR_PATH_SEPARATOR_CHR
334
#undef CUR_PATH_SEPARATOR_STR
335
#undef PATH_CCH_APPEND
336
337
#define DEFINE_UNICODE TRUE
338
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
339
0
#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR_W
340
#define PATH_CCH_APPEND NativePathCchAppendW
341
#include "include/PathCchAppend.c"
342
#undef DEFINE_UNICODE
343
#undef CUR_PATH_SEPARATOR_CHR
344
#undef CUR_PATH_SEPARATOR_STR
345
#undef PATH_CCH_APPEND
346
347
/*
348
 * PathCchAppendEx
349
 */
350
351
HRESULT PathCchAppendExA(PSTR pszPath, size_t cchPath, PCSTR pszMore, unsigned long dwFlags)
352
0
{
353
0
  WLog_ERR(TAG, "not implemented");
354
0
  return E_NOTIMPL;
355
0
}
356
357
HRESULT PathCchAppendExW(PWSTR pszPath, size_t cchPath, PCWSTR pszMore, unsigned long dwFlags)
358
0
{
359
0
  WLog_ERR(TAG, "not implemented");
360
0
  return E_NOTIMPL;
361
0
}
362
363
/*
364
 * PathCchCanonicalize
365
 */
366
367
HRESULT PathCchCanonicalizeA(PSTR pszPathOut, size_t cchPathOut, PCSTR pszPathIn)
368
0
{
369
0
  WLog_ERR(TAG, "not implemented");
370
0
  return E_NOTIMPL;
371
0
}
372
373
HRESULT PathCchCanonicalizeW(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn)
374
0
{
375
0
  WLog_ERR(TAG, "not implemented");
376
0
  return E_NOTIMPL;
377
0
}
378
379
/*
380
 * PathCchCanonicalizeEx
381
 */
382
383
HRESULT PathCchCanonicalizeExA(PSTR pszPathOut, size_t cchPathOut, PCSTR pszPathIn,
384
                               unsigned long dwFlags)
385
0
{
386
0
  WLog_ERR(TAG, "not implemented");
387
0
  return E_NOTIMPL;
388
0
}
389
390
HRESULT PathCchCanonicalizeExW(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn,
391
                               unsigned long dwFlags)
392
0
{
393
0
  WLog_ERR(TAG, "not implemented");
394
0
  return E_NOTIMPL;
395
0
}
396
397
/*
398
 * PathAllocCanonicalize
399
 */
400
401
HRESULT PathAllocCanonicalizeA(PCSTR pszPathIn, unsigned long dwFlags, PSTR* ppszPathOut)
402
0
{
403
0
  WLog_ERR(TAG, "not implemented");
404
0
  return E_NOTIMPL;
405
0
}
406
407
HRESULT PathAllocCanonicalizeW(PCWSTR pszPathIn, unsigned long dwFlags, PWSTR* ppszPathOut)
408
0
{
409
0
  WLog_ERR(TAG, "not implemented");
410
0
  return E_NOTIMPL;
411
0
}
412
413
/*
414
 * PathCchCombine
415
 */
416
417
HRESULT PathCchCombineA(PSTR pszPathOut, size_t cchPathOut, PCSTR pszPathIn, PCSTR pszMore)
418
0
{
419
0
  WLog_ERR(TAG, "not implemented");
420
0
  return E_NOTIMPL;
421
0
}
422
423
HRESULT PathCchCombineW(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn, PCWSTR pszMore)
424
0
{
425
0
  WLog_ERR(TAG, "not implemented");
426
0
  return E_NOTIMPL;
427
0
}
428
429
/*
430
 * PathCchCombineEx
431
 */
432
433
HRESULT PathCchCombineExA(PSTR pszPathOut, size_t cchPathOut, PCSTR pszPathIn, PCSTR pszMore,
434
                          unsigned long dwFlags)
435
0
{
436
0
  WLog_ERR(TAG, "not implemented");
437
0
  return E_NOTIMPL;
438
0
}
439
440
HRESULT PathCchCombineExW(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn, PCWSTR pszMore,
441
                          unsigned long dwFlags)
442
0
{
443
0
  WLog_ERR(TAG, "not implemented");
444
0
  return E_NOTIMPL;
445
0
}
446
447
/*
448
 * PathAllocCombine
449
 */
450
451
/* Windows-style Paths */
452
453
#define DEFINE_UNICODE FALSE
454
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
455
#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR
456
#define PATH_ALLOC_COMBINE PathAllocCombineA
457
#include "include/PathAllocCombine.c"
458
#undef DEFINE_UNICODE
459
#undef CUR_PATH_SEPARATOR_CHR
460
#undef CUR_PATH_SEPARATOR_STR
461
#undef PATH_ALLOC_COMBINE
462
463
#define DEFINE_UNICODE TRUE
464
0
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
465
0
#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR_W
466
#define PATH_ALLOC_COMBINE PathAllocCombineW
467
#include "include/PathAllocCombine.c"
468
#undef DEFINE_UNICODE
469
#undef CUR_PATH_SEPARATOR_CHR
470
#undef CUR_PATH_SEPARATOR_STR
471
#undef PATH_ALLOC_COMBINE
472
473
/* Unix-style Paths */
474
475
#define DEFINE_UNICODE FALSE
476
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
477
#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR
478
#define PATH_ALLOC_COMBINE UnixPathAllocCombineA
479
#include "include/PathAllocCombine.c"
480
#undef DEFINE_UNICODE
481
#undef CUR_PATH_SEPARATOR_CHR
482
#undef CUR_PATH_SEPARATOR_STR
483
#undef PATH_ALLOC_COMBINE
484
485
#define DEFINE_UNICODE TRUE
486
0
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
487
0
#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR_W
488
#define PATH_ALLOC_COMBINE UnixPathAllocCombineW
489
#include "include/PathAllocCombine.c"
490
#undef DEFINE_UNICODE
491
#undef CUR_PATH_SEPARATOR_CHR
492
#undef CUR_PATH_SEPARATOR_STR
493
#undef PATH_ALLOC_COMBINE
494
495
/* Native-style Paths */
496
497
#define DEFINE_UNICODE FALSE
498
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
499
#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR
500
#define PATH_ALLOC_COMBINE NativePathAllocCombineA
501
#include "include/PathAllocCombine.c"
502
#undef DEFINE_UNICODE
503
#undef CUR_PATH_SEPARATOR_CHR
504
#undef CUR_PATH_SEPARATOR_STR
505
#undef PATH_ALLOC_COMBINE
506
507
#define DEFINE_UNICODE TRUE
508
0
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
509
0
#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR_W
510
#define PATH_ALLOC_COMBINE NativePathAllocCombineW
511
#include "include/PathAllocCombine.c"
512
#undef DEFINE_UNICODE
513
#undef CUR_PATH_SEPARATOR_CHR
514
#undef CUR_PATH_SEPARATOR_STR
515
#undef PATH_ALLOC_COMBINE
516
517
/**
518
 * PathCchFindExtension
519
 */
520
521
HRESULT PathCchFindExtensionA(PCSTR pszPath, size_t cchPath, PCSTR* ppszExt)
522
0
{
523
0
  const char* p = (const char*)pszPath;
524
525
0
  if (!pszPath || !cchPath || !ppszExt)
526
0
    return E_INVALIDARG;
527
528
  /* find end of string */
529
530
0
  while (*p && --cchPath)
531
0
  {
532
0
    p++;
533
0
  }
534
535
0
  if (*p)
536
0
  {
537
    /* pszPath is not null terminated within the cchPath range */
538
0
    return E_INVALIDARG;
539
0
  }
540
541
  /* If no extension is found, ppszExt must point to the string's terminating null */
542
0
  *ppszExt = p;
543
544
  /* search backwards for '.' */
545
546
0
  while (p > pszPath)
547
0
  {
548
0
    if (*p == '.')
549
0
    {
550
0
      *ppszExt = (PCSTR)p;
551
0
      break;
552
0
    }
553
554
0
    if ((*p == '\\') || (*p == '/') || (*p == ':'))
555
0
      break;
556
557
0
    p--;
558
0
  }
559
560
0
  return S_OK;
561
0
}
562
563
HRESULT PathCchFindExtensionW(PCWSTR pszPath, size_t cchPath, PCWSTR* ppszExt)
564
0
{
565
0
  WLog_ERR(TAG, "not implemented");
566
0
  return E_NOTIMPL;
567
0
}
568
569
/**
570
 * PathCchRenameExtension
571
 */
572
573
HRESULT PathCchRenameExtensionA(PSTR pszPath, size_t cchPath, PCSTR pszExt)
574
0
{
575
0
  WLog_ERR(TAG, "not implemented");
576
0
  return E_NOTIMPL;
577
0
}
578
579
HRESULT PathCchRenameExtensionW(PWSTR pszPath, size_t cchPath, PCWSTR pszExt)
580
0
{
581
0
  WLog_ERR(TAG, "not implemented");
582
0
  return E_NOTIMPL;
583
0
}
584
585
/**
586
 * PathCchRemoveExtension
587
 */
588
589
HRESULT PathCchRemoveExtensionA(PSTR pszPath, size_t cchPath)
590
0
{
591
0
  WLog_ERR(TAG, "not implemented");
592
0
  return E_NOTIMPL;
593
0
}
594
595
HRESULT PathCchRemoveExtensionW(PWSTR pszPath, size_t cchPath)
596
0
{
597
0
  WLog_ERR(TAG, "not implemented");
598
0
  return E_NOTIMPL;
599
0
}
600
601
/**
602
 * PathCchIsRoot
603
 */
604
605
BOOL PathCchIsRootA(PCSTR pszPath)
606
0
{
607
0
  WLog_ERR(TAG, "not implemented");
608
0
  return FALSE;
609
0
}
610
611
BOOL PathCchIsRootW(PCWSTR pszPath)
612
0
{
613
0
  WLog_ERR(TAG, "not implemented");
614
0
  return FALSE;
615
0
}
616
617
/**
618
 * PathIsUNCEx
619
 */
620
621
BOOL PathIsUNCExA(PCSTR pszPath, PCSTR* ppszServer)
622
0
{
623
0
  if (!pszPath)
624
0
    return FALSE;
625
626
0
  if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
627
0
  {
628
0
    *ppszServer = &pszPath[2];
629
0
    return TRUE;
630
0
  }
631
632
0
  return FALSE;
633
0
}
634
635
BOOL PathIsUNCExW(PCWSTR pszPath, PCWSTR* ppszServer)
636
0
{
637
0
  if (!pszPath)
638
0
    return FALSE;
639
640
0
  if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
641
0
  {
642
0
    *ppszServer = &pszPath[2];
643
0
    return TRUE;
644
0
  }
645
646
0
  return FALSE;
647
0
}
648
649
/**
650
 * PathCchSkipRoot
651
 */
652
653
HRESULT PathCchSkipRootA(PCSTR pszPath, PCSTR* ppszRootEnd)
654
0
{
655
0
  WLog_ERR(TAG, "not implemented");
656
0
  return E_NOTIMPL;
657
0
}
658
659
HRESULT PathCchSkipRootW(PCWSTR pszPath, PCWSTR* ppszRootEnd)
660
0
{
661
0
  WLog_ERR(TAG, "not implemented");
662
0
  return E_NOTIMPL;
663
0
}
664
665
/**
666
 * PathCchStripToRoot
667
 */
668
669
HRESULT PathCchStripToRootA(PSTR pszPath, size_t cchPath)
670
0
{
671
0
  WLog_ERR(TAG, "not implemented");
672
0
  return E_NOTIMPL;
673
0
}
674
675
HRESULT PathCchStripToRootW(PWSTR pszPath, size_t cchPath)
676
0
{
677
0
  WLog_ERR(TAG, "not implemented");
678
0
  return E_NOTIMPL;
679
0
}
680
681
/**
682
 * PathCchStripPrefix
683
 */
684
685
HRESULT PathCchStripPrefixA(PSTR pszPath, size_t cchPath)
686
0
{
687
0
  BOOL hasPrefix;
688
689
0
  if (!pszPath)
690
0
    return E_INVALIDARG;
691
692
0
  if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
693
0
    return E_INVALIDARG;
694
695
0
  hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
696
0
               (pszPath[3] == '\\'))
697
0
                  ? TRUE
698
0
                  : FALSE;
699
700
0
  if (hasPrefix)
701
0
  {
702
0
    if (cchPath < 6)
703
0
      return S_FALSE;
704
705
0
    if (IsCharAlpha(pszPath[4]) && (pszPath[5] == ':')) /* like C: */
706
0
    {
707
0
      memmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4);
708
      /* since the passed pszPath must not necessarily be null terminated
709
       * and we always have enough space after the strip we can always
710
       * ensure the null termination of the stripped result
711
       */
712
0
      pszPath[cchPath - 4] = 0;
713
0
      return S_OK;
714
0
    }
715
0
  }
716
717
0
  return S_FALSE;
718
0
}
719
720
HRESULT PathCchStripPrefixW(PWSTR pszPath, size_t cchPath)
721
0
{
722
0
  BOOL hasPrefix;
723
724
0
  if (!pszPath)
725
0
    return E_INVALIDARG;
726
727
0
  if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
728
0
    return E_INVALIDARG;
729
730
0
  hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
731
0
               (pszPath[3] == '\\'))
732
0
                  ? TRUE
733
0
                  : FALSE;
734
735
0
  if (hasPrefix)
736
0
  {
737
0
    int rc;
738
0
    if (cchPath < 6)
739
0
      return S_FALSE;
740
741
0
    rc = (_wcslen(&pszPath[4]) + 1);
742
0
    if ((rc < 0) || ((INT64)cchPath < rc))
743
0
      return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
744
745
0
    if (IsCharAlphaW(pszPath[4]) && (pszPath[5] == L':')) /* like C: */
746
0
    {
747
0
      wmemmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4);
748
      /* since the passed pszPath must not necessarily be null terminated
749
       * and we always have enough space after the strip we can always
750
       * ensure the null termination of the stripped result
751
       */
752
0
      pszPath[cchPath - 4] = 0;
753
0
      return S_OK;
754
0
    }
755
0
  }
756
757
0
  return S_FALSE;
758
0
}
759
760
/**
761
 * PathCchRemoveFileSpec
762
 */
763
764
HRESULT PathCchRemoveFileSpecA(PSTR pszPath, size_t cchPath)
765
0
{
766
0
  WLog_ERR(TAG, "not implemented");
767
0
  return E_NOTIMPL;
768
0
}
769
770
HRESULT PathCchRemoveFileSpecW(PWSTR pszPath, size_t cchPath)
771
0
{
772
0
  WLog_ERR(TAG, "not implemented");
773
0
  return E_NOTIMPL;
774
0
}
775
776
/*
777
 * Path Portability Functions
778
 */
779
780
/**
781
 * PathCchConvertStyle
782
 */
783
784
HRESULT PathCchConvertStyleA(PSTR pszPath, size_t cchPath, unsigned long dwFlags)
785
0
{
786
0
  size_t index;
787
788
0
  if (dwFlags == PATH_STYLE_WINDOWS)
789
0
  {
790
0
    for (index = 0; index < cchPath; index++)
791
0
    {
792
0
      if (pszPath[index] == PATH_SLASH_CHR)
793
0
        pszPath[index] = PATH_BACKSLASH_CHR;
794
0
    }
795
0
  }
796
0
  else if (dwFlags == PATH_STYLE_UNIX)
797
0
  {
798
0
    for (index = 0; index < cchPath; index++)
799
0
    {
800
0
      if (pszPath[index] == PATH_BACKSLASH_CHR)
801
0
        pszPath[index] = PATH_SLASH_CHR;
802
0
    }
803
0
  }
804
0
  else if (dwFlags == PATH_STYLE_NATIVE)
805
0
  {
806
#if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR)
807
    /* Unix-style to Windows-style */
808
809
    for (index = 0; index < cchPath; index++)
810
    {
811
      if (pszPath[index] == PATH_SLASH_CHR)
812
        pszPath[index] = PATH_BACKSLASH_CHR;
813
    }
814
#elif (PATH_SEPARATOR_CHR == PATH_SLASH_CHR)
815
    /* Windows-style to Unix-style */
816
817
0
    for (index = 0; index < cchPath; index++)
818
0
    {
819
0
      if (pszPath[index] == PATH_BACKSLASH_CHR)
820
0
        pszPath[index] = PATH_SLASH_CHR;
821
0
    }
822
#else
823
    /* Unexpected error */
824
    return E_FAIL;
825
#endif
826
0
  }
827
0
  else
828
0
  {
829
    /* Gangnam style? */
830
0
    return E_FAIL;
831
0
  }
832
833
0
  return S_OK;
834
0
}
835
836
HRESULT PathCchConvertStyleW(PWSTR pszPath, size_t cchPath, unsigned long dwFlags)
837
0
{
838
0
  size_t index;
839
840
0
  if (dwFlags == PATH_STYLE_WINDOWS)
841
0
  {
842
0
    for (index = 0; index < cchPath; index++)
843
0
    {
844
0
      if (pszPath[index] == PATH_SLASH_CHR)
845
0
        pszPath[index] = PATH_BACKSLASH_CHR;
846
0
    }
847
0
  }
848
0
  else if (dwFlags == PATH_STYLE_UNIX)
849
0
  {
850
0
    for (index = 0; index < cchPath; index++)
851
0
    {
852
0
      if (pszPath[index] == PATH_BACKSLASH_CHR)
853
0
        pszPath[index] = PATH_SLASH_CHR;
854
0
    }
855
0
  }
856
0
  else if (dwFlags == PATH_STYLE_NATIVE)
857
0
  {
858
#if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR)
859
    {
860
      /* Unix-style to Windows-style */
861
862
      for (index = 0; index < cchPath; index++)
863
      {
864
        if (pszPath[index] == PATH_SLASH_CHR)
865
          pszPath[index] = PATH_BACKSLASH_CHR;
866
      }
867
    }
868
#elif (PATH_SEPARATOR_CHR == PATH_SLASH_CHR)
869
0
    {
870
      /* Windows-style to Unix-style */
871
872
0
      for (index = 0; index < cchPath; index++)
873
0
      {
874
0
        if (pszPath[index] == PATH_BACKSLASH_CHR)
875
0
          pszPath[index] = PATH_SLASH_CHR;
876
0
      }
877
0
    }
878
#else
879
    {
880
      /* Unexpected error */
881
      return E_FAIL;
882
    }
883
#endif
884
0
  }
885
0
  else
886
0
  {
887
    /* Gangnam style? */
888
0
    return E_FAIL;
889
0
  }
890
891
0
  return S_OK;
892
0
}
893
894
/**
895
 * PathGetSeparator
896
 */
897
898
char PathGetSeparatorA(unsigned long dwFlags)
899
0
{
900
0
  char separator = PATH_SEPARATOR_CHR;
901
902
0
  if (!dwFlags)
903
0
    dwFlags = PATH_STYLE_NATIVE;
904
905
0
  if (dwFlags == PATH_STYLE_WINDOWS)
906
0
    separator = PATH_SEPARATOR_CHR;
907
0
  else if (dwFlags == PATH_STYLE_UNIX)
908
0
    separator = PATH_SEPARATOR_CHR;
909
0
  else if (dwFlags == PATH_STYLE_NATIVE)
910
0
    separator = PATH_SEPARATOR_CHR;
911
912
0
  return separator;
913
0
}
914
915
WCHAR PathGetSeparatorW(unsigned long dwFlags)
916
0
{
917
0
  WCHAR separator = PATH_SEPARATOR_CHR;
918
919
0
  if (!dwFlags)
920
0
    dwFlags = PATH_STYLE_NATIVE;
921
922
0
  if (dwFlags == PATH_STYLE_WINDOWS)
923
0
    separator = PATH_SEPARATOR_CHR;
924
0
  else if (dwFlags == PATH_STYLE_UNIX)
925
0
    separator = PATH_SEPARATOR_CHR;
926
0
  else if (dwFlags == PATH_STYLE_NATIVE)
927
0
    separator = PATH_SEPARATOR_CHR;
928
929
0
  return separator;
930
0
}
931
932
/**
933
 * PathGetSharedLibraryExtension
934
 */
935
936
static const CHAR SharedLibraryExtensionDllA[] = "dll";
937
static const CHAR SharedLibraryExtensionSoA[] = "so";
938
static const CHAR SharedLibraryExtensionDylibA[] = "dylib";
939
940
static const WCHAR SharedLibraryExtensionDllW[] = { 'd', 'l', 'l', '\0' };
941
static const WCHAR SharedLibraryExtensionSoW[] = { 's', 'o', '\0' };
942
static const WCHAR SharedLibraryExtensionDylibW[] = { 'd', 'y', 'l', 'i', 'b', '\0' };
943
944
static const CHAR SharedLibraryExtensionDotDllA[] = ".dll";
945
static const CHAR SharedLibraryExtensionDotSoA[] = ".so";
946
static const CHAR SharedLibraryExtensionDotDylibA[] = ".dylib";
947
948
static const WCHAR SharedLibraryExtensionDotDllW[] = { '.', 'd', 'l', 'l', '\0' };
949
static const WCHAR SharedLibraryExtensionDotSoW[] = { '.', 's', 'o', '\0' };
950
static const WCHAR SharedLibraryExtensionDotDylibW[] = { '.', 'd', 'y', 'l', 'i', 'b', '\0' };
951
952
PCSTR PathGetSharedLibraryExtensionA(unsigned long dwFlags)
953
0
{
954
0
  if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
955
0
  {
956
0
    if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
957
0
    {
958
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
959
0
        return SharedLibraryExtensionDotDllA;
960
961
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
962
0
        return SharedLibraryExtensionDotSoA;
963
964
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
965
0
        return SharedLibraryExtensionDotDylibA;
966
0
    }
967
0
    else
968
0
    {
969
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
970
0
        return SharedLibraryExtensionDllA;
971
972
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
973
0
        return SharedLibraryExtensionSoA;
974
975
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
976
0
        return SharedLibraryExtensionDylibA;
977
0
    }
978
0
  }
979
980
0
  if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
981
0
  {
982
#ifdef _WIN32
983
    return SharedLibraryExtensionDotDllA;
984
#elif defined(__APPLE__)
985
    if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
986
      return SharedLibraryExtensionDotSoA;
987
    else
988
      return SharedLibraryExtensionDotDylibA;
989
#else
990
0
    return SharedLibraryExtensionDotSoA;
991
0
#endif
992
0
  }
993
0
  else
994
0
  {
995
#ifdef _WIN32
996
    return SharedLibraryExtensionDllA;
997
#elif defined(__APPLE__)
998
    if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
999
      return SharedLibraryExtensionSoA;
1000
    else
1001
      return SharedLibraryExtensionDylibA;
1002
#else
1003
0
    return SharedLibraryExtensionSoA;
1004
0
#endif
1005
0
  }
1006
1007
0
  return NULL;
1008
0
}
1009
1010
PCWSTR PathGetSharedLibraryExtensionW(unsigned long dwFlags)
1011
0
{
1012
0
  if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
1013
0
  {
1014
0
    if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1015
0
    {
1016
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1017
0
        return SharedLibraryExtensionDotDllW;
1018
1019
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1020
0
        return SharedLibraryExtensionDotSoW;
1021
1022
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1023
0
        return SharedLibraryExtensionDotDylibW;
1024
0
    }
1025
0
    else
1026
0
    {
1027
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1028
0
        return SharedLibraryExtensionDllW;
1029
1030
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1031
0
        return SharedLibraryExtensionSoW;
1032
1033
0
      if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1034
0
        return SharedLibraryExtensionDylibW;
1035
0
    }
1036
0
  }
1037
1038
0
  if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1039
0
  {
1040
#ifdef _WIN32
1041
    return SharedLibraryExtensionDotDllW;
1042
#elif defined(__APPLE__)
1043
    if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1044
      return SharedLibraryExtensionDotSoW;
1045
    else
1046
      return SharedLibraryExtensionDotDylibW;
1047
#else
1048
0
    return SharedLibraryExtensionDotSoW;
1049
0
#endif
1050
0
  }
1051
0
  else
1052
0
  {
1053
#ifdef _WIN32
1054
    return SharedLibraryExtensionDllW;
1055
#elif defined(__APPLE__)
1056
    if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1057
      return SharedLibraryExtensionSoW;
1058
    else
1059
      return SharedLibraryExtensionDylibW;
1060
#else
1061
0
    return SharedLibraryExtensionSoW;
1062
0
#endif
1063
0
  }
1064
1065
0
  return NULL;
1066
0
}
1067
1068
const char* GetKnownPathIdString(int id)
1069
0
{
1070
0
  switch (id)
1071
0
  {
1072
0
    case KNOWN_PATH_HOME:
1073
0
      return "KNOWN_PATH_HOME";
1074
0
    case KNOWN_PATH_TEMP:
1075
0
      return "KNOWN_PATH_TEMP";
1076
0
    case KNOWN_PATH_XDG_DATA_HOME:
1077
0
      return "KNOWN_PATH_XDG_DATA_HOME";
1078
0
    case KNOWN_PATH_XDG_CONFIG_HOME:
1079
0
      return "KNOWN_PATH_XDG_CONFIG_HOME";
1080
0
    case KNOWN_PATH_XDG_CACHE_HOME:
1081
0
      return "KNOWN_PATH_XDG_CACHE_HOME";
1082
0
    case KNOWN_PATH_XDG_RUNTIME_DIR:
1083
0
      return "KNOWN_PATH_XDG_RUNTIME_DIR";
1084
0
    default:
1085
0
      return "KNOWN_PATH_UNKNOWN_ID";
1086
0
  }
1087
0
}
1088
1089
static WCHAR* concat(const WCHAR* path, size_t pathlen, const WCHAR* name, size_t namelen)
1090
0
{
1091
0
  WCHAR* str = calloc(pathlen + namelen + 1, sizeof(WCHAR));
1092
0
  if (!str)
1093
0
    return NULL;
1094
1095
0
  _wcsncat(str, path, pathlen);
1096
0
  _wcsncat(str, name, namelen);
1097
0
  return str;
1098
0
}
1099
1100
BOOL winpr_RemoveDirectory_RecursiveA(LPCSTR lpPathName)
1101
0
{
1102
0
  WCHAR* name = ConvertUtf8ToWCharAlloc(lpPathName, NULL);
1103
0
  if (!name)
1104
0
    return FALSE;
1105
0
  const BOOL rc = winpr_RemoveDirectory_RecursiveW(name);
1106
0
  free(name);
1107
0
  return rc;
1108
0
}
1109
1110
BOOL winpr_RemoveDirectory_RecursiveW(LPCWSTR lpPathName)
1111
0
{
1112
0
  BOOL ret = FALSE;
1113
1114
0
  if (!lpPathName)
1115
0
    return FALSE;
1116
1117
0
  const size_t pathnamelen = _wcslen(lpPathName);
1118
0
  const size_t path_slash_len = pathnamelen + 3;
1119
0
  WCHAR* path_slash = calloc(pathnamelen + 4, sizeof(WCHAR));
1120
0
  if (!path_slash)
1121
0
    return FALSE;
1122
0
  _wcsncat(path_slash, lpPathName, pathnamelen);
1123
1124
0
  const WCHAR star[] = { '*', '\0' };
1125
0
  const HRESULT hr = NativePathCchAppendW(path_slash, path_slash_len, star);
1126
0
  if (FAILED(hr))
1127
0
    goto fail;
1128
1129
0
  WIN32_FIND_DATAW findFileData = { 0 };
1130
0
  HANDLE dir = FindFirstFileW(path_slash, &findFileData);
1131
1132
0
  if (dir == INVALID_HANDLE_VALUE)
1133
0
    goto fail;
1134
1135
0
  ret = TRUE;
1136
0
  path_slash[path_slash_len - 1] = '\0'; /* remove trailing '*' */
1137
0
  do
1138
0
  {
1139
0
    const size_t len = _wcsnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName));
1140
1141
0
    if ((len == 1 && findFileData.cFileName[0] == '.') ||
1142
0
        (len == 2 && findFileData.cFileName[0] == '.' && findFileData.cFileName[1] == '.'))
1143
0
    {
1144
0
      continue;
1145
0
    }
1146
1147
0
    WCHAR* fullpath = concat(path_slash, path_slash_len, findFileData.cFileName, len);
1148
0
    if (!fullpath)
1149
0
      goto fail;
1150
1151
0
    if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1152
0
      ret = winpr_RemoveDirectory_RecursiveW(fullpath);
1153
0
    else
1154
0
      ret = DeleteFileW(fullpath);
1155
1156
0
    free(fullpath);
1157
1158
0
    if (!ret)
1159
0
      break;
1160
0
  } while (ret && FindNextFileW(dir, &findFileData) != 0);
1161
1162
0
  FindClose(dir);
1163
1164
0
  if (ret)
1165
0
  {
1166
0
    if (!RemoveDirectoryW(lpPathName))
1167
0
      ret = FALSE;
1168
0
  }
1169
1170
0
fail:
1171
0
  free(path_slash);
1172
0
  return ret;
1173
0
}