FreeRDP
Loading...
Searching...
No Matches
path.c
1
20#include <winpr/config.h>
21#include <winpr/version.h>
22#include <winpr/build-config.h>
23
24#include <winpr/crt.h>
25#include <winpr/tchar.h>
26
27#include <winpr/path.h>
28#include <winpr/file.h>
29
30#include "../utils.h"
31
32#if defined(WITH_CWALK)
33#include <cwalk.h>
34#endif
35
36static const char PATH_SLASH_CHR = '/';
37static const char PATH_SLASH_STR[] = "/";
38
39static const char PATH_BACKSLASH_CHR = '\\';
40static const char PATH_BACKSLASH_STR[] = "\\";
41
42#ifdef _WIN32
43static const WCHAR PATH_SLASH_CHR_W = L'/';
44static const WCHAR PATH_BACKSLASH_CHR_W = L'\\';
45static const WCHAR PATH_SLASH_STR_W[] = L"/";
46static const WCHAR PATH_BACKSLASH_STR_W[] = L"\\";
47#else
48#if defined(__BIG_ENDIAN__)
49static const WCHAR PATH_SLASH_CHR_W = 0x2f00;
50static const WCHAR PATH_BACKSLASH_CHR_W = 0x5c00;
51static const WCHAR PATH_SLASH_STR_W[] = { 0x2f00, '\0' };
52static const WCHAR PATH_BACKSLASH_STR_W[] = { 0x5c00, '\0' };
53#else
54static const WCHAR PATH_SLASH_CHR_W = '/';
55static const WCHAR PATH_BACKSLASH_CHR_W = '\\';
56static const WCHAR PATH_SLASH_STR_W[] = { '/', '\0' };
57static const WCHAR PATH_BACKSLASH_STR_W[] = { '\\', '\0' };
58#endif
59#endif
60
61#ifdef _WIN32
62#define PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
63#define PATH_SEPARATOR_STR PATH_BACKSLASH_STR
64#define PATH_SEPARATOR_CHR_W PATH_BACKSLASH_CHR_W
65#define PATH_SEPARATOR_STR_W PATH_BACKSLASH_STR_W
66#else
67#define PATH_SEPARATOR_CHR PATH_SLASH_CHR
68#define PATH_SEPARATOR_STR PATH_SLASH_STR
69#define PATH_SEPARATOR_CHR_W PATH_SLASH_CHR_W
70#define PATH_SEPARATOR_STR_W PATH_SLASH_STR_W
71#endif
72
73#include "../log.h"
74#define TAG WINPR_TAG("path")
75
76/*
77 * PathCchAddBackslash
78 */
79
80/* Windows-style Paths */
81
82#define DEFINE_UNICODE FALSE
83#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
84#define PATH_CCH_ADD_SEPARATOR PathCchAddBackslashA
85#include "include/PathCchAddSeparator.h"
86#undef DEFINE_UNICODE
87#undef CUR_PATH_SEPARATOR_CHR
88#undef PATH_CCH_ADD_SEPARATOR
89
90#define DEFINE_UNICODE TRUE
91#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
92#define PATH_CCH_ADD_SEPARATOR PathCchAddBackslashW
93#include "include/PathCchAddSeparator.h"
94#undef DEFINE_UNICODE
95#undef CUR_PATH_SEPARATOR_CHR
96#undef PATH_CCH_ADD_SEPARATOR
97
98/* Unix-style Paths */
99
100#define DEFINE_UNICODE FALSE
101#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
102#define PATH_CCH_ADD_SEPARATOR PathCchAddSlashA
103#include "include/PathCchAddSeparator.h"
104#undef DEFINE_UNICODE
105#undef CUR_PATH_SEPARATOR_CHR
106#undef PATH_CCH_ADD_SEPARATOR
107
108#define DEFINE_UNICODE TRUE
109#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
110#define PATH_CCH_ADD_SEPARATOR PathCchAddSlashW
111#include "include/PathCchAddSeparator.h"
112#undef DEFINE_UNICODE
113#undef CUR_PATH_SEPARATOR_CHR
114#undef PATH_CCH_ADD_SEPARATOR
115
116/* Native-style Paths */
117
118#define DEFINE_UNICODE FALSE
119#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
120#define PATH_CCH_ADD_SEPARATOR PathCchAddSeparatorA
121#include "include/PathCchAddSeparator.h"
122#undef DEFINE_UNICODE
123#undef CUR_PATH_SEPARATOR_CHR
124#undef PATH_CCH_ADD_SEPARATOR
125
126#define DEFINE_UNICODE TRUE
127#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
128#define PATH_CCH_ADD_SEPARATOR PathCchAddSeparatorW
129#include "include/PathCchAddSeparator.h"
130#undef DEFINE_UNICODE
131#undef CUR_PATH_SEPARATOR_CHR
132#undef PATH_CCH_ADD_SEPARATOR
133
134/*
135 * PathCchRemoveBackslash
136 */
137
138HRESULT PathCchRemoveBackslashA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
139{
140 WLog_ERR(TAG, "not implemented");
141 return E_NOTIMPL;
142}
143
144HRESULT PathCchRemoveBackslashW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
145{
146 WLog_ERR(TAG, "not implemented");
147 return E_NOTIMPL;
148}
149
150/*
151 * PathCchAddBackslashEx
152 */
153
154/* Windows-style Paths */
155
156#define DEFINE_UNICODE FALSE
157#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
158#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddBackslashExA
159#include "include/PathCchAddSeparatorEx.h"
160#undef DEFINE_UNICODE
161#undef CUR_PATH_SEPARATOR_CHR
162#undef PATH_CCH_ADD_SEPARATOR_EX
163
164#define DEFINE_UNICODE TRUE
165#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
166#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddBackslashExW
167#include "include/PathCchAddSeparatorEx.h"
168#undef DEFINE_UNICODE
169#undef CUR_PATH_SEPARATOR_CHR
170#undef PATH_CCH_ADD_SEPARATOR_EX
171
172/* Unix-style Paths */
173
174#define DEFINE_UNICODE FALSE
175#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
176#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSlashExA
177#include "include/PathCchAddSeparatorEx.h"
178#undef DEFINE_UNICODE
179#undef CUR_PATH_SEPARATOR_CHR
180#undef PATH_CCH_ADD_SEPARATOR_EX
181
182#define DEFINE_UNICODE TRUE
183#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
184#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSlashExW
185#include "include/PathCchAddSeparatorEx.h"
186#undef DEFINE_UNICODE
187#undef CUR_PATH_SEPARATOR_CHR
188#undef PATH_CCH_ADD_SEPARATOR_EX
189
190/* Native-style Paths */
191
192#define DEFINE_UNICODE FALSE
193#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
194#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSeparatorExA
195#include "include/PathCchAddSeparatorEx.h"
196#undef DEFINE_UNICODE
197#undef CUR_PATH_SEPARATOR_CHR
198#undef PATH_CCH_ADD_SEPARATOR_EX
199
200#define DEFINE_UNICODE TRUE
201#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
202#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSeparatorExW
203#include "include/PathCchAddSeparatorEx.h"
204#undef DEFINE_UNICODE
205#undef CUR_PATH_SEPARATOR_CHR
206#undef PATH_CCH_ADD_SEPARATOR_EX
207
208HRESULT PathCchRemoveBackslashExA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
209 WINPR_ATTR_UNUSED PSTR* ppszEnd,
210 WINPR_ATTR_UNUSED size_t* pcchRemaining)
211{
212 WLog_ERR(TAG, "not implemented");
213 return E_NOTIMPL;
214}
215
216HRESULT PathCchRemoveBackslashExW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
217 WINPR_ATTR_UNUSED PWSTR* ppszEnd,
218 WINPR_ATTR_UNUSED size_t* pcchRemaining)
219{
220 WLog_ERR(TAG, "not implemented");
221 return E_NOTIMPL;
222}
223
224/*
225 * PathCchAddExtension
226 */
227
228/* Windows-style Paths */
229
230#define DEFINE_UNICODE FALSE
231#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
232#define PATH_CCH_ADD_EXTENSION PathCchAddExtensionA
233#include "include/PathCchAddExtension.h"
234#undef DEFINE_UNICODE
235#undef CUR_PATH_SEPARATOR_CHR
236#undef PATH_CCH_ADD_EXTENSION
237
238#define DEFINE_UNICODE TRUE
239#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
240#define PATH_CCH_ADD_EXTENSION PathCchAddExtensionW
241#include "include/PathCchAddExtension.h"
242#undef DEFINE_UNICODE
243#undef CUR_PATH_SEPARATOR_CHR
244#undef PATH_CCH_ADD_EXTENSION
245
246/* Unix-style Paths */
247
248#define DEFINE_UNICODE FALSE
249#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
250#define PATH_CCH_ADD_EXTENSION UnixPathCchAddExtensionA
251#include "include/PathCchAddExtension.h"
252#undef DEFINE_UNICODE
253#undef CUR_PATH_SEPARATOR_CHR
254#undef PATH_CCH_ADD_EXTENSION
255
256#define DEFINE_UNICODE TRUE
257#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
258#define PATH_CCH_ADD_EXTENSION UnixPathCchAddExtensionW
259#include "include/PathCchAddExtension.h"
260#undef DEFINE_UNICODE
261#undef CUR_PATH_SEPARATOR_CHR
262#undef PATH_CCH_ADD_EXTENSION
263
264/* Native-style Paths */
265
266#define DEFINE_UNICODE FALSE
267#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
268#define PATH_CCH_ADD_EXTENSION NativePathCchAddExtensionA
269#include "include/PathCchAddExtension.h"
270#undef DEFINE_UNICODE
271#undef CUR_PATH_SEPARATOR_CHR
272#undef PATH_CCH_ADD_EXTENSION
273
274#define DEFINE_UNICODE TRUE
275#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
276#define PATH_CCH_ADD_EXTENSION NativePathCchAddExtensionW
277#include "include/PathCchAddExtension.h"
278#undef DEFINE_UNICODE
279#undef CUR_PATH_SEPARATOR_CHR
280#undef PATH_CCH_ADD_EXTENSION
281
282/*
283 * PathCchAppend
284 */
285
286/* Windows-style Paths */
287
288#define DEFINE_UNICODE FALSE
289#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
290#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR
291#define PATH_CCH_APPEND PathCchAppendA
292#include "include/PathCchAppend.h"
293#undef DEFINE_UNICODE
294#undef CUR_PATH_SEPARATOR_CHR
295#undef CUR_PATH_SEPARATOR_STR
296#undef PATH_CCH_APPEND
297
298#define DEFINE_UNICODE TRUE
299#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
300#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR_W
301#define PATH_CCH_APPEND PathCchAppendW
302#include "include/PathCchAppend.h"
303#undef DEFINE_UNICODE
304#undef CUR_PATH_SEPARATOR_CHR
305#undef CUR_PATH_SEPARATOR_STR
306#undef PATH_CCH_APPEND
307
308/* Unix-style Paths */
309
310#define DEFINE_UNICODE FALSE
311#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
312#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR
313#define PATH_CCH_APPEND UnixPathCchAppendA
314#include "include/PathCchAppend.h"
315#undef DEFINE_UNICODE
316#undef CUR_PATH_SEPARATOR_CHR
317#undef CUR_PATH_SEPARATOR_STR
318#undef PATH_CCH_APPEND
319
320#define DEFINE_UNICODE TRUE
321#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
322#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR_W
323#define PATH_CCH_APPEND UnixPathCchAppendW
324#include "include/PathCchAppend.h"
325#undef DEFINE_UNICODE
326#undef CUR_PATH_SEPARATOR_CHR
327#undef CUR_PATH_SEPARATOR_STR
328#undef PATH_CCH_APPEND
329
330/* Native-style Paths */
331
332#define DEFINE_UNICODE FALSE
333#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
334#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR
335#define PATH_CCH_APPEND NativePathCchAppendA
336#include "include/PathCchAppend.h"
337#undef DEFINE_UNICODE
338#undef CUR_PATH_SEPARATOR_CHR
339#undef CUR_PATH_SEPARATOR_STR
340#undef PATH_CCH_APPEND
341
342#define DEFINE_UNICODE TRUE
343#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
344#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR_W
345#define PATH_CCH_APPEND NativePathCchAppendW
346#include "include/PathCchAppend.h"
347#undef DEFINE_UNICODE
348#undef CUR_PATH_SEPARATOR_CHR
349#undef CUR_PATH_SEPARATOR_STR
350#undef PATH_CCH_APPEND
351
352/*
353 * PathCchAppendEx
354 */
355
356HRESULT PathCchAppendExA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
357 WINPR_ATTR_UNUSED PCSTR pszMore, WINPR_ATTR_UNUSED unsigned long dwFlags)
358{
359 WLog_ERR(TAG, "not implemented");
360 return E_NOTIMPL;
361}
362
363HRESULT PathCchAppendExW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
364 WINPR_ATTR_UNUSED PCWSTR pszMore, WINPR_ATTR_UNUSED unsigned long dwFlags)
365{
366 WLog_ERR(TAG, "not implemented");
367 return E_NOTIMPL;
368}
369
370#if !defined(_WIN32)
371
372#if !defined(WITH_CWALK)
373static void replace(char* str, size_t slen, const char* pattern)
374{
375 const size_t len = strlen(pattern);
376 while (TRUE)
377 {
378 char* cur = strstr(str, pattern);
379 if (!cur)
380 return;
381
382 const char* src = &cur[len];
383 /* Ensure terminating '\0' is moved as well */
384 const size_t rem = strnlen(src, slen) + 1;
385 memmove(&cur[1], src, rem);
386 }
387}
388
389WINPR_ATTR_NODISCARD
390static BOOL replace_dotdot(char* str, size_t slen)
391{
392 const char pattern[] = "/../";
393 const size_t len = strlen(pattern);
394 while (TRUE)
395 {
396 char* cur = strstr(str, pattern);
397 if (!cur)
398 return TRUE;
399
400 char* start = cur;
401 const char* end = &cur[len];
402 while (start > str)
403 {
404 start--;
405 if (*start == '/')
406 break;
407 }
408 if (*start != '/')
409 return FALSE;
410
411 /* Ensure terminating '\0' is moved as well */
412 const size_t rem = strnlen(end, slen) + 1;
413 memmove(&start[1], end, rem);
414 }
415}
416
417WINPR_ATTR_NODISCARD
418static BOOL replace_trailing_dotdot(char* str, size_t slen)
419{
420 const size_t len = strnlen(str, slen);
421 if (len < 3)
422 return TRUE;
423
424 if (strcmp(&str[len - 3], "/..") != 0)
425 return TRUE;
426
427 char* start = &str[len - 4];
428 while (start >= str)
429 {
430 if (*start == '/')
431 {
432 start[1] = '\0';
433 return TRUE;
434 }
435 start--;
436 }
437 return FALSE;
438}
439
440#endif
441
442WINPR_ATTR_NODISCARD
443static char* canonicalize(const char* path)
444{
445 WINPR_ASSERT(path);
446
447 const size_t len = strlen(path);
448#if defined(WITH_CWALK)
449 char* str = calloc(len + 1, sizeof(char));
450 if (!str)
451 return nullptr;
452 (void)cwk_path_normalize(path, str, len + 1);
453 return str;
454#else
455 char* str = strndup(path, len);
456 if (!str)
457 return nullptr;
458 replace(str, len, "/./");
459 replace(str, len, "//");
460 if (!replace_dotdot(str, len) || !replace_trailing_dotdot(str, len))
461 {
462 free(str);
463 return nullptr;
464 }
465
466 size_t slen = 0;
467 while ((slen = strnlen(str, len)) > 1)
468 {
469 if ((str[slen - 1] == '.') || (str[slen - 1] == '/'))
470 str[slen - 1] = '\0';
471 else
472 break;
473 }
474
475 return str;
476#endif
477}
478
479/*
480 * PathCchCanonicalize
481 */
482
483HRESULT PathCchCanonicalizeA(PSTR pszPathOut, size_t cchPathOut, PCSTR pszPathIn)
484{
485 char* out = canonicalize(pszPathIn);
486 if (!out)
487 return E_OUTOFMEMORY;
488 const size_t len = strnlen(out, cchPathOut);
489 if (len >= cchPathOut)
490 {
491 free(out);
492 return E_INVALIDARG;
493 }
494 strncpy(pszPathOut, out, cchPathOut);
495 free(out);
496 return S_OK;
497}
498
499HRESULT PathCchCanonicalizeW(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn)
500{
501 if (!pszPathIn)
502 return E_OUTOFMEMORY;
503 char* str = ConvertWCharToUtf8Alloc(pszPathIn, nullptr);
504 if (!str)
505 return E_OUTOFMEMORY;
506
507 char* out = calloc(cchPathOut, sizeof(CHAR));
508 if (!out)
509 {
510 free(str);
511 return E_OUTOFMEMORY;
512 }
513
514 HRESULT hr = PathCchCanonicalizeA(out, cchPathOut, str);
515 free(str);
516 (void)ConvertUtf8NToWChar(out, cchPathOut, pszPathOut, cchPathOut);
517 free(out);
518 return hr;
519}
520
521/*
522 * PathCchCanonicalizeEx
523 */
524
525HRESULT PathCchCanonicalizeExA(WINPR_ATTR_UNUSED PSTR pszPathOut,
526 WINPR_ATTR_UNUSED size_t cchPathOut,
527 WINPR_ATTR_UNUSED PCSTR pszPathIn,
528 WINPR_ATTR_UNUSED unsigned long dwFlags)
529{
530 if (dwFlags != 0)
531 WLog_WARN(TAG, "flags 0x%08lx not implemented", dwFlags);
532 return PathCchCanonicalizeA(pszPathOut, cchPathOut, pszPathIn);
533}
534
535HRESULT PathCchCanonicalizeExW(WINPR_ATTR_UNUSED PWSTR pszPathOut,
536 WINPR_ATTR_UNUSED size_t cchPathOut,
537 WINPR_ATTR_UNUSED PCWSTR pszPathIn,
538 WINPR_ATTR_UNUSED unsigned long dwFlags)
539{
540 if (dwFlags != 0)
541 WLog_WARN(TAG, "flags 0x%08lx not implemented", dwFlags);
542 return PathCchCanonicalizeW(pszPathOut, cchPathOut, pszPathIn);
543}
544
545/*
546 * PathAllocCanonicalize
547 */
548
549HRESULT PathAllocCanonicalizeA(PCSTR pszPathIn, unsigned long dwFlags, PSTR* ppszPathOut)
550{
551 if (!ppszPathOut)
552 return E_INVALIDARG;
553 if (!pszPathIn)
554 return E_OUTOFMEMORY;
555 if (dwFlags != 0)
556 WLog_WARN(TAG, "flags 0x%08lx not implemented", dwFlags);
557 *ppszPathOut = canonicalize(pszPathIn);
558 if (!*ppszPathOut)
559 return E_OUTOFMEMORY;
560 return S_OK;
561}
562
563HRESULT PathAllocCanonicalizeW(PCWSTR pszPathIn, unsigned long dwFlags, PWSTR* ppszPathOut)
564{
565 if (!ppszPathOut)
566 return E_INVALIDARG;
567 if (!pszPathIn)
568 return E_OUTOFMEMORY;
569 char* str = ConvertWCharToUtf8Alloc(pszPathIn, nullptr);
570 if (!str)
571 return E_OUTOFMEMORY;
572
573 char* out = nullptr;
574 HRESULT hr = PathAllocCanonicalizeA(str, dwFlags, &out);
575 if (out)
576 *ppszPathOut = ConvertUtf8ToWCharAlloc(out, nullptr);
577 free(str);
578 free(out);
579 return hr;
580}
581
582#endif
583
584/*
585 * PathCchCombine
586 */
587
588HRESULT PathCchCombineA(WINPR_ATTR_UNUSED PSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
589 WINPR_ATTR_UNUSED PCSTR pszPathIn, WINPR_ATTR_UNUSED PCSTR pszMore)
590{
591 WLog_ERR(TAG, "not implemented");
592 return E_NOTIMPL;
593}
594
595HRESULT PathCchCombineW(WINPR_ATTR_UNUSED PWSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
596 WINPR_ATTR_UNUSED PCWSTR pszPathIn, WINPR_ATTR_UNUSED PCWSTR pszMore)
597{
598 WLog_ERR(TAG, "not implemented");
599 return E_NOTIMPL;
600}
601
602/*
603 * PathCchCombineEx
604 */
605
606HRESULT PathCchCombineExA(WINPR_ATTR_UNUSED PSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
607 WINPR_ATTR_UNUSED PCSTR pszPathIn, WINPR_ATTR_UNUSED PCSTR pszMore,
608 WINPR_ATTR_UNUSED unsigned long dwFlags)
609{
610 WLog_ERR(TAG, "not implemented");
611 return E_NOTIMPL;
612}
613
614HRESULT PathCchCombineExW(WINPR_ATTR_UNUSED PWSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
615 WINPR_ATTR_UNUSED PCWSTR pszPathIn, WINPR_ATTR_UNUSED PCWSTR pszMore,
616 WINPR_ATTR_UNUSED unsigned long dwFlags)
617{
618 WLog_ERR(TAG, "not implemented");
619 return E_NOTIMPL;
620}
621
622/*
623 * PathAllocCombine
624 */
625
626/* Windows-style Paths */
627
628#define DEFINE_UNICODE FALSE
629#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
630#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR
631#define PATH_ALLOC_COMBINE PathAllocCombineA
632#include "include/PathAllocCombine.h"
633#undef DEFINE_UNICODE
634#undef CUR_PATH_SEPARATOR_CHR
635#undef CUR_PATH_SEPARATOR_STR
636#undef PATH_ALLOC_COMBINE
637
638#define DEFINE_UNICODE TRUE
639#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
640#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR_W
641#define PATH_ALLOC_COMBINE PathAllocCombineW
642#include "include/PathAllocCombine.h"
643#undef DEFINE_UNICODE
644#undef CUR_PATH_SEPARATOR_CHR
645#undef CUR_PATH_SEPARATOR_STR
646#undef PATH_ALLOC_COMBINE
647
648/* Unix-style Paths */
649
650#define DEFINE_UNICODE FALSE
651#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
652#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR
653#define PATH_ALLOC_COMBINE UnixPathAllocCombineA
654#include "include/PathAllocCombine.h"
655#undef DEFINE_UNICODE
656#undef CUR_PATH_SEPARATOR_CHR
657#undef CUR_PATH_SEPARATOR_STR
658#undef PATH_ALLOC_COMBINE
659
660#define DEFINE_UNICODE TRUE
661#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
662#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR_W
663#define PATH_ALLOC_COMBINE UnixPathAllocCombineW
664#include "include/PathAllocCombine.h"
665#undef DEFINE_UNICODE
666#undef CUR_PATH_SEPARATOR_CHR
667#undef CUR_PATH_SEPARATOR_STR
668#undef PATH_ALLOC_COMBINE
669
670/* Native-style Paths */
671
672#define DEFINE_UNICODE FALSE
673#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
674#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR
675#define PATH_ALLOC_COMBINE NativePathAllocCombineA
676#include "include/PathAllocCombine.h"
677#undef DEFINE_UNICODE
678#undef CUR_PATH_SEPARATOR_CHR
679#undef CUR_PATH_SEPARATOR_STR
680#undef PATH_ALLOC_COMBINE
681
682#define DEFINE_UNICODE TRUE
683#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
684#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR_W
685#define PATH_ALLOC_COMBINE NativePathAllocCombineW
686#include "include/PathAllocCombine.h"
687#undef DEFINE_UNICODE
688#undef CUR_PATH_SEPARATOR_CHR
689#undef CUR_PATH_SEPARATOR_STR
690#undef PATH_ALLOC_COMBINE
691
696HRESULT PathCchFindExtensionA(PCSTR pszPath, size_t cchPath, PCSTR* ppszExt)
697{
698 const char* p = (const char*)pszPath;
699
700 if (!pszPath || !cchPath || !ppszExt)
701 return E_INVALIDARG;
702
703 /* find end of string */
704
705 while (*p && --cchPath)
706 {
707 p++;
708 }
709
710 if (*p)
711 {
712 /* pszPath is not null terminated within the cchPath range */
713 return E_INVALIDARG;
714 }
715
716 /* If no extension is found, ppszExt must point to the string's terminating null */
717 *ppszExt = p;
718
719 /* search backwards for '.' */
720
721 while (p > pszPath)
722 {
723 if (*p == '.')
724 {
725 *ppszExt = (PCSTR)p;
726 break;
727 }
728
729 if ((*p == '\\') || (*p == '/') || (*p == ':'))
730 break;
731
732 p--;
733 }
734
735 return S_OK;
736}
737
738HRESULT PathCchFindExtensionW(WINPR_ATTR_UNUSED PCWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
739 WINPR_ATTR_UNUSED PCWSTR* ppszExt)
740{
741 WLog_ERR(TAG, "not implemented");
742 return E_NOTIMPL;
743}
744
749HRESULT PathCchRenameExtensionA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
750 WINPR_ATTR_UNUSED PCSTR pszExt)
751{
752 WLog_ERR(TAG, "not implemented");
753 return E_NOTIMPL;
754}
755
756HRESULT PathCchRenameExtensionW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
757 WINPR_ATTR_UNUSED PCWSTR pszExt)
758{
759 WLog_ERR(TAG, "not implemented");
760 return E_NOTIMPL;
761}
762
767HRESULT PathCchRemoveExtensionA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
768{
769 WLog_ERR(TAG, "not implemented");
770 return E_NOTIMPL;
771}
772
773HRESULT PathCchRemoveExtensionW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
774{
775 WLog_ERR(TAG, "not implemented");
776 return E_NOTIMPL;
777}
778
783BOOL PathCchIsRootA(WINPR_ATTR_UNUSED PCSTR pszPath)
784{
785 WLog_ERR(TAG, "not implemented");
786 return FALSE;
787}
788
789BOOL PathCchIsRootW(WINPR_ATTR_UNUSED PCWSTR pszPath)
790{
791 WLog_ERR(TAG, "not implemented");
792 return FALSE;
793}
794
799BOOL PathIsUNCExA(PCSTR pszPath, PCSTR* ppszServer)
800{
801 if (!pszPath)
802 return FALSE;
803
804 if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
805 {
806 *ppszServer = &pszPath[2];
807 return TRUE;
808 }
809
810 return FALSE;
811}
812
813BOOL PathIsUNCExW(PCWSTR pszPath, PCWSTR* ppszServer)
814{
815 if (!pszPath)
816 return FALSE;
817
818 if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
819 {
820 *ppszServer = &pszPath[2];
821 return TRUE;
822 }
823
824 return FALSE;
825}
826
831HRESULT PathCchSkipRootA(WINPR_ATTR_UNUSED PCSTR pszPath, WINPR_ATTR_UNUSED PCSTR* ppszRootEnd)
832{
833 WLog_ERR(TAG, "not implemented");
834 return E_NOTIMPL;
835}
836
837HRESULT PathCchSkipRootW(WINPR_ATTR_UNUSED PCWSTR pszPath, WINPR_ATTR_UNUSED PCWSTR* ppszRootEnd)
838{
839 WLog_ERR(TAG, "not implemented");
840 return E_NOTIMPL;
841}
842
847HRESULT PathCchStripToRootA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
848{
849 WLog_ERR(TAG, "not implemented");
850 return E_NOTIMPL;
851}
852
853HRESULT PathCchStripToRootW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
854{
855 WLog_ERR(TAG, "not implemented");
856 return E_NOTIMPL;
857}
858
863HRESULT PathCchStripPrefixA(PSTR pszPath, size_t cchPath)
864{
865 BOOL hasPrefix = 0;
866
867 if (!pszPath)
868 return E_INVALIDARG;
869
870 if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
871 return E_INVALIDARG;
872
873 hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
874 (pszPath[3] == '\\'));
875
876 if (hasPrefix)
877 {
878 if (cchPath < 6)
879 return S_FALSE;
880
881 if (IsCharAlpha(pszPath[4]) && (pszPath[5] == ':')) /* like C: */
882 {
883 if (memmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4) < 0)
884 return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
885
886 /* since the passed pszPath must not necessarily be null terminated
887 * and we always have enough space after the strip we can always
888 * ensure the null termination of the stripped result
889 */
890 pszPath[cchPath - 4] = 0;
891 return S_OK;
892 }
893 }
894
895 return S_FALSE;
896}
897
898HRESULT PathCchStripPrefixW(PWSTR pszPath, size_t cchPath)
899{
900 BOOL hasPrefix = 0;
901
902 if (!pszPath)
903 return E_INVALIDARG;
904
905 if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
906 return E_INVALIDARG;
907
908 hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
909 (pszPath[3] == '\\'));
910
911 if (hasPrefix)
912 {
913 if (cchPath < 6)
914 return S_FALSE;
915
916 const size_t rc = (_wcslen(&pszPath[4]) + 1);
917 if (cchPath < rc)
918 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
919
920 if (IsCharAlphaW(pszPath[4]) && (pszPath[5] == L':')) /* like C: */
921 {
922 if (wmemmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4) < 0)
923 return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
924 /* since the passed pszPath must not necessarily be null terminated
925 * and we always have enough space after the strip we can always
926 * ensure the null termination of the stripped result
927 */
928 pszPath[cchPath - 4] = 0;
929 return S_OK;
930 }
931 }
932
933 return S_FALSE;
934}
935
940HRESULT PathCchRemoveFileSpecA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
941{
942 WLog_ERR(TAG, "not implemented");
943 return E_NOTIMPL;
944}
945
946HRESULT PathCchRemoveFileSpecW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
947{
948 WLog_ERR(TAG, "not implemented");
949 return E_NOTIMPL;
950}
951
952/*
953 * Path Portability Functions
954 */
955
960HRESULT PathCchConvertStyleA(PSTR pszPath, size_t cchPath, unsigned long dwFlags)
961{
962 if (dwFlags == PATH_STYLE_WINDOWS)
963 {
964 for (size_t index = 0; index < cchPath; index++)
965 {
966 if (pszPath[index] == PATH_SLASH_CHR)
967 pszPath[index] = PATH_BACKSLASH_CHR;
968 }
969 }
970 else if (dwFlags == PATH_STYLE_UNIX)
971 {
972 for (size_t index = 0; index < cchPath; index++)
973 {
974 if (pszPath[index] == PATH_BACKSLASH_CHR)
975 pszPath[index] = PATH_SLASH_CHR;
976 }
977 }
978 else if (dwFlags == PATH_STYLE_NATIVE)
979 {
980 if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR)
981 {
982 /* Unix-style to Windows-style */
983
984 for (size_t index = 0; index < cchPath; index++)
985 {
986 if (pszPath[index] == PATH_SLASH_CHR)
987 pszPath[index] = PATH_BACKSLASH_CHR;
988 }
989 }
990 else if (PATH_SEPARATOR_CHR == PATH_SLASH_CHR)
991 {
992 /* Windows-style to Unix-style */
993
994 for (size_t index = 0; index < cchPath; index++)
995 {
996 if (pszPath[index] == PATH_BACKSLASH_CHR)
997 pszPath[index] = PATH_SLASH_CHR;
998 }
999 }
1000 else
1001 {
1002 /* Unexpected error */
1003 return E_FAIL;
1004 }
1005 }
1006 else
1007 {
1008 /* Gangnam style? */
1009 return E_FAIL;
1010 }
1011
1012 return S_OK;
1013}
1014
1015HRESULT PathCchConvertStyleW(PWSTR pszPath, size_t cchPath, unsigned long dwFlags)
1016{
1017 if (dwFlags == PATH_STYLE_WINDOWS)
1018 {
1019 for (size_t index = 0; index < cchPath; index++)
1020 {
1021 if (pszPath[index] == PATH_SLASH_CHR_W)
1022 pszPath[index] = PATH_BACKSLASH_CHR_W;
1023 }
1024 }
1025 else if (dwFlags == PATH_STYLE_UNIX)
1026 {
1027 for (size_t index = 0; index < cchPath; index++)
1028 {
1029 if (pszPath[index] == PATH_BACKSLASH_CHR_W)
1030 pszPath[index] = PATH_SLASH_CHR_W;
1031 }
1032 }
1033 else if (dwFlags == PATH_STYLE_NATIVE)
1034 {
1035 if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR_W)
1036 {
1037 /* Unix-style to Windows-style */
1038
1039 for (size_t index = 0; index < cchPath; index++)
1040 {
1041 if (pszPath[index] == PATH_SLASH_CHR_W)
1042 pszPath[index] = PATH_BACKSLASH_CHR_W;
1043 }
1044 }
1045 else if (PATH_SEPARATOR_CHR == PATH_SLASH_CHR_W)
1046 {
1047 /* Windows-style to Unix-style */
1048
1049 for (size_t index = 0; index < cchPath; index++)
1050 {
1051 if (pszPath[index] == PATH_BACKSLASH_CHR_W)
1052 pszPath[index] = PATH_SLASH_CHR_W;
1053 }
1054 }
1055 else
1056 {
1057 /* Unexpected error */
1058 return E_FAIL;
1059 }
1060 }
1061 else
1062 {
1063 /* Gangnam style? */
1064 return E_FAIL;
1065 }
1066
1067 return S_OK;
1068}
1069
1074char PathGetSeparatorA(unsigned long dwFlags)
1075{
1076 if (dwFlags == PATH_STYLE_WINDOWS)
1077 return PATH_BACKSLASH_CHR;
1078 if (dwFlags == PATH_STYLE_UNIX)
1079 return PATH_SLASH_CHR;
1080
1081 return PATH_SEPARATOR_CHR;
1082}
1083
1084WCHAR PathGetSeparatorW(unsigned long dwFlags)
1085{
1086 if (dwFlags == PATH_STYLE_WINDOWS)
1087 return PATH_BACKSLASH_CHR_W;
1088 if (dwFlags == PATH_STYLE_UNIX)
1089 return PATH_SLASH_CHR_W;
1090
1091 return PATH_SEPARATOR_CHR;
1092}
1093
1097static const CHAR SharedLibraryExtensionDllA[] = "dll";
1098static const CHAR SharedLibraryExtensionSoA[] = "so";
1099static const CHAR SharedLibraryExtensionDylibA[] = "dylib";
1100
1101static const CHAR SharedLibraryExtensionDotDllA[] = ".dll";
1102static const CHAR SharedLibraryExtensionDotSoA[] = ".so";
1103static const CHAR SharedLibraryExtensionDotDylibA[] = ".dylib";
1104PCSTR PathGetSharedLibraryExtensionA(unsigned long dwFlags)
1105{
1106 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
1107 {
1108 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1109 {
1110 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1111 return SharedLibraryExtensionDotDllA;
1112
1113 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1114 return SharedLibraryExtensionDotSoA;
1115
1116 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1117 return SharedLibraryExtensionDotDylibA;
1118 }
1119 else
1120 {
1121 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1122 return SharedLibraryExtensionDllA;
1123
1124 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1125 return SharedLibraryExtensionSoA;
1126
1127 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1128 return SharedLibraryExtensionDylibA;
1129 }
1130 }
1131
1132 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1133 {
1134#ifdef _WIN32
1135 return SharedLibraryExtensionDotDllA;
1136#elif defined(__APPLE__)
1137 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1138 return SharedLibraryExtensionDotSoA;
1139 else
1140 return SharedLibraryExtensionDotDylibA;
1141#else
1142 return SharedLibraryExtensionDotSoA;
1143#endif
1144 }
1145 else
1146 {
1147#ifdef _WIN32
1148 return SharedLibraryExtensionDllA;
1149#elif defined(__APPLE__)
1150 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1151 return SharedLibraryExtensionSoA;
1152 else
1153 return SharedLibraryExtensionDylibA;
1154#else
1155 return SharedLibraryExtensionSoA;
1156#endif
1157 }
1158}
1159
1160PCWSTR PathGetSharedLibraryExtensionW(unsigned long dwFlags)
1161{
1162 static WCHAR buffer[6][16] = WINPR_C_ARRAY_INIT;
1163 const WCHAR* SharedLibraryExtensionDotDllW = InitializeConstWCharFromUtf8(
1164 SharedLibraryExtensionDotDllA, buffer[0], ARRAYSIZE(buffer[0]));
1165 const WCHAR* SharedLibraryExtensionDotSoW =
1166 InitializeConstWCharFromUtf8(SharedLibraryExtensionDotSoA, buffer[1], ARRAYSIZE(buffer[1]));
1167 const WCHAR* SharedLibraryExtensionDotDylibW = InitializeConstWCharFromUtf8(
1168 SharedLibraryExtensionDotDylibA, buffer[2], ARRAYSIZE(buffer[2]));
1169 const WCHAR* SharedLibraryExtensionDllW =
1170 InitializeConstWCharFromUtf8(SharedLibraryExtensionDllA, buffer[3], ARRAYSIZE(buffer[3]));
1171 const WCHAR* SharedLibraryExtensionSoW =
1172 InitializeConstWCharFromUtf8(SharedLibraryExtensionSoA, buffer[4], ARRAYSIZE(buffer[4]));
1173 const WCHAR* SharedLibraryExtensionDylibW =
1174 InitializeConstWCharFromUtf8(SharedLibraryExtensionDylibA, buffer[5], ARRAYSIZE(buffer[5]));
1175
1176 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
1177 {
1178 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1179 {
1180 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1181 return SharedLibraryExtensionDotDllW;
1182
1183 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1184 return SharedLibraryExtensionDotSoW;
1185
1186 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1187 return SharedLibraryExtensionDotDylibW;
1188 }
1189 else
1190 {
1191 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1192 return SharedLibraryExtensionDllW;
1193
1194 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1195 return SharedLibraryExtensionSoW;
1196
1197 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1198 return SharedLibraryExtensionDylibW;
1199 }
1200 }
1201
1202 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1203 {
1204#ifdef _WIN32
1205 return SharedLibraryExtensionDotDllW;
1206#elif defined(__APPLE__)
1207 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1208 return SharedLibraryExtensionDotSoW;
1209 else
1210 return SharedLibraryExtensionDotDylibW;
1211#else
1212 return SharedLibraryExtensionDotSoW;
1213#endif
1214 }
1215 else
1216 {
1217#ifdef _WIN32
1218 return SharedLibraryExtensionDllW;
1219#elif defined(__APPLE__)
1220 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1221 return SharedLibraryExtensionSoW;
1222 else
1223 return SharedLibraryExtensionDylibW;
1224#else
1225 return SharedLibraryExtensionSoW;
1226#endif
1227 }
1228}
1229
1230const char* GetKnownPathIdString(int id)
1231{
1232 switch (id)
1233 {
1234 case KNOWN_PATH_HOME:
1235 return "KNOWN_PATH_HOME";
1236 case KNOWN_PATH_TEMP:
1237 return "KNOWN_PATH_TEMP";
1238 case KNOWN_PATH_XDG_DATA_HOME:
1239 return "KNOWN_PATH_XDG_DATA_HOME";
1240 case KNOWN_PATH_XDG_CONFIG_HOME:
1241 return "KNOWN_PATH_XDG_CONFIG_HOME";
1242 case KNOWN_PATH_XDG_CACHE_HOME:
1243 return "KNOWN_PATH_XDG_CACHE_HOME";
1244 case KNOWN_PATH_XDG_RUNTIME_DIR:
1245 return "KNOWN_PATH_XDG_RUNTIME_DIR";
1246 case KNOWN_PATH_SYSTEM_CONFIG_HOME:
1247 return "KNOWN_PATH_SYSTEM_CONFIG_HOME";
1248 default:
1249 return "KNOWN_PATH_UNKNOWN_ID";
1250 }
1251}
1252
1253static char* concat(const char* path, size_t pathlen, const char* name, size_t namelen)
1254{
1255 const size_t strsize = pathlen + namelen + 2;
1256 char* str = calloc(strsize, sizeof(char));
1257 if (!str)
1258 return nullptr;
1259
1260 winpr_str_append(path, str, strsize, "");
1261 winpr_str_append(name, str, strsize, "");
1262 return str;
1263}
1264
1265BOOL winpr_RemoveDirectory_RecursiveA(LPCSTR lpPathName)
1266{
1267 BOOL ret = FALSE;
1268
1269 if (!lpPathName)
1270 return FALSE;
1271
1272 const size_t pathnamelen = strlen(lpPathName);
1273 const size_t path_slash_len = pathnamelen + 3;
1274 char* path_slash = calloc(pathnamelen + 4, sizeof(char));
1275 if (!path_slash)
1276 return FALSE;
1277 strncat(path_slash, lpPathName, pathnamelen);
1278
1279 const char star[] = "*";
1280 const HRESULT hr = NativePathCchAppendA(path_slash, path_slash_len, star);
1281 HANDLE dir = INVALID_HANDLE_VALUE;
1282 if (FAILED(hr))
1283 goto fail;
1284
1285 {
1286 WIN32_FIND_DATAA findFileData = WINPR_C_ARRAY_INIT;
1287 dir = FindFirstFileA(path_slash, &findFileData);
1288
1289 if (dir == INVALID_HANDLE_VALUE)
1290 goto fail;
1291
1292 ret = TRUE;
1293 path_slash[path_slash_len - 1] = '\0'; /* remove trailing '*' */
1294 do
1295 {
1296 const size_t len = strnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName));
1297
1298 if ((len == 1 && findFileData.cFileName[0] == '.') ||
1299 (len == 2 && findFileData.cFileName[0] == '.' && findFileData.cFileName[1] == '.'))
1300 {
1301 continue;
1302 }
1303
1304 char* fullpath = concat(path_slash, path_slash_len, findFileData.cFileName, len);
1305 if (!fullpath)
1306 goto fail;
1307
1308 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1309 ret = winpr_RemoveDirectory_RecursiveA(fullpath);
1310 else
1311 {
1312 WINPR_PRAGMA_DIAG_PUSH
1313 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
1314 ret = winpr_DeleteFile(fullpath);
1315 WINPR_PRAGMA_DIAG_POP
1316 }
1317
1318 free(fullpath);
1319
1320 if (!ret)
1321 break;
1322 } while (ret && FindNextFileA(dir, &findFileData) != 0);
1323 }
1324
1325 if (ret)
1326 {
1327 if (!winpr_RemoveDirectory(lpPathName))
1328 ret = FALSE;
1329 }
1330
1331fail:
1332 FindClose(dir);
1333 free(path_slash);
1334 return ret;
1335}
1336
1337BOOL winpr_RemoveDirectory_RecursiveW(LPCWSTR lpPathName)
1338{
1339 char* name = ConvertWCharToUtf8Alloc(lpPathName, nullptr);
1340 if (!name)
1341 return FALSE;
1342 const BOOL rc = winpr_RemoveDirectory_RecursiveA(name);
1343 free(name);
1344 return rc;
1345}
1346
1347char* winpr_GetConfigFilePathVA(BOOL system, WINPR_FORMAT_ARG const char* filename, va_list ap)
1348{
1349 eKnownPathTypes id = system ? KNOWN_PATH_SYSTEM_CONFIG_HOME : KNOWN_PATH_XDG_CONFIG_HOME;
1350 const char* vendor = winpr_getApplicationDetailsVendor();
1351 const char* product = winpr_getApplicationDetailsProduct();
1352 const SSIZE_T version = winpr_getApplicationDetailsVersion();
1353
1354 if (!vendor || !product)
1355 return nullptr;
1356
1357 char* config = GetKnownSubPathV(id, "%s", vendor);
1358 if (!config)
1359 return nullptr;
1360
1361 char* base = nullptr;
1362 if (version < 0)
1363 base = GetCombinedPathV(config, "%s", product);
1364 else
1365 base = GetCombinedPathV(config, "%s%" PRIdz, product, version);
1366 free(config);
1367
1368 if (!base)
1369 return nullptr;
1370 char* path = GetCombinedPathVA(base, filename, ap);
1371 free(base);
1372
1373 return path;
1374}
1375
1376char* winpr_GetConfigFilePath(BOOL system, const char* filename)
1377{
1378 if (!filename)
1379 return winpr_GetConfigFilePathV(system, "%s", "");
1380 return winpr_GetConfigFilePathV(system, "%s", filename);
1381}
1382
1383char* winpr_GetConfigFilePathV(BOOL system, const char* filename, ...)
1384{
1385 va_list ap = WINPR_C_ARRAY_INIT;
1386 va_start(ap, filename);
1387 char* str = winpr_GetConfigFilePathVA(system, filename, ap);
1388 va_end(ap);
1389 return str;
1390}