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