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